错误是不可避免的,但是不要重复错误——周恩来
首先贴成品链接:https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/275
使用方式:
在你的vo
或者po/do
上添加注解@Desensitization
可指定预设类型type
为:cn.hutool.core.util.DesensitizedUtil.DesensitizedType
例如
@Desensitization(type = DesensitizedUtil.DesensitizedType.EMAIL) private String email;
也可自定义正则表达式
@Desensitization(regex = "(?<=\\d{3})\\d(?=\\d{4})") private String mobile;
还可以自定义处理器进行处理
@Desensitization(handler = MyDesensitizedHandler.class) private String myField;
MyDesensitizedHandler
实现cn.iocoder.yudao.framework.desensitization.core.handler.DesensitizationHandler
即可
主要代码是这个拦截器:
package cn.iocoder.yudao.framework.desensitization.interceptor; import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ReflectUtil; import cn.iocoder.yudao.framework.desensitization.core.annotation.Desensitization; import cn.iocoder.yudao.framework.desensitization.core.handler.DesensitizationHandler; import com.baomidou.mybatisplus.core.toolkit.Constants; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.update.Update; import org.apache.ibatis.binding.MapperMethod; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.Statement; import java.util.Collection; import java.util.Objects; import java.util.Properties; /** * @author VampireAchao * @since 2022/10/6 11:24 */ @Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})) public class DesensitizationInterceptor extends JsqlParserSupport implements InnerInterceptor, Interceptor { /** * {@link StatementHandler#prepare(Connection, Integer)} 操作前置处理 * <p> * 改改sql啥的 * * @param sh StatementHandler(可能是代理对象) * @param connection Connection * @param transactionTimeout transactionTimeout */ @Override public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); MappedStatement ms = mpSh.mappedStatement(); SqlCommandType sct = ms.getSqlCommandType(); if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE) { PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); mpBs.sql(parserMulti(mpBs.sql(), mpBs)); } } @Override public void setProperties(Properties properties) { InnerInterceptor.super.setProperties(properties); } /** * 更新 * * @param update * @param index * @param sql * @param obj */ @Override protected void processUpdate(Update update, int index, String sql, Object obj) { if (!(obj instanceof PluginUtils.MPBoundSql)) { return; } PluginUtils.MPBoundSql boundSql = (PluginUtils.MPBoundSql) obj; Object parameterObject = boundSql.parameterObject(); if (!(parameterObject instanceof MapperMethod.ParamMap<?>)) { return; } MapperMethod.ParamMap<?> paramMap = (MapperMethod.ParamMap<?>) parameterObject; Object entity = paramMap.get(Constants.ENTITY); if (!Objects.nonNull(entity)) { return; } processDesensitization(entity); } /** * 新增 * * @param insert * @param index * @param sql * @param obj */ @Override protected void processInsert(Insert insert, int index, String sql, Object obj) { if (!(obj instanceof PluginUtils.MPBoundSql)) { return; } PluginUtils.MPBoundSql boundSql = (PluginUtils.MPBoundSql) obj; Object entity = boundSql.parameterObject(); processDesensitization(entity); } private void processDesensitization(Object entity) { for (Field field : ReflectUtil.getFields(entity.getClass())) { if (!field.isAnnotationPresent(Desensitization.class)) { continue; } Desensitization desensitization = field.getAnnotation(Desensitization.class); Object fieldValue = ReflectUtil.getFieldValue(entity, field); Opt.ofBlankAble(fieldValue).map(Object::toString).ifPresent(value -> { DesensitizationHandler desensitizationHandler = ReflectUtil.newInstance(desensitization.handler()); String newValue = desensitizationHandler.apply(value, desensitization); ReflectUtil.setFieldValue(entity, field, newValue); }); } } @Override public Object intercept(Invocation invocation) throws Throwable { Object proceed = invocation.proceed(); if (Collection.class.isAssignableFrom(proceed.getClass())) { Collection<?> collection = (Collection<?>) proceed; collection.forEach(this::processDesensitization); } return proceed; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } }
po
:
package cn.iocoder.yudao.module.pojo.po; import cn.hutool.core.util.DesensitizedUtil; import cn.iocoder.yudao.framework.desensitization.core.annotation.Desensitization; import lombok.Builder; import lombok.Data; import lombok.experimental.Tolerate; /** * @author VampireAchao * @since 2022/10/6 15:19 */ @Data @Builder public class UserInfo { @Tolerate public UserInfo() { // this is an accessible parameterless constructor. } private Long id; private String name; @Desensitization(type = DesensitizedUtil.DesensitizedType.EMAIL) private String email; @Desensitization(regex = "(?<=\\d{3})\\d(?=\\d{4})") private String mobile; }
单元测试:
package cn.iocoder.yudao.module; import cn.iocoder.yudao.framework.desensitization.config.YudaoDesensitizationAutoConfiguration; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.pojo.po.UserInfo; import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import org.springframework.test.context.jdbc.Sql; /** * @author VampireAchao * @since 2022/10/6 15:11 */ @Import(YudaoDesensitizationAutoConfiguration.class) @Sql(scripts = "/sql/insert_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) // 每个单元测试结束前,新增 DB class DesensitizationTest extends BaseDbUnitTest { @Test void testQuery() { UserInfo userInfo = SqlHelper.execute(UserInfo.class, m -> m.selectById(1L)); Assertions.assertEquals("123****8910", userInfo.getMobile()); Assertions.assertEquals("a**************@gmail.com", userInfo.getEmail()); } @Test void testUpdate() { UserInfo userInfo = UserInfo.builder().id(1L).mobile("12345678910").email("achao1441470436@gmail.com").build(); SqlHelper.execute(UserInfo.class, m -> m.updateById(userInfo)); Assertions.assertEquals("123****8910", userInfo.getMobile()); Assertions.assertEquals("a**************@gmail.com", userInfo.getEmail()); } @Test void testSave() { UserInfo userInfo = UserInfo.builder().name("张三").mobile("12345678910").email("achao1441470436@gmail.com").build(); SqlHelper.execute(UserInfo.class, m -> m.insert(userInfo)); Assertions.assertEquals("123****8910", userInfo.getMobile()); Assertions.assertEquals("a**************@gmail.com", userInfo.getEmail()); } }