引言:
从天美的王者荣耀引发的测试数据展示到生产环境问题,及目前很多实际情况,需要测试在生产环境进行验证,如何把测试账号的数据从生产环境上过滤掉,但测试又可以在线上进行验证,这确实是个比较头疼的事情,我司也存在类似问题,我这边在进行预演,先说下预演情况,实际还是未真正解决(主要是希望优雅的解决)
方案一--AOP 切面
策略
采用 AOP 切面方式,把对应的 DAO 层文件做切面,把返回结果中过滤掉测试账号 ID
优势
可以指定特定 DAO 文件及特定方法进行处理
劣势
编写规则需要规范
预演代码
package com.finger.test.common.net;
import com.finger.test.pojo.UserAccountDO;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @Des: mybatis结果集拦截器
* @Auther: 飞狐
* @Date: 2018/12/6
*/
public class SelectResultInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable{
String className = methodInvocation.getClass().getName();
String methodName = methodInvocation.getMethod().getName();
Object result = methodInvocation.proceed();
if(className.equals("UserAccountDOMapper")){
if(methodName.startsWith("select")){
UserAccountDO userAccountDO = (UserAccountDO) result;
System.out.println(userAccountDO.getAccountNo());
}
}
return result;
}
}
拦截器 XML 配置
<bean id = "selectResultInterceptor" class="com.finger.test.common.net.SelectResultInterceptor" />
<aop:config>
<aop:pointcut id = "selectResultInterceptorCut" expression="execution(* com.finger.test.dao.*Mapper.*(..))" />
<aop:advisor pointcut-ref="selectResultInterceptorCut" advice-ref="selectResultInterceptor"/>
</aop:config>
方案二--mybatis 拦截器方案
策略
采用 mybatis 拦截器方案,针对 mybatis 底层 query 方法的返回结果进行拦截,过滤测试账号
优势
不区分 DAO 的命名规范,可随意定义
预演代码
package com.finger.test.common.net;
import com.finger.test.pojo.UserAccountDO;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.ArrayList;
import java.util.Properties;
/**
* @Des:
* @Auther: 飞狐
* @Date: 2018/12/6
*/
@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }) })
public class InterceptorQuery implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable{
MappedStatement statement = (MappedStatement)invocation.getArgs()[0];
// statement.getStatementType().
// System.out.println(statement.getSqlSource());
Object result = invocation.proceed();
if(result instanceof ArrayList){
ArrayList resultList = (ArrayList) result;
for(int i = 0; i < resultList.size(); i++){
if(resultList.get(i) instanceof UserAccountDO){
UserAccountDO userAccountDO = (UserAccountDO) resultList.get(i);
if(userAccountDO.getUserId().equals(16904380000L)){
result = null;
}
}
}
}
return result;
}
public Object plugin(Object target){
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties){
}
}
mybatis-config XML 配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局配置参数,需要时再设置 -->
<settings>
<!--<!– 打开延迟加载 的开关 –>-->
<!--<setting name="lazyLoadingEnabled" value="true"/>-->
<!-- 将积极加载改为消极加载即按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启二级缓存 默认也是开启的-->
<setting name="cacheEnabled" value="true"/>
</settings>
<plugins>
<plugin interceptor="com.finger.test.common.net.InterceptorQuery"></plugin>
</plugins>
</configuration>
方案三 -- 自定义注解形式处理
说明
在对应的 DAO 层添加注解,在执行 sql 语句前,在注解层添加过滤测试账号的数据到 sql,生成新的 sql 语句进行执行
目前暂未预演此代码
方案四 -- 最不优雅的方式
说明
把测试账号统一写入到 redis,业务层把原账号 ID 输入到该方法中,返回过滤结果的 ID 列表
弊端
不用说,业务调用的地方太多,代码看起来非常冗余
综合考虑以上四种方式
还是无法解决,部分接口,可能是不想过滤测试账号,部分接口又是要过滤测试账号,又想代码优雅的情况
- 前面 2 种是一刀切方案,但好处是无感知;
- 第三种方案可能会让开发重新写一个一摸一样的 DAO 层方法,从而区别是否过滤测试账号,在已有的业务上增加,也是较大的工作量
- 第四种方案就不多说了,谁都看到是最笨的方案了
也想知道下其他同学有没好的方案建议
转载文章时务必注明原作者及原始链接,并注明「发表于 TesterHome 」,并不得对作品进行修改。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!