7天学完Spring:AOP实战,SpringMVC统一处理

前言

接下来是 Spring Boot 统一功能处理模块了,也是 AOP 的实战环节,要实现的课程目标有以下 3 个:

  1. 统一用户登录权限验证;
  2. 统一数据格式返回;
  3. 统一异常处理。

一丶用户登录权限效验

用户登录权限的发展从之前每个方法中自己验证用户登录权限,到现在统一的用户登录验证处理,它是 一个逐渐完善和逐渐优化的过程。

<1>最初用户登录验证

我们先来回顾一下最初用户登录验证的实现方法:

@RestController
@RequestMapping("/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 && session.getAttribute("userinfo") != null) {
            // 说明已经登录,业务处理
            return true;
       } else {
            // 未登录
            return false;
       }
   }
    // 其他方法...
}

这是我们刚开始的用法,就是刚刚学习完SpringBoot时候的用法,用Session来判断当前的登录状态。但是问题是什么呢?
1. 每个方法中都要单独写用户登录验证的方法,即使封装成公共方法,也一样要传参调用和在方法中进行判断。
2. 添加控制器越多,调用用户登录验证的方法也越多,这样就增加了后期的修改成本和维护成本。
3. 这些用户登录验证的方法和接下来要实现的业务几何没有任何关联,但每个方法中都要写一遍。

所以就很麻烦,但是小伙伴们灵机一动,诶,上节课不是学了AOP吗?刚才切面编程是处理这个问题的好手呀

<2>Spring AOP 用户统一登录验证的问题

竟我们上节课刚学,但是这里有一个问题

然后就又有小伙伴说了,我们可以这么写呀

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {
    // 定义切点方法 controller 包下、子孙包下所有类的所有方法
    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void pointcut(){ }
    // 前置方法
    @Before("pointcut()")
    public void doBefore(){
       
   }
    
    // 环绕方法
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object obj = null;
        System.out.println("Around 方法开始执行");
        try {
            // 执行拦截方法
           obj = joinPoint.proceed();
       } catch (Throwable throwable) {
            throwable.printStackTrace();
       }
        System.out.println("Around 方法结束执行");
        return obj;
   }
}

对,没错,你是判断了是否登录,但是,是有问题的!在这里插入图片描述

<3>拦截器

对于以上问题 Spring 中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步骤:

  1. 创建自定义拦截器,实现 HandlerInterceptor 接口的 preHandle(执行具体方法之前的预处理)方法。
  2. 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中。

如下
在这里插入图片描述

拦截功能演示

首先,我们原本的代码是没有登录验证的,这里先随便写一个登录功能
在这里插入图片描述
在这里插入图片描述
然后开始书写我们的拦截器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
嗯?怎么回事?怎么回事空呢?这没有道理,但是仔细想想,我们当前的代码,是在AOP基础上书写的,然后前面的AOP代码有没有什么问题,仔细一想,好像有点!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<4>拦截器原理

所有的 Controller 执行都会通过一个调度器 DispatcherServlet 来实现,这一点可以从 Spring Boot 控制台的打印信息看出,如下图所示:
在这里插入图片描述
而所有方法都会执行 DispatcherServlet 中的 doDispatch 调度方法。
执行 Controller 之前,会先调用 预处理方法 applyPreHandle,而applyPreHandle 方法的实现源码如下:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse
response) throws Exception {
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex =
i++) {
        // 获取项目中使用的拦截器 HandlerInterceptor
        HandlerInterceptor interceptor =
(HandlerInterceptor)this.interceptorList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
            this.triggerAfterCompletion(request, response, (Exception)null);
            return false;
       }
   }
    return true;
}

从上述源码可以看出,在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor 并执行拦截器中
的 preHandle 方法,这样就会咱们前面定义的拦截器对应上了,

<5>统一访问前缀添加

这个是个挺简单的语法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那可能会有铁子问了,你这么搞的意义在哪里呢?还特意加个访问前缀
在这里插入图片描述

二丶统一异常处理

统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件
此时我们给个异常事件
在这里插入图片描述
这个时候应该会有一个异常信息
在这里插入图片描述
但是此时,就很难受不是嘛?我们换种方法来写
在这里插入图片描述
这种也可以,可是就很不现实不是嘛?一个错误来一个异常?每个错误都给你加一个?
在这里插入图片描述
看我下面的写法,当前类加上@ControllerAdvice注解
在这里插入图片描述
在这里插入图片描述此时打印信息如下:
在这里插入图片描述
在这里插入图片描述

<1>重改1/0异常

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<2>重改登录异常

所以这里修改一下登录报错的信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<3>写法小梳理

在这里插入图片描述

在这里插入图片描述

三丶统一数据格式封装

<1>为什么需要统一的数据格式封装呢?

统一数据返回格式的优点有很多,比如以下几个:
1. 方便前端程序员更好的接收和解析后端数据接口返回的数据。
2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就行了,因为所有接口都是这样返回
的。
3. 有利于项目统一数据的维护和修改。
4. 有利于后端技术部门的统一规范的标准制定,不会出现稀奇古怪的返回内容。


如果感觉有点迷的话,那就不看上面这个,看我下面的图示
在这里插入图片描述

<2>怎么实现呢?

这个不难,看我下面图示的步骤
在这里插入图片描述
然后之后返回的内容如下
在这里插入图片描述
然后到了这里,就讲完啦,不对,还有个问题要忘了说了
在这里插入图片描述
就是返回值不能是你要统一返回的不能是null值嗷

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringAOP 全称为 Spring Aspect-Oriented Programming,是 Spring 框架中的一个模块,用于实现面向切面编程。在 SpringAOP 中,我们可以通过定义切点和通知来实现对目标对象的增强。 在平台开发中,我们可以使用 SpringAOP 来解决平台统一异常处理的问题。具体实现步骤如下: 1. 定义异常处理切面 在 SpringAOP 中,我们可以使用 @Aspect 注解来定义切面。在切面类中,我们需要定义一个处理异常的方法,并使用 @AfterThrowing 注解来指定这个方法是用于处理异常的。例如: ```java @Aspect public class ExceptionHandlerAspect { @AfterThrowing(pointcut = "execution(* com.example.*.*(..))", throwing = "ex") public void handleException(Exception ex) { // 处理异常的逻辑 } } ``` 在上述代码中,我们定义了一个名为 ExceptionHandlerAspect 的切面类,并在其中定义了一个名为 handleException 的方法,该方法的参数为 Exception 类型,用于处理异常。我们使用 @AfterThrowing 注解来指定这个方法是用于处理异常的,pointcut 属性用于指定切入点,这里我们使用 execution 表达式来匹配 com.example 包及其子包下的所有方法。 2. 配置 SpringAOPSpring 配置文件中,我们需要配置 SpringAOP。具体来说,我们需要定义一个名为 exceptionHandlerAspect 的 bean,并在其中指定切面的实现类。例如: ```xml <bean id="exceptionHandlerAspect" class="com.example.ExceptionHandlerAspect"/> <aop:config> <aop:aspect ref="exceptionHandlerAspect"> <aop:after-throwing method="handleException" throwing="ex"/> </aop:aspect> </aop:config> ``` 在上述代码中,我们首先定义了一个名为 exceptionHandlerAspect 的 bean,该 bean 的 class 属性指定了切面的实现类。然后,在 aop:config 标签中,我们使用 aop:aspect 标签来定义切面,并在其中指定切面的实现类。在 aop:aspect 标签中,我们使用 aop:after-throwing 标签来指定切面所织入的方法,method 属性用于指定处理异常的方法名,throwing 属性用于指定方法抛出的异常类型。 3. 使用统一异常处理 在业务代码中,当发生异常时,SpringAOP 会自动调用我们定义的异常处理方法。在这个方法中,我们可以根据具体的业务需求来处理异常。例如: ```java @Service public class UserServiceImpl implements UserService { @Override public void addUser(User user) { // 业务逻辑 try { // 执行业务操作 } catch (Exception e) { throw new RuntimeException("添加用户失败!"); } } } ``` 在上述代码中,当执行 addUser 方法时,如果发生异常,SpringAOP 会自动调用我们定义的异常处理方法 handleException,并将异常对象作为参数传入该方法中。在 handleException 方法中,我们可以根据具体的业务需求来处理异常,例如记录日志、发送邮件等。 通过使用 SpringAOP,我们可以实现平台统一异常处理,避免代码中出现大量的 try-catch 代码块,提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值