Java自定义注解代码实现与扩展

一、注解:可以作为配置信息控制程序的运行,注解可以在一些场合用来替代配置文件
Annotation 注解:程序中给人看到提示信息叫注释,给程序看的提示信息叫做注解
@xxxx(....)

这里有四种类型的元注解

1. @Documented —— 指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API。

2. @Target——指明该类型的注解可以注解的程序元素的范围。该元注解的取值可以为TYPE,METHOD,CONSTRUCTOR,FIELD等。如果Target元注解没有出现,那么定义的注解可以应用于程序的任何元素。

3. @Inherited——指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。

4.@Retention——指明了该Annotation被保留的时间长短。RetentionPolicy取值为SOURCE,CLASS,RUNTIME。


jdk1.5内置的注解:
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告. 
自定义注解:
1.声明注解
(1)使用 @interface关键字来定义注解,在这个类中可以声明注解的属性
注解属性的声明类似于在为接口声明一个方法,同时可以为属性设定默认值
注解属性支持如下类型:String、基本数据类型、枚举、Class 、其它注解类型、以上数据类型相应一维数组
如果注解中只包含一个名为value的属性,则这个属性在使用时可以省略注解的名字直接写值
public @interface tran{
//String name();  
//String name2() default "xxx";
String value();
}

(2)使用元注解对注解进行描述

          1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

@Retention:用来指定注解的保留范围
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
!! RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
@Target:指定被修饰的注解可以使用在什么位置
ElementType的成员变量。可以是类/方法/字段/构造方法/包声明.....  以下枚举常量
                  1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.

@Inherited: 被它修饰的 Annotation 将具有 继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
2.使用注解
在 @Target声明的位置上使用 @Tran(属性名=属性值,.....)


3.反射注解
JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement  接口, 该接口代表程序中可以接受注释的程序元素,包括Class Field Method Constructor Package都是这个接口的实现,所以这个接口中定义的反射注解的方法,他们都具有

 T  getAnnotation(Class annotationClass) 
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 
Annotation[] getAnnotations() 
 返回此元素上存在的所有注释。 
Annotation[] getDeclaredAnnotations() 
 返回直接存在于此元素上的所有注释。 
boolean isAnnotationPresent(Class annotationClass) 
 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。 

获取注解上的属性?获取到注解对象后,就像调用方法一样后去注解的属性


注解元素的默认值:

  注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。例如:

@Target(ElementType.FIELD)
15 @Retention(RetentionPolicy.RUNTIME)
16 @Documented
17 public @interface FruitProvider {
18     /**
19      * 供应商编号
20      * @return
21      */
22     public int id() default -1;
23     
24     /**
25      * 供应商名称
26      * @return
27      */
28     public String name() default "";
29     
30     /**
31      * 供应商地址
32      * @return
33      */
34     public String address() default "";

二、代码实现

1.作用在类上面

@Retention(RetentionPolicy.RUNTIME)// 用于反射 注解的保留范围
@Target(ElementType.TYPE) // 注解的作用目标 类方法或包

public @interface TranSName{
public String name();
public int age() default 100;
}

业务实现

@TranSName(name="ans")
public class Student {


}

public static void main(String[] args) {
Class sc = Student.class;
//sc.getAnnotation(annotationClass)
if(sc.isAnnotationPresent(TranSName.class)){// 判断此类上是否有此注解
TranSName  ts = sc.getAnnotation(TranSName.class); // 获取注解对象
System.out.println(ts.name());// 读取参数
}


}

2、作用在方法上

/**
 * 自定义注�?
 */
//被这个注解修饰的注解,利用反射,将其他的注解读取出来
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationLimit {
String mid();  //子模块模块名�?
String pid(); //父模块操作名�?
}

通过拦截器实现权限的控制,模仿配置文件,操作某个方法时,查看当前用户所具有的角色是否有此方法的访问权限,方法的访问权限用自定义注解的方式在方法上,

通过拦截器。do获取角色与方法权限查数据库,是否有对应的记录,,有则放行,执行方法代码。

package cn.itcast.elec.util;


import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;


import javax.servlet.http.HttpServletRequest;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.StrutsStatics;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;


import cn.itcast.elec.domain.ElecUser;
import cn.itcast.elec.service.IElecRoleService;


import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;


@SuppressWarnings("serial")
public class ErrorAndLimitInterceptor extends MethodFilterInterceptor {


public void init() {


}


/**
* 过滤器过滤url�?do�?jsp�?
* 拦截器拦截url�?do�?
*   actioninvocation.invoke():调用struts2的Action的方法,并返回String类型的对应的返回�?
*/
public String doIntercept(ActionInvocation actioninvocation) {
//把自定义错误信息 放置到request�?
HttpServletRequest request = (HttpServletRequest) actioninvocation
.getInvocationContext().get(StrutsStatics.HTTP_REQUEST);
try {
//获取请求的action对象
Object action = actioninvocation.getAction();
//获取请求的方法的名称
String methodName = actioninvocation.getProxy().getMethod();
//获取action中的方法的封装类(action中的方法没有参数)
Method method = action.getClass().getMethod(methodName, null);
// Action的返回�?   
String result = null; 

boolean flag = isCheckLimit(request,method);
//if(flag){
if(true){//去掉细颗粒权限控�?
// 运行被拦截的Action,期间如果发生异常会被catch�?  
result = actioninvocation.invoke();
}
else{
request.setAttribute("errorMsg", "对不起!您没有权限操作此功能�?);
return "errorMsg";
}
return result;


} catch (Exception e) {
/**  
* 处理异常  
*/
String errorMsg = "出现错误信息,请查看日志�?;
//通过instanceof判断到底是什么异常类�?  
if (e instanceof RuntimeException) {
//未知的运行时异常   
RuntimeException re = (RuntimeException) e;
//re.printStackTrace();
errorMsg = re.getMessage().trim();
}
/**  
* 发�?错误消息到页�? 
*/
request.setAttribute("errorMsg", errorMsg);


/**  
* log4j记录日志  
*/
Log log = LogFactory
.getLog(actioninvocation.getAction().getClass());
log.error(errorMsg, e);
return "errorMsg";
}// ...end of catch   
}


public void destroy() {


}


public boolean isCheckLimit(HttpServletRequest request, Method method) {
if(method == null){
return false;
}
//获取当前的登陆用�?
ElecUser elecUser = (ElecUser)request.getSession().getAttribute("globle_user");
if(elecUser == null){
return false;
}

//获取当前登陆用户的角色(�?��用户可以对应多个角色�?
Hashtable ht = (Hashtable)request.getSession().getAttribute("globle_role");
if(ht == null){
return false;
}
//处理注解,判断方法上是否存在注解(注解的名称为:AnnotationLimit�?
/*
* 例如�?
* @AnnotationLimit(mid="aa",pid="0")
       public String home(){
*/
boolean isAnnotationPresent = method.isAnnotationPresent(AnnotationLimit.class);

//不存在注解(此时不能操作该方法)
if(!isAnnotationPresent){
return false;
}

//存在注解(调用注解)
AnnotationLimit limit = method.getAnnotation(AnnotationLimit.class);

//获取注解上的�?
String mid = limit.mid();  //权限子模块名�?
String pid = limit.pid();  //权限父操作名�?

/**
* 如果登陆用户的角色id+注解上的@AnnotationLimit(mid="aa",pid="0")
*   * 在elec_role_popedom表中存在   flag=true,此时可以访问Action的方�?
*   * 在elec_role_popedom表中不存�?flag=false,此时不能访问Action的方�?
*/
boolean flag = false;
//从Session中获取当前登录名�?��有的权限code的集合(aa@ab@ac@ad�?
// String popedom = (String)request.getSession().getAttribute("globle_popedom");
// if(popedom.contains(mid)){
// flag = true;
// }
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
IElecRoleService elecRoleService = (IElecRoleService)wac.getBean(IElecRoleService.SERVICE_NAME);
//遍历角色ID
if(ht!=null && ht.size()>0){
for(Iterator> ite = ht.entrySet().iterator();ite.hasNext();){
Entry entry = ite.next();
//获取角色ID
String roleID = entry.getKey();
flag = elecRoleService.findRolePopedomByID(roleID, mid, pid);
if(flag){
break;
}
}
}


return flag;
}




}


你可能感兴趣的:(Java自定义注解代码实现与扩展)