拦截器
SpringMVC 内置拦截器机制 ,允许在请求被目标方法处理的前后进行拦截,执行一些额外操作。
使用步骤: ①实现 HandlerInterceptor 接口的组件即可成为拦截器
②创建 WebMvcConfigurer 组件,并配置拦截器的拦截路径。
java
@Component
//拦截器
public class MyHandlerInterceptor implements HandlerInterceptor {
// 目标方法执行之前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyHandlerInterceptor.preHandle");
return true; //true放行,false拦截
}
// 目标方法执行完成之后
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
System.out.println("MyHandlerInterceptor.postHandle");
}
// 页面渲染完后
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyHandlerInterceptor.afterCompletion");
}
}
java
/**
* 拦截器需要配置,告诉spring,这个拦截器主要拦截什么
*WebMvcConfigurer:专门对springmvc底层做一些配置
* 容器需要有 WebMvcConfigurer组件
* 方式1:@Bean 放一个 WebMvcConfigurer
* 方式2:实现 WebMvcConfigurer接口
*/
@Configuration
public class MySpringMVCConfig implements WebMvcConfigurer {
@Autowired
private MyHandlerInterceptor myHandlerInterceptor;
// 添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myHandlerInterceptor).addPathPatterns("/**"); //拦截所有请求
}
}
拦截器执行顺序
~当拦截器有多个时,执行顺序:
preHandle顺序执行------>postHandle逆序执行------>afterCompletion逆序执行。
~当postHandle、afterCompletion从哪炸炸了,倒序链路从哪结束。
~当某个preHandle返回false进行拦截时,
postHandle是目标方法执行之后执行,preHandle返回true时,afterCompletion才会执行。
画图
拦截器or过滤器
异常处理
~异常处理:
后端只编写正确的业务逻辑,如出现异常,通过抛异常方式提前中断业务逻辑,
让前端感知异常。
~异常处理最终方式:
必须有业务异常类(区分异常),
必须有异常枚举类,(列举项目中每个模块出现的所有异常)
编写业务代码的时候,只需要编写正确业务逻辑,如果出现预期问题,
使用抛异常方式(抛的时候把异常枚举一传),中断业务逻辑并通知上层controller
- GlobalExceptionHandler全局异常处理器捕获Controller层抛出的异常并处理,
全局拿到业务异常code msg 最终给前端响应。
java
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeDao employeeDao;
@Override
public void updateEmployee(Employee employee) {
Long id=employee.getId();
if (id==null){
throw new BuzException(BizExceptionEnume.ORDER_NOT_EXIST); //抛到业务异常类
}
employeeDao.updateEmp(employee);
}
java
/**
* 业务异常类
*/
@Data
public class BuzException extends RuntimeException {
private Integer code; //异常码
private String msg; //异常信息
// 只传异常枚举对象
public BuzException(BizExceptionEnume exceptionEnume){
super(exceptionEnume.getMsg());
System.out.println("业务异常类");
this.code = exceptionEnume.getCode();
this.msg = exceptionEnume.getMsg();
}
}
java
/**
* 异常处理文档 枚举类
* 将来修改的时候,很麻烦,得改很多地方,使用枚举类进行固化
*/
public enum BizExceptionEnume {
// 根据业务动态扩充
// ORDER_xx订单模块相关异常
ORDER_CLOSED(10001,"订单已关闭"),
ORDER_NOT_EXIST(10002,"订单不存在"),
// PRODUCT_xx商品模块相关异常
PRODUCT_NOT_EXIST(10003,"库存不足"),
PRODUCT_STOCK_ERROR(10004,"库存错误");
// ...........
@Getter
private Integer code;
@Getter
private String msg;
private BizExceptionEnume(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
java
/**
* 全局异常处理- 只对controller层进行处理
* @RestControllerAdvice合成注解<------@ResponseBody(R以json方式返回)、@ControllerAdvice(告诉springmvc这是一个全局异常处理类)
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
// 业务异常
@ExceptionHandler(BuzException.class)
public R handleBizException(BuzException e){
return R.error(e.getCode(), e.getMessage());
}
// 最终的兜底异常处理方法
@ExceptionHandler(Throwable.class) //处理异常错误
public R error(Exception e){
return R.error(500, e.getMessage());
}
}