Implementing a MyBatis Encryption/Decryption Plugin for Sensitive Data in Java
This article explains how to protect user‑sensitive information such as ID numbers and phone numbers by encrypting data before insertion and decrypting after retrieval using a MyBatis interceptor that leverages custom annotations, AES utilities, and minimal code intrusion.
Problem
In a project, user‑sensitive data such as identification numbers and phone numbers must be masked by encrypting before storing in the database.
Solution Overview
Two approaches are discussed: directly encrypt/decrypt in each service method (high code intrusion) and a cleaner method using a MyBatis interceptor that handles encryption on parameter setting and decryption on result processing.
MyBatis Plugin Principle
The plugin works via MyBatis Interceptor and can intercept four core objects; the diagram is omitted.
Implementation Details
Encryption/decryption is applied to ParameterHandler and ResultSetHandler . The ParameterInterceptor encrypts fields annotated with @EncryptTransaction or classes annotated with @SensitiveData before the SQL is executed. The ResultSetInterceptor decrypts fields after query results are returned.
Utility interfaces IEncryptUtil and IDecryptUtil define generic encrypt and decrypt methods. Concrete implementations use DBAESUtil , which performs AES/CBC/PKCS5Padding encryption with a static key and IV.
Annotations:
@SensitiveData marks a class for scanning.
@EncryptTransaction marks a field or method parameter for encryption.
Usage Example
Annotate an entity class with @SensitiveData and the fields that need encryption with @EncryptTransaction . Alternatively, annotate mapper method parameters directly.
All code snippets are provided in the original source.
import java.lang.annotation.*;
/**
* 该注解定义在类上
* 插件通过扫描类对象是否包含这个注解来决定是否继续扫描其中的字段注解
* 这个注解要配合EncryptTransaction注解
*/
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveData {
} import java.lang.annotation.*;
/**
* 该注解有两种使用方式
* ①:配合@SensitiveData加在类中的字段上
* ②:直接在Mapper中的方法参数上使用
*/
@Documented
@Inherited
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptTransaction {
} package sicnu.cs.ich.common.util.keyCryptor;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class DBAESUtil {
private static final String DEFAULT_V = "6859505890402435";
private static final String KEY = "***"; // replace with your key
private static final String ALGORITHM = "AES";
private static SecretKeySpec getKey() { /* omitted for brevity */ }
public static String encrypt(String content) throws Exception { /* omitted */ }
public static String decrypt(String content) throws Exception { /* omitted */ }
} package sicnu.cs.ich.common.interceptor.transaction;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import sicnu.cs.ich.common.interceptor.transaction.service.IEncryptUtil;
import sicnu.cs.ich.common.util.keyCryptor.DBAESUtil;
@Component
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
public class ParameterInterceptor implements Interceptor {
@Autowired
private IEncryptUtil IEncryptUtil;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// implementation omitted for brevity
return invocation.proceed();
}
// other methods omitted
} package sicnu.cs.ich.common.interceptor.transaction;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
@Component
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class ResultSetInterceptor implements Interceptor {
@Autowired
private IDecryptUtil IDecryptUtil;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object result = invocation.proceed();
// decryption logic omitted for brevity
return result;
}
// other methods omitted
}Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.