Implementing MyBatis Encryption with a Custom TypeHandler for Sensitive Data
This article demonstrates how to securely store and retrieve sensitive fields such as phone numbers in a MySQL database by creating a custom MyBatis TypeHandler that encrypts data on insert and decrypts it on query, including full implementation code and configuration steps.
When sensitive information like phone numbers or bank cards is stored in plain text, it poses a security risk. To protect such data, the article proposes using MyBatis's TypeHandler to automatically encrypt values before persisting them and decrypt them when reading from the database.
Background : The need arises from potential data leaks if a database is compromised. The solution leverages MyBatis as the persistence layer.
Solution Overview : Two MyBatis extension points are considered – TypeHandler and Plugin. The author chooses TypeHandler for its simplicity in handling encryption/decryption at the field level.
Requirements :
Automatically encrypt the phone number when inserting a new customer record.
Automatically decrypt the phone number when querying customer data.
Implementation Steps :
Create an Encrypt class that wraps the raw string value.
Develop a custom EncryptTypeHandler extending BaseTypeHandler<Encrypt> to handle encryption on setNonNullParameter and decryption on the various getNullableResult methods.
Define the MyBatis resultMap and SQL statements, referencing the encrypted column.
Configure MyBatis to scan the package containing the custom TypeHandler.
Provide service methods for adding a customer and querying by phone number.
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));
}
} <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> mybatis.type-handlers-package=com.huan.study.mybatis.typehandlerTesting Results : After inserting a customer, the phone column stores an encrypted string. When querying the same record, the TypeHandler automatically decrypts the value, returning the original phone number.
The article concludes with a link to the full source repository and a brief invitation to join a community for further discussion.
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.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.
