Mybatis自定义TypeHandler完成字段加解密And枚举数据处理
Mybatis自定义TypeHandler完成字段加解密And枚举数据处理
新增And查询对枚举数据处理
定义枚举
@Getter public enum UserEnum { HOLD_A_POST("在职", 10), RESIGN("离职", 20); private String name; private Integer value; UserEnum(String name, Integer value) { this.name = name; this.value = value; } /** * <P>根据状态码返回UserEnum对象</P> */ public static UserEnum getEnumByValue(Integer value) { return switch (value) { case 10 -> HOLD_A_POST; case 20 -> RESIGN; default -> null; }; } }
处理对象User
- 处理对象中包含
UserEnum
并给与默认值
@Data public class User implements Serializable { @Serial private static final long serialVersionUID = 123456789L; private Long id; private Integer age; private String username; private String email; private String did; private Dept dept; private UserEnum userEnum =UserEnum.RESIGN; }
UserMapp.xml
-
以下解释在加解密字段时会用上
-
在
ResultMap
标签中的查询映射字段age
添加typeHandler
,在查询时对字段解密typeHandler
: 自定义ypeHandler
的项目路径
-
#{user.age,typeHandler="com.unknown.c.MyUserEnumTypeHandler}
在新增时对age
字段加密
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.unknown.c.base.UserMapper"> <resultMap id="userResultMapper" type="com.unknown.c.base.User"> <result column="id" property="id"/> <result column="age" property="age" typeHandler="com.unknown.c.MyUserEnumTypeHandler"/> <result column="username" property="username"/> <result column="email" property="email"/> <result column="did" property="did"/> <result column="user_enum" property="userEnum"/> </resultMap> <select id="findById" resultMap="userResultMapper"> select * from user u where id = ${id} </select> <insert id="InsertUserAndEnum" useGeneratedKeys="true" keyProperty="id"> insert into user value (null, #{user.age,typeHandler="com.unknown.c.MyUserEnumTypeHandler}, #{user.username}, # {user.email}, #{user.did},#{user.userEnum"}) </insert> </mapper>
自定义TypeHandler
- 处理User对象中的枚举类型
package com.unknown.c; import com.unknown.c.base.UserEnum; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * @author unknown * @since 2023/10/15 15:40 * TypeHandler<UserEnum>: TypeHandler处理的类型需要处理的类型 */ public class MyUserEnumTypeHandler implements TypeHandler<UserEnum> { /** * <P>对枚举的处理</P> * @param ps PreparedStatement对象 * @param i * @param userEnum 枚举参数 * @param jdbcType jdbcType * @throws SQLException */ @Override public void setParameter(PreparedStatement ps, int i, UserEnum userEnum, JdbcType jdbcType) throws SQLException { // 获取userEnum的value值 ps.setString(i,userEnum.getValue().toString()); } /** * <P>根据列名从返回结果中获取数据</P> * @param resultSet 返回结果 * @param columnName 列名 * @return UserEnum */ @Override public UserEnum getResult(ResultSet resultSet, String columnName) throws SQLException { // 根据字段获取值 int value = resultSet.getInt(columnName); return UserEnum.getEnumByValue(value); } /** * <P>根据索引从返回结果中获取数据</P> * @param resultSet 返回结果 * @param columnIndex 索引 * @return UserEnum */ @Override public UserEnum getResult(ResultSet resultSet, int columnIndex) throws SQLException { int value = resultSet.getInt(columnIndex); System.out.println("从数据库获取的状态: " + value ); return UserEnum.getEnumByValue(value); } /** * <P>从存储过程中获取数据</P> * @param cs 存储过程 * @param columnIndex 索引 * @return UserEnum */ @Override public UserEnum getResult(CallableStatement cs, int columnIndex) { return null; } }
注册自定义TypeHandler
-
properties
配置文件-
mybatis.type-handlers-package=com.unknown.c.MyUserEnumTypeHandler
-
-
yml
配置文件-
mybatis: type-handlers-package: com.unknown.c.MyUserEnumTypeHandler
-
-
mybatis-config.xml
配置文件-
<typeHandlers> <typeHandler handler="com.unknown.c.MyUserEnumTypeHandler" javaType="com.unknown.c.base.UserEnum"/> </typeHandlers>
-
测试结果
-
新增
@Test public void InsertUserAndEnumTest() throws IOException { // 读取Mybatis配置文件 InputStream resourceAsStream = getResourceAsStream("mybatis-config.xml"); // 构建SqlSessionFactorBean对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获取SqlSession.设置自动提交数据 SqlSession sqlSession = sqlSessionFactory.openSession(true); // 获取Mapper接口对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setAge(11); user.setUsername("111"); user.setEmail("1111"); user.setDid("1"); /** * 如不自定义TypeHandler,数据库中存储的将是 HOLD_A_POST 化的字符串 * 如果将User中的 UserEnum 枚举变为Long或者int类型,可以 user.setUserEnum(UserEnum.HOLD_A_POST.getValue()).但UserEnum必须有get方法 */ user.setUserEnum(UserEnum.HOLD_A_POST); mapper.InsertUserAndEnum(user); System.out.println("数据库中自增的ID:"+user.getId()); } -
结果验证
- 如下图所示,红色框框中的是在没有对枚举字段进行处理,在新增中直接添加到是HOLD_A_POST化的字符串
- 橘色框框中的是自定义
TypeHandle
后,在TypeHandle
取出枚举的value
进行存储
-
查询
@Test public void findByIdTest() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User byId = mapper.findById(50); System.out.println("统计当前用户ID=2: "+byId); } -
结果验证
- 在下图所示,
ID=50
的数据在数据库中是10,对应的枚举字段HOLD_A_POST
,图片显示RESIGN
是笔者出了个bug。现笔记已修复。不影响此段笔记的正常使用
- 在下图所示,
总结
- 笔者突发奇想,在小型项目(例如自己的博客网站)中,完全可以使用枚举代替数据字典。
字段加解密
自定义TypeHandler
- 笔者在此并没有做什么加密操作,只是拿到字段做了一个字符串拼接。
package com.unknown.c; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * <P>自定义TypeHandler完成加解密</P> * @author unknown * @since 2023/10/16 11:05 * TypeHandler<String>: 处理String类型的字段 */ public class MyTypeHandlerEncryption implements TypeHandler<String> { @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { String username="加密字段"+parameter; ps.setString(i,username); } @Override public String getResult(ResultSet rs, String columnName) throws SQLException { String string = rs.getString(columnName)+"解密字段"; return string; } @Override public String getResult(ResultSet rs, int columnIndex) throws SQLException { return null; } @Override public String getResult(CallableStatement cs, int columnIndex) throws SQLException { return null; } }
注册自定义TypeHandler
-
properties
配置文件-
mybatis.type-handlers-package=com.unknown.c.MyTypeHandlerEncryption
-
-
yml
配置文件-
mybatis: type-handlers-package: com.unknown.c.MyTypeHandlerEncryption
-
-
mybatis-config.xml
配置文件-
<typeHandlers> <typeHandler handler="com.unknown.c.MyTypeHandlerEncryption"/> </typeHandlers>
-
UserMapper.xml
typeHandler="com.unknown.c.MyUserEnumTypeHandler"
: 查询时解密typeHandler=com.unknown.c.MyTypeHandlerEncryption
: 新增是加密
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.unknown.c.base.UserMapper"> <resultMap id="findByIdEncryptionMap" type="com.unknown.c.base.User"> <result column="id" property="id"/> <result column="age" property="age"/> <result column="username" property="username" typeHandler="com.unknown.c.MyTypeHandlerEncryption"/> <result column="email" property="email"/> <result column="did" property="did"/> <result column="user_enum" property="userEnum"/> </resultMap> <select id="findByIdEncryption" resultMap="findByIdEncryptionMap"> select id,age,username,email,did,user_enum from user u where id = ${id} </select> <insert id="insertEncryption" useGeneratedKeys="true" keyProperty="id"> insert into user value (null, #{user.age}, #{user.username,typeHandler=com.unknown.c.MyTypeHandlerEncryption}, #{user.email}, #{user.did}, #{user.userEnum}) </insert> </mapper>
新增代码
/** * <P>新增加密测试</P> * 参阅: {@link MyTypeHandlerEncryption} */ @Test public void insertEncryption() throws IOException { // 读取Mybatis配置文件 InputStream resourceAsStream = getResourceAsStream("mybatis-config.xml"); // 构建SqlSessionFactorBean对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); // 获取SqlSession.设置自动提交数据 SqlSession sqlSession = sqlSessionFactory.openSession(true); // 获取Mapper接口对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setAge(11); user.setUsername("111"); user.setEmail("1111"); user.setDid("1"); user.setUserEnum(UserEnum.HOLD_A_POST); mapper.insertEncryption(user); System.out.println("数据库中自增的ID:"+user.getId()); }
-
添加结果
- 在控制台中可以看到
TypeHandler
成功的执行
- 在控制台中可以看到
查询代码
/** * <P>查询解密测试</P> * @throws IOException */ @Test public void findByIdEncryption() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User byId = mapper.findByIdEncryption(51); System.out.println("统计当前用户ID=50: "+byId); }
-
查询结果
- 成功的改变了原本的数据,但数据库中的字段值并没有变
总结
- 相对于这种加解密方法,笔者更喜欢
Jackson
的注解式,更加灵活多变,不使用不加注解就行,而实现Mybatis
的TypeHandler
,每次都需要再SQL
和ResultMap
映射上添加,有很大的误伤可能
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端