文章目录
- 一、AOP实战------SpringBoot统一功能处理
-
- 1.1、使用拦截器实现用户登录权限的统一验证
-
- [1.1.1、使用原生Spring AOP实现统一拦截的难点](#1.1.1、使用原生Spring AOP实现统一拦截的难点)
- [1.1.2、Spring 拦截器](#1.1.2、Spring 拦截器)
-
- [1.1.2.1、Spring拦截器 使用步骤](#1.1.2.1、Spring拦截器 使用步骤)
- 1.1.2.2、拦截器实现原理
- 1.2、统一数据格式返回
- 1.3、统一异常处理
一、AOP实战------SpringBoot统一功能处理
1.1、使用拦截器实现用户登录权限的统一验证
以前进行用户登陆权限的验证方法:
java
@RestController
@Reques tMapping("/user")
public class UserController {
/**
*某方法1
*/
@RequestMapping("/m1")
public object method (HttpServletRequest request) {
//有session 就获取,没有不会创建
HttpSession session = request. getSession(false);
if (session != null && session.getAttribute ("userinfo") != null) {
//说明已经登录,业务处理
return true;
} else {
//未登录
return false;
}
}
/**
*某方法2
*/
@RequestMapping ("/m2")
public object method2(HttpServletRequest request) {
//有session 就获取,没有不会创建
HttpSession session = request.getSession(false);
if (session != null && sess ion.getAttribute("userinfo") != null) {
//说明已经登录,业务处理
return true;
} else {
//未登录
return false;
}
}
// 其他方法...
1.1.1、使用原生Spring AOP实现统一拦截的难点
前面已经学习了AOP知识知道可以通过AOP规则拦截未登录页面(除了拦截接口,还有前端页面...),但是使用原生的Spring AOP实现同意拦截有一些难点:
(1)、切点的拦截表达式规则复杂,难以定义
(2)、在切面类里拿到 HttpSession类 比较难
1.1.2、Spring 拦截器
Spring 引入 拦截器 解决Spring AOP上述所说的这些问题。
1.1.2.1、Spring拦截器 使用步骤
(1)、自定义一个拦截器类(随意命名),该类必须实现 HandlerInterceptor,并且该自定义类里必须重写 preHandle()方法。
(2)、将⾃定义拦截器加⼊到系统配置
再自定义一个配置类(命名随意),此配置类必须实现 WebMvcConfigurer ,并且当前这个配置类是需要随着Spring的启动而启动,因此配置类必须加上 注解@Configuration,然后配置类里必须重写 addInterceptors()方法,然后将上面自定义的拦截类加入到该配置类中,此时我们自定义的拦截类才能生效。
早期的项目数据交互流程:
拦截器出现之后:
1.1.2.2、拦截器实现原理
那为什么拦截器可以在controller执行之前先执行??
所有的Controller执行时都会通过一个调度器 DispatcherServlet 来实现:
而程序中所有方法都会执行 DispatcherServlet 中的 doDispatch() 调度方法,doDispatch()源码中在开始执行 Controller 之前,首先是调用了预处理方法 applyPreHandle(),而applyPreHandle的源码中,首先是获取到所有的拦截器HandlerInterceptor,并执行拦截器中的preHandle()方法,因此拦截器的预处理会比Controller先执行。
如果大家感兴趣 doDispatch() 、applyPreHandle的源码的话,可以自己去搜索看看,由于篇幅太长,我就不放在这里了。
1.2、统一数据格式返回
1.2.1、为什么要返回统一的数据格式
统一数据返回格式的优点有很多,如下:
(1)、方便前端程序员更好的接收和解析 后端接口返回的数据。
(2)、降低前端程序员和后端程序员的沟通成本,按照某个格式实现就行了,因为所有接口都是这样返回的。
(3)、有利于项目统一数据的维护和修改 。
(4)、有利于后端技术部门统一规范的标准制定, 不会出现稀奇古怪的返回内容。
1.2.2、返回统一数据格式的步骤
1.2.2.1、创建一个类,并在类上添加注解@ControllerAdvice
1.2.2.2、且该类要实现接口ResponseBodyAdvice,并重写supports、beforeBodyWrite方法(统一对象是在此方法中实现的)
例子:
test接口下前端接收到的数据格式:
当程序中设置了统一的数据返回格式后:
注意一个知识点 :
那为什么会出现这个异常信息呢?其实是因为:只要你的返回类型不是String,都能被统一数据返回格式转成标准的json格式返回给前端。String和其他类型都不一样:
所以我们在统一返回时,对于String,不能再借助Spring把HashMap转成json字符串格式了,需要对String进行单独的处理:先判断当前body是否为String,如果是,使用jackson将HashMap手动转为json字符串才行。
但是其实我们的统一数据返回格式还有其他问题:
1.2.3、最终版统一数据格式返回
待补充。
1.3、统一异常处理
1.3.1、感知系统异常
如何感知到异常??使用注解:@ControllerAdvice 感知到异常:即自己定义的异常类上加上该注解,加上该注解之后,当前类会随着项目的启动而启动。注解@ControllerAdvice表示控制器通知类。
然后该自定义的异常类里的方法需要加上注解 @ExceptionHandler(异常管理器),加上这个注解之后,相当于订阅了系统的异常事件了。如果项目出了异常,加了该注解的方法就能够获取到项目的异常。 @ExceptionHandler(这里面写的是什么异常的反射,就能拿到什么异常),比如说:@ExceptionHandler(Exception.class) 那就能拿到所有异常,如果是:@ExceptionHandler(IOException.class) 就能拿到IO产生的异常...
但其实虽然我们定义了统一处理的异常类,上述图片我们定义了空指针异常统一处理、算数异常统一处理,但是其实如果程序代码中若还出现了其他异常如:越界异常、栈溢出异常...这些异常我们还是没办法统一处理到,这该怎么办?要么继续添加定义该异常的统一异常处理方法,要么定义一个保底的异常方法。比较推荐第二种办法。
1.3.2、统一返回异常对象。
感知到异常之后,再将异常封装成统一对象返回给前端。
上述项目例子链接,自行下载练习。