2016.07.26
首先介绍些基本概念:
Annotations(also known as metadata)provide a formalized way to add information to your code so that you can easily use that data at some later point.
Annotations are partly motivated by a general trend toward combining metadata with source-code files,instead of keeping it in external documents. They are also a response to feature pressure from other languages like C#.
Annotations are one of the fundamental language changes introduced in Java SE5. They provide information that you need to fully describe your program, but that cannot be expressed in Java.Thus,annotations allow you to store extra information about your program in a format that is tested and verified by the compiler.Annotations can be used to generate descriptor files or even new class definitions and help ease the burden of writing "boilerplate" code.Using annotations,you can keep this metadata in the Java source code,and have the advantage of cleaner looking code,compile-time type checking and the annotation API to help build processing tools for your annotations.
---《Thinking in java》
1.java用@interface xx{}定义一个注解。
2.There are currently only three standard annotations(described earlier)(@Override @Deprecated @SuppressWarnings)and four meta-annotations defined in the Java language(@Target @Retention @Documented @Inherited):
@Retention(RetentionPolicy.SOURCE) // 注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
(RUNTIME的值得注意下,因为意味着可以反射来获取)
@Target(ElementType.TYPE) // 接口、类、枚举、注解
@Target(ElementType.FIELD) // 字段、枚举的常量
@Target(ElementType.METHOD) // 方法
@Target(ElementType.PARAMETER) // 方法参数
@Target(ElementType.CONSTRUCTOR) // 构造函数
@Target(ElementType.LOCAL_VARIABLE) // 局部变量
@Target(ElementType.ANNOTATION_TYPE) // 注解
@Target(ElementType.PACKAGE) // 包
有一种做法就是在定义注解时加上@Taget(xx)和@Retention(RetentionPolicy.RUNTIME) ,但没有在注解中写方法,只是在运行时通过反射机制来获取注解,然后自己写相应逻辑(所谓注解解析器)
大概是类似的写法:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Documented
@Inherited
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate
{
public int min() default 1; public int max() default 10; public boolean isNotNull() default true;
}
之后运行时,用反射获取注解,具体不谈。
之前在网上查找这方面技术文章找到的都是这种,给当时的我带来很大困惑。觉得不是我想要的。
关于Java 注解,在《java编程思想》一书里第十章有详细的介绍(包括@Retention(RetentionPolicy.RUNTIME)的方式,的注解处理器的例子),具体不多谈。
其实是可以通过@Constraint来限定自定义注解的方法。
@Constraint(validatedBy = xxxx.class)
下面是我做的 java自定义注解实现前后台参数校验 的代码示例:
package sonn.sonnannotation; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload; import sonn.util.StringUtill; /**
* @ClassName: IsValidString
* @Description: 自定义注解实现前后台参数校验,判断是否包含非法字符
* @author 无名
* @date 2016-7-25 下午8:22:58
* @version 1.0
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IsValidString.ValidStringChecker.class)
@Documented
public @interface IsValidString
{
String message() default "The string is invalid."; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default{}; class ValidStringChecker implements ConstraintValidator<IsValidString,String>
{ @Override
public void initialize(IsValidString arg0)
{
} @Override
public boolean isValid(String strValue, ConstraintValidatorContext context)
{
if(StringUtill.isStringEmpty(strValue))
{
return true;
}
if(strValue.contains("<"))
{
return false;
}
return true;
} }
}
上述代码,通过@Constraint(validatedBy = IsValidString.ValidStringChecker.class)限定了注解的方法逻辑---该注解类的名为ValidStringChecker的内部类。
而该内部类实现了ConstraintValidator<IsValidString,String>接口
官方文档是这样描述的:
Interface ConstraintValidator<A extends Annotation,T>
-
public interface ConstraintValidator<A extends Annotation,T>
Defines the logic to validate a given constraintA
for a given object typeT
.Implementations must comply to the following restriction:
-
T
must resolve to a non parameterized type - or generic parameters of
T
must be unbounded wildcard types
The annotation
SupportedValidationTarget
can be put on aConstraintValidator
implementation to mark it as supporting cross-parameter constraints. Check outSupportedValidationTarget
andConstraint
for more information. -
实现的isValid方法便是,该接口的校验方法。
试验一下效果,在要校验的实体类字段加上注解:
写文章页面,文章标题内加入'<'然后提交:
提交失败,报500错误,说明注解生效:
但这样还有问题,我的blog网站不能直接打印出报错信息。还是要搞一个error页面出来。
这个简单,web.xml下加入error页面路径,然后做一个页面即可:
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
参考文章:
http://www.cnblogs.com/liangweiping/p/3837332.html