Struts2.x 服务器端数据验证

本文介绍在Struts2.x框架中实现服务器端数据验证的方法,包括定义验证规则、使用拦截器进行验证及错误处理流程。通过自定义验证规则和拦截器,确保数据在服务器端的有效性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于数据验证的操作定义是分为两端进行,一端是客户端验证(虽然无用,但是必须提供),另外一种是基于服务器端的应用,但是所有的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文件里面编写验证失败的跳转,那么就可以实现服务器端的操作验证了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值