网站首页 > 精选教程 正文
前提引入:「开发思路」Java 开发中你是如何处理字典值释义的?
业务场景:在后期的运维维护中,发现创建人在业务表中使用的不是 创建人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 logLabel
from sys_log sl ;
-- 方式二,关联查询1
select
sl.id
, sdi.label as logLabel
from sys_log sl
left join sys_dict_item sdi on sl.`type` = sdi.value and sdi.`type` = 'log_type' ;
-- 方式三:关联查询2
select id
, sdit.label as logLabel
from 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)创建一个自定义的TypeHandler
import 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等)中,然后给个公共的查询替换方法,在每个业务接口中替换数据)
- 上一篇: 如何从业务测试过渡到测试开发呢?
- 下一篇: 面向测试人员的 Java:完整的分步指南
猜你喜欢
- 2024-11-04 使用JavaSnoop测试Java应用程序 java怎么测试程序
- 2024-11-04 java开发中常见编译报错和解决举例汇总
- 2024-11-04 Java单元测试技巧之JSON序列化 json序列化是什么意思
- 2024-11-04 2022最全java面试题及答案(208道)你能坚持到哪一道呢?
- 2024-11-04 Java 接口改造:UserTest 变 BaseTest,一键重构搞定
- 2024-11-04 自动化测试、回归测试平台调研,基于流量回放
- 2024-11-04 测试开发java常见面试题_Java常见面试题
- 2024-11-04 JAVA考试真题测试 java试题百度文库
- 2024-11-04 使用Jtest 2022.2简化严格的Java测试
- 2024-11-04 如何用TestNG进行java单元测试? java怎么单元测试
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)