Struts2验证框架

Struts2验证框架

1.使用validate()方法校验

在Struts2框架中,validate()方法是专门用来校验数据的方法,具体实现时可以通过继承ActionSupport类,并重写validate方法完成校验。示例如下:

  1. 先建立一个Member的简单Java类,并覆写toString()方法。
import java.io.Serializable;
import java.util.Date;

@SuppressWarnings("serial")
public class Member implements Serializable {
    private Integer id;
    private String name;
    private Double salary;
    private Date credate;

    public Member() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Date getCredate() {
        return credate;
    }

    public void setCredate(Date credate) {
        this.credate = credate;
    }

    @Override
    public String toString() {
        return "Member{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", credate=" + credate +
                '}';
    }
}
  1. 建立MemberAction类接受数据并进行验证(此处为方便只编写了空验证)。
import com.bank.vo.Member;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.*;

@ParentPackage("root")//表示继承了root父包
@Namespace(value="/pages/member")//定义了自己的命名空间
@Action(value="MemberAction")//定义了Action的访问名称
//配置了发生错误时的跳转页面为根目录下的/pages/errors.jsp
@Results(@Result(name="input",location ="/pages/errors.jsp",type="dispatcher"))
public class MemberAction extends ActionSupport {
    private Member member;
    public Member getMember() {
        return member;
    }
    public void setMember(Member member) {
        this.member = member;
    }

    @Override
    public void validate() {
        if(this.member.getId()==null){
            super.addFieldError("member.id","用户编号不能为空");
        }
        if(this.member.getName()==null||"".equals(this.member.getName())){
            super.addFieldError("member.name","用户名不能为空");
        }
        if(this.member.getSalary()==null){
            super.addFieldError("member.salary","工资不能为空");
        }
        if(this.member.getCredate()==null){
            super.addFieldError("member.credate","注册日期不能为空");
        }
    }

    public void test(){
        System.out.println(this.member);
    }
}
  1. 在/pages/member目录下新建member.jsp页面,编写提交表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
    <title>Member</title>
</head>
<body>
<form action="MemberAction!test.action" method="post">
    用户编号:<input type="text" id="member.id" name="member.id" /><br>
    用户名:<input type="text" id="member.name" name="member.name" /><br>
    工资:<input type="text" id="member.salary" name="member.salary" /><br>
    注册日期:<input type="text" id="member.credate" name="member.credate" /><br>
    <input type="submit" value="提交" />
</form>
</body>
</html>
  1. 在/pages目录下新建errors.jsp页面显示错误信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
    <title>Errors</title>
</head>
<body>
<h1>Errors</h1>
 错误信息:${fieldErrors}
</body>
</html>
  1. 随后我们运行程序找到表单后不填写内容直接提交,就会跳转到errors.jsp显示错误信息

注意:如果一个在Action中采用分发的处理方式(即一个Action中编写多个方法),如果我们只想对某一个方法进行数据校验,其他的方法不需要校验,我们就可以便编写validateXxx()方法,Xxx为方法名,即我们编写的validateXxx方法只对Xxx方法进行数据校验。在上面的实例中,我们只需要将validate()方法变为validateTest()方法,就可以只针对test()方法进行数据校验。

public void validateTest() {
    if(this.member.getId()==null){
        super.addFieldError("member.id","用户编号不能为空");
    }
    if(this.member.getName()==null||"".equals(this.member.getName())){
       super.addFieldError("member.name","用户名不能为空");
    }
    if(this.member.getSalary()==null){
       super.addFieldError("member.salary","工资不能为空");
    }
    if(this.member.getCredate()==null){
        super.addFieldError("member.credate","注册日期不能为空");
    }
}
2.使用配置文件的方式进行数据校验

使用validate()方法和validateXxx()方法虽然可以完成数据校验的任务,但是将校验嵌入到Action类之中会使Action类变得非常复杂和臃肿,同时增加Action和输入校验之间的耦合度,使得开发变得不方便。因此Struts2提供了一种基于框架的校验方式,将校验规则保存在文件中,使Action和校验分离,提高了系统的维护性和扩展性。使用验证框架完善上面历程中的功能。

  1. 在包含Action类的包中定义ActionName-validation.xml或ActionName-alias-validation.xml文件(定义的校验文件一定要与Action类放在同一目录下,ActionName表示实际的Action类名,alias表示struts.xml文件或注解中配置的Action访问名字) ,验证文件的结构如下图所示:
    • 标记为( + )的元素:该元素可以使用一次或者多次。
    • 标记为( * )的元素:该元素可以使用0次或者多次。
    • 没有标记的元素:该元素是必须的。
  2. 解压xwork-x.x.x.jar文件,在xwork-x.x.x\com\opensymphony\xwork2\validator\validators目录下,可以找到default.xml文件,该XML文件定义了Struts2框架的内建校验器,通过这些内建校验器的使用,可以很方便的实现各种数据的校验。该文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Definition 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">

<!-- START SNIPPET: validators-default -->
<validators>
    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
    <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
    <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
<!--  END SNIPPET: validators-default -->
  1. 使用验证框架对上例的校验进行修改,新建MemberAction.xml文件,加入如下内容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
    <field name="member.id">
        <field-validator type="required">
            <message>用户编号不许为空</message>
        </field-validator>
        <field-validator type="int">
            <message>用户编号必须为数字</message>
        </field-validator>
    </field>
    <field name="member.name">
        <field-validator type="requiredstring">
            <message>用户名不许为空</message>
        </field-validator>
        <field-validator type="stringlength">
            <param name="maxLength">10</param>
            <param name="minLength">4</param>
            <message>用户名长度在${minLength}-${maxLength}之间</message>
        </field-validator>
    </field>
    <field name="member.salary">
        <field-validator type="required">
            <message>工资不许为空</message>
        </field-validator>
        <field-validator type="double">
            <message>工资必须为数字</message>
        </field-validator>
    </field>
    <field name="member.credate">
        <field-validator type="required">
            <message>日期不许为空</message>
        </field-validator>
        <field-validator type="date">
            <param name="min">1998-1-3</param>
            <param name="max">2020-5-1</param>
            <message>日期应在${min}-${max}之间</message>
        </field-validator>
    </field>
</validators>

3.使用拦截器编写自己的验证框架

Struts2中拦截器的实现原理如下图所示:

Struts2中的自动赋值功能是由名叫DefaultStack的拦截器实现的,如果我们要进行数据的验证,则应在赋值之前进行,以防止类型转换出现错误。

  1. 首先定义自己的验证工具类,应包含对常用数据类型的验证,如空验证、整数验证、小数验证、日期验证等。
public class ValidateUtil {
    /**
     * 验证数据是否非空
     * @param data 要验证的数据
     * @return 若数据非空,返回true,否则返回false
     */
    public static boolean validateEmpty(String data){
        return data!=null&&data.length()>0;
    }

    /**
     * 验证数据是否满足正则要求
     * @param data 要验证的数据
     * @param regex 正则表达式
     * @return 若数据满足正则返回true,否则返回false
     */
    public static boolean validateRegex(String data,String regex){
        if(validateEmpty(data)){
            return data.matches(regex);
        }
        return false;
    }

    /**
     * 验证数据是否为整数
     * @param data 要验证的数据
     * @return 若数据为整数返回true,否则返回false
     */
    public static boolean validateInt(String data){
        return validateRegex(data,"\\d+");
    }

    /**
     * 验证数据是否为数字
     * @param data 要验证的数据
     * @return 若数据为数字返回true,否则返回false
     */
    public static boolean validateNum(String data){
        return validateRegex(data,"\\d+(\\.\\d+)?");
    }

    /**
     * 验证数据是否为日期
     * @param data 要验证的数据
     * @return 若数据为日期返回true,否则返回false
     */
    public static boolean validateDate(String data){
        //判断是否满足日期格式
        if(validateRegex(data,"\\d{4}-\\d{1,2}-\\d{1,2}")){
            return true;
        }else{
            //判断是否满足日期时间格式
            return validateRegex(data,"\\d{4}-\\d{1,2}-\\d{1,2} \\d{2}:\\d{2}:\\d{2}");
        }
    }
}

2.编写数据验证拦截器。

import com.bank.util.StrutsValidate;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import org.apache.struts2.ServletActionContext;

import java.lang.reflect.Field;
import java.util.Map;

public class ValidateInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        Object actionObj = actionInvocation.getAction();//取得要访问的Action类对象
        String uri = ServletActionContext.getRequest().getRequestURI();//取得请求的相对地址
        uri = uri.substring(uri.indexOf("!")+1);
        uri = uri.substring(0,uri.indexOf("."))+"VF";//取得验证规则属性名称
        Field ruleField = actionObj.getClass().getDeclaredField(uri);//取得包含验证规则的属性
        ruleField.setAccessible(true);//解除属性操作禁制
        String rule = (String)ruleField.get(actionObj);//取得验证规则
        //取的请求的所有参数名称和值(包含要验证的数据)
        Map<String,Object> params = actionInvocation.getInvocationContext().getParameters();
        //将验证操作交给StrutsValidate类来完成
        StrutsValidate sv = new StrutsValidate(actionObj,rule,params);
        if(sv.validate()){//验证通过则请求继续传递
            return actionInvocation.invoke();
        }else{//验证失败跳转到显示错误的页面进行错误显示
            return ActionSupport.INPUT;
        }
    }
}

  1. 编写StrutsValidate类,接收要访问的Action类对象、验证规则和要验证的数据,通过validate方法进行验证。
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class StrutsValidate {
    private Object actionObj;//表示要触发此操作的Action类
    private String rule;//每个Action类里定义的规则
    private Map<String,Object> params;//所有页面传递来的数据(包含要验证的数据)
    private Map<String,String> errors = new HashMap<String,String>();//保存所有的错误信息

    public StrutsValidate(Object actionObj,String rule,Map<String,Object> params){
        this.actionObj = actionObj;
        this.rule = rule;
        this.params = params;
    }

    public boolean validate(){
        //如果验证规则为空,则表示没有数据要进行验证,验证可以直接通过
        if(!ValidateUtil.validateEmpty(this.rule)){
            return true;
        }
        try{
            //通过此方法取得错误的提示信息
            Method getTextMethod = this.actionObj.getClass().getMethod("getText",String.class);
            //取得增加错误信息的方法,通过此方法保存错误信息
            Method addFieldErrorMethod = this.actionObj.getClass().getMethod("addFieldError",String.class,String.class);
            //所有的验证操作都应该由rule发起,里面的组成是 参数名称:类型
            String[] results = rule.split("\\|");//取出每一组验证规则
            for(int x=0;x<results.length;x++){//循环每一个验证
                String paramName = results[x].split(":")[0];//取得参数名字
                String paramType = results[x].split(":")[1];//取得参数验证类型
                String[] datas = (String[])this.params.get(paramName);//取得参数值
                String errorTie = null;//保存每次的错误提示信息
                for(int y=0;y<datas.length;y++){//进行有效的验证
                    if("string".equalsIgnoreCase(paramType)){
                        if(!ValidateUtil.validateEmpty(datas[y])){
                            errorTie = (String) getTextMethod.invoke(this.actionObj,"validate.string");
                        }
                    }else if("integer".equalsIgnoreCase(paramType)||"int".equalsIgnoreCase(paramType)){
                        if(!ValidateUtil.validateInt(datas[y])){
                            errorTie = (String) getTextMethod.invoke(this.actionObj,"validate.int");
                        }
                    }else if("double".equalsIgnoreCase(paramType)){
                        if(!ValidateUtil.validateNum(datas[y])){
                            errorTie = (String) getTextMethod.invoke(this.actionObj,"validate.double");
                        }
                    }else if("date".equalsIgnoreCase(paramType)){
                        if(!ValidateUtil.validateDate(datas[y])){
                            errorTie = (String) getTextMethod.invoke(this.actionObj,"validate.date");
                        }
                    }
                    if(errorTie!=null){
                        //添加错误信息
                        this.errors.put(results[x],errorTie);
                        addFieldErrorMethod.invoke(this.actionObj,results[x],errorTie);
                    }
                    errorTie = null;//错误信息重置
                }
            }
            if(this.errors.size()==0){
                return true;
            }
            return false;
        }catch(Exception e){
            e.printStackTrace();
        }
        return true;
    }

    public Map<String,String> getErrors(){
        return this.errors;
    }
}
  1. 新建资源文件,写入验证失败时的提示信息
validate.string=不许为空!
validate.int=必须为整数!
validate.double=必须为数字!
validate.date=必须为日期!
  1. 修改Action类,在里面加入验证规则,并启用拦截器
import com.bank.vo.Member;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.*;

@ParentPackage("root")
@Namespace(value="/pages/member")
@Action(value="MemberAction")
@InterceptorRefs(value={
        @InterceptorRef(value="ValidateInterceptor"),//启用我们自己编写的验证拦截器
        @InterceptorRef(value="defaultStack")//启用Struts2的自动赋值功能
})
@Results(@Result(name="input",location ="/pages/errors.jsp",type="dispatcher"))
public class MemberAction extends ActionSupport {
    //编写验证规则
    private String testVF = "member.id:integer|member.name:string|" +
                         "member.salary:double|member.credate:date";
    private Member member;
    public Member getMember() {
        return member;
    }
    public void setMember(Member member) {
        this.member = member;
    }

    public void test(){
        System.out.println(this.member);
    }
}

这时再使用表单访问此Action,就会自动启用自己便编写的验证了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值