Spring AOP以及统一处理

这篇具有很好参考价值的文章主要介绍了Spring AOP以及统一处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.Spring AOP 

1.什么是Spring AOP 

AOP(Aspect Oriented Programming):面向切面编程,它是一种思想,它是对某一类事情的集中处理

2.AOP的作用

想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面调用的前端控制器( Controller)都需要先验证用户登录的状态,那这个时候我们要怎么处 理呢?
我们之前的处理方式是每个 Controller 都要写一遍用户登录验证,然而当你的功能越来越多,那么你要 写的登录验证也越来越多,而这些方法又是相同的,这么多的方法就会代码修改和维护的成本。那有没 有简单的处理方案呢?答案是有的,对于这种功能统一,且使用的地方较多的功能,就可以考虑 AOP 来统一处理了。

  • 除了统一的用户登录判断之外,AOP 还可以实现:
  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等
  • AOP是OOP的补充 

 3.AOP的相关概念

1.切面(Aspect)

面(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包

括了连接点的定义。

2.连接点 (Join Point)

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

3.切点(Pointcut)

Pointcut 是匹配 Join Point 的谓词。 Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述)来 匹配 Join Point,给满足规则的 Join Point 添加 Advice

4.通知(Advice)

 切面也是有目标的 ——它必须完成的工作。在 AOP 术语中,切面的工作被称之为通知。

通知:定义了切面是什么,何时使用,其描述了面要完成的工作,还解决何时执行这个工作的

问题。

Spring 切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本

方法进行调用:

  • 前置通知使用 @Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用 @After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用 @AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用 @AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执
  • 行自定义的行为。

Spring AOP以及统一处理,SSM,spring,java,后端

Spring AOP以及统一处理,SSM,spring,java,后端

 4.Spring AOP的实现

1.添加 AOP 框架支持

在 pom.xml 中添加如下配置:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
<!--        Springboot test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--      Spring AOP 框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

2.定义切面和切点

@Component
@Slf4j
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..))")
    public void pointcut() {
    }

}

@Aspect类注解表示LoginAspect是一个切面类,@Pointcut表示定义一个切点,其中的内容表示连接点的规则,也就是包括哪些类或者方法属于这个切点,连接点.

其中 pointcut 方法为空方法,它不需要有方法体,此方法名就是起到⼀个“标识”的作用,标识下面的

通知方法具体指的是哪个切点(因为切点可能有很多个)

AspectJ 支持三种通配符

* :匹配任意字符,只匹配⼀个元素(包,类,或方法,方法参数)

.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。

+ :表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.cad.Car+ ,表示继承该类的

所有子类包括本身

切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为:

execution(<修饰符><返回类型><包.类.方法(参数)><异常>)

修饰符和异常可以省略,具体含义如下:

Spring AOP以及统一处理,SSM,spring,java,后端

上面我们定义的含义为,匹配com.javastudy.springaopdemo5.controller.LoginController类下所有的方法.

3.定义相关通知

先来定义controller层的内容

@RestController
@Slf4j
@RequestMapping("/user")
public class LoginController {

    @RequestMapping("/login")
    public String login() {
        log.info("login...");
        return "login...";
    }

    @RequestMapping("/register")
    public String register() {
        log.info("register...");
        return "register...";
    }

    @RequestMapping("/get")
    public String get() {
        log.info("get...");
        return "get...";
    }

}
1.前置通知 @Before

通知方法会在目标方法调用之前执行。

注意:@Before里面的内容表示切点,即在哪些接口中执行这些通知.

@Component
@Slf4j
@Aspect
public class LoginAspect {
    @Pointcut("execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..))")
    public void pointcut() {
    }

    //前置通知
    @Before("pointcut()")
    public void doBefore() {
        log.info("do before....");
    }


}

 当我们访问任意一个页面的时候,控制台打印如下日志

Spring AOP以及统一处理,SSM,spring,java,后端

可以看到都会先执行doBefore通知.

2.后置通知 @After

通知方法会在目标方法返回或者抛出异常后调用

    //后置通知
    @After("pointcut()")
    public void doAfter() {
        log.info("do after...");
    }

Spring AOP以及统一处理,SSM,spring,java,后端

 模拟异常情况,可以在LoginController中某一个方法加10/0,观察

    @RequestMapping("/login")
    public String login() {
        log.info("login...");
        int i=10/0;
        return "login...";
    }

Spring AOP以及统一处理,SSM,spring,java,后端

可以观察到在方法异常之后, @After通知仍然会执行.

3.返回之后通知 @AfterReturning

通知方法会在目标方法返回后调用

    // return 之前通知
    @AfterReturning("pointcut()")
    public void doAfterReturning() {
        log.info("do after returning...");
    }

当我们访问login接口的时候(10/0,有异常),观察是否有输出

Spring AOP以及统一处理,SSM,spring,java,后端

此时是没有输出的.

访问其它接口,没有异常的接口

Spring AOP以及统一处理,SSM,spring,java,后端 此时@AfterReturning通知正常执行

4.抛异常后通知 @AfterThrowing

通知方法会在目标方法抛出异常后调用。

    //抛出异常之前通知
    @AfterThrowing("pointcut()")
    public void doAfterThrowing() {
        log.info("do after throwing");
    }

执行有异常的接口,有日志的打印

Spring AOP以及统一处理,SSM,spring,java,后端

执行没有异常的接口,没有日志的打印 

Spring AOP以及统一处理,SSM,spring,java,后端

5.环绕通知 @Around

通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object oj = null;
        log.info("环绕通知执行之前...");
        log.info(joinPoint.getSignature().toLongString());
        try {
            oj = joinPoint.proceed();//调用目标方法
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info("环绕通知执行之后....");
        return oj;
    }

执行没有异常的接口:

Spring AOP以及统一处理,SSM,spring,java,后端

执行有异常的接口: 

Spring AOP以及统一处理,SSM,spring,java,后端

接下来我们看看ProceedingJoinPoint 常用方法

toString 连接点所在位置的相关信息
toShortString 连接点所在位置的简短相关信息
toLongString 连接点所在位置的全部相关信息
getThis 返回AOP代理对象,也就是com.sun.proxy.$Proxy18
getTarget 返回目标对象(定义方法的接口或类)
getArgs() 返回被通知方法参数列表
getSignature 返回当前连接点签名,其getName()方法返回方法的FQN

执行所有的通知,观察环绕通知和前置通知和后置通知的先后顺序

Spring AOP以及统一处理,SSM,spring,java,后端

 可以观察到,环绕通知先于before,后于after.

如果一个切点只含有一个通知,那么我们可以将切点的规则放在通知上

@Component
@Slf4j
@Aspect
public class LoginAspect {
    //前置通知
    @Before("execution(* com.javastudy.springaopdemo5.controller.LoginController.*(..))")
    public void doBefore() {
        log.info("do before....");
    }


}

4.Spring AOP 实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的支持局限于方法级别的拦截。

Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下,实现了接口的类,使

用 AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。

Spring AOP以及统一处理,SSM,spring,java,后端

代理模式:

1.静态代理
1.定义接口
public interface PayService {
    void pay();
}
2.实现接口
public class AliPayService implements PayService{
    @Override
    public void pay() {
        System.out.println("ali pay...");
    }
}
3.创建代理类, 并同样实现支付接口
public class StaticProxy implements PayService {
    private final PayService payService;

    public StaticProxy(PayService payService) {
        this.payService = payService;
    }

    @Override
    public void pay() {
        System.out.println("before...");
        payService.pay();
        System.out.println("after...");
    }
}
4.实际使用
    public static void main(String[] args) {
        PayService service = new AliPayService();
        PayService proxy = new StaticProxy(service);
        proxy.pay();
    }

Spring AOP以及统一处理,SSM,spring,java,后端 静态代理有个很大的缺点,就是当有很多不同的接口的时候,我们需要定义很多个代理类实现不同的接口,当我们代理实现的功能相同的时候,但是有多个接口,此时完成这么多代理类很麻烦,此时需要我们的动态代理.

2.动态代理
1.JDK动态代理

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中 的。

就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态 代理等等。

定义JDK动态代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author Chooker
 * @create 2023-07-27 22:36
 */

public class JDKInvocationHandler implements InvocationHandler {
    //⽬标对象即就是被代理对象
    private Object target;

    public JDKInvocationHandler(Object target) {
        this.target = target;
    }
    //proxy代理对象

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录⽇志
        System.out.println("记录⽇志");
        //3.时间统计开始
        System.out.println("记录开始时间");
        //通过反射调⽤被代理类的⽅法
        Object retVal = method.invoke(target, args);
        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }
}

创建⼀个代理对象并使用 

    public static void main(String[] args) {
        PayService target = new AliPayService();
        //创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建
        PayService proxy = (PayService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{PayService.class},
                new JDKInvocationHandler(target)
        );
        proxy.pay();
    }

Spring AOP以及统一处理,SSM,spring,java,后端

缺点:JDK的动态代理必须有接口

2.CGLIB动态代理

CGLIB 动态代理类使用步骤

1. 定义一个类;

2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强

被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;

3. 通过 Enhancer 类的 create()创建代理类

添加依赖(如果创建的是一个Spring项目,不需要引入,因为Spring底层已经引入了cglib框架)

<dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>3.3.0</version>
</dependency>

自定义 MethodInterceptor(方法拦截器)

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author Chooker
 * @create 2023-07-27 22:48
 */
public class CGLIBInterceptor implements MethodInterceptor {
    //被代理对象
    private Object target;

    public CGLIBInterceptor(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录⽇志
        System.out.println("记录⽇志");
        //3.时间统计开始
        System.out.println("记录开始时间");
        //通过cglib的代理⽅法调⽤
        Object retVal = methodProxy.invoke(target, args);
        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }


}

1. obj : 被代理的对象(需要增强的对象)

2. method : 被拦截的方法(需要增强的方法)

3. args : 方法入参

4. proxy : 用于调用原始方法

 创建代理类, 并使用 

    public static void main(String[] args) {
        PayService target = new AliPayService();
        PayService proxy = (PayService) Enhancer.create(target.getClass(), new CGLIBInterceptor(target));
        proxy.pay();
    }

Spring AOP以及统一处理,SSM,spring,java,后端

JDK 动态代理和 CGLIB 动态代理对比

1. JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代 理未实现任何接口的类。

2. CGLIB 动态代理是通过生成⼀个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 

性能: 大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更 加明显。

Spring代理选择

1. proxyTargetClass 为false, 目标实现了接口, 用jdk代理

2. proxyTargetClass 为false, 目标未实现接口, 用cglib代理

3. proxyTargetClass 为true, 用cglib代理

织入(Weaving):代理的生成时机
织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对
象中。
在目标对象的生命周期里有多个点可以进行织入:

  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
  • 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving. LTW)就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某⼀时刻被织入。⼀般情况下,在织入切面时,AOP容器会为目标对象动态创建⼀个代理对象。SpringAOP就是以这种方式织入切面的。

上面我们学习的是Spring AOP的原理,是接下来我们学习内容的底层,SpringBoot一些常见的功能进行了封装,底层使用AOP实现的

二.SpringBoot 统一功能处理

需要实现用户的登录权限的校验功能,在Servlet阶段,我们可以通过在Session中保存用户的信息,之后每个页面先通过session中判断是否存在用户的信息,如果存在说明用户已经登录过了,没有就跳转到登录的页面.

1.Spring AOP 用户统一登录验证的问题

我们第一时间想到的就是通过环绕通知来解决这个问题,可以对除了登录和注册的页面采用环绕通知,用来判断用户是否登录过了.但是会出现以下两个问题

1.. 没办法获取到 HttpSession 对象。

2. 我们要对一部分方法进行拦截,而另一部分方法不拦截,如注册方法和登录方法是不拦截的,这样 的话排除方法的规则很难定义,甚至没办法定义。

那么该如何解决呢?

2.Spring 拦截器

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

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

2. 将自定义拦截器加入 WebMvcConfigurer 的 addInterceptors 方法中

1.自定义拦截器

@Component
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("username") != null) {
            //通过
            return true;
        }
        //没有权限访问
        response.setStatus(401);
        return false;
    }
}

2.将自定义拦截器加入到系统配置

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor).
                //表示拦截所有的路径
                addPathPatterns("/**").
                //不拦截login接口
                excludePathPatterns("/login").
                //不拦截register接口
                excludePathPatterns("/register");
    }
}

其中:

addPathPatterns:表示需要拦截的 URL,“**”表示拦截任意方法(也就是所有方法)。

excludePathPatterns:表示需要排除的 URL。

说明:以上拦截规则可以拦截此项目中的使用 URL,包括静态文件(图片文件、JS 和 CSS 等文件)。

排除所有的静态资源

    // 拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有接⼝
                .excludePathPatterns("/**/*.js")
                .excludePathPatterns("/**/*.css")
                .excludePathPatterns("/**/*.jpg")
                .excludePathPatterns("/login.html")
                .excludePathPatterns("/**/login"); // 排除接⼝
    }

拓展以下,可以在里面添加统一前缀的添加

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")// 拦截所有url
                .excludePathPatterns("/api/user/login")
                .excludePathPatterns("/api/user/reg");
    }

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

3.controller接口模仿登录

@RestController
@Slf4j
@RequestMapping("/user")
public class LoginController {

    @RequestMapping("/login")
    public boolean login(HttpServletRequest request, String username, String password) {
        log.info("login...");
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            return false;
        }
        //此时表示账号密码正确
        if ("admin".equals(username) && "123456".equals(password)) {
            HttpSession session = request.getSession(true);
            session.setAttribute("username", username);
            return true;
        }
        return false;

    }

    @RequestMapping("/register")
    public String register() {
        log.info("register...");
        return "register...";
    }

    @RequestMapping("/get")
    public String get() {
        log.info("get...");
        return "get...";
    }

}

当我们直接访问get接口的时候:显示的是401,表示没有权限

Spring AOP以及统一处理,SSM,spring,java,后端

正常访问login和register接口都是可以实现的

 Spring AOP以及统一处理,SSM,spring,java,后端

 此时我们使用正确的账号密码登录:可以看到此时已经正确登录了

Spring AOP以及统一处理,SSM,spring,java,后端

 此时我们再次访问get接口:可以看到此时正确访问

Spring AOP以及统一处理,SSM,spring,java,后端

 3.拦截器的实现原理

正常情况下的调用顺序:

Spring AOP以及统一处理,SSM,spring,java,后端

 然而有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图所示:

Spring AOP以及统一处理,SSM,spring,java,后端

Spring AOP以及统一处理,SSM,spring,java,后端

拦截器是基于AOP的,Spring是基于Servlet的 

三.统一异常处理

统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知, 也就是执行某个方法事件,具体实现代码如下
@ControllerAdvice
@ResponseBody
public class ErrorHandler {

    @ExceptionHandler(Exception.class)
    public Object error(Exception e) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("success", 0);
        map.put("status", -1);
        map.put("msg", e.getMessage());
        return map;

    }

    @ExceptionHandler(NullPointerException.class)
    public Object error2(NullPointerException e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("success", 0);
        result.put("status", -2);

        result.put("message", "空指针异常:" + e.getMessage());
        return result;
    }

    @ExceptionHandler(ArithmeticException.class)
    public Object error2(ArithmeticException e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("success", 0);
        result.put("status", -3);

        result.put("message", "算数异常:" + e.getMessage());
        return result;
    }
}

controller

@RestController
@Slf4j
@RequestMapping("/error")
public class ErrorController {

    @RequestMapping("/test1")
    public boolean test1() {
        int i = 10 / 0;
        return true;
    }

    @RequestMapping("/test2")
    public boolean test2() {
        String a = null;
        a.length();
        return true;
    }

    @RequestMapping("/test3")
    public String test3() {
        throw new RuntimeException("test3手动创建异常");
    }
}
当有多个异常通知时,匹配顺序为当前类及其子类向上依次匹配

访问test1

Spring AOP以及统一处理,SSM,spring,java,后端

访问test2

Spring AOP以及统一处理,SSM,spring,java,后端

访问test3

Spring AOP以及统一处理,SSM,spring,java,后端

可以观察到当错误异常为子类的时候,匹配顺序为当前类及其子类向上依次匹配

三.统一数据返回格式

1.为什么需要统一返回格式

统一数据返回格式的优点有很多,比如以下几个:

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

2.统一数据返回格式的实现

统一的数据返回格式可以使⽤ @ControllerAdvice + ResponseBodyAdvice 的方式实现,具体实现代码如下:
@ControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice {

    /**
     * 内容是否需要重写(通过此⽅法可以选择性部分控制器和⽅法进⾏重写)
     * 返回 true 表示重写
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
    /**
     * ⽅法返回之前调⽤此⽅法
     */
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 构造统⼀返回对象
        HashMap<String, Object> result = new HashMap<>();
        result.put("state", 1);
        result.put("msg", "");
        result.put("data", body);
        if(body instanceof String){
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(result);
        }
        return result;
    }
}

假如没有if((body instanceof String)这一段代码,会发生如下的错误

Spring AOP以及统一处理,SSM,spring,java,后端

 controller:

@RestController
@Slf4j
@RequestMapping("/user")
public class LoginController {

    @RequestMapping("/login")
    public boolean login(HttpServletRequest request, String username, String password) {
        log.info("login...");
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
            return false;
        }
        //此时表示账号密码正确
        if ("admin".equals(username) && "123456".equals(password)) {
            HttpSession session = request.getSession(true);
            session.setAttribute("username", username);
            return true;
        }
        return false;

    }

    @RequestMapping("/register")
    public String register() {
        log.info("register...");
        return "register...";
    }

    @RequestMapping("/get")
    public String get() {
        log.info("get...");
        return "get...";
    }

}

Spring AOP以及统一处理,SSM,spring,java,后端

Spring AOP以及统一处理,SSM,spring,java,后端

Spring AOP以及统一处理,SSM,spring,java,后端文章来源地址https://www.toymoban.com/news/detail-727912.html

到了这里,关于Spring AOP以及统一处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [SSM]Spring面向切面编程AOP

    目录 十五、面向切面编程AOP 15.1AOP介绍 15.2AOP的七大术语 15.3切点表达式 15.4使用Spring的AOP 15.4.1准备工作 15.4.2基于AspectJ的AOP注解式开发 15.4.3基于XML配置方式的AOP(了解) 15.5AOP的实际案例:事务处理 15.6AOP的实际案例:安全日志 IoC使软件组件松耦合。AOP让你能够捕捉系统中经

    2024年02月15日
    浏览(49)
  • Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    今天主要说说如何通过自定义注解的方式,在 Spring Boot 中来实现 AOP 切面统一打印出入参日志。小伙伴们可以收藏一波。 废话不多说,进入正题! 在看看实现方法之前,我们先看下切面日志输出效果咋样: 从上图中可以看到,每个对于每个请求,开始与结束一目了然,并且

    2024年02月08日
    浏览(49)
  • 【Spring Boot 】Spring Boot 统一功能处理

    🎉🎉🎉 点进来你就是我的人了 博主主页: 🙈🙈🙈 戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔 🤺🤺🤺 目录 前言 1. Spring 拦截器 1.1 自定义拦截器 1.2 将自定义拦截器加入到系统配置中 1.3 拦截器实现原理 统一访问前缀添加 (扩展) 2. 统一异常的处理 (@Co

    2024年02月09日
    浏览(38)
  • Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

            在我们的项目开发中,我们都会对数据返回格式进行统一的处理,这样可以方便前端人员取数据,当然除了正常流程的数据返回格式需要统一以外,我们也需要对异常的情况进行统一的处理,以及项目必备的日志。         在项目开发中返回的是json格式的数据

    2024年01月19日
    浏览(43)
  • spring的异常统一处理

    前情回顾:         首先明确,当你的代码遇到bug时会报错,那报错后不处理就会程序停止运行。 那就需要异常捕获了,两种方法:         一、try...catch...直接自己处理         二、throws 将异常抛给调用者         在spring的框架中,要求就是简洁,在大量的代码中有t

    2024年02月04日
    浏览(40)
  • Spring统一功能处理

    获取参数复杂 AOP的规则相对简单 2.1.1. 自定义拦截器 新建interceptor文件夹 2.1.2. 将自定义拦截器加入到系统配置 新建config文件夹 2.1.3. 业务代码 方法1 方法2 2.3.1. 总体思路 2.3.2. 部分源码分析 拦截器是基于AOP实现的 (AOP基于动态代理(JDK|CGLIB)) 参考上一节 拦截器的应用 对于下面

    2024年02月11日
    浏览(32)
  • Spring Boot 统一功能处理

    ✏️作者:银河罐头 📋系列专栏:JavaEE 🌲 “种一棵树最好的时间是十年前,其次是现在” Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节。 Spring 中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步 骤: 创建⾃定义拦截器,实现 HandlerInterceptor 接

    2024年02月08日
    浏览(43)
  • 【Spring】SpringBoot 统一功能处理

    在日常使用 Spring 框架进行开发的时候,对于一些板块来说,可能需要实现一个相同的功能,这个功能可以是验证你的登录信息,也可以是其他的,但是由于各个板块实现这个功能的代码逻辑都是相同的,如果一个板块一个板块进行添加的话,开发效率就会很低,所以 Spring

    2024年01月18日
    浏览(40)
  • Spring 统一功能处理(拦截器)

    SpringBoot统一功能处理。也就是AOP的具体实现。 最原始的用户登录验证方法,我们通过封装了一个方法来判断用户是否登录,但如果实现的功能多了,那么每一个需要登录的功能都要在对应的接口中来调用这个函数来判读是否登录。 上面的代码虽然已经封装成了方法,但是如

    2024年02月03日
    浏览(54)
  • 【Spring Boot】拦截器与统一功能处理:统一登录验证、统一异常处理与统一数据返回格式

     Spring AOP是一个基于面向切面编程的框架,用于将横切性关注点(如日志记录、事务管理)与业务逻辑分离,通过代理对象将这些关注点织入到目标对象的方法执行前后、抛出异常或返回结果时等特定位置执行,从而提高程序的可复用性、可维护性和灵活性。但使用原生Sp

    2024年02月16日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包