JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

Java开发中常见的几种替换字典值替换的方法,你会几招?

wys521 2024-11-04 15:37:31 精选教程 19 ℃ 0 评论

前提引入:「开发思路」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 ...  
}

四、前端请求自动映射查询

前端读取所有的字典数据缓存于前端,然后需要的业务表格中,从缓存的数据获取匹配即可。(缓存的数据如果调整了,可以通过标记告知前端重新更新缓存数据。)

五、其他方法

  1. 使用AOP 框架(如 Spring AOP):
    1. 在数据序列化之前拦截它;
    2. 然后再 切面中检查数据并处理;
  2. 使用过滤器或者拦截器:
    1. 在Web应用程序中,使用过滤器或拦截器在响应发送到客户端之前拦截它。
    2. 修改响应体中的JSON数据,以替换(或删除敏感)信息。
  3. 使用 DTO 或者 对应每个接口需要处理的时候通过逻辑替换处理。(比如:先将所有的字典值数据存入缓存(redis/cache/memcache等)中,然后给个公共的查询替换方法,在每个业务接口中替换数据)

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表