Three Practical Data Masking Solutions That Really Work
This article walks through three common data‑masking approaches—SQL queries using string functions, a Java‑based "sensitive‑plus" plugin, and the mybatis‑mate‑sensitive‑jackson extension—showing configuration, code examples, and how each method masks phone numbers, ID cards and other personal fields.
1. SQL Data Masking
Using MySQL string functions CONCAT(), LEFT() and RIGHT(), the article demonstrates how to mask phone numbers and ID numbers directly in SQL queries.
-- Phone number masking
SELECT mobilePhone AS original_phone,
CONCAT(LEFT(mobilePhone,3),'********') AS masked_phone
FROM t_s_user;
-- ID card masking
SELECT idcard AS original_id,
CONCAT(LEFT(idcard,3),'****',RIGHT(idcard,4)) AS masked_id
FROM t_s_user;2. Java Data Masking with sensitive‑plus
The open‑source plugin hosted at https://gitee.com/strong_sea/sensitive-plus supports address, bank‑card, Chinese name, landline, ID card, mobile phone, and password masking. It offers both regex‑based and length‑based masking, configurable via custom rules.
3. mybatis‑mate‑sensitive‑jackson
A MyBatis‑Plus extension (free for testing, paid for production) that applies masking strategies defined by SensitiveType. The interface lists built‑in types such as chineseName, idCard, phone, mobile, address, email, bankCard, password, and carNumber.
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";
}The accompanying demo includes the following files:
pom.xml – adds the MySQL connector dependency.
application.yml – configures the datasource and a test license for mybatis‑mate.
<?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> 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:
grant: thisIsTestLicense
license: <long‑base64‑string>
logging:
level:
mybatis.mate: debug4. Spring Boot Application Entry
package mybatis.mate.sensitive.jackson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SensitiveJacksonApplication {
public static void main(String[] args) {
SpringApplication.run(SensitiveJacksonApplication.class, args);
}
}5. Custom Masking Strategy Configuration
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 a custom masking strategy */
@Bean
public ISensitiveStrategy sensitiveStrategy() {
return new SensitiveStrategy().addStrategy(
"testStrategy", t -> t + "***test***");
}
}6. Entity Definition
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;
@FieldSensitive("testStrategy")
private String username; // uses custom strategy
@FieldSensitive(SensitiveType.mobile)
private String mobile; // built‑in mobile masking
@FieldSensitive(SensitiveType.email)
private String email; // built‑in email masking
}7. REST Controller
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;
// Retrieve a single user
@GetMapping("/info")
public User info() {
return userMapper.selectById(1L);
}
// Return a map with nested objects and manual masking
@GetMapping("/map")
public Map<String, Object> map() {
Map<String, Object> userMap = new HashMap<>();
userMap.put("user", userMapper.selectById(1L));
userMap.put("test", 123);
userMap.put("userMap", new HashMap<String, Object>() {{
put("user2", userMapper.selectById(2L));
put("test2", "hi china");
}});
// Manually apply mobile masking
userMap.put("mobile", sensitiveStrategy.getStrategyFunctionMap()
.get(SensitiveType.mobile).apply("15315388888"));
return userMap;
}
// List users, optionally skipping masking with ?skip=1
@GetMapping("/list")
public List<User> list(HttpServletRequest request) {
if ("1".equals(request.getParameter("skip"))) {
RequestDataTransfer.skipSensitive();
}
return userMapper.selectList(null);
}
}8. Mapper Interface
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<User> {}9. Test Results
Request GET http://localhost:8080/list returns masked fields:
[
{"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"}
]Adding the query parameter ?skip=1 disables masking and returns the original data:
[
{"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]"}
]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.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
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.
