AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
本次完成了使用IDE进行SpringBoot进行AOP的用户全向判断。
本次项目整体结构:
引入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!--<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>-->
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
</dependencies>
用户信息实体类:
package com.wen.entity;
import lombok.Data;
/**
* 作者: WENHENG
* 时间: 2020/10/19 10:30
* 说明: 用于对用户进行描述
*/
@Data
public class Users {
private String name;
private String role;
public Users() {
}
public Users(String name, String role) {
this.name = name;
this.role = role;
}
}
自定义权限注解:
package com.wen.service;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 作者: WENHENG
* 时间: 2020/10/15 19:30
* 说明: 权限注解
*/
//注解的作用目标:方法
@Target(ElementType.METHOD)
//注解传递存活时间,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)
public @interface RoleInfo{
//角色的名字
String role() default "";
}
编译自定义的注解的解析器(用于完成对注解的方法的权限判断处理):
package com.wen.service;
import com.wen.entity.Users;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import static jdk.nashorn.internal.objects.NativeMath.log;
/**
* 作者: WENHENG
* 时间: 2020/10/19 10:46
* 说明:
*/
@Aspect
@Component
@Slf4j
public class RolesAspect {
@Pointcut("@annotation(com.wen.service.RoleInfo)")
private void checkCut(){
}
// 前置通知
@Before("checkCut()")
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知,目标:");
System.out.print(joinPoint.getTarget() + "方法名称:");
System.out.println(joinPoint.getSignature().getName());
}
// 前置通知
@After("checkCut()")
public void myAfter(JoinPoint joinPoint) {
System.out.print("hou置通知,目标:");
System.out.print(joinPoint.getTarget() + "方法名称:");
System.out.println(joinPoint.getSignature().getName());
}
@Around("checkCut()")
public void parse(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕开始");
Class targetClassName = joinPoint.getTarget().getClass();
String methodName = joinPoint.getSignature().getName();
// 获取目标方法
// Method method = targetClassName.getMethod(methodName);
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
String methAccess = "";
// 判断注解中是否存在@RoleInfo注解
if(method.isAnnotationPresent(RoleInfo.class)){
RoleInfo roleInfo = method.getAnnotation(RoleInfo.class);
// 获取到注解中的name值
methAccess = roleInfo.role();
System.out.println(methAccess);
Object[] parm = joinPoint.getArgs();
if (parm[0].equals(methAccess)){
System.out.println("获取到该权限");
joinPoint.proceed();
} else {
System.out.println("没有执行权限");
}
System.out.println("环绕结束");
}
}
}
Service接口:
package com.wen.service;
import com.wen.entity.Users;
/**
* 作者: WENHENG
* 时间: 2020/10/19 10:54
* 说明: 用户业务接口
*/
public interface UserService {
public void save(Users user);
public void update(String root, Users user);
public void get(Users user);
}
ServiceImpl接口实现类:
package com.wen.service.serviceImpl;
import com.wen.entity.Users;
import com.wen.service.RoleInfo;
import com.wen.service.UserService;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* 作者: WENHENG
* 时间: 2020/10/19 11:30
* 说明:
*/
@Service
@Repository("UserService")
public class UserServiceImpl implements UserService {
@Override
@RoleInfo(role = "admin")
public void save(Users user) {
System.out.println("save()方法");
}
@Override
@RoleInfo(role = "admin")
public void update(String root, Users user) {
System.out.println("update()方法");
}
@Override
@RoleInfo(role = "admin")
public void get(Users user) {
System.out.println("get()方法");
}
}
测试类:
package com.wen;
import com.wen.entity.Users;
import com.wen.service.RoleInfo;
import com.wen.service.UserService;
import org.apache.catalina.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class Exp1ApplicationTests {
@Qualifier("UserService")
@Autowired(required = false)
private UserService userService;
@Test
void contextLoads() {
}
@Test
public void actionLogAnno() throws Exception {
Users users = new Users();
users.setName("admin");
users.setRole("admin");
userService.update("admin",users);
}
}
注意:在Users实体类中使用的@Data注解需要使用到Lombok插件,请自行到IDE的插件库进行下载安装,并导入LomBok依赖或者jar包。
AOP通知的优先级:环绕通知 > 前置通知 > 后置通知。