Mybatis自定义类型转换,数据加密解密全攻略【实战

2023年 10月 6日 74.5k 0

环境:springboot2.6.12 + MyBatis3.5.6 + MySQL

MyBatis是一种优秀的持久层框架,它支持自定义类型转换和数据加密解密。通过自定义类型转换,你可以轻松地将数据库中的数据类型转换为Java对象中的数据类型,以及将Java对象中的数据类型转换为数据库中的数据类型。而数据加密解密则可以提高数据的安全性,保护敏感信息不被泄露。在MyBatis中,你可以使用类型处理器(TypeHandler)来实现自定义类型转换,使用加密和解密算法来实现数据加密解密。

本案例使用自定义类型转换器对数据列进行加解密

1. 依赖及相关配置


  
    org.springframework.boot
    spring-boot-starter-web
  
  
    org.springframework.boot
    spring-boot-starter-data-jpa
  
  
    mysql
    mysql-connector-java
    runtime
  
  
    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.1.4
  
  
    com.github.pagehelper
    pagehelper-spring-boot-starter
    1.3.0
  
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/testjpa?serverTimezone=GMT%2B8
    username: root
    password: xxxxx
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimumIdle: 10
      maximumPoolSize: 200
      autoCommit: true
      idleTimeout: 30000
      poolName: MasterDatabookHikariCP
      maxLifetime: 1800000
      connectionTimeout: 30000
      connectionTestQuery: SELECT 1
---
spring:
  jpa:
    generateDdl: false
    hibernate:
      ddlAuto: update
    openInView: true
    show-sql: true
---
pagehelper:
  helperDialect: mysql
  reasonable: true
  pageSizeZero: true
  offsetAsPageNum: true
  rowBoundsWithCount: true
---
mybatis:
  type-aliases-package: com.pack.domain
  mapper-locations:
  - classpath:/mappers/*.xml
  configuration:
    lazy-loading-enabled: true
    aggressive-lazy-loading: false
---
logging:
  level:
    com.pack.mapper: debug

实体对象

@Entity
@Table(name = "BC_PERSON")
public class Person extends BaseEntity {
  private String name ;
  private String idNo ;
}

这里是用JPA来帮助我们生成数据表。

2. 自定义类型转换器及数据加解密工具

public class EncryptTypeHandler implements TypeHandler {
  @Override
  public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, EncryptUtils.encrypt(parameter)) ;
  }
  @Override
  public String getResult(ResultSet rs, String columnName) throws SQLException {
    String value = rs.getString(columnName) ;
    if (value == null || value.length() == 0) {
      return null ;
    }
    return EncryptUtils.decrypt(value);
  }


  @Override
  public String getResult(ResultSet rs, int columnIndex) throws SQLException {
    String value = rs.getString(columnIndex) ;
    if (value == null || value.length() == 0) {
      return null ;
    }
    return EncryptUtils.decrypt(value);
  }


  @Override
  public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
    String value = cs.getString(columnIndex) ;
    if (value == null || value.length() == 0) {
      return null ;
    }
    return EncryptUtils.decrypt(value);
  }
}

加解密工具类

public class EncryptUtils {


  private static final String secretKey = "1111222244445555" ;
  private static final String ALGORITHM  = "AES" ;


  public static String encrypt(String data) {
    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding") ;
      cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getBytes(), ALGORITHM)) ;
      return Hex.encode(cipher.doFinal(data.getBytes())) ;
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
      e.printStackTrace();
      return null ;
    }
  }


  public static String decrypt(String secretText) {
    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding") ;
      cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey.getBytes(), ALGORITHM)) ;
      return new String(cipher.doFinal(Hex.decode(secretText))) ;
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
      e.printStackTrace();
      return null ;
    }
  }


  private static class Hex {


    private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };


    public static byte[] decode(CharSequence s) {
      int nChars = s.length();
      if (nChars % 2 != 0) {
        throw new IllegalArgumentException("16进制数据错误");
      }
      byte[] result = new byte[nChars / 2];
      for (int i = 0; i < nChars; i += 2) {
        int msb = Character.digit(s.charAt(i), 16);
        int lsb = Character.digit(s.charAt(i + 1), 16);
        if (msb < 0 || lsb > 4]).append(HEX[buf[i] & 0x0F]) ;
      }
      return sb.toString() ;
    }


  }


}

Mapper及XML文件

@Mapper
public interface PersonMapper {
  List queryPersons() ;


  int insertPerson(Person person) ;
}

  
    
    
    
    
  
  
    SELECT * FROM bc_person
  
  
    insert into bc_person (id, name, id_no, create_time) values (#{id}, #{name}, #{idNo, typeHandler=com.pack.mybatis.EncryptTypeHandler}, #{createTime})
  

查询数据时在resultMap中的result中配置typeHandler="com.pack.mybatis.EncryptTypeHandler",指明该列的类型转换。

在insert中对具体的列进行指明类型转换。

3. 测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootComprehensiveApplicationTests {


  @Resource
  private PersonMapper personMapper ;
  @Test
  public void testInsertMapper() {
    com.pack.domain.Person person = new com.pack.domain.Person() ;
    person.setId("0001") ;
    person.setCreateTime(new Date()) ;
    person.setIdNo("111111") ;
    person.setName("中国") ;
    personMapper.insertPerson(person) ;
  }
  @Test
  public void testQueryUers() {
    System.out.println(personMapper.queryPersons()) ;
  }
}

图片图片

插入数据时数据已经被我们自定义的类型转换器进行了加密处理。

图片图片

查询数据进行了解密处理。

完毕!!!

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论