Spring AOP自定义注解实现权限控制

来源:互联网 发布:大容量背包 知乎 编辑:程序博客网 时间:2024/05/22 03:33

在学习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;}}

3.  自定义的注解和解析器有了,现在应该将对应的Service层写出来,并且在要使用访问权限的方法上添加这个注解。一般情况下,Service层都包含接口和实现类。

接口

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();}}


4.  上面我们已经写好了:自定义注解+注解解析器+service层。但是,有时候权限需要满足一些条件:比如姓名、年龄、VIP等级等等信息,所以我们需要将这些信息封装到一个bean中。(下面例子值封装一个属性name).

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;}}


6.Spring配置文件applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-3.2.xsd           http://www.springframework.org/schema/aop           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">           <bean id="personDao" class="com.yangguang.aop.privilage.dao.impl.PersonDaoImpl"></bean><bean id="personService" class="com.yangguang.aop.privilage.service.impl.PersonServiceImpl"><property name="personDao"><ref bean="personDao"/></property></bean><bean id="accessMethod" class="com.yangguang.aop.privilage.aspect.AccessTargetObject"></bean><aop:config><!-- 定义一个切入点表达式,用来确定哪些类需要代理execution(* com.yangguang.aop.privilage.service.impl.*.*(..))代表包内的所有的类的所有的方法都会被代理 --><aop:pointcut expression="execution(* com.yangguang.aop.privilage.service.impl.*.*(..))" id="perform"/><aop:aspect ref="accessMethod"><aop:around method="accessMethod" pointcut-ref="perform"/></aop:aspect></aop:config></beans>


7.测试类



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 {@Testpublic void test() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//初始化用户的权限AccessTargetObject targetObject = (AccessTargetObject) context.getBean("accessMethod");List<Privilege> privileges = targetObject.getUserPrivilege();Privilege privilege = new Privilege();privilege.setName("savPerson");privileges.add(privilege);PersonService personService = (PersonService) context.getBean("personService");personService.savePerson();}}

输出信息:



原创粉丝点击