项目里面一定会有很多的action,每一个都需要验证参数的合法性,这是个很繁琐的工作,jfinal自带的拦截器功能用着还是觉得麻烦;参考hibernate-validator等现有的框架写了点东西,自我感觉美美的,特地来晒一晒
(内容挺长,不过关键点只有一丢丢)
废话不多说,上代码(我的环境jfinal-java8,版本3.3):
一、首先需要定义自己的注解(参照了现有的很多验证框架)

我这儿定义了挺多的,不过有个别的还没有完全实现,呵呵
贴出几个来打个样儿,其他的都类似
1. Length(被注解的字符串的大小必须在指定的范围内)
@Documented
@Repeatable(LengthArray.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface Length {
String value();
int min();
int max();
String message() default "数据校验不合法";
}2. NotBlank(被注解的字符串必须非null,且长度必须大于0),注意下Repeatable,这个是java1.8才有的
@Documented
@Repeatable(NotBlankArray.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface NotBlank {
String value();
String message() default "数据必须有内容";
}3. NotBlankArray(同2,这个表示同一位置可以出现多个相同的注解)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface NotBlankArray {
NotBlank[] value();
}4.(被注释的元素必须符合指定的正则表达式)
@Documented
//@Repeatable(LengthArray.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface Pattern {
String value();
String message() default "字段不符合规则";
String regexp();
}说明:
value的值就是getPara("xxx");里面的xxx
message是校验失败时的提示信息
其他min,max,regexp等属性按需添加
二、然后编写action
public class TestController extends Controller {
public void index(){
renderText("/test/index");
}
@NotBlank(value="name", message="来者报上名来,空着算毛啊")
@NotBlank(value="address")
@Length(value="mobile", max = 11, min = 11, message="手机号码11位你不知道吗")
//由数字、26个英文字母或下划线组成的字符串
@Pattern(value="content", regexp="^\\w+$")
@URL(value="debug", host = "", port = 0, protocol = "")
public void valid01(){
String name1 = getPara("name");
String address1 = getPara("address");
String mobile1 = getPara("mobile");
Integer age1 = getParaToInt("age");
String content1 = getPara("content");
String result = "[" + name1 + "/" + address1 + "/" + mobile1 + "/" + content1 + "/" + age1 + "]";
renderText("/test/valid01 " + result);
}
public void valid02(
@NotBlank(value="")String name,
@NotBlank(value="")String address,
@Length(value="", max = 11, min = 11)String mobile,
//由数字、26个英文字母或下划线组成的字符串
@Pattern(value="", regexp="^\\w+$")String content){
String name2 = getPara("name");
String address2 = getPara("address");
String mobile2 = getPara("mobile");
Integer age2 = getParaToInt("age");
String content2 = getPara("content");
String result = "[" + name2 + "/" + address2 + "/" + mobile2 + "/" + content2 + "/" + age2 + "]";
renderText("/test/valid02 " + result);
}
}三、编写拦截器
代码看着挺长,不过都不复杂,前面的四个方法是关键、后面都是各个校验的具体代码,只看其中一两个就明白了,可以自由扩展哈,so easy~~~
public class ParameterValidateInterceptor implements Interceptor {
@Override
public void intercept(Invocation inv) {
//处理method的注解
CheckResult checkResult = validateMethodAnnotation(inv);
if (!checkResult.result) {
inv.getController().renderJson( MyResult.build(7295, checkResult.paraName + ": " + checkResult.message) );
return;
}
//处理parameter的注解
checkResult = validateParameterAnnotation(inv);
if (!checkResult.result) {
inv.getController().renderJson( MyResult.build(7297, checkResult.paraName + ": " + checkResult.message) );
return;
}
//method和parameter注解验证都通过之后,才会继续调用action方法
inv.invoke();
}
//处理方法上定义的注解
private CheckResult validateMethodAnnotation(Invocation inv){
CheckResult checkResult = new CheckResult(true, null, null);
Annotation[] annotations = inv.getMethod().getDeclaredAnnotations();// .getAnnotations();
for (Annotation annotation : annotations) {
checkResult = validateSingleAnnotation(annotation, inv, null, false);
if (!checkResult.result) {
return checkResult;
}
}
return checkResult;//new CheckResult(true, null, null);
}
//处理参数上定义的注解
private CheckResult validateParameterAnnotation(Invocation inv){
CheckResult checkResult = new CheckResult(true, null, null);
//遍历action方法的所有参数
Parameter[] parameters = inv.getMethod().getParameters();
for (Parameter parameter : parameters) {
String paraName = parameter.getName();
//String paraValue = inv.getController().getPara(paraName);
//遍历参数的所有注解
Annotation[] annotations = parameter.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
//System.out.println(" check parameter [ "+ paraName + "/" + paraValue + " ], annotition: " + annotation.annotationType().getSimpleName());
checkResult = validateSingleAnnotation(annotation, inv, paraName, true);
if (!checkResult.result) {
return checkResult;
}
}
}
return checkResult;//new CheckResult(true, null, null);
}
/**
* 处理每个单独的注解
* @param annotation 发现的注解
* @param inv
* @param paraName 参数名(方法的注解得从value去获取,现在还没有;参数的注解直接就是参数名)
* @param type 类型:false说明是方法注解(还没有取到参数名paraName属性),true说明是参数注解(已经拿到了参数名paraName属性)
* @return
*/
private CheckResult validateSingleAnnotation(Annotation annotation, Invocation inv, String paraName, boolean type){
CheckResult checkResult = new CheckResult(true, null, "");
if (annotation.annotationType().equals(NotBlank.class)) {
NotBlank singleAnnotation = (NotBlank) annotation;
checkResult = notBlankValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(NotBlankArray.class)) {
NotBlankArray arrayAnnotation = (NotBlankArray) annotation;
checkResult = notBlankArrayValidator(inv, arrayAnnotation);
} else if (annotation.annotationType().equals(Length.class)) {
Length singleAnnotation = (Length) annotation;
checkResult = lengthValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(LengthArray.class)) {
LengthArray arrayAnnotation = (LengthArray) annotation;
checkResult = lengthArrayValidator(inv, arrayAnnotation);
} else if (annotation.annotationType().equals(MobileNumber.class)) {
MobileNumber singleAnnotation = (MobileNumber) annotation;
checkResult = mobileNumberValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(NotNull.class)) {
NotNull singleAnnotation = (NotNull) annotation;
checkResult = notNullValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(Past.class)) {
Past singleAnnotation = (Past) annotation;
checkResult = pastValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(Future.class)) {
Future singleAnnotation = (Future) annotation;
checkResult = futureValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(Null.class)) {
Null singleAnnotation = (Null) annotation;
checkResult = nullValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(AssertTrue.class)) {
AssertTrue singleAnnotation = (AssertTrue) annotation;
checkResult = assertTrueValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(AssertFalse.class)) {
AssertFalse singleAnnotation = (AssertFalse) annotation;
checkResult = assertFalseValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(Email.class)) {
Email singleAnnotation = (Email) annotation;
checkResult = emailValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(URL.class)) {
URL singleAnnotation = (URL) annotation;
checkResult = urlValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else if (annotation.annotationType().equals(Pattern.class)) {
Pattern singleAnnotation = (Pattern) annotation;
checkResult = patternValidator(inv, singleAnnotation, type ? paraName : singleAnnotation.value());
} else {
System.out.println("unknown method annotation ---------------- " + annotation.toString());
}
return checkResult;
}
/**
* @Null(value="xxx")
* 校验:被注释的元素必须为 null
*/
private CheckResult nullValidator(Invocation inv, Null nullAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... Null -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue==null, paraName, nullAnnotation.message());
}
/**
* @NotNull(value="xxx")
* 校验:string参数xxx的值不能为 null
*/
private CheckResult notNullValidator(Invocation inv, NotNull notNullAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... NotNull -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue!=null, paraName, notNullAnnotation.message());
}
/**
* @AssertTrue(value="xxx")
* 校验: boolean参数xxx的值必须为true
*/
private CheckResult assertTrueValidator(Invocation inv, AssertTrue assertTrueAnnotation, String paraName){
Boolean paraValue = inv.getController().getParaToBoolean(paraName);
System.out.println(" ...... AssertTrue -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue==null||paraValue, paraName, assertTrueAnnotation.message());
}
/**
* @AssertTrue(value="xxx")
* 校验: boolean参数xxx的值必须为false
*/
private CheckResult assertFalseValidator(Invocation inv, AssertFalse assertFalseAnnotation, String paraName){
Boolean paraValue = inv.getController().getParaToBoolean(paraName);
System.out.println(" ...... AssertFalse -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue==null||!paraValue, paraName, assertFalseAnnotation.message());
}
/**
* @Past(value="xxx")
* 校验: date参数的xxx的值必须是已经过去的时间(jfinal目前只认“yyyy-MM-dd”的格式)
*/
private CheckResult pastValidator(Invocation inv, Past pastAnnotation, String paraName){
Date paraValue = inv.getController().getParaToDate(paraName);
System.out.println(" ...... Past -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue==null||paraValue.getTime()<new Date().getTime(), paraName, pastAnnotation.message());
}
/**
* @Future(value="xxx")
* 校验: date参数的xxx的值必须是将来的时间(jfinal目前只认“yyyy-MM-dd”的格式)
*/
private CheckResult futureValidator(Invocation inv, Future futureAnnotation, String paraName){
Date paraValue = inv.getController().getParaToDate(paraName);
System.out.println(" ...... Future -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue==null||paraValue.getTime()>new Date().getTime(), paraName, futureAnnotation.message());
}
/**
* @Pattern(value="xxx", message="...", regexp="......")
* 校验: string参数xxx的值必须能匹配正则表达式regexp(但可以为null或空串)
*/
private CheckResult patternValidator(Invocation inv, Pattern patternAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... Pattern -- para: " + paraName + ", value: " + paraValue);
//开始校验
if (StrKit.isBlank(paraValue)) {
return new CheckResult(true, null, null);
}
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(patternAnnotation.regexp());
Matcher matcher = pattern.matcher(paraValue);
return new CheckResult(matcher.matches(), paraName, patternAnnotation.message());
}
/**
* @Email(value="xxx", message="...")
* 校验: string参数xxx的值必须是合法的email地址,还未完成!!!
*/
private CheckResult emailValidator(Invocation inv, Email emailAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... Pattern -- para: " + paraName + ", value: " + paraValue);
//开始校验,参考【https://github.com/hibernate/hibernate-validator/blob/ff4324e6c182992c74110bfb51021a2bfee39d5e/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/bv/EmailValidator.java】
if (StrKit.isBlank(paraValue)) {
return new CheckResult(true, null, null);
}
String regexp = "\\w+@\\w+(\\.\\w+)+";
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regexp);
Matcher matcher = pattern.matcher(paraValue);
return new CheckResult(matcher.matches(), paraName, emailAnnotation.message());
}
/**
* @Length(value="xxx", min=mm, max=nn, message="...")
* 校验: string参数xxx的值长度必须在min和max的范围内
*/
private CheckResult lengthValidator(Invocation inv, Length lengthAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... Length -- para: " + paraName + ", value: " + paraValue);
//开始校验
int min = lengthAnnotation.min();
int max = lengthAnnotation.max();
return new CheckResult(paraValue!=null&&(paraValue.length()>=min&¶Value.length()<=max), paraName, lengthAnnotation.message());
}
/**
* @Length(value="xxx",...)
* @Length(value="yyy",...)
* 同一位置有多个@Length注解
*/
private CheckResult lengthArrayValidator(Invocation inv, LengthArray lengthArrayAnnotation){
for (Length lengthAnnotation : lengthArrayAnnotation.value()) {
CheckResult checkResult = lengthValidator(inv, lengthAnnotation, lengthAnnotation.value());
if(!checkResult.result){
return checkResult;
}
}
return new CheckResult(true, null, null);
}
/**
* @NotBlank(value="xxx", message="...")
* 校验: string参数xxx的值不能为null,且长度必须大于0
*/
private CheckResult notBlankValidator(Invocation inv, NotBlank notBlankAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... NotBlank -- para: " + paraName + ", value: " + paraValue);
//开始校验
return new CheckResult(paraValue!=null && paraValue.trim().length() > 0, paraName, notBlankAnnotation.message());
}
/**
* @NotBlank(value="xxx")
* @NotBlank(value="yyy")
* 同一位置有多个@NotBlank注解
*/
private CheckResult notBlankArrayValidator(Invocation inv, NotBlankArray notBlankArrayAnnotation){
for (NotBlank notBlankAnnotation : notBlankArrayAnnotation.value()) {
CheckResult checkResult = notBlankValidator(inv, notBlankAnnotation, notBlankAnnotation.value());
if(!checkResult.result){
return checkResult;
}
}
return new CheckResult(true, null, null);
}
/**
* @URL(value="xxx", protocol="aaa", host="bbb", port=zzz, message="")
* 校验:string参数xxx必须是一个有效的url,还未完成
*/
private CheckResult urlValidator(Invocation inv, URL urlAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... URL -- para: " + paraName + ", value: " + paraValue);
//开始校验
if (StrKit.isBlank(paraValue)) {
return new CheckResult(true, paraName, null);
}
String regexp = "^(?:https?://)?[\\w]{1,}(?:\\.?[\\w]{1,})+[\\w-_/?&=#%:]*$";
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regexp);
Matcher matcher = pattern.matcher(paraValue);
return new CheckResult(matcher.matches(), paraName, urlAnnotation.message());
//下面这个方法复杂些,可以验证协议、主机、端口,等等
// CheckResult checkResultSuccess = new CheckResult(true, paraName, null);
// CheckResult checkResultFail = new CheckResult(false, paraName, urlAnnotation.message());
// if ( paraValue == null || paraValue.length() == 0 ) {
// return checkResultSuccess;
// }
// //^(?:https?://)?[\\w]{1,}(?:\\.?[\\w]{1,})+[\\w-_/?&=#%:]*$
// java.net.URL url;
// try {
// url = new java.net.URL( paraValue );
// }
// catch (MalformedURLException e) {
// return checkResultFail;
// }
// if ( urlAnnotation.protocol() != null && urlAnnotation.protocol().length() > 0 && !url.getProtocol().equals( urlAnnotation.protocol() ) ) {
// return checkResultFail;
// }
// if ( urlAnnotation.host() != null && urlAnnotation.host().length() > 0 && !url.getHost().equals( urlAnnotation.host() ) ) {
// return checkResultFail;
// }
// if ( urlAnnotation.port() != -1 && url.getPort() != urlAnnotation.port() ) {
// return checkResultFail;
// }
// return checkResultSuccess;
}
/**
* @MobileNumber(value="xxx")
* 验证: string参数xxx的值必须是合法的手机号码
*/
private CheckResult mobileNumberValidator(Invocation inv, MobileNumber mobileNumberAnnotation, String paraName){
String paraValue = inv.getController().getPara(paraName);
System.out.println(" ...... MobileNumber -- para: " + paraName + ", value: " + paraValue);
//开始校验
if (StrKit.isBlank(paraValue)) {
return new CheckResult(true, paraName, null);
}
String regexp = "^((17[0-9])|(14[0-9])|(13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regexp);
Matcher matcher = pattern.matcher(paraValue);
return new CheckResult(matcher.matches(), paraName, mobileNumberAnnotation.message());
}
class CheckResult {
private boolean result;
private String paraName;
private String message;
public CheckResult(boolean result, String paraName, String message) {
super();
this.result = result;
this.paraName = paraName;
this.message = message;
}
}
}还有个MyResult,也贴出来吧
public class MyResult {
private Integer status;
private String message;
private Integer totalPage;
private Integer totalNum;
private Object data;
private static final Integer SUCCESS_CODE = 0;
private static final String SUCCESS_MSG = "success";
// get,set 略
@Override
public String toString() {
return "MyCustomResult [status=" + status + ", message=" + message + ", totalPage=" + totalPage + ", totalNum="
+ totalNum + ", data=" + data + "]";
}
// 构造方法
public MyResult(){
}
public MyResult(Integer status, String message, Object data) {
this.status = status;
this.message = message;
if (data instanceof Page) {
this.data = ((Page<?>) data).getList();
setTotalNum(((Page<?>) data).getTotalRow());
setTotalPage(((Page<?>) data).getTotalPage());
} else {
this.data = data;
}
}
// 静态方法
public static MyResult build(Integer status, String message, Object data){
return new MyResult(status, message, data);
}
public static MyResult build(Integer status, String message){
return new MyResult(status, message, null);
}
public static MyResult ok(Object data){
return new MyResult(SUCCESS_CODE, SUCCESS_MSG, data);
}
public static MyResult ok(){
return new MyResult(SUCCESS_CODE, SUCCESS_MSG, null);
}
}四、配置路由和拦截器
@Override
public void configRoute(Routes me) {
me.add("test", TestController.class);
} @Override
public void configInterceptor(Interceptors me) {
me.addGlobalActionInterceptor(new ParameterValidateInterceptor());
}五、测试喽~~~
我用的是Postman,贴图

六、谢谢~~~