Backend Development 14 min read

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.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Implementing a MyBatis Encryption/Decryption Plugin for Sensitive Data in Java

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
}
backendJavapluginMyBatisEncryptiondecryptionSensitive Data
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.