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的注解式,更加灵活多变,不使用不加注解就行,而实现MybatisTypeHandler,每次都需要再SQLResultMap映射上添加,有很大的误伤可能
posted @   unknown-n2  阅读(335)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示

目录导航