SpringBoot3.32 + Sharding Sphere5.5 + Mybatis-plus:轻松搞定数据加解密,支持字段级!
在当今数字化的时代,数据已成为企业和组织的核心资产。然而,随着数据量的不断增长以及对数据安全性要求的日益提高,如何有效地保护敏感数据成为了至关重要的问题。在众多解决方案中,SpringBoot 与 Sharding Sphere + Mybatis-plus 的结合为我们提供了一种强大且高效的数据加解密机制,特别是在字段级别的加密处理方面表现出色。
这种结合的优势不仅在于能够确保数据在存储和传输过程中的保密性,还在于其高度的灵活性和可扩展性。通过字段级的加密,我们可以有针对性地对特定的敏感信息进行保护,而无需对整个数据集进行统一处理,从而在保障安全性的同时,最大程度地减少对系统性能的影响。
运行效果:
数据表记录:
在深入探讨技术实现之前,让我们先了解一下项目的前期准备工作。首先,创建一个 Spring Boot 项目,并配置好必要的依赖。以下是项目的 pom.xml 依赖配置:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.icoderoad</groupId>
<artifactId>shardingsphere</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shardingsphere</name>
<description>Demo project for shardingsphere And Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring.boot.version>2.7.12</spring.boot.version>
<shardingsphere.version>5.4.1</shardingsphere.version>
<sharding-jdbc-spring-boot-starter.version>4.1.1</sharding-jdbc-spring-boot-starter.version>
<mybatis-plus-boot-starter.version>3.5.7</mybatis-plus-boot-starter.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
</properties>
<dependencies>
<!-- Spring Boot 相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sharding Sphere 相关依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- 数据库驱动依赖 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
接着,配置 application.yaml 属性文件:
server:
port: 8080
spring:
datasource:
driverClassName: org.apache.shardingsphere.driver.ShardingSphereDriver
url: jdbc:shardingsphere:classpath:config.yaml
name: EncryptHikariCP
hikari:
minimumIdle: 10
maximumPoolSize: 200
autoCommit: true
idleTimeout: 30000
poolName: BaseHikariCP
maxLifetime: 1800000
connectionTimeout: 30000
connectionTestQuery: SELECT 1
mybatis-plus:
configuration:
mapUnderscoreToCamelCase: true
mapperLocations: classpath*:/mapper/**/*.xml
typeAliasesPackage: com.pack
config.yaml 属性文件:
#数据源配置
dataSources:
ds1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/electronic_seal?serverTimeznotallow=GMT%2B8&useSSL=false
username: root
password: root
#规则配置
rules:
- !ENCRYPT
tables:
users:
columns:
id_card_number_cipher:
cipher:
name: id_card_number_cipher
encryptorName: aes_encryptor
encryptors:
aes_encryptor:
type: AES
props:
aes-key-value: ec9ad139f14f49b5f0da36bace883292
digest-algorithm-name: SHA-1
assisted_encryptor:
type: MD5
用户表的 SQL DDL 定义语句:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
id_card_number_plain VARCHAR(40),
id_card_number_cipher VARCHAR(255)
);
接下来,我们将逐步深入探讨后端和前端的代码实现,以及如何在实际应用中充分发挥这一技术组合的优势。
后端代码实现
应用启动类 ShardingsphereApplication:
package com.icoderoad.shardingsphere;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ShardingsphereApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingsphereApplication.class, args);
}
}
创建实体类 User:
package com.icoderoad.shardingsphere.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("users")
public class User {
private Long id;
private String username;
private String idCardNumberPlain;
private String idCardNumberCipher;
}
创建 UserMapper 接口:
package com.icoderoad.shardingsphere.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.icoderoad.shardingsphere.entity.User;
public interface UserMapper extends BaseMapper<User> {
}
创建 UserService 接口:
package com.icoderoad.shardingsphere.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.icoderoad.shardingsphere.entity.User;
public interface UserService extends IService<User>{
public void insertUser(User user);
public String getDataByUsername(String username);
}
创建 UserServiceImpl 实现类:
package com.icoderoad.shardingsphere.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icoderoad.shardingsphere.entity.User;
import com.icoderoad.shardingsphere.mapper.UserMapper;
import com.icoderoad.shardingsphere.service.UserService;
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService{
@Override
public void insertUser(User user) {
this.save(user);
}
@Override
public String getDataByUsername(String username) {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.eq("username", username);
return this.getOne(wrapper).getIdCardNumberCipher();
}
}
前端实现
使用 Thymeleaf 模板和 JavaScript 来展示和处理数据。以下是一个简单的示例:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户数据管理</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<h2>添加用户</h2>
<form th:action="@{/submitUser}" method="post">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" class="form-control" id="username" name="username">
</div>
<div class="form-group">
<label for="idCardNumber">身份证号:</label>
<input type="text" class="form-control" id="idCardNumber" name="idCardNumber">
</div>
<button type="button" class="btn btn-primary" onclick="submitUser()">提交</button>
</form>
<h2>用户列表</h2>
<table class="table">
<thead>
<tr>
<th>用户名</th>
<th>身份证号</th>
</tr>
</thead>
<tbody th:each="user : ${userList}">
<tr>
<td th:text="${user.username}"></td>
<td th:text="${user.idCardNumberCipher}"></td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-secondary" onclick="reloadData()">重新加载</button>
</div>
<script>
function submitUser() {
var username = $('#username').val();
var idCardNumber = $('#idCardNumber').val();
$.ajax({
type: 'POST',
url: '/submitUser',
data: {username: username, idCardNumber: idCardNumber},
success: function(response) {
alert('用户添加成功!');
location.reload();
},
error: function(error) {
alert('添加用户时出错:' + error);
}
});
}
function reloadData() {
$.ajax({
type: 'GET',
url: '/reloadUserList',
success: function(response) {
// 清空原有的表格内容
$('tbody').empty();
// 重新填充新的数据
$.each(response, function(index, user) {
$('tbody').append('<tr><td>' + user.username + '</td><td>' + user.idCardNumberCipher + '</td></tr>');
});
},
error: function(error) {
alert('重新加载数据时出错:' + error);
}
});
}
</script>
</body>
</html>
视图显示类:
package com.icoderoad.shardingsphere.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.icoderoad.shardingsphere.entity.User;
import com.icoderoad.shardingsphere.service.UserService;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String index(Model model) {
List<User> userList = userService.list();
model.addAttribute("userList", userList);
return "index";
}
}
在控制器中处理前端的请求:
package com.icoderoad.shardingsphere.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.icoderoad.shardingsphere.entity.User;
import com.icoderoad.shardingsphere.service.UserService;
@RestController
public class UserRestController {
@Autowired
private UserService userService;
@PostMapping("/submitData")
public String submitData(@RequestParam String username, @RequestParam String idCardNumber) {
User user = new User();
user.setUsername(username);
user.setIdCardNumberPlain(idCardNumber);
userService.insertUser(user);
return "数据提交成功";
}
@GetMapping("/reloadUserList")
public List<User> reloadUserList() {
return userService.getUserList();
}
}
通过以上的配置和代码实现,我们成功地利用 SpringBoot 和 Sharding Sphere 实现了数据的字段级加解密操作,为数据安全提供了有力的保障。
希望这篇文章能够帮助您深入理解并在实际项目中应用 SpringBoot 和 Sharding Sphere 的数据加解密功能。