本文为后端团队通用开发规范,聚焦接口统一响应封装 与数据库敏感字段自动加解密两大核心场景,配套可直接落地的代码示例,解决前后端交互混乱、数据安全合规、代码维护成本高的问题,适用于抽奖系统、用户中心等各类 SpringBoot 后端项目。
一、规范总纲
1. 核心目标
- 统一接口返回格式,降低前后端联调成本
- 敏感数据加密存储,满足数据安全合规要求
- 业务代码与通用逻辑解耦,提升可维护性
- 全局标准化,减少重复造轮子与低级 Bug
2. 适用范围
SpringBoot + MyBatis/MyBatis-Plus 项目,Controller/DAO 层通用规范。
二、接口统一响应规范(CommonResult<T>)
1. 为什么需要统一响应?
- 原生接口返回结构杂乱,成功返数据、失败抛异常,前端需多套解析逻辑
- 错误码、提示信息无统一标准,排查问题困难
- 业务代码与响应格式耦合,扩展性差
2. 统一响应结构
固定返回code+msg+data,前端一套逻辑适配所有接口:
{
"code": 200,
"msg": "操作成功",
"data": {}
}
3. 完整代码实现
j
import java.io.Serializable;
/**
* 全局统一响应封装
*/
public class CommonResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
// 成功状态码
public static final int SUCCESS = 200;
// 服务器异常
public static final int ERROR = 500;
// 参数错误
public static final int BAD_REQUEST = 400;
// 未授权
public static final int UNAUTHORIZED = 401;
private Integer code;
private String msg;
private T data;
// 全参构造
public CommonResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
// 成功响应(带数据)
public static <T> CommonResult<T> success(T data) {
return new CommonResult<>(SUCCESS, "操作成功", data);
}
// 成功响应(无数据)
public static <T> CommonResult<T> success() {
return new CommonResult<>(SUCCESS, "操作成功", null);
}
// 失败响应
public static <T> CommonResult<T> error(int code, String msg) {
return new CommonResult<>(code, msg, null);
}
// Getter & Setter
public Integer getCode() {return code;}
public void setCode(Integer code) {this.code = code;}
public String getMsg() {return msg;}
public void setMsg(String msg) {this.msg = msg;}
public T getData() {return data;}
public void setData(T data) {this.data = data;}
}
4. 接口使用示例
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@GetMapping("/{id}")
public CommonResult<UserDTO> getUserById(@PathVariable Long id) {
UserDTO user = userService.getUserById(id);
return CommonResult.success(user);
}
@PostMapping("/add")
public CommonResult<Void> addUser(@RequestBody UserDTO userDTO) {
userService.addUser(userDTO);
return CommonResult.success();
}
}
5. 规范优势
- 泛型
<T>支持任意数据类型,复用性拉满 - 静态方法快速构建响应,一行代码完成返回
- 状态码统一管理,避免魔法值
- 实现序列化,支持 JSON 网络传输
三、数据库敏感字段自动加解密规范
1. 应用场景
手机号、身份证、银行卡等敏感信息,明文存储违反合规要求,需加密入库、解密出库。
2. 实现方案
基于 MyBatis 自定义TypeHandler,实现写入自动加密、查询自动解密,业务代码无侵入。
3. 步骤 1:定义加密标记类
用于标识需要加解密的字段:
package com.example.lotterysystem.dao.dataobject;
/**
* 敏感字段加密标记类
*/
public class Encrypt {
private String value;
public Encrypt(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
4. 步骤 2:自定义加解密类型处理器
package com.example.lotterysystem.dao.handler;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.example.lotterysystem.dao.dataobject.Encrypt;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 敏感字段AES自动加解密处理器
*/
@MappedTypes(Encrypt.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {
// AES密钥(16字节,生产环境需配置化,禁止硬编码)
private static final byte[] KEY = "123456789abcdefg".getBytes(StandardCharsets.UTF_8);
/**
* 写入数据库:明文加密为密文
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null || !StringUtils.hasText(parameter.getValue())) {
ps.setString(i, null);
return;
}
AES aes = SecureUtil.aes(KEY);
String encryptStr = aes.encryptHex(parameter.getValue());
ps.setString(i, encryptStr);
}
/**
* 读取数据库:密文解密为明文
*/
@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 str) {
if (!StringUtils.hasText(str)) {
return null;
}
String decryptStr = SecureUtil.aes(KEY).decryptStr(str);
return new Encrypt(decryptStr);
}
}
5. 步骤 3:实体类使用示例
package com.example.lotterysystem.dao.dataobject;
/**
* 用户DO
*/
public class UserDO {
private Long id;
private String userName;
// 敏感字段:手机号,自动加解密
private Encrypt phone;
private Integer age;
// Getter & Setter
}
6. 执行流程
- 写入:
Encrypt(明文)→ TypeHandler 加密 → 数据库存储密文 - 读取:数据库密文 → TypeHandler 解密 →
Encrypt(明文)
7. 生产环境优化建议
- 密钥从配置中心 / 环境变量读取,禁止硬编码
- 加解密添加
try-catch,避免解密失败导致服务崩溃 - 密钥定期轮换,提升安全性
四、配套规范补充
1. 异常处理规范
结合统一响应,全局捕获异常并封装返回:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public CommonResult<Void> handleException(Exception e) {
return CommonResult.error(CommonResult.ERROR, "服务器异常:" + e.getMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public CommonResult<Void> handleBadRequest(IllegalArgumentException e) {
return CommonResult.error(CommonResult.BAD_REQUEST, e.getMessage());
}
}
2. 分层开发规范
- Controller:仅处理请求参数、返回统一响应
- Service:专注业务逻辑,不关心响应格式
- DAO:数据交互,敏感字段自动加解密
- 禁止跨层调用,保持职责单一
五、规范价值总结
- 前端体验提升:统一响应格式,一套解析逻辑,联调效率提升 50%+
- 后端开发高效:通用封装减少重复代码,专注业务实现
- 数据安全合规:敏感字段自动加密,满足监管要求
- 项目可维护性:全局标准化,新人快速上手,迭代成本更低
六、落地注意事项
- 统一响应类全局唯一,禁止自定义多个响应类
- 敏感字段仅标记核心隐私数据,避免过度加密影响性能
- 生产环境务必替换硬编码密钥,优先使用配置中心管理
- 加解密逻辑添加日志,便于问题排查