1. 项目背景与核心需求
《苍穹外卖》作为一款餐饮行业SaaS系统,其员工管理模块是支撑日常运营的核心组件。在day02的迭代中,我们重点实现了员工基础信息的CRUD操作,这是任何业务系统中最基础但至关重要的功能模块。
从技术实现角度看,这类功能看似简单,实则暗藏多个技术难点:
- 高并发场景下的数据一致性保障
- 敏感信息的权限控制与脱敏处理
- 操作日志的完整追溯
- 前后端数据格式的标准化约定
2. 技术架构设计
2.1 分层架构实现
我们采用经典的三层架构:
code复制表现层:Spring MVC + Thymeleaf模板
业务层:Spring Service + Transaction管理
持久层:MyBatis-Plus + MySQL
选择MyBatis-Plus而非JPA主要基于:
- 需要更灵活的SQL控制
- 现有团队更熟悉MyBatis生态
- 内置的AR模式简化基础CRUD开发
2.2 关键实体设计
java复制@Entity
public class Employee {
@TableId(type = IdType.AUTO)
private Long id;
@NotBlank
private String username;
@JsonIgnore
private String password;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
// 其他字段及getter/setter
}
特别注意:
- 密码字段添加@JsonIgnore防止序列化泄露
- 使用字段自动填充功能处理创建时间
- 手机号字段需添加@Pattern正则校验
3. 核心功能实现细节
3.1 新增员工实现
java复制@PostMapping
public Result add(@Valid @RequestBody EmployeeDTO dto) {
// 1. 用户名唯一性校验
if (employeeService.exists(dto.getUsername())) {
throw new BusinessException("用户名已存在");
}
// 2. 密码加密存储
Employee entity = new Employee();
BeanUtils.copyProperties(dto, entity);
entity.setPassword(DigestUtils.md5Hex("salt"+dto.getPassword()));
// 3. 保存并记录操作日志
employeeService.save(entity);
logService.record(LogType.EMPLOYEE, "新增员工:"+entity.getUsername());
return Result.success();
}
关键点:
- 使用全局异常处理器捕获BusinessException
- 密码采用加盐MD5存储(生产环境建议使用BCrypt)
- 操作日志需要记录操作人IP等信息
3.2 分页查询优化
xml复制<select id="selectPage" resultType="EmployeeVO">
SELECT e.*, d.name AS deptName
FROM employee e LEFT JOIN department d ON e.dept_id = d.id
<where>
<if test="query.name != null">
AND e.name LIKE CONCAT('%',#{query.name},'%')
</if>
<if test="query.status != null">
AND e.status = #{query.status}
</if>
</where>
ORDER BY e.create_time DESC
</select>
性能优化建议:
- 为name和status字段建立复合索引
- 超过100万数据考虑使用ES检索
- 前端添加防抖控制查询频率
4. 安全防护措施
4.1 接口权限控制
java复制@PreAuthorize("hasAuthority('employee:add')")
@PostMapping
public Result addEmployee(...) {
// ...
}
权限标识规范:
- 模块:操作 如 employee:query
- 使用Spring Security的注解保护接口
4.2 数据脱敏处理
java复制public class EmployeeVO {
@JsonSerialize(using = PhoneSerializer.class)
private String phone;
@JsonSerialize(using = IdCardSerializer.class)
private String idCard;
}
自定义序列化器实现手机号(138****1234)和身份证号的脱敏显示
5. 常见问题排查
5.1 批量导入性能问题
现象:导入1000条员工数据耗时超过30秒
解决方案:
- 使用MyBatis-Plus的saveBatch方法
- 开启rewriteBatchedStatements=true
- 分批次提交(每500条一个批次)
5.2 并发更新冲突
典型报错:OptimisticLockingFailureException
处理方案:
- 为实体添加@Version注解
- 前端提交携带version字段
- 重试机制或提示用户刷新后重试
6. 扩展思考
-
如何实现员工信息的版本追溯?
- 建议使用触发器记录变更历史
- 或采用CDC工具捕获数据变更
-
超大规模数据下的解决方案?
- 考虑分库分表(按地区或时间分片)
- 读写分离架构
-
微服务架构下的演进?
- 将员工服务独立部署
- 通过Feign暴露API
- 引入JWT鉴权机制
关键提示:所有员工敏感操作必须留有审计日志,且日志记录应包含操作人、操作时间、IP地址等关键信息,这是等保合规的基本要求。