Databases 7 min read

Implementing MyBatis TypeHandler for Field Encryption and Decryption

This article demonstrates how to securely store and retrieve sensitive user data such as phone numbers in a MySQL database by creating a custom MyBatis TypeHandler that automatically encrypts values on insert and decrypts them on query, complete with code examples and configuration steps.

Architecture Digest
Architecture Digest
Architecture Digest
Implementing MyBatis TypeHandler for Field Encryption and Decryption

Background: Storing sensitive information like phone numbers or bank cards in plain text in a database is insecure; if the database is compromised, data can be leaked. Therefore a method to encrypt these fields is required.

Solution: Because the project uses MyBatis as the persistence layer, a MyBatis TypeHandler (or Plugin) can be employed. The article chooses a TypeHandler for encryption/decryption.

Requirements:

When adding a customer, the phone number must be encrypted before persisting.

When querying a customer, the phone number must be automatically decrypted.

Implementation Idea:

Create an entity class Encrypt that wraps a String value.

Implement a custom EncryptTypeHandler extending BaseTypeHandler<Encrypt> that uses Hutool's AES utilities to encrypt on setNonNullParameter and decrypt on the various getNullableResult methods.

Configure MyBatis mapper XML to map the phone column to the Encrypt type.

Specify the package containing the TypeHandler in mybatis.type-handlers-package.

Provide service methods for adding a customer and retrieving a customer by phone.

Code Samples:

<result column="phone" property="phone" typeHandler="com.huan.study.mybatis.typehandler.EncryptTypeHandler"/>
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; }
}
package com.huan.study.mybatis.typehandler;

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

@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));
    }
}
<?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>

Configuration entry:

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

Testing shows that after inserting a customer, the phone column stores an encrypted string, and when querying, the value is automatically decrypted back to the original phone number.

For a complete runnable example, refer to the linked Gitee repository.

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.

JavaMyBatisencryptionDatabase SecurityTypeHandler
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

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.