业务场景:在后期的运维掩护中,创造创建人在业务表中利用的不是 创建人ID 或 创建人名称,而是利用的是 账号名,而 账号名虽说是唯一的,但全是英文/拼音存储的不知足业务需求,业务需求是须要现在是用户的姓名,你说这……是不是很无语呢?
当然有人会说了,为了查询方便,插入的时候就该当改动过来,然后做一下数据梳理,将数据库的数据找个空闲韶光讲创建人ID/创建人账号名处理成存为创建人名称,你说这是不是很好?好好好,当然好,但不是本文的谈论的重点哦
本文谈论重点:基于已运行的系统在查询的时候做一些处理的几种方法。如果有兴趣可以连续理解,欢迎评论磋商!

文章解释:文章只谈论实现思路,不做详细完全的实现案例展示。
零、数据库数据准备(1)字典表(sys_dict)CREATE TABLE `sys_dict` ( `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `type` varchar(100) DEFAULT NULL, `description` varchar(100) DEFAULT NULL, `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建韶光', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新韶光', `remarks` varchar(255) DEFAULT NULL, `system` char(1) DEFAULT '0', `del_flag` char(1) DEFAULT '0', PRIMARY KEY (`id`) USING BTREE, KEY `sys_dict_del_flag` (`del_flag`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='字典表';-- 添加测试数据INSERT INTO pig.sys_dict (`type`,description,create_time,update_time,remarks,`system`,del_flag) VALUES ('dict_type','字典类型','2019-05-16 14:16:20','2019-05-16 14:20:16','系统类不能修正','1','0'), ('log_type','日志类型','2020-03-13 14:21:01','2020-03-13 14:21:01','0-正常 1 非常','1','0');
(2)字典值表(sys_dict_item)
CREATE TABLE `sys_dict_item` ( `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `dict_id` int(11) NOT NULL, `value` varchar(100) DEFAULT NULL, `label` varchar(100) DEFAULT NULL, `type` varchar(100) DEFAULT NULL, `description` varchar(100) DEFAULT NULL, `sort` int(10) NOT NULL DEFAULT '0' COMMENT '排序(升序)', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建韶光', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新韶光', `remarks` varchar(255) DEFAULT NULL, `del_flag` char(1) DEFAULT '0', PRIMARY KEY (`id`) USING BTREE, KEY `sys_dict_value` (`value`) USING BTREE, KEY `sys_dict_label` (`label`) USING BTREE, KEY `sys_dict_del_flag` (`del_flag`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='字典项';-- 添加测试数据字典值项目INSERT INTO pig.sys_dict_item (dict_id,value,label,`type`,description,sort,create_time,update_time,remarks,del_flag) VALUES (1,'1','系统类','dict_type','系统类字典',0,'2019-05-16 14:20:40','2019-05-16 14:20:40','不能修正删除','0'), (1,'0','业务类','dict_type','业务类字典',0,'2019-05-16 14:20:59','2019-05-16 14:20:59','可以修正','0'), (2,'0','正常','log_type','正常',0,'2020-03-13 14:23:22','2020-03-13 14:23:22','正常','0'), (2,'9','非常','log_type','非常',1,'2020-03-13 14:23:35','2020-03-13 14:23:35','非常','0');
(3)业务表:系统日志
CREATE TABLE `sys_log` ( `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '编号', `type` char(1) DEFAULT '1' COMMENT '日志类型', `title` varchar(255) DEFAULT '' COMMENT '日志标题', `service_id` varchar(32) DEFAULT NULL COMMENT '做事ID', `create_by` varchar(64) DEFAULT NULL COMMENT '创建者', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建韶光', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新韶光', `remote_addr` varchar(255) DEFAULT NULL COMMENT '操作IP地址', `user_agent` varchar(1000) DEFAULT NULL COMMENT '用户代理', `request_uri` varchar(255) DEFAULT NULL COMMENT '要求URI', `method` varchar(10) DEFAULT NULL COMMENT '操作办法', `params` text COMMENT '操作提交的数据', `time` mediumtext COMMENT '实行韶光', `del_flag` char(1) DEFAULT '0' COMMENT '删除标记', `exception` text COMMENT '非常信息', PRIMARY KEY (`id`), KEY `sys_log_create_by` (`create_by`), KEY `sys_log_request_uri` (`request_uri`), KEY `sys_log_type` (`type`), KEY `sys_log_create_date` (`create_time`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='日志表';-- 测试业务日志表数据插入INSERT INTO pig.sys_log (`type`,title,service_id,create_by,create_time,update_time,remote_addr,user_agent,request_uri,`method`,params,`time`,del_flag,`exception`) VALUES ('0','添加角色','pig','admin','2021-06-04 10:43:05',NULL,'127.0.0.1','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.37','/role','POST','','6','0',NULL);
一、数据库SQL直接联查更换
-- 办法一,直接查询的时候处理select id , (select label from sys_dict_item sdi where `type` = 'log_type' and sdi.value = sl.`type`) as logLabelfrom sys_log sl ;-- 办法二,关联查询1select sl.id, sdi.label as logLabelfrom sys_log sl left join sys_dict_item sdi on sl.`type` = sdi.value and sdi.`type` = 'log_type' ;-- 办法三:关联查询2select id, sdit.label as logLabelfrom sys_log sl left join (select value, label from sys_dict_item sdi where sdi.`type` = 'log_type') as sdit on sl.`type` = sdit.value
二、mybatis XML 文件 typyHandler 更换处理
自定义一个类型转换器,处理数据更换问题。
(1)创建一个自定义的TypeHandlerimport org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class YesNoTypeHandler extends BaseTypeHandler<Boolean> { // 从 ResultSet 读取数据并转换为 Java 类型 @Override public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException { String value = rs.getString(columnName); return "Y".equalsIgnoreCase(value); } @Override public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String value = rs.getString(columnIndex); return "Y".equalsIgnoreCase(value); } @Override public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String value = cs.getString(columnIndex); return "Y".equalsIgnoreCase(value); } // 将 Java 类型转换为数据库类型 @Override public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter ? "Y" : "N"); } // 指定该处理器处理的 Java 类型 @Override public Class<Boolean> getRawType() { return Boolean.class; } // 指定该处理器处理的 JDBC 类型(可选) @Override public JdbcType getJdbcType() { return JdbcType.VARCHAR; } }
(2)mybatis-config.xml 中配置 或者 SpringBoot 配置类型转换器存放目录包
<typeHandlers> <typeHandler handler="com.example.YesNoTypeHandler" javaType="java.lang.Boolean" jdbcType="VARCHAR"/> </typeHandlers>
@MapperScan(basePackages = "com.example.mapper", typeHandlersPackage = "com.example.typehandler") @SpringBootApplication public class YourApplication { // ... }
(3)XML 中对应字段配置
<resultMap id="yourResultMap" type="com.example.YourEntity"> <id property="id" column="id" /> <result property="isActive" column="active_flag" typeHandler="com.example.YesNoTypeHandler" /> <!-- 其他字段... --> </resultMap>
三、Spring Boot 内置 Jackson 序列化处理(1)准备序列化处理类
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; @Component@RequiredArgsConstructor // Lombok 的布局器注入public class UserNameSensitiveDataSerializer extends JsonSerializer<String> { // 业务处理 private final SysUserPlusService userPlusService; @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { //if (isSensitiveData(value)) { // 假设这是一个检讨数据是否敏感的方法 // gen.writeString(""); // 利用占位符更换敏感数据 //} else { // gen.writeString(value); //} gen.writeString(this.handleUserName(s));// 须要处理更换的业务逻辑 } //private boolean isSensitiveData(String value) { // // 实现你的敏感数据检讨逻辑 // return false; //} private String handleUserName(String userName) { return Optional.ofNullable(this.userPlusService.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, userName))) .orElse(new SysUser()).getName(); }}
(2)利用此序列化器
public class UserDTO { // ... 其他字段 ... @JsonSerialize(using = UserNameSensitiveDataSerializer.class) private String password; // ... getter和setter ... }
四、前端要求自动映射查询
前端读取所有的字典数据缓存于前端,然后须要的业务表格中,从缓存的数据获取匹配即可。(缓存的数据如果调度了,可以通过标记奉告前端重新更新缓存数据。)
五、其他方法利用AOP 框架(如 Spring AOP):在数据序列化之前拦截它;然后再 切面中检讨数据并处理;利用过滤器或者拦截器:在Web运用程序中,利用过滤器或拦截器在相应发送到客户端之前拦截它。修正相应体中的JSON数据,以更换(或删除敏感)信息。利用 DTO 或者 对应每个接口须要处理的时候通过逻辑更换处理。(比如:先将所有的字典值数据存入缓存(redis/cache/memcache等)中,然后给个公共的查询更换方法,在每个业务接口中更换数据)