JavaWeb Day05:全局异常、AOP 日志与管理模块
932 字
5 分钟
JavaWeb Day05:全局异常、AOP 日志与管理模块
模块与代码结构
| 模块 | 代码锚点 |
|---|---|
| 员工删除 | EmpController.delete(@RequestParam List<Integer> ids)+ EmpServiceImpl.delete(@Transactional(rollbackFor) + empMapper.deleteByIds + empExprMapper.deleteByEmpIds) |
| 全局异常处理 | GlobalExceptionHandler(@RestControllerAdvice + @ExceptionHandler,DuplicateKeyException 截取 Duplicate entry 提示「xxx已存在」) |
| 操作日志 AOP | LogAspect(@Aspect + @Pointcut("execution(* com.ryuki.controller..*.*(..)) && !execution(* ...LogController.*(..))") + @Around) |
| 班级管理 CRUD | ClazzController/Service/Mapper(分页 + case when 开班状态 + 删除前校验 + 动态 <set> 修改) |
| 学员管理 CRUD | StudentController/Service/Mapper(条件分页 <where>/<if> + <foreach> 批量删 + 学号生成 + 违纪处理阈值 30) |
| 报表统计 | ReportController/Service(员工职位/性别 + 学员学历 case when + 班级人数 right join) |
核心结论
- 全局异常:
@RestControllerAdvice(=@ControllerAdvice+@ResponseBody)统一捕获;@ExceptionHandler可按异常类型分流(Exception兜底 + 具体异常精准处理);DuplicateKeyException解析Duplicate entry 'xxx' for key ...后返回「xxx已存在」。 - AOP 操作日志:
@Pointcut定义切入点(execution 表达式 +&&/||/!组合排除);@Around+ProceedingJoinPoint(proceed()放行 +getArgs()参数 +getTarget()目标类 +getSignature()方法名);finally 中记录保证成功失败都记;日志插入失败 catch 掉只 warn,不影响主业务——与 EmpLog 的 try-finally 同事务方案形成对照。 - 操作人识别:无登录功能时从请求头
X-Emp-Id读取(经RequestContextHolder.getRequestAttributes()拿到 ServletRequest);真实项目应从 JWT/ThreadLocal 登录态取。 - 班级删除业务校验:删除前
count该班级下的学员数,大于 0 则抛业务异常,由全局异常处理器兜底返回Result.error;无学员才真正删除。 - 动态 SQL 复用:
<where>自动去掉多余的 and/or,<if>按条件拼接,<set>用于动态更新,<foreach>生成批量 in 的 id 列表;模糊匹配用like concat('%', #{name}, '%'),即防注入的#{}写法。 - 报表 SQL:
case when把枚举数值转成中文(如学历);right join保证没有学员的班级也显示为 0 人;配合group by+count。 - 学号生成:年份 + 月份(
%02d)+ 4 位随机数(%04d)。 - 事务:批量删除、违纪处理都加
@Transactional(rollbackFor = Exception.class);违纪扣分执行violation_count+1、violation_score+score,累计扣满 30 分清零。
AOP 与事务的补充要点
- AOP 把日志这类横切逻辑从业务代码中抽离统一封装;Spring AOP 底层使用 JDK 动态代理或 CGLIB。切点(Pointcut)是匹配连接点(JoinPoint)的表达式。
- 通知类型共五种:
@Before、@After、@AfterReturning、@AfterThrowing、@Around,其中@Around最灵活,可控制目标方法是否执行并改写返回值。 - Spring 事务有两种用法:编程式事务手动控制提交与回滚,声明式事务通过
@Transactional声明,底层由 AOP 代理实现。 - 事务传播行为共 7 种,常用的两种对比:
REQUIRED加入当前事务,随当前事务一并提交或回滚;REQUIRES_NEW挂起当前事务并新建独立事务,两者各自提交、各自回滚。
踩坑与发现
-
countByClazzId 查错表:
<!-- 当前写法:查 clazz 表自己 → id 存在恒为 1 → 永远抛「该班级下还有学员」→ 班级永远删不掉 --><select id="countByClazzId" resultType="java.lang.Integer">select count(*) from clazz where id = #{id}</select>正确写法应查学员表:
select count(*) from student where clazz_id = #{id}。 -
logback 输出路径指向盘符根目录:
logback.xml第 15 行<FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>写的是 D 盘根目录,本机拒绝写入,mvn test启动上下文直接失败(FileNotFoundException: D:\tlias-2026-08-15-0.log (拒绝访问)),mvn compile不受影响。修复方向是改成相对路径,或用logging.file配置接管。 -
AOP 切点要排除日志查询自身:切点若不排除
LogController,「查日志」这个请求也会被记录日志,递归触发死循环。 -
@Around忘记调用proceed():目标方法不会执行也不会报错,环绕方法直接返回自己的返回值(可能为 null)。 -
删除接口参数风格:员工删除用
@RequestParam List<Integer> ids(?ids=1,2,3),学员删除用@PathVariable List<Integer> ids(/students/1,2,3),两种风格都可用,注意与接口文档口径一致。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!
JavaWeb Day05:全局异常、AOP 日志与管理模块
https://ryuki.icu/posts/javaweb-day05/相关文章智能推荐
1
JavaWeb Day02:MyBatis XML 开发与 tlias 部门管理
JavaWebMyBatis XML 方式开发、tlias 部门管理三层 CRUD 实战与 SLF4J 日志配置。
2
JavaWeb Day07:项目部署与 Docker 基础
JavaWebDocker 镜像、容器、仓库与分层存储概念,常用命令、数据卷、Dockerfile 与 Compose,以及三容器项目部署链路
3
JavaWeb Day01:SpringBoot 入门与 MyBatis 注解开发
JavaWebSpringBoot Web 快速入门、三层分层与 IoC/DI 解耦、原生 JDBC、MyBatis 注解开发与 MySQL 基础。
4
JavaWeb Day03:Tlias 员工管理之分页查询
JavaWeb员工分页查询接口实现:LIMIT 物理分页、PageResult 泛型封装与 left join 关联部门名
5
JavaWeb Day04:条件分页、事务新增与本地上传
JavaWeb条件查询改为 POJO 对象收参并以 PageHelper 分页;员工新增覆盖事务回滚、批量插入、主键回填、操作日志与本地上传
随机文章随机推荐





















