Implementing MyBatis TypeHandler for Field Encryption in Java

This article demonstrates how to securely store and retrieve sensitive fields such as phone numbers in a MySQL database by creating a custom Java Encrypt class, a MyBatis TypeHandler for automatic encryption/decryption, configuring the mapper XML, and verifying the solution with test results.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Implementing MyBatis TypeHandler for Field Encryption in Java

Background : Storing sensitive data like phone numbers or bank cards in plain text is insecure; if the database is compromised, the data can be leaked. Therefore, an automatic encryption/decryption mechanism is needed.

Solution Overview : Because the project uses MyBatis as the persistence layer, a custom TypeHandler (or plugin) is employed to encrypt data before persisting and decrypt it when reading.

Step 1 – Define an Encrypt wrapper class :

public class Encrypt {
    private String value;
    public Encrypt() {}
    public Encrypt(String value) { this.value = value; }
    public String getValue() { return value; }
    public void setValue(String value) { this.value = value; }
}

Step 2 – Implement the TypeHandler :

package com.huan.study.mybatis.typehandler;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.nio.charset.StandardCharsets;
import java.sql.*;

/**
 * Encryption TypeHandler for MyBatis
 */
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(Encrypt.class)
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {
    private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8);

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null || parameter.getValue() == null) {
            ps.setString(i, null);
            return;
        }
        AES aes = SecureUtil.aes(KEYS);
        String encrypt = aes.encryptHex(parameter.getValue());
        ps.setString(i, encrypt);
    }

    @Override
    public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return decrypt(rs.getString(columnName));
    }

    @Override
    public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return decrypt(rs.getString(columnIndex));
    }

    @Override
    public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return decrypt(cs.getString(columnIndex));
    }

    private Encrypt decrypt(String value) {
        if (value == null) return null;
        return new Encrypt(SecureUtil.aes(KEYS).decryptStr(value));
    }
}

Step 3 – Mapper XML configuration (no special SQL syntax needed):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huan.study.mybatis.mappers.CustomerMapper">
    <resultMap id="BaseResultMapper" type="com.huan.study.mybatis.entity.Customer">
        <id column="id" property="id"/>
        <result column="phone" property="phone"/>
        <result column="address" property="address"/>
    </resultMap>
    <insert id="addCustomer">
        insert into customer(phone, address) values (#{phone}, #{address})
    </insert>
    <select id="findCustomer" resultMap="BaseResultMapper">
        select * from customer where phone = #{phone}
    </select>
</mapper>

Step 4 – Register the TypeHandler package in mybatis-config.xml (or Spring Boot properties):

mybatis.type-handlers-package=com.huan.study.mybatis.typehandler

Step 5 – Backend service methods : provide an API to add a customer (the phone field is automatically encrypted) and another to query by phone (the value is automatically decrypted).

Testing : After inserting a record, the phone column in the database contains an encrypted hex string; querying the same record returns the original plain phone number, confirming that the TypeHandler works as intended.

The article ends with links to the full source code repository and a reminder to share the content.

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.

databaseMyBatisencryptionTypeHandler
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.