How to Auto‑Encrypt Sensitive Fields in Spring Boot with MyBatis Using Annotations
This article explains a Spring Boot and MyBatis solution that automatically encrypts and decrypts sensitive database fields via an @Encrypted annotation, eliminating manual cryptographic code, reducing maintenance overhead, and preserving performance while ensuring strong data protection.
Background
With data security becoming increasingly critical, developers must protect sensitive user information such as phone numbers, ID cards, and bank cards; storing these values in plain text can lead to severe breaches.
Problems with Traditional Encryption
Code duplication across queries and inserts
Frequent modifications required when adding new encrypted fields
High maintenance cost and difficulty debugging
Desired Solution
Mark fields that need encryption with @Encrypted Encryption and decryption happen automatically
Business code remains unaware of cryptographic logic
Performance impact is minimal
Design Overview
The core idea consists of three parts: an annotation to mark encrypted fields, a MyBatis interceptor that performs transparent encryption/decryption, and a thin configuration layer that wires everything together.
Technical flow: Business code → MyBatis Mapper → EncryptionInterceptor → Auto encrypt/decrypt → Database.
Implementation
1. Define Annotation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypted {
boolean supportFuzzyQuery() default false;
}2. Encryption Utility (AES‑GCM)
public class CryptoUtil {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int IV_LENGTH = 12;
public static String encrypt(String plaintext) { /* generate IV, encrypt, Base64 encode */ }
public static String decrypt(String encryptedText) { /* Base64 decode, extract IV, decrypt */ }
public static boolean isEncrypted(String value) { return value != null && value.contains(":"); }
}3. MyBatis Interceptor
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class EncryptionInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
if ("update".equals(methodName)) {
Object param = getParameter(invocation);
if (shouldEncrypt(param)) encryptFields(param);
}
Object result = invocation.proceed();
if ("query".equals(methodName)) decryptResult(result);
return result;
}
// encryptFields, decryptResult, decryptFields implementations omitted for brevity
}4. Auto‑Configuration
@Configuration
@ConditionalOnProperty(name = "encryption.enabled", havingValue = "true", matchIfMissing = true)
public class EncryptionAutoConfiguration {
@Bean
public ConfigurationCustomizer encryptionConfigurationCustomizer() {
return configuration -> configuration.addInterceptor(new EncryptionInterceptor());
}
}Usage Example
Entity definition with the annotation:
public class User {
private Long id;
private String username;
@Encrypted private String phone; // automatically encrypted
@Encrypted private String email; // automatically encrypted
}Service layer can insert and query users without any cryptographic code; the interceptor handles encryption on write and decryption on read.
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void createUser(User user) {
user.setPhone("13812345678");
user.setEmail("[email protected]");
userMapper.insert(user);
}
public User getUser(Long id) {
User user = userMapper.findById(id);
System.out.println(user.getPhone()); // 13812345678
System.out.println(user.getEmail()); // [email protected]
return user;
}
}Security Considerations
Key Management
Never hard‑code the secret key; obtain it from environment variables, a configuration center, or a dedicated KMS.
Logging
Avoid logging raw sensitive values; mask or omit them before writing to logs.
Pros and Cons
Simple to use – just add an annotation.
Business code stays clean and free of encryption logic.
Relies on standard AES‑GCM, providing strong security.
All cryptographic logic is centralised, easing maintenance.
Suitable for user‑management systems, payment platforms, medical information systems, or any application that stores confidential data. Not ideal for ultra‑high‑performance workloads, scenarios requiring complex encrypted queries, or massive‑scale data sets.
Repository
https://github.com/yuboon/java-examples/tree/master/springboot-column-encryptionSigned-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.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.
