对于数据验证的操作定义是分为两端进行,一端是客户端验证(虽然无用,但是必须提供),另外一种是基于服务器端的应用,但是所有的Struts 2.x的操作有一点很麻烦,给出的验证方法或者是验证框架都必须在数据已经转换为VO对象后才可以正常执行验证,而拦截器使用之后,发现可以在拦截器中针对于数据进行验证处理;
如果想进行验证,那么必须满足如下的几点:
可以为每一个Action设置指定的验证规则,例如:现在编写NewsAction的验证规则,那么这个类里卖弄要接收的参数名称:news.nid、news.title、news.content、news.pubdate,那么很明显每一种数据都有自己的类型;
范例;在NewsAction.java类里面定义规则
private String insertRule="news.nid:int|news.title.string|news.content.string|news.pubdate.date";
public String insert(){
System.out.println(this.news);
return "news.show";
}
可以验证的数据类型最多只有两大类,数组、普通类型,但是不管如何划分,常见类型:String、int、double、date.
但是这个规则现在是保存在每一个Action里面的,而拦截器需要知道这个Action;这个时候就需要观察拦截器方法里面所具备的参数了ActionInvocation,在这个接口里面定义有如下操作方法:
取得要操作的Action类对象:public Object getAction().
Object actionObject=invocation.getAction();
此时取得了整个的Action对象,那么意味着可以利用反射进行这个类属性或者是方法的调用;
实际上取得了NewsAction类对象后,就必须要想办法取出一个适合我们自己的操作类型:
范例;取得验证规则
public class ValidateInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocation invocation)throws Exception{
//取得要操作的Action,根据发送的提交路径的不同,Action对象也不同
Object actionObject = invocation.getAction();
//为了可以确定要使用的验证操作成员,必须从里面取出分发的存在代码
String uri = ServletActionContext.getRequest().getRequestURI();
if(uri != null){//为了保险起见,可以在增加一个null的验证
//取出关键的业务方法的名称,那么就相当于取得了业务方法名称Rule的验证规则
uri = uri.substring(uri.lastIndexOf("!"),uri.lastIndexOf("."));
//有了Action 对象,又有了名称,就可以取得成员了
String filedName = uri+"Rule";//这个是验证规则的成员
//根据成员名称取得对象的具体呢,那么只能够依靠反射完成
Field fieldRule = FieldactionObject.getClass().getDeclaredField(filedName);
fieldRule.setAccessible(true);//取消掉封装处理
String rule = (String)fieldRule.get(actionObject);
System.out.println("【操作的验证规则】" + rule);
}
return invocation.invoke();
}
}
所有的验证规则必须要和具体的输入参数进行捆绑才是最有用的。为了方便代码的维护,专门编写一个实现验证的具体操作类,这个类只是负责验证,那么这个类里面不需要保存任何的属性内容,那么很明显,使用全部的static方法就够了;
在Struts2.x中为了省事,将所有的参数取得都不再去区分getParameter()或者是getParameterValues(),
而是统一按照getParameterValues()方法取得,也就是说所有取得的内容都是字符串数组。
public class ValidateUtil{
/*
进行数据验证的操作方法
actionObject 表示要触发此操作的Action类
rule 每个Action类里面定义的规则
params 表示所有的输入参数
return 验证成功返回true,验证失败返回false;
*/
public static boolean validate (Object actionObject,
String rule,Map<String,Object>params){
//需要知道有哪些参数
Iterator<Map.Entry<String,Object>> iter = params.entrySet().iterator();
while(iter.hasNext()){
Map.Entry<String,Object> map = iter.next();
String str[] = (String[]) map.getValue();
System.out.println(map.getKey() + "=" + Arrays.toString(str));
}
return false;
}
}
所有的参数输出是没有任何意义的,因为必须要针对于我们给出的参数进行验证。
public class ValidateUtil{
/*
进行数据验证的操作方法
actionObject 表示要触发此操作的Action类
rule 每个Action类里面定义的规则
params 表示所有的输入参数
return 验证成功返回true,验证失败返回false;
*/
public static boolean validate (Object actionObject,
String rule,Map<String,Object>params){
//所有的验证操作都应该由rule发起,里面的组成“参数名称:类型”
String result[] = rule.split("\\|");//取出每一组验证规则
for(int x = 0 ; x < result.length ; x ++){//表示此处取得了循环每一次验证
String temp[] = result[x].split(":");//取出参数名称以及验证规则
if(temp[1].contains("[]")) {//应该按照数组结构验证
}else{//如果不是数组,则证明参数只有一个
String paramValue[] = (String[]) params.get(temp[0]);
for(int y = 0 ; y < paramValue.length ; y ++){//循环每一个数组内容
switch(temp[1]){
case"string":{
System.out.println(temp[0] + ",string验证");
break;
}
case"int":{
System.out.println(temp[0] + ",int验证");
break;
}
case "double":{
System.out.println(temp[0] + ",double验证");
break;
}
case "date":{
System.out.println(temp[0] + ",date验证");
break;
}
}
}
}
}
return false;
}
}
随后在每一种规则中进行具体的验证操作。
public class ValidateUtil{
/*
进行数据验证的操作方法
actionObject 表示要触发此操作的Action类
rule 每个Action类里面定义的规则
params 表示所有的输入参数
return 验证成功返回true,验证失败返回false;
*/
public static boolean validate (Object actionObject,
String rule,Map<String,Object>params){
//所有的验证操作都应该由rule发起,里面的组成“参数名称:类型”
String result[] = rule.split("\\|");//取出每一组验证规则
for(int x = 0 ; x < result.length ; x ++){//表示此处取得了循环每一次验证
String temp[] = result[x].split(":");//取出参数名称以及验证规则
if(temp[1].contains("[]")){//应该按照数组结构验证
}else{//如果不是数组,则证明参数只有一个
String paramValue[] = (String[]) params.get(temp[0]);
for(int y = 0 ; y < paramValue.length ; y ++){//循环每一个数组内容
switch(temp[1]){
case"string":{
if(ValidateUtil.validateString(paramValue[y])){
System.out.println(temp[0] + ",string验证通过。");
}
break;
}
case"int":{
if(ValidateUtil.validateInt(parmaValue[y])){
System.out.println(temp[0] + ",int验证通过。");
}
break;
}
case "double":{
if(ValidateUtil.validateDouble(paramValue[y])){
System.out.println(temp[0] + ",double验证通过");
}
break;
}
case "date":{
if(Validate.validateDate(paramValue[y])){
System.out.println(temp[0] + ",date验证通过");
}
break;
}
}
}
}
}
return false;
}
/*
进行字符串的操作验证
str 要验证的内容
return 如果字符串为空或者长度为0,那么返回false,否则返回true;
*/
public static boolean validateString(String str){
if(str == null || "".equals(str)){
return false;
}
return true;
}
/*
进行数据的验证操作,验证之前首先要判断数据是否为空
str 要验证的内容
return 如果是由数字组成返回true,否则返回false;
*/
public static boolean validateInt(String str){
if(validateString(str)){//首先判断数据是否合法
return str.matches("\\d+");
}
return false;
}
/*
进行小数的验证操作,验证之前要先判断数据是否为空
str 要验证的内容
return 如果字符串由小数组成返回true,否则返回false
*/
public static boolean validateDouble(String str){
if(validateString(str)){
return str.matches("\\d+(\\.\\d+)?");
}
return false;
}
/*
验证字符串是否是日期类型或者是日期时间类型
str 要验证的内容
return 如果字符串由小数组成返回true,否则返回false
*/
public static boolean validateString(String str){
if(validateString(str)){
if(str.matches("\\d{4]-\\d{2}-\\d{2}")){
return true;
}else{//有可能是日期时间类型
return str.matches("\\d{4]-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}");
}
}
return true;
}
}
信息都在拦截器中存在了,可是一旦验证失败的话,那么怎么进行返回呢?
所有的错误信息实际上都会在前台以fieldErrors形式进行保存,而且保存的都是Map集合,这一切都要源自于addFieldError()这个方法的使用,但是同时还要定义好错误信息的内容。
范例:定义Messages.properties文件,在这个文件里面编写错误提示信息
string.validate.error.msg=该数据不允许为空!
number.validate.error.msg=数据类型必须是数字!
date.validate.error.,msg=数据类型应该为日期(yyyy-mm-dd)或者是日期时间(yyyy-mm-dd hh:mm:ss)!
所有的错误信息必须调用Action中的addFieldError()方法完成
public class ValidateUtil{
/*
进行数据验证的操作方法
actionObject 表示要触发此操作的Action类
rule 每个Action类里面定义的规则
params 表示所有的输入参数
return 验证成功返回true,验证失败返回false;
*/
public static boolean validate (Object actionObject,
String rule,Map<String,Object>params){
boolean flag = false;//综合的验证成功与否的标记
try{
//取得增加错误信息的操作方法,通过此方法保存错误信息
Method addFieldErrorMethod = actionObject.getClass()
.getMethod("addFieldError",String.class,String.class);
//通过此方法取得错误的提示信息
Method textMethod = action=actionObeject.getClass()
.getMethod("getText",String.class);
//所有的验证操作都应该由rule发起,里面的组成“参数名称:类型”
String result[] = rule.split("\\|");//取出每一组验证规则
for(int x = 0 ; x < result.length ; x ++){//表示此处取得了循环每一次验证
String temp[] = result[x].split(":");//取出参数名称以及验证规则
if(temp[1].contains("[]")){//应该按照数组结构验证
}else{//如果不是数组,则证明参数只有一个
String paramValue[] = (String[]) params.get(temp[0]);
String text = null;//保存每一个的错误提示信息
for(int y = 0 ; y < paramValue.length ; y ++){//循环每一个数组内容
switch(temp[1]){
case"string":{
flag = ValidateUtil.validateString(paramValue[y]);
if(!flag){//没有验证成功
text = textMethod.invoke(actionObject,"string.validate.error.msg");
}
break;
}
case"int":{
flag = ValidateUtil.validateInt(parmaValue[y]);
if(!flag){//没有验证成功
text=textMethod.invoke(actionObject,"number.validate.error.msg");
}
break;
}
case "double":{
flag = ValidateUtil.validateDouble(paramValue[y]);
if(!flag){//没有验证成功
text=textMethod.invoke(actionObject,"number.validate.error.msg");
}
break;
}
case "date":{
flag = Validate.validateDate(paramValue[y]);
if(!flag){//没有验证成功
text = textMethod.invoke(actionObject,"number.validate.error.msg");
}
break;
}
}
}
if(!flag){//验证失败
addFieldErrorMethod.invoke(actionObject,temp[0],text);
}
}
}
}catch(Exception e){
e.printStackTrace();
}
return flag;
}
/*
进行字符串的操作验证
str 要验证的内容
return 如果字符串为空或者长度为0,那么返回false,否则返回true;
*/
public static boolean validateString(String str){
if(str == null || "".equals(str)){
return false;
}
return true;
}
/*
进行数据的验证操作,验证之前首先要判断数据是否为空
str 要验证的内容
return 如果是由数字组成返回true,否则返回false;
*/
public static boolean validateInt(String str){
if(validateString(str)){//首先判断数据是否合法
return str.matches("\\d+");
}
return false;
}
/*
进行小数的验证操作,验证之前要先判断数据是否为空
str 要验证的内容
return 如果字符串由小数组成返回true,否则返回false
*/
public static boolean validateDouble(String str){
if(validateString(str)){
return str.matches("\\d+(\\.\\d+)?");
}
return false;
}
/*
验证字符串是否是日期类型或者是日期时间类型
str 要验证的内容
return 如果字符串由小数组成返回true,否则返回false
*/
public static boolean validateString(String str){
if(validateString(str)){
if(str.matches("\\d{4]-\\d{2}-\\d{2}")){
return true;
}else{//有可能是日期时间类型
return str.matches("\\d{4]-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}");
}
}
return true;
}
}
以最基础的CRUD为主,如果是增加出现了问题,那么应该返回到增加的错误页上,如果要是修改出现,应该返回到修改的错误页,同样,依次类推...所有的错误页都应该在struts.xml文件里面进行配置。
为每一个页面验证失败定义一个错误页,例如:insert业务验证规则是insertRule,那么它的错误的跳转页面就定义为:insertVF;
<result name="insertVF">news_insert.jsp</result>
public class ValidateInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocation invocation)throws Exception{
//取得要操作的Action,根据发送的提交路径的不同,Action对象也不同
Object actionObject = invocation.getAction();
//为了可以确定要使用的验证操作成员,必须从里面取出分发的存在代码
String uri = ServletActionContext.getRequest().getRequestURI();
if(uri != null){//为了保险起见,可以在增加一个null的验证
//取出关键的业务方法的名称,那么就相当于取得了业务方法名称Rule的验证规则
uri = uri.substring(uri.lastIndexOf("!"),uri.lastIndexOf("."));
//有了Action 对象,又有了名称,就可以取得成员了
String filedName = uri+"Rule";//这个是验证规则的成员
try{
//根据成员名称取得对象的具体呢,那么只能够依靠反射完成
Field fieldRule = FieldactionObject.getClass().getDeclaredField(filedName);
fieldRule.setAccessible(true);//取消掉封装处理
String rule = (String)fieldRule.get(actionObject);
//代码验证通过
if(validateUtil.validate(actionObject,rule,invocation
.getInvocationContext().getParameters())){
return invocation.invoke();
}else{//跳转到错误页面,应该回到错误页面
return uri+"VF";//跳转到指定的页面
}
}catch(Exception e){}
}
return invocation.invoke();
}
}
如果这个类完成了,那么以后服务器端的验证,只需要将拦截器配置上。而后在需要的地方编写验证规则,在struts.xml文件里面编写验证失败的跳转,那么就可以实现服务器端的操作验证了。