Spring Boot系列-使用自定义注解校验用户是否登录

简介:

记得今年年初刚开始面试的时候,被问的最多的就是你知道Spring的两大核心嘛?那你说说什么是AOP,什么是IOC?我相信你可能也被问了很多次了。

1、到底是什么是AOP?

所谓AOP也就是面向切面编程,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。这里面有一个比较显眼的词我们需要注意一下,横切,它是基于横切面对程序进行扩展的。

2、AOP相关术语

在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:

 ●  连接点(Joinpoint) :在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后;
 ●  切点(Pointcut :所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;
 ●  增强(Advice :增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;
 ●  目标对象(Target) :增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;
 ●  引介(Introduction :一种特殊的增强,它可以为类添加一些属性喝方法;
 ●  织入(Weaving :织入就是讲增强逻辑添加到目标对象的过程;
 ●  代理(Proxy :一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;

 ●  切面(Aspect:切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;

3、AOP功能实践

我们这里主要是学习SpringBoot中的一些功能,所以我们这里用的是SpringBoot工程,版本也是最新的2.0.5版本。

创建SpringBoot工程就不说了,我们直接引入Maven的依赖:


<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

<!-- 引入AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
</executions>
</plugin>
</plugins>
</build>

首先我们来创建一个Controller类:


@RestController
public class LoginController {

 @GetMapping(value = "/username")
public String getLoginUserName(String userName, Integer age) {
 
return userName + " --- " + age;
}
}

创建切面:


@Aspect
@Component
public class LogAspect {

 /**
* 功能描述: 拦截对这个包下所有方法的访问
*
* @param:[]
* @return:void
**/
@Pointcut("execution(* com.example.springbootaop.controller.*.*(..))")
public void loginLog() {
}

// 前置通知
@Before("loginLog()")
public void loginBefore(JoinPoint joinPoint) {

// 我们从请求的上下文中获取request,记录请求的内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

System.out.println("请求路径 : " + request.getRequestURL());
System.out.println("请求方式 : " + request.getMethod());
System.out.println("方法名 : " + joinPoint.getSignature().getName());
System.out.println("类路径 : " + joinPoint.getSignature().getDeclaringTypeName());
System.out.println("参数 : " + Arrays.toString(joinPoint.getArgs()));
}

@AfterReturning(returning = "object", pointcut = "loginLog()")
public void doAfterReturning(Object object) {

System.out.println("方法的返回值 : " + object);
}

// 方法发生异常时执行该方法
@AfterThrowing(throwing = "e",pointcut = "loginLog()")
public void throwsExecute(JoinPoint joinPoint, Exception e) {

System.err.println("方法执行异常 : " + e.getMessage());
}

// 后置通知
@After("loginLog()")
public void afterInform() {

System.out.println("后置通知结束");
}

// 环绕通知
@Around("loginLog()")
public Object surroundInform(ProceedingJoinPoint proceedingJoinPoint) {

System.out.println("环绕通知开始...");

try {
Object o = proceedingJoinPoint.proceed();
System.out.println("方法环绕proceed,结果是 :" + o);
return o;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}

注解概述:

 ●  @Apsect :将当前类标识为一个切面;
 ●  @Pointcut :定义切点,这里使用的是条件表达式;
 ●  @Before :前置增强,就是在目标方法执行之前执行;
 ●  @AfterReturning :后置增强,方法退出时执行;
 ●  @AfterThrowing :有异常时该方法执行;
 ●  @After :最终增强,无论什么情况都会执行;
 ●  @Afround :环绕增强;

测试:

fa7a52d0f144fe970d037c599d04fd540aae0ff7

异常测试:

336c61d568cddca2e9eded9d7aa16ef081e08f47

4、定义自定义注解

应用场景:在我之前上个项目的时候,有这样一个注解,就是在访问其他接口的时候必须要登录,那么这个时候我们就定义一个注解,让它去对用户是否登录进行校验,那么基于这样的一个场景,我们来定义一个校验登录的注解。

创建一个注解:


@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {

 String desc() default "验证是否登录";
}

创建一个AOP切面:


@Aspect
@Component
public class LoginAspect {

 @Pointcut(value = "@annotation(com.example.springbootaop.annotation.Auth)")
public void access() {
}

@Before("access()")
public void before() {

System.out.println("开始验证用户是否登录...");
}

@Around("@annotation(auth)")
public Object around(ProceedingJoinPoint pj, Auth auth) {

// 获取注解中的值
System.out.println("注解中的值 : " + auth.desc());
try {

// 检验是否登录 true 已经登录 false 未登录
Boolean flag = false;

if (flag == true) {
return "登录成功";
} else {
return "未登录";
}
} catch (Throwable throwable) {
return null;
}
}
}

测试未登录:

975601262099724420753547b98e2ca5a6a9a791

测试登录:

c43c4e49812c0f063c8cf5b6061859456feb82ea

这样我们就可以简单的实现了一个登录校验的注解。

通过今天的分享你会使用AOP和自定义注解了吗?我把源码的地址放在下面,有兴趣的朋友可以看看。


原文发布时间为:2018-10-19
本文作者:一个程序员的成长
本文来自云栖社区合作伙伴“ Web项目聚集地”,了解相关信息可以关注“ Web项目聚集地”。
相关文章
|
2月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
432 128
|
30天前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
262 2
|
2月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
244 12
|
2月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
143 0
探索Spring Boot的@Conditional注解的上下文配置
|
2月前
|
Java 测试技术 编译器
@GrpcService使用注解在 Spring Boot 中开始使用 gRPC
本文介绍了如何在Spring Boot应用中集成gRPC框架,使用`@GrpcService`注解实现高效、可扩展的服务间通信。内容涵盖gRPC与Protocol Buffers的原理、环境配置、服务定义与实现、测试方法等,帮助开发者快速构建高性能的微服务系统。
429 0
|
7月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
201 0
|
4月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
367 0
|
8月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——指定项目配置文件
在实际项目中,开发环境和生产环境的配置往往不同。为简化配置切换,可通过创建 `application-dev.yml` 和 `application-pro.yml` 分别管理开发与生产环境配置,如设置不同端口(8001/8002)。在 `application.yml` 中使用 `spring.profiles.active` 指定加载的配置文件,实现环境快速切换。本节还介绍了通过配置类读取参数的方法,适用于微服务场景,提升代码可维护性。课程源码可从 [Gitee](https://gitee.com/eson15/springboot_study) 下载。
309 0
|
JSON 前端开发 Java
SpringBoot自定义异常,优雅解决业务逻辑中的错误
SpringBoot自定义异常,优雅解决业务逻辑中的错误
6750 0
SpringBoot自定义异常,优雅解决业务逻辑中的错误