Mastering MyBatis Interceptors: Custom Encryption, Decryption, and Parameter Handling
This article explains MyBatis interceptors, showing how to intercept SQL execution, parameter setting, and result processing, and provides step‑by‑step code for custom encryption/decryption annotations, a parameter interceptor, a result‑set interceptor, and the supporting IEncryptDecrypt interface.
Interceptor Introduction
Mybatis Interceptoris treated as a plugin in MyBatis, located under org.apache.ibatis.plugin.
Interceptors can intercept execution of SQL statements, request parameters, and return values when MyBatis reaches the persistence layer.
Interceptor Usage
To implement a custom interceptor, implement org.apache.ibatis.plugin.Interceptor with three methods:
Object intercept(Invocation invocation) throws Throwable;
Object plugin(Object target);
void setProperties(Properties properties);Example code for a parameter handling interceptor that encrypts data before setting parameters:
@Intercepts({
@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)
})
@ConditionalOnProperty(value = "domain.encrypt", havingValue = "true")
@Component
@Slf4j
public class ParameterInterceptor implements Interceptor {
@Autowired
private IEncryptDecrypt encryptDecrypt;
@Override
public Object intercept(Invocation invocation) throws Throwable {
log.info("Interceptor ParamInterceptor");
if (invocation.getTarget() instanceof ParameterHandler) {
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);
Object parameterObject = parameterField.get(parameterHandler);
if (Objects.nonNull(parameterObject)) {
Class<?> parameterObjectClass = parameterObject.getClass();
EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(parameterObjectClass, EncryptDecryptClass.class);
if (Objects.nonNull(encryptDecryptClass)) {
Field[] declaredFields = parameterObjectClass.getDeclaredFields();
Object encrypt = encryptDecrypt.encrypt(declaredFields, parameterObject);
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}
@Override
public void setProperties(Properties properties) {
// no custom properties
}
}Similarly, a result‑set interceptor can decrypt data after query execution:
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@ConditionalOnProperty(value = "domain.decrypt", havingValue = "true")
@Component
@Slf4j
public class ResultInterceptor implements Interceptor {
@Autowired
private IEncryptDecrypt encryptDecrypt;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object result = invocation.proceed();
if (Objects.isNull(result)) {
return null;
}
if (result instanceof ArrayList) {
ArrayList resultList = (ArrayList) result;
if (CollectionUtils.isNotEmpty(resultList) && needToDecrypt(resultList.get(0))) {
for (int i = 0; i < resultList.size(); i++) {
encryptDecrypt.decrypt(resultList.get(i));
}
}
} else {
if (needToDecrypt(result)) {
encryptDecrypt.decrypt(result);
}
}
return result;
}
public boolean needToDecrypt(Object object) {
Class<?> objectClass = object.getClass();
EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(objectClass, EncryptDecryptClass.class);
return Objects.nonNull(encryptDecryptClass);
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// no custom properties
}
}Custom Annotations
Define class‑level and field‑level annotations to mark entities and fields that require encryption/decryption:
@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptDecryptClass {
} @Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptDecryptField {
}Encryption/Decryption Interface
The IEncryptDecrypt interface declares methods for encrypting parameters and decrypting results:
public interface IEncryptDecrypt {
<T> T encrypt(Field[] declaredFields, T parameterObject) throws IllegalAccessException;
<T> T decrypt(T result) throws IllegalAccessException;
}Both interceptors are conditionally loaded via YAML properties, enabling flexible global configuration of encryption and decryption logic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
