SpringBoot统一功能处理
目录
一.拦截器
拦截器的实现
拦截器的定义
注册拦截器
登录校验
二.DispatcherServlet源码分析
编辑适配器
适配器模式
三.统一数据返回格式
编辑
四.统一异常处理
一.拦截器
拦截器是Spring框架提供的核心功能之一,在指定方法前后,根据业务需要执行预先设定的代码。
按照图书管理系统举例子:
登录验证
指定方法:我们登录验证后可以执行的某些方法(图书的增删改查)
预先设定的代码:对用户是否登录进行验证


再举例:去银行办理业务,办理业务前后,都会有一些工作,我们可以把业务前后的这些工作视为拦截工作。办理业务前,拦截器做的工作是取号(带身份证取号);办理业务后,拦截工作则是进行服务评价。
拦截器的实现
拦截器的实现分为两步
1.定义一个拦截器
2.把拦截器注册到项目中
拦截器的定义
我们自己写的拦截器的类要继承HanderInterceptor这个类,并且重写这个类中自带的两个方法。
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("目标方法执行前");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {log.info("目标方法执行后");}
}

注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器//**表示给所有方法添加拦截器registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("");//排除不进行拦截的}
}
继承的WebMvcConfigurer类中有添加拦截器的方法addInterceptors
测试拦截器的效果


登录校验
通过拦截器完成图书管理系统中的最后一步操作:通过拦截器完成图书管理系统中的登录校验功能。
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器//**表示给所有方法添加拦截器registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");//排除不进行拦截的}
}
把controller中的注册注释掉

拦截器内的工作内容
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("登录拦截器校验...");//返回true表示放行,返回false表示拦截//用户是否登录HttpSession session = request.getSession();UserInfo userInfo = (UserInfo) session.getAttribute(Constants.SESSION_USER_KEY);if (userInfo != null &&userInfo.getId() >= 0) {return true;}response.setStatus(401);return false;//401表示未认证登录}@Overridepublic void postHandle (HttpServletRequest request, HttpServletResponse response, Objecthandler, @Nullable ModelAndView modelAndView) throws Exception {log.info("目标方法执行后");}}
以上拦截器只是排除拦截的后端的注册登录代码,这个时候拦截器拦截住了前端页面,此时我们还需要排除前端页面的代码。将所有的前端页面内容放入一个队列中,然后直接排除掉这个队列。
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;private static List<String> excludePath = Arrays.asList("/user/login","/css/**","/js/**","/pic/**","/**/*.html");@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器//**表示给所有方法添加拦截器registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//表示给所有方法都添加拦截器.excludePathPatterns(excludePath);}
}
二.DispatcherServlet源码分析
当Tomcat启动时,有一个核心的类DispatcherServlet来控制程序进行的顺序,如果有拦截器则会先执行拦截器的内容。

Ctrl+N搜索DispatcherServlet这个类
阅读源码的流程


拦截器的执行流程
适配器
适配器模式, 也叫包装器模式. 简单来说就是目标类不能直接使用, 通过⼀个新类进行包装⼀下, 适配调用方使用. 把两个不兼容的接口通过⼀定的方式使之兼容。


适配器模式
举例:

一般来说,适配器模式可以看做一种“补偿模式”来补救设计上的缺陷,应用这种模式是“无奈之举”。所以适配器模式更多的应用场景是对正在运行的代码进行改造,并且希望可以复用原有代码实现新的功能,比如版本升级等。
三.统一数据返回格式
统一数据返回格式使用@ControllerAdvice和ResponseBodyAdvice(继承的类)
@ControllerAdvice表示控制器通知类
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {//重写的support方法中,返回改为truereturn true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//在返回前要做的事情return Result.success(body);}
} 但是在测试中会出现两个问题:
1.请求返回类型为Result时,结果会出现嵌套(有重复出现的部分),不需要再进行处理了。
2.返回结果为String时,不能正确进行处理。
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {//重写的support方法中,返回改为truereturn true;}@SneakyThrows //下面body转换成String的方法,idea给的解决异常的方法(相当于添加的try...catch语句)@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//在返回前要做的事情if (body instanceof Result){return body;}if(body instanceof String){return objectMapper.writeValueAsString(Result.success(body));}return Result.success(body);}
} 四.统一异常处理
对统一结果处理的代码进行调整统⼀异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的, @ControllerAdvice 表示控制器通知类, @ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。添加@ResponseBody返回数据(不添加表示返回页面)。
@ResponseBody//结果返回数据
@Slf4j
@ControllerAdvice
public class ErrorHandler {@ExceptionHandlerpublic Result exception(Exception e){log.error("发生异常,e:{}",e);return Result.fail("内部错误");}@ExceptionHandlerpublic Result exception(NullPointerException e){log.error("发生异常,e:{}",e);return Result.fail("NullPointerException异常,请联系管理员");}@ExceptionHandlerpublic Result exception(ArithmeticException e){log.error("发生异常,e:{}",e);return Result.fail("ArithmeticException异常");}
}

