Implementing Data Masking in MySQL and Java with MyBatis-Mate Sensitive Jackson
This article demonstrates how to mask sensitive data such as phone numbers and ID cards using SQL functions, introduces Java masking libraries, and provides a complete MyBatis-Mate Sensitive Jackson example with configuration, custom strategies, entity annotations, controller endpoints, and sample responses.
1. SQL Data Masking Implementation
Shows how to mask phone numbers and ID cards in MySQL using CONCAT, LEFT and RIGHT functions.
-- CONCAT(), LEFT() and RIGHT() string functions combined usage
-- CONCAT(str1,str2,…) returns the concatenated string
-- LEFT(str,len) returns the leftmost len characters of str
-- RIGHT(str,len) returns the rightmost len characters of str
-- Phone number masking SQL:
SELECT mobilePhone AS originalPhone,
CONCAT(LEFT(mobilePhone,3), '********') AS maskedPhone
FROM t_s_user;
-- ID card masking SQL:
SELECT idcard AS originalIdCard,
CONCAT(LEFT(idcard,3), '****', RIGHT(idcard,4)) AS maskedIdCard
FROM t_s_user;2. Java Data Masking Implementation
References the open‑source project sensitive-plus which provides plugins for address, bank card, Chinese name, landline, ID card, mobile, email and password masking, supporting both regex‑based and length‑based strategies.
3. mybatis-mate-sensitive-jackson
Introduces the mybatis‑mate‑sensitive‑jackson library (commercial) that applies masking strategies defined by SensitiveType to entity fields.
package mybatis.mate.strategy;
public interface SensitiveType {
String chineseName = "chineseName";
String idCard = "idCard";
String phone = "phone";
String mobile = "mobile";
String address = "address";
String email = "email";
String bankCard = "bankCard";
String password = "password";
String carNumber = "carNumber";
}Configuration files (pom.xml, application.yml) and the Spring Boot startup class are provided.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-mate-examples</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-mate-sensitive-jackson</artifactId>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project> # DataSource Config
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_mate?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
mybatis-mate:
cert:
# Add your license here; test license will expire.
grant: thisIsTestLicense
license: as/bsBaSVrsA9FfjC/N77ruEt2/QZDrW+MHETNuEuZBra5mlaXZU+DE1ZvF8UjzlLCpH3TFVH3WPV+Ya7Ugiz1Rx4wSh/FK6Ug9lhos7rnsNaRB/+mR30aXqtlLt4dAmLAOCT56r9mikW+t1DDJY8TVhERWMjEipbqGO9oe1fqYCegCEX8tVCpToKr5J1g1V86mNsNnEGXujnLlEw9jBTrGxAyQroD7Ns1Dhwz1K4Y188mvmRQp9t7OYrpgsC7N9CXq1s1c2GtvfItHArkqHE4oDrhaPjpbMjFWLI5/XqZDtW3D+AVcH7pTcYZn6vzFfDZEmfDFV5fQlT3Rc+GENEg==
logging:
level:
mybatis.mate: debug package mybatis.mate.sensitive.jackson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SensitiveJacksonApplication {
// Test endpoints: http://localhost:8080/info , http://localhost:8080/list
public static void main(String[] args) {
SpringApplication.run(SensitiveJacksonApplication.class, args);
}
}Custom strategy bean is defined to handle a user‑defined “testStrategy”.
package mybatis.mate.sensitive.jackson.config;
import mybatis.mate.databind.ISensitiveStrategy;
import mybatis.mate.strategy.SensitiveStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SensitiveStrategyConfig {
/** Inject custom masking strategy */
@Bean
public ISensitiveStrategy sensitiveStrategy() {
// Custom "testStrategy" handling
return new SensitiveStrategy().addStrategy("testStrategy", t -> t + "***test***");
}
}Entity class User demonstrates usage of @FieldSensitive with built‑in and custom strategies.
package mybatis.mate.sensitive.jackson.entity;
import lombok.Getter;
import lombok.Setter;
import mybatis.mate.annotation.FieldSensitive;
import mybatis.mate.strategy.SensitiveType;
@Getter
@Setter
public class User {
private Long id;
/** Custom strategy defined in SensitiveStrategyConfig */
@FieldSensitive("testStrategy")
private String username;
/** Built‑in strategy for mobile numbers */
@FieldSensitive(SensitiveType.mobile)
private String mobile;
@FieldSensitive(SensitiveType.email)
private String email;
}Controller provides endpoints /info, /map, /list with optional skipping of masking via the request parameter skip .
package mybatis.mate.sensitive.jackson.controller;
import mybatis.mate.databind.ISensitiveStrategy;
import mybatis.mate.databind.RequestDataTransfer;
import mybatis.mate.sensitive.jackson.entity.User;
import mybatis.mate.sensitive.jackson.mapper.UserMapper;
import mybatis.mate.strategy.SensitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@Autowired
private ISensitiveStrategy sensitiveStrategy;
// GET http://localhost:8080/info
@GetMapping("/info")
public User info() {
return userMapper.selectById(1L);
}
// GET http://localhost:8080/map
@GetMapping("/map")
public Map
map() {
Map
userMap = new HashMap<>();
userMap.put("user", userMapper.selectById(1L));
userMap.put("test", 123);
userMap.put("userMap", new HashMap
() {{
put("user2", userMapper.selectById(2L));
put("test2", "hi china");
}});
// Manual strategy masking
userMap.put("mobile", sensitiveStrategy.getStrategyFunctionMap()
.get(SensitiveType.mobile).apply("15315388888"));
return userMap;
}
// GET http://localhost:8080/list (masking) or /list?skip=1 (no masking)
@GetMapping("/list")
public List
list(HttpServletRequest request) {
if ("1".equals(request.getParameter("skip"))) {
// Skip masking
RequestDataTransfer.skipSensitive();
}
return userMapper.selectList(null);
}
}Mapper interface for MyBatis.
package mybatis.mate.sensitive.jackson.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import mybatis.mate.sensitive.jackson.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper
{}Sample HTTP responses show masked data when the endpoint is called normally and original data when masking is skipped.
[
{
"id": 1,
"username": "Jone***test***",
"mobile": "153******81",
"email": "t****@baomidou.com"
},
{
"id": 2,
"username": "Jack***test***",
"mobile": "153******82",
"email": "t****@baomidou.com"
},
{
"id": 3,
"username": "Tom***test***",
"mobile": "153******83",
"email": "t****@baomidou.com"
}
]
[ // when skip=1
{
"id": 1,
"username": "Jone",
"mobile": "15315388881",
"email": "[email protected]"
},
{
"id": 2,
"username": "Jack",
"mobile": "15315388882",
"email": "[email protected]"
},
{
"id": 3,
"username": "Tom",
"mobile": "15315388883",
"email": "[email protected]"
}
]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.