在学习Java Spring框架中,学习到AOP的过程中,有一个很难理解的问题就是:自定义注解,然后解析注解实现权限控制。
权限控制:因为在一些项目中,service层的一些方法需要不同的权限才能访问。所以需要权限控制。
所以,我下面写了一个小例子来看一下具体的实现过程。
实现方案: 1. 自定义一个注解PrivilegeInfo,使用这个注解为service层中的方法进行权限配置
2. 编写一个注解解析器AnnotationParse。解析注解@PrivilegeInfo(name=” *”)
(注解解析器应该把@PrivilegeInfo中的name属性值解析出来)
3. 在AOP中根据PrivilegeInfo注解的值,判断用户是否拥有访问目标方法的权限,有则访问目标,没有则给 出提示关键技术:自定义注解+注解解析+Spring AOP
最终实现的目录结构:
UML类结构图:
具体实现步骤:
1.自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义的注解
* @author yangguang
*
*/
@Target(ElementType.METHOD)//注解的作用目标:方法
@Retention(RetentionPolicy.RUNTIME)//注解会在class字节码文件中存在,在运行时可以通过反射获取到
public @interface PrivilegeInfo {
//权限的名字
String name() default "";
}
完成自定义的注解之后,还需要写一个注解解析器,主要是返回目标方法上的注解PrivilegeInfo设置的name值。
2.注解解析器
import java.lang.reflect.Method;
/**
* 权限注解解析器
* 这个解析器的作用就是:解析目标方法上如果有PrivilegeInfo注解,解析器就解析出这个注解中的name值(权限的值)
* @author yangguang
*
*/
public class AnnotationParse {
/**
* 解析注解
* @param targetClassName 目标类(Class形式)
* @param methodName 目标方法(在客户端调用哪个方法,methodName就代表哪个方法)
* @return
* @throws Exception
*/
public static String parse(Class targetClassName,String methodName) throws Exception{
//获得目标方法
Method method = targetClassName.getMethod(methodName);
String methodAccess = "";
//判断目标方法上面是否存在@PrivilegeInfo注解
//@Privilege(name="savePerson")
if(method.isAnnotationPresent(PrivilegeInfo.class)){
//得到方法上的注解
PrivilegeInfo privilegeInfo = method.getAnnotation(PrivilegeInfo.class);
//得到注解中的name值
methodAccess = privilegeInfo.name();
}
return methodAccess;
}
}
接口:
package com.yangguang.aop.privilage.service;
/**
* 用户业务接口
* @author yangguang
*
*/
public interface PersonService {
//在需要权限的目标方法上,使用PrivilegeInfo注解
public void savePerson();
}
package com.yangguang.aop.privilage.service.impl;
import com.yangguang.aop.privilage.annotation.PrivilegeInfo;
import com.yangguang.aop.privilage.dao.PersonDao;
import com.yangguang.aop.privilage.service.PersonService;
/**
* 用户业务实现
* @author yangguang
*
*/
public class PersonServiceImpl implements PersonService {
PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
//配置PrivilegeInfo注解
@PrivilegeInfo(name="savePerson")
public void savePerson() {
this.personDao.savePerson();
}
}
package com.yangguang.aop.privilage.bean;
/**
* 封装用户权限信息(此处只封装name)
* @author yangguang
*
*/
public class Privilege {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5. 编写切面代码
在切面中,我们使用的是环绕通知,在调用目标方法之前,我们需要在程序中做以下处理:
现有目标方法上的PrivilegeInfo注解配置的权限,与用户拥有的权限进行匹配。
a) 如果匹配成功,则认为用户有这个权限使用该目标方法
b) 如果匹配失败,则给出无权访问的提示信息
package com.yangguang.aop.privilage.annotation;
import java.lang.reflect.Method;
/**
* 权限注解解析器
* 这个解析器的作用就是:解析目标方法上如果有PrivilegeInfo注解,解析器就解析出这个注解中的name值(权限的值)
* @author yangguang
*
*/
public class AnnotationParse {
/**
* 解析注解
* @param targetClassName 目标类(Class形式)
* @param methodName 目标方法(在客户端调用哪个方法,methodName就代表哪个方法)
* @return
* @throws Exception
*/
public static String parse(Class targetClassName,String methodName) throws Exception{
//获得目标方法
Method method = targetClassName.getMethod(methodName);
String methodAccess = "";
//判断目标方法上面是否存在@PrivilegeInfo注解
//@Privilege(name="savePerson")
if(method.isAnnotationPresent(PrivilegeInfo.class)){
//得到方法上的注解
PrivilegeInfo privilegeInfo = method.getAnnotation(PrivilegeInfo.class);
//得到注解中的name值
methodAccess = privilegeInfo.name();
}
return methodAccess;
}
}
package com.yangguang.aop.privilege.test;
import java.util.List;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.yangguang.aop.privilage.aspect.AccessTargetObject;
import com.yangguang.aop.privilage.bean.Privilege;
import com.yangguang.aop.privilage.service.PersonService;
public class PrivilegeTest {
@Test
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//初始化用户的权限
AccessTargetObject targetObject = (AccessTargetObject) context.getBean("accessMethod");
List privileges = targetObject.getUserPrivilege();
Privilege privilege = new Privilege();
privilege.setName("savPerson");
privileges.add(privilege);
PersonService personService = (PersonService) context.getBean("personService");
personService.savePerson();
}
}