Spring AOP、Spring Boot统一功能处理与事务的学习


前言

Spring AOP是一个实现面向切面编程思想的框架,可以实现对功能统一且使用地方较多的功能进行统一处理。


一、Spring AOP

1.Spring AOP是什么?

AOP(Aspect Oriented Programming):面向切面编程,是一种思想,是对某一类事情的集中处理。Spring AOP是一个框架,是对AOP思想的具体实现。类似于IoC和DI的关系。
主要学习:
1.AOP是如何组成的。
2.Spring AOP的使用。
3.Spring AOP的实现原理。

2.AOP组成

(1)切面(Aspect)

切面由切点和连接点组成。在程序中就是一个处理某方面具体问题的一个类,类里面包含了很多方法,这些方法就是切点和通知。

(2)切点(Pointcut)

用来进行主动拦截的规则(配置)。

(3)通知(Advice)

切面的工作,程序中被拦截请求触发的具体动作,就是在通知中实现的具体业务代码。
(1)前置通知:在执行目标方法之前执行的方法就叫做前置通知。
(2)后置通知:在执行了目标方法之后执行的方法就叫做后置通知。
(3)异常通知:在执行了目标方法出现异常时,执行的通知。
(4)返回通知:目标方法执行了返回数据(return)时,执行的通知。
(5)环绕通知:在目标方法执行的周期范围内(执行之前、执行中、执行后)都可以执行的方法叫做环绕通知。

(4)连接点(Joint Point)

应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
可能会触发AOP规则的所有点(所有请求)。

3.Spring AOP使用

1.添加Spring AOP依赖;
创建Spring Boot项目时是没有Spring AOP框架可以选择的,创建好项目之后,再在pom.xml中添加Spring AOP的依赖即可。
在这里插入图片描述
在这里插入图片描述

		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
			<version>2.7.9</version>
		</dependency>

2.定义切面(创建切面类);

在这里插入图片描述

3.定义切点(配置拦截规则);
在这里插入图片描述

4.定义通知的实现。
在这里插入图片描述
环绕通知:

    //环绕通知
    @Around("pointcut()")
    public Object aroundAdvice(ProceedingJoinPoint jointPoint) throws Throwable {
    
    
        System.out.println("进入环绕通知了~");
        Object obj = null;
        //执行目标方法
        obj = jointPoint.proceed();
        System.out.println("退出环绕通知了~");
        return obj;
    }

4.Spring AOP实现原理

Spring AOP是构建在动态代理基础上,因此Spring对AOP的支持局限于方法级别的拦截。
Spring的切面包裹了目标对象的代理类实现,代理类处理方法的调用,执行额外的切面逻辑,并调用额外方法。

二、Spring Boot统一功能处理

1.使用拦截器实现用户登录权限的统一效验

(1)原生Spring AOP实现统一拦截的难点:
a.定义拦截的规则(表达式)非常难;
b.在切面类中拿到HttpSession比较难。
(2)实现一个普通拦截器
关键步骤:
a.实现HandlerInterceptor接口;
b.重写preHeadler方法,在方法中编写自己的业务代码。

public class LoginInterceptor implements HandlerInterceptor {
    
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        //用户登录业务逻辑
        HttpSession session = request.getSession(false);
        if (session!=null && session.getAttribute("userinfo") !=null) {
    
    
            //说明用户以及登录
            return true;
        }
        //可以调整到登录页面 或者 返回一个 401/403 没有权限码
        response.sendRedirect("/login.html");
        return false;
    }
}

(3)将拦截器添加到配置文件中,并且设置拦截规则

@Configuration
public class AppConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") //拦截所有请求
                .excludePathPatterns("/user/login") //排除URL地址(不拦截的URL地址)
                .excludePathPatterns("/user/reg")
                .excludePathPatterns("/**/*.html");
    }
}

给当前项目配置统一的前缀:
(1)在系统的配置文件中设置;

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
    
    
        configurer.addPathPrefix("/zhangsan",c->true);
    }

(2)在application.properties/.yml中配置。

2.统一异常的返回

异常统一封装:
(1)创建一个类,并在类上标识@ControllerAdvice;

(2)添加方法@ExceptionHandler来订阅异常。

@ControllerAdvice
public class MyExHandler {
    
    

    //拦截所有的空指针异常,并统一处理
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String,Object> nullException(NullPointerException e) {
    
    
        HashMap<String,Object> result = new HashMap<>();
        result.put("code","-1");
        result.put("msg","空指针异常:"+e.getMessage());
        result.put("data",null);
        return result;
    }
}

3.统一数据格式的返回

优点:
(1)方便前端更好地接收和解析后端数据接口返回的数据;
(2)降低前端与后端的沟通成本,按照某个格式实现就行;
(3)有利于项目统一数据的维护和修改;
(4)有利于后端技术的统一规范的标准制定。
实现:
(1)创建一个类,并添加@ControllerAdvice;
(2)实现ResponseBodyAdvice接口,并重写supports和beforeBodyWrite(统一对象就是此方法实现的)

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    
    
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
    
    
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    
    
        HashMap<String,Object> result = new HashMap<>();
        result.put("code",200);
        result.put("msg","");
        result.put("data",body);
        //String在转换时会出错  需要特殊处理,
        if (body instanceof String) {
    
    
            try {
    
    
                return objectMapper.writeValueAsString(result);
            } catch (JsonProcessingException e) {
    
    
                e.printStackTrace();
            }
        }
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45283185/article/details/129496550