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

在学习Java Spring框架中,学习到AOP的过程中,有一个很难理解的问题就是:自定义注解,然后解析注解实现权限控制。

         

权限控制:因为在一些项目中,service层的一些方法需要不同的权限才能访问。所以需要权限控制。

         所以,我下面写了一个小例子来看一下具体的实现过程。

实现方案:   1. 自定义一个注解PrivilegeInfo,使用这个注解为service层中的方法进行权限配置

           2. 编写一个注解解析器AnnotationParse。解析注解@PrivilegeInfo(name=” *”)

              (注解解析器应该把@PrivilegeInfo中的name属性值解析出来)

3. 在AOP中根据PrivilegeInfo注解的值,判断用户是否拥有访问目标方法的权限,有则访问目标,没有则给 出提示

关键技术:自定义注解+注解解析+Spring AOP

最终实现的目录结构:

Spring AOP自定义注解实现权限控制_第1张图片

UML类结构图:

Spring AOP自定义注解实现权限控制_第2张图片


具体实现步骤

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




           
	
	
		
			
		
	
	
	
	
	
		
		
			
		
	
	


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

输出信息:



你可能感兴趣的:(spring)