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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
How to Auto‑Encrypt Sensitive Fields in Spring Boot with MyBatis Using Annotations

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-encryption
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootMyBatisAnnotationEncryptiondatabase security
Code Ape Tech Column
Written by

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

0 followers
Reader feedback

How this landed with the community

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.