简单的通用后台校验代码

萌生写这个代码的原因,是在使用struts2的验证框架时,总觉的有些不太灵活。当一个action中有多个表单需要处理的时候,struts处理起来就稍微麻烦一点,当校验失败时都会return "input"字符串。但我不同表单单校验失败后一般都希望返回不同的result,渲染不同的视图。另外如果我的校验是异步发起的,而我想要的结果是json的时候,也比较麻烦。虽然这些问题可以通过修改result type类型和在result中使用ognl表达式来做到,但绕来绕去实在太过麻烦。而若不适用这校验框架,在action中自己来if else if else 来判断更不可取。于是便回想到yii和 laravel框架的校验,这些校验框架在我看来做的非常优秀,非常灵活,于是我想借鉴它们来自己写一写这个校验插件。

首先,我希望做到两点

  • 可以对实体进行校验,不管实体封装的是表单数据还是数据库记录
  • 可以直接对request.getParameterMap()获得的map进行校验,这个我暂时还没完成。
  • 灵活校验,当校验失败后可以马上通过getErrors拿到错误数据,这样你想咋么响应怎么响应,发json也好,把errors传递到视图也好,都可以。
    • 也就是想下面这样,if(!entity.validate()){....}else{Map map = entity.getErrors()}

另外当实体的属性没有被struts填充时,也可以使用我写的一个fill方法进行填充,为什么要写这个呢,因为struts的属性驱动,类驱动,模型驱动都有点局限,但我的action里有多个模型,模型驱动只能为一个模型注值,不够灵活

 1 public class BaseEntity{
 2     public void fill(Map<String, String[]> parameterMap) {
 3         //System.out.println(this.getClass());
 4         Class clazz = this.getClass();
 5         Field fields[] = clazz.getDeclaredFields();
 6         for (int i = 0; i < fields.length; i++) {
 7             String fieldName = fields[i].getName();
 8             //System.out.println(fieldName);
 9             try {
10                 // 查找参数集合
11                 String values [] = parameterMap.get(fieldName);
12                 if(values!=null && values.length>0){
13                     String methodName = "set"+fieldName.substring(0, 1).toUpperCase()
14                         + fieldName.substring(1);
15                     Class fieldType = fields[i].getType();
16                     Method method = clazz.getMethod(methodName,new Class[]{fieldType});
17                     // 设值
18                     method.invoke(this,new Object[]{fieldType.cast(values[0])});
19                 }
20             } catch (Exception e) {
21                 e.printStackTrace();
22             }
23         }
24     }
25     ///...
26 }

我把代码放在了svnchinagithub上,有兴趣看看的可以去,有一起做的更好了。

  • http://www.svnchina.com/svn/entity_validator
  • https://github.com/lvyahui8/validator.git

我暂时只做了对实体的校验,这里还有个问题,java本身是强类型的语言。对于实体的某些字段,他的类型本身就存在了校验,比如一个字段是Integer类型,那你觉得还有必要去校验他是number类型吗?完全多次一举。只有当属性是字符串,校验它是否是number才有意义,比如手机号码

这里我写了一个BaseEntity类,如果一个子类要进行校验,那么这个子类要覆写父类的两个方法,rules和labels方法。这两个方法,一个用来定义对该试题的校验规则,一个定义对实体字段的中文翻译。

 1 package org.lyh.validator;
 2
 3 import java.lang.reflect.Field;
 4 import java.lang.reflect.Method;
 5 import java.util.HashMap;
 6 import java.util.Map;
 7
 8 /**
 9  * Created by lvyahui on 2015-06-27.
10  */
11 public class BaseEntity {
12
13     private Validator validator = new Validator(this);
14
15     protected Map<String,String> labelMap = new HashMap<String,String>();
16
17     {
18         String [][] allLabels = labels();
19         if(allLabels != null){
20             for(String [] label : allLabels){
21                 String prop = label[0],propLabel = label[1];
22                 if(prop != null && hasProp(prop) && propLabel != null){
23                     labelMap.put(prop,propLabel);
24                 }
25             }
26         }
27     }
28
29     public boolean hasProp(String prop) {
30         try {
31             Field field = this.getClass().getDeclaredField(prop);
32             return true;
33         } catch (NoSuchFieldException e) {
34             return false;
35         }
36     }
37
38     public String getLabel(String prop){
39         return labelMap.get(prop);
40     }
41
42     public void fill(Map<String, String[]> parameterMap) {
43         //System.out.println(this.getClass());
44         Class clazz = this.getClass();
45         Field fields[] = clazz.getDeclaredFields();
46         for (int i = 0; i < fields.length; i++) {
47             String fieldName = fields[i].getName();
48             //System.out.println(fieldName);
49             try {
50                 // 查找参数集合
51                 String values [] = parameterMap.get(fieldName);
52                 if(values!=null && values.length>0){
53                     String methodName = "set"+fieldName.substring(0, 1).toUpperCase()
54                         + fieldName.substring(1);
55                     Class fieldType = fields[i].getType();
56                     Method method = clazz.getMethod(methodName,new Class[]{fieldType});
57                     // 设值
58                     method.invoke(this,new Object[]{fieldType.cast(values[0])});
59                 }
60             } catch (Exception e) {
61                 e.printStackTrace();
62             }
63         }
64     }
65
66     /**
67      * 进行校验
68      * @return 校验
69      */
70     public boolean validate() {
71         return this.validator.validate();
72     }
73
74     /**
75      * 如果校验失败通过他获取错误信息
76      * @return 错误信息
77      */
78     public Map<String,Map<String,String>> getErrors(){
79         return this.validator.getErrors();
80     }
81
82     /**
83      * 校验规则
84      * @return 校验规则
85      */
86
87     public String[][] labels(){return null;}
88
89     /**
90      * 字段翻译
91      * @return 字段翻译
92      */
93     public String [][] rules(){return null;}
94
95 }

下面创建一个子类,重写rules和labels方法。

 1 package org.lyh.validator;
 2
 3 import java.sql.Timestamp;
 4
 5 /**
 6  * Created by lvyahui on 2015-06-26.
 7  */
 8
 9 public class UserEntity extends BaseEntity {
10     private String username;
11     private String password;
12     private String name;
13     private Integer gold;
14     private Integer progress;
15     private Timestamp createdAt;
16     private String email;
17     private String phone;
18     private String site;
19     /*省略 getter\setter方法*/
20     @Override
21     public String[][] rules() {
22         return new String [][] {
23                 {"username,password,email,gold,progress,phone","required"},
24                 {"username,password","length","6","14"},
25                 {"rePassword","equals","password"},
26                 {"email","email","\\w{6,12}"},
27                 {"createdAt","timestamp"},
28                 {"phone","number"},
29                 {"site","url"}
30         };
31     }
32
33     public String[][] labels() {
34         return new String[][]{
35                 {"username","用户名"},
36                 {"password","密码"},
37                 {"rePassword","确认密码"},
38                 {"email","邮箱"},
39                 {"progress","进度"},
40                 {"phone","电话"},
41                 {"gold","金币"}
42         };
43     }
44
45 }

可以看到,校验规则的写法,很简单,每一行第一个字符串写了需要校验的字段,第二个字符串写了这些字段应该满足的规则,后面的字符串是这个规则需要的参数

labels 就更简单了。

另外这个实例化validator类的时候,除了传递实体外,还可以传递第二个参数,表示是否是短路校验。

下面是这个校验的核心类Validator

  1 package org.lyh.validator;
  2
  3 import java.lang.reflect.Field;
  4 import java.lang.reflect.Method;
  5 import java.sql.Timestamp;
  6 import java.text.MessageFormat;
  7 import java.util.*;
  8
  9 /**
 10  * Created by lvyahui on 2015-06-27.
 11  *
 12  */
 13 public class Validator {
 14     /**
 15      * 校验类型
 16      */
 17     public static final String required = "required";
 18     public static final String length = "length";
 19     public static final String number = "number";
 20     public static final String equals = "equals";
 21     public static final String email = "email";
 22     public static final String url = "url";
 23     public static final String regex = "regex";
 24     public static final String timestamp = "timestamp";
 25
 26     /**
 27      * 附加参数类型
 28      */
 29     private static final int PATTERN = 1;
 30     private static final int MIN = 2;
 31     private static final int MAX = 3;
 32     private static final int PROP = 4;
 33
 34     private Map<Integer,Object> params = new HashMap<Integer,Object>();
 35     /**
 36      * 验证失败的错误信息,形式如下
 37      * {"username":{"REQUIRED":"用户名必须为空",...},...}
 38      */
 39     protected Map<String,Map<String,String>> errors
 40         = new HashMap<String,Map<String,String>>();
 41
 42     /**
 43      * 被校验的实体
 44      */
 45     private BaseEntity baseEntity;
 46
 47     /**
 48      * 被校验实体的类型
 49      */
 50     private Class entityClass = null;
 51
 52     /**
 53      * 当前正在被校验的字段
 54      */
 55     private Field field;
 56     /**
 57      * 当前执行的校验
 58      */
 59     private String validateType ;
 60
 61     /**
 62      * 当前被校验字段的值
 63      */
 64     private Object value;
 65
 66     /**
 67      * 是否短路
 68      */
 69     private boolean direct;
 70
 71     private String [][] rules ;
 72
 73     /**
 74      *
 75      * @param baseEntity
 76      */
 77     public Validator(BaseEntity baseEntity) {
 78         this(baseEntity,false);
 79     }
 80
 81     public Validator(BaseEntity baseEntity,boolean direct){
 82         this.baseEntity = baseEntity;
 83         entityClass = baseEntity.getClass();
 84         rules = baseEntity.rules();
 85     }
 86
 87     public Map<String,Map<String,String>> getErrors() {
 88         return errors;
 89     }
 90
 91     public Map<String,String> getError(String prop){
 92         return this.errors.get(prop);
 93     }
 94
 95     public void addError(String prop,String validatorType,String message){
 96         Map<String,String> error = this.errors.get(prop);
 97         if(error==null || error.size() == 0){
 98             error = new HashMap<String,String>();
 99             errors.put(prop, error);
100         }
101         error.put(validatorType,message);
102     }
103
104     public void setRules(String[][] rules) {
105         this.rules = rules;
106     }
107
108     public boolean required(){
109         if(value!=null){
110             if(value.getClass() == String.class && "".equals(((String)value).trim())){
111                 return false;
112             }
113             return true;
114         }
115         return false;
116     }
117
118     public boolean number(){
119         if(value.getClass().getGenericSuperclass() == Number.class){
120             return true;
121         }else if(((String)value).matches("^\\d+$")){
122             return true;
123         }
124         return false;
125     }
126
127     public boolean email(){
128         return ((String) value).matches("^\\[email protected]\\w+.\\w+.*\\w*$");
129     }
130
131     public boolean url(){
132         return ((String)value).matches("^([a-zA-Z]*://)?([\\w-]+\\.)+[\\w-]+(/[\\w\\-\\.]+)*[/\\?%&=]*$");
133     }
134
135     public boolean regex(){
136         return ((String)value).matches((String) params.get(regex));
137     }
138
139     public boolean equals() throws NoSuchFieldException, IllegalAccessException {
140         String prop = (String) params.get(PROP);
141         Field equalsField = entityClass.getDeclaredField(prop);
142         equalsField.setAccessible(true);
143         return value.equals(equalsField.get(baseEntity));
144     }
145     public boolean timestamp(){
146         if(field.getType().equals(Timestamp.class)){
147             return true;
148         }
149         return false;
150     }
151     public boolean length() {
152         String val = (String) value;
153         Integer min = (Integer) params.get(MIN);
154         Integer max = (Integer) params.get(MAX);
155
156         return val.length() > min && (max == null || val.length() < max);
157
158
159     }
160
161     public boolean validate(){
162         errors.clear();
163         if(rules==null){
164             return true;
165         }
166
167         for (int i = 0; i < rules.length; i++) {
168             String [] rule = rules[i],fields = rule[0].split(",");
169             validateType = rule[1];
170             setParams(rule);
171             try {
172                 Method validateMethod = this.getClass()
173                     .getMethod(validateType);
174                 for (int j = 0; j < fields.length; j++) {
175                     if(direct && getError(fields[j]) != null){ continue; }
176
177                     field = entityClass.getDeclaredField(fields[j]);
178                     field.setAccessible(true);
179                     value = field.get(baseEntity);
180                     if(value != null || (value == null && validateType == required)){
181                         if(!(Boolean)validateMethod.invoke(this)){
182                             handleError();
183                         }
184                     }
185                 }
186             } catch (Exception e) {
187                 e.printStackTrace();
188             }
189         }
190         return true;
191     }
192
193     private void setParams(String [] rule) {
194         params.clear();
195         // 取附加参数
196         switch (validateType){
197             case regex:
198                 params.put(PATTERN,rule[3]);
199                 break;
200             case equals:
201                 params.put(PROP, rule[2]);
202                 break;
203             case length:
204                 if(rule[2] != null) {
205                     params.put(MIN, Integer.valueOf(rule[2]));
206                 }
207                 if(rule.length >= 4){
208                     params.put(MAX,Integer.valueOf(rule[3]));
209                 }
210                 break;
211             default:
212         }
213     }
214
215     private void handleError() {
216         String name = this.baseEntity.getLabel(field.getName()) != null
217                 ? this.baseEntity.getLabel(field.getName()) : field.getName(),
218                 message = MessageFormat.format(Messages.getMsg(validateType),name);
219         this.addError(field.getName(), validateType, message);
220     }
221
222 }

下面是错误消息模板

 1 package org.lyh.validator;
 2
 3 import java.util.HashMap;
 4 import java.util.Map;
 5
 6 /**
 7  * Created by lvyahui on 2015-06-28.
 8  */
 9 public class Messages {
10     private static Map<String,String> msgMap = new HashMap<String,String>();
11
12     static{
13         msgMap.put(Validator.required,"{0}必须填写");
14         msgMap.put(Validator.email,"{0}不合法");
15         msgMap.put(Validator.equals,"{0}与{1}不相同");
16         msgMap.put(Validator.length,"{0}长度必须在{1}-{2}之间");
17         msgMap.put(Validator.regex,"{0}不符合表达式");
18         msgMap.put(Validator.timestamp,"{0}不是合法的日期格式");
19         msgMap.put(Validator.number,"{0}不是数字格式");
20         msgMap.put(Validator.url,"{0}不是合法的url");
21     }
22
23     public static String getMsg(String validateType) {
24         return msgMap.get(validateType);
25     }
26 }

下面写个main方法测试

 1 package org.lyh.validator;
 2
 3 /**
 4  * Created by lvyahui on 2015-06-28.
 5  */
 6 public class MainTest {
 7     public static void main(String[] args) {
 8
 9         UserEntity userEntity = new UserEntity();
10         userEntity.validate();
11         System.out.println(userEntity.getErrors());
12
13         userEntity.setUsername("lvyahui");
14         userEntity.setRePassword("admin888");
15         userEntity.setPassword("admin888");
16         userEntity.setEmail("lvyaui82.com");
17         userEntity.validate();
18         System.out.println(userEntity.getErrors());
19
20         userEntity.setEmail("[email protected]");
21         userEntity.setPhone("hjhjkhj7867868");
22         userEntity.setGold(1);
23         userEntity.setSite("www.baidu.com");
24
25         userEntity.validate();
26
27         System.out.println(userEntity.getErrors());
28         // ([a-zA-Z]*://)?([\w-]+\.)+[\w-]+(/[\w-]+)*[/?%&=]*
29         userEntity.setSite("http://www.baidu.com/index.php");
30         userEntity.setProgress(123);
31         userEntity.setPhone("156464564512");
32         userEntity.validate();
33
34         System.out.println(userEntity.getErrors());
35
36     }
37
38 }

运行程序,得到这样的输出

1 {gold={required=金币必须填写}, password={required=密码必须填写}, phone={required=电话必须填写}, progress={required=进度必须填写}, email={required=邮箱必须填写}, username={required=用户名必须填写}}
2 {gold={required=金币必须填写}, phone={required=电话必须填写}, progress={required=进度必须填写}, email={email=邮箱不合法}}
3 {phone={number=电话不是数字格式}, progress={required=进度必须填写}}
4 {}

后面要做的就是直接对map进行校验

我的想法是通过validator类添加set方法注入规则和翻译。当然上面的错误信息模板可以到xml文件中进行配置,至于校验规则和翻译个人认为没有必要放到xml中去。

时间: 2024-10-13 21:47:40

简单的通用后台校验代码的相关文章

PD003-NET通用后台系统

PD003-NET通用后台系统 开发语言.Net 成品成品 前端技术jquery 数据库sql server .net 通用后台框架 详细信息 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用,提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,也可用来学习. Framework 业务无关的底层通用机制及功能 -Model基类:提供数据传输和底层的最基本的基类及接口 -DAL底层:基于EF c

通用后台管理系统(ExtJS 4.2 + Spring MVC 3.2 + Hibernate)

通用后台管理系统(ExtJS 4.2 +Spring MVC 3.2 + Hibernate) 开发语言JAVA 成品成品 前端技术extjs 数据库mysql,sql server,oracle 系统可作为OA.网站.电子政务.ERP.CRM.APP后台等基于B/S架构的应用软件系统的快速开发框架. 详细信息 原文:http://www.yctxkj.com/product/showproduct.php?lang=cn&id=16 系统可作为OA.网站.电子政务.ERP.CRM.APP后台等

分享基于EF+MVC+Bootstrap的通用后台管理系统及架构(转)

http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,且能作为代码实践及参考,欢迎提出意见. Demo预览 点击在线预览 admin/111111 请勿删数据 Framework 业务无关的底层通用机制及功能 Model基类:提供数据传输和底层的最基本的

分享基于EF+MVC+Bootstrap的通用后台管理系统及架构

原文来源:http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,且能作为代码实践及参考,欢迎提出意见. Demo预览 点击在线预览 admin/111111 请勿删数据 Framework 业务无关的底层通用机制及功能 Model基类:提供数据传输和底层

基于ExtJS 4.2.1 + Hibernate 4.1.7 + Spring MVC 3.2.8 的通用后台管理系统

一.系统介绍 1.基于最新的ExtJS 4.2.1.883开发. 2.支持MySQL.SQL Server.Oracle.DB2等关系数据库. 3.本系统可作为OA.网站.电子政务.ERP.CRM等基于B/S架构的应用软件系统的快速开发框架. 源码有50多M(包括Jar包和SQL文件),点此获取. 二.特色功能1.采用Spring MVC的静态加载缓存功能,在首页将Javascript文件.CSS文件和图片等静态资源文件加载进来放进内存,极大提高ExtJS的加载速度.2.增加新的ExtJS Ne

第5章—构建Spring Web应用程序—关于spring中的validate注解后台校验的解析

关于spring中的validate注解后台校验的解析 在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节.比如参数不能为null,email那么必须符合email的格式,如果手动进行if判断或者写正则表达式判断无意开发效率太慢,在时间.成本.质量的博弈中必然会落后.所以把校验层抽象出来是必然的结果,下面说下几种解决方案. 1.简单的校验Demo 依赖: <dependency> <groupId>javax.validation</groupId> <

springMVC(八)——数据校验(后台校验 hibernate validate).

数据校验(后台校验 hibernate validate) 1.首先要导入jar包 2.在相应的实体类中加入注解 package com.zhiyou100.zjc.bean; import javax.validation.constraints.Pattern; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; public class

SpringMVC-------3.文件上传,拦截器和数据校验(后台校验)

1.文件上传 1.1导入jar包 1.2设置表单提交属性 文件上传只允许表单为post提交,并且编码类型为multipart/form-data 1.3在springmvc中配置文件上传解析器. 其中的id名不能更改,否则报错 设置最大上传大小maxUploadSize 1.4 在控制层处理代码 @RequestMapping("upload") public String upload(MultipartFile myfile,HttpServletRequest request)

对一个简单的时间片轮转多道程序内核代码的浅析

这周在网易云课堂上学习了<Linux内核分析>——操作系统是如何工作的.本周学习内容有利用 mykernel 实验模拟计算机平台和利用 mykernel 实验模拟计算机硬件平台两部分内容. 这是实验楼中 mykernel 平台运行的结果: 下面是一段一个简单的时间片轮转多道程序内核代码: 1 /* 2 * linux/mykernel/myinterrupt.c 3 * 4 * Kernel internal my_timer_handler 5 * 6 * Copyright (C) 201