spring4 - 自定义注解并使用
1、元注解(meta-annotation):
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
- @Target,
- @Retention,
- @Documented,
- @Inherited
1.1@Target:
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
1.2@Retention:
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(ElementType)有:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在运行时有效(即运行时保留)
1.3@Documented::
作用:用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
1.4@Inherited:
作用:标记注解,阐述了某个被标注的类型是被继承的。
取值(ElementType)有:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在运行时有效(即运行时保留)
2、自定义注解
public @interface 注解名 {定义体}
/**
* 水果供应者注解
* @author peida
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
/**
* 供应商编号
* @return
*/
public int id() default -1;
/**
* 供应商名称
* @return
*/
public String name() default "";
/**
* 供应商地址
* @return
*/
public String address() default "";
}
#3、注解的使用
3.1自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{
String hello () default "hello";
String world();
}
3.2自定义使用-标记
public class MyTest
{
@MyAnnotation(hello = "Hello,Beijing",world = "Hello,world")
public void output() {
System.out.println("method output is running ");
}
}
3.3自定义使用-解析
public class MyReflection
{
public static void main(String[] args) throws Exception
{
//1.获得要调用的类
Class<MyTest> myTestClass = MyTest.class;
//2.获得要调用的方法,output是要调用的方法名字,new Class[]{}为所需要的参数。空则不是这种
Method method = myTestClass.getMethod("output", new Class[]{});
//3.方法中是否有类型为MyAnnotation的注解
if (method.isAnnotationPresent(MyAnnotation.class))
{
//4.获得注解
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
//5.调用注解的内容
System.out.println(annotation.hello());
System.out.println(annotation.world());
}
System.out.println("----------------------------------");
// 获得所有注解。必须是runtime类型的
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations)
{
// 遍历所有注解的名字
System.out.println(annotation.annotationType().getName());
}
}
}
实际使用:权限控制与校验
用户—角色—资源
自定义标签
@Permission({role1,role2})
权限注解 用于检查权限 规定访问权限
对目标方法进行标注@Permission(Const.ADMIN_NAME)
相当于shiro的@RequiresPermissions(“/mgr/role_assign”) ,指定某方法需要指定的资源访问权限【资源】/mgr/role_assign
@Permission不需要写资源参数。他的参数代表指定角色的权限【任意1即可】。
本质:无参-判断hasPermission 有参-判断hasAnyRoles
控制和使用
@Order(200) 控制AOP顺序
1.将实现类加入spring管理
2.编写切面类 PermissionAop
3.定义可以定义可重用的切点@Pointcut
4.在需要执行的切面的方法上即可【这里是无参节点】
当需要AOP操作时,相关注解内传入刚才定义的方法就可以。
@Pointcut(value = "@annotation(cn.stylefeng.guns.core.common.annotion.Permission)")
private void cutPermission() {}
@Around("cutPermission()")
public Object doPermission(ProceedingJoinPoint point) throws Throwable {
//获得注释方法签名【方法名+形参】
MethodSignature ms = (MethodSignature)
//获得方法
point.getSignature();
Method method = ms.getMethod();
//获取方法上的注释
Permission permission = method.getAnnotation(Permission.class);
//获取注释的值
Object[] permissions = permission.value();
if (permissions.length == 0) {
//检查全体角色-用户是否拥有当前请求的servlet的权限
boolean result = check.checkAll();
if (result) {
return point.proceed();
} else {
throw new NoPermissionException();
}
} else {
//检查指定角色
boolean result = check.check(permissions);
if (result) {
return point.proceed();
} else {
throw new NoPermissionException();
}
}
}
5.有参案例:
有参切点定义:
@Pointcut("execution(* com.ooo.Pointcut.OperatorTest.add222(..))"+"&& args(food,name)")
public void function(String food,String name){}
@Before("function(food,name)")
public void beforeMethod(JoinPoint jp,String food,String name){
String methodName = jp.getSignature().getName();
System.out.println("【前置通知】获取参数food:"+food);
System.out.println("【前置通知】获取参数name:"+name);
System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
}
权限检查服务check的实现
1.接口定义
public interface PermissionCheckService {
/**
* 检查当前登录用户是否拥有指定的角色访问当
*/
boolean check(Object[] permissions);
/**
* 检查当前登录用户是否拥有当前请求的servlet的权限
*/
boolean checkAll();
}
2.接口实现
- 获取request
- 获取user
- 获取requestURI
只判断前2/段的权限
@Override
public boolean checkAll() {
HttpServletRequest request = HttpContext.getRequest();
ShiroUser user = ShiroKit.getUser();
if (null == user) {
return false;
}
String requestURI = request.getRequestURI().replaceFirst(ConfigListener.getConf().get("contextPath"), "");
String[] str = requestURI.split("/");
if (str.length > 3) {
requestURI = "/" + str[1] + "/" + str[2];
}
if (ShiroKit.hasPermission(requestURI)) {
return true;
}
return false;
}
http://localhost:8080/news/main/list.jsp
1.request.getContextPath()–>/news
2.request.getServletPath()–>/main/list.jsp
3.request.getRequestURI() —>/news/main/list.jsp
还没有评论,来说两句吧...