Struts2学习--带校验的注册程序

Reference :《Struts2 输入校验 实例讲解》《ST2.NO.0006 struts2.0 官网文档学习笔记之六 - Form Validation

 

Struts的信息校验方式有两种

1.硬编码的方式:重写ActionSupport类的validate()方法。

2.采用Struts2的输入校验框架,即采用XML配置的方式进行校验。

硬编码方式

Register.jsp

<s:form action="register" theme="simple">

    <font color="red" size="2"><s:fielderror /></font>

    <table border="1" >

	<tr><td>UserName:</td>

		<td><s:textfield name="person.userName"  label="usernmae"/>6-10 cahr</td>

	</tr>

	<tr><td>Password:</td>

		<td><s:password name="person.password" label="password"/></td>

	</tr>

	<tr><td>Re-password:</td>

		<td><s:password name="person.repassword" label="repassword" /></td>

	</tr>

	<tr><td>Age:</td>

		<td><s:textfield name="person.age" label="age" />0-150</td>

	</tr>

	<tr><td>Birthday:</td>

		<td><s:textfield name="person.birthday" label="birthday"/>must be date</td>

	</tr>

	<tr>

		<td><s:submit /></td></tr>

   </table>

</s:form>

RegisterAction.java

public void validate() {

    if (null == person.getUsername() || person.getUsername().length() < 6

            || person.getUsername().length() > 10) {

        this.addFieldError("username", "username is invalid");

    }

    if (null == person.getPassword() || person.getPassword().length() < 6

            || person.getPassword().length() > 10) {

        this.addFieldError("password", "password is invalid!");

    } else if (null == person.getRepassword()

            || person.getRepassword().length() < 6

            || person.getRepassword().length() > 10) {

        this.addFieldError("password", "password is invalid!");

    } else if (!person.getRepassword().equals(person.getRepassword())) {

        this.addFieldError("password", "tow password is not be same!");

    }

    if (person.getAge() <= 0 || person.getAge() > 150) {

        this.addFieldError("age", "age is invalid!");

    }

}

Struts.xml

<action name="register" class="test.RegisterAction">

	<result name="success">/test/Thankyou.jsp</result>

	<result name="input">/test/Register.jsp</result>

</action>

<result name="input">标签是必须添加的,Struts2在验证不成功的情况下会自动return这个input出来,所以一定要在Struts.xml里面指定一个jsp页面来接着!否则会报404错误哦~

 注意:1.personBean中定义的age和birthday分别是int型和Date型,所以在填写表单时候如果值不能转换为对应的类型,Struts2会首先报错。

image如图:验证失败并且 Struts2 返回 "input", Struts2 框架将重新显示 register.jsp 页面. 因为我们使用了 Struts2 form 标签, 所以Struts2 会自动的添加这些错误消息.这些错误的消息来自我们在 调用addFieldError() 方法中设置的错误消息之一. 这个 addFieldError 方法有两个参数. 第一个是表单的属性名称来说明哪一个属性输入有误, 另一个是需要在Form表单属性上面显示的错误消息.

2.之后才会到RegisterAction里面去找valide()方法进行其他方面的验证。

原理分析:

关键在于继承的ActionSupport类,ActionSupport类里面有个

private final ValidationAwareSupport validationAware = new ValidationAwareSupport();

我们在validate()里面调用的addFieldError实际上就是调用的ValidationAwareSupport 类里面的setFieldErrors方法。下面是ValidationAwareSupport 的部分代码:

public class ValidationAwareSupport implements ValidationAware, Serializable {

    private Collection<String> actionErrors;//保存Action级别的错误信息  Collection

    private Map<String, List<String>> fieldErrors; //保存Field级别的错误信息 Map

    //添加一条字段错误的详细代码

    public synchronized void addFieldError(String fieldName, String errorMessage) {

        //获取所有字段错误的Map

        final Map<String, List<String>> errors = internalGetFieldErrors();

        //取出对应字段的错误信息列表

        List<String> thisFieldErrors = errors.get(fieldName); 

        //如果之前没有错误,新创建一个List保存错误信息

        if (thisFieldErrors == null) {

            thisFieldErrors = new ArrayList<String>();

            errors.put(fieldName, thisFieldErrors);

        }

        //将错误信息添加到列表中

        thisFieldErrors.add(errorMessage);

    }

    //初始化存储错误的信息的Map

    private Map<String, List<String>> internalGetFieldErrors() {

        if (fieldErrors == null) {

            fieldErrors = new LinkedHashMap<String, List<String>>();

        }

        return fieldErrors;

    }

   //检查是否有错误

   public synchronized boolean hasErrors() {

        return (hasActionErrors() || hasFieldErrors());

    }

}

注意到ValidationAwareSupport 类里面还有一个actionErrors的Collection,其实Struts2中的错误有两种级别:

1. Action级别的错误

2. Field 级别的错误

而Struts2只有判断到两种错误级别的信息都没有的情况,才认为是输入校验通过。

validate代码能跑在execute之前要归功于Struts2的默认拦截器DefaultWorkflowInterceptor,部分代码如下:

public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {

 private String inputResultName = Action.INPUT; //INPUT哦

 /**

     * Intercept {@link ActionInvocation} and returns a <code>inputResultName</code>

     * when action / field errors is found registered.

     *

     * @return String result name

     */

 @Override

 protected String doIntercept(ActionInvocation invocation) throws Exception {

        Object action = invocation.getAction();

        if (action instanceof ValidationAware) {

            ValidationAware validationAwareAction = (ValidationAware) action;

            //如果validate没通过

            if (validationAwareAction.hasErrors()) {

                if (LOG.isDebugEnabled()) {

                    LOG.debug("Errors on action " + validationAwareAction + ", returning result name 'input'");

                }

                String resultName = inputResultName; //input哦!!

                //需要action实现ValidationWorkflowAware才能返回true,我们的例子返回的是false

                if (action instanceof ValidationWorkflowAware) {

                    resultName = ((ValidationWorkflowAware) action).getInputResultName();

                }

                //好像是某种可配置的annotation,在我们的例子里显然是null啦

                  InputConfig annotation = action.getClass().

                               getMethod(invocation.getProxy().

                                getMethod(), EMPTY_CLASS_ARRAY).getAnnotation(InputConfig.class);

                if (annotation != null) {

                    if (!annotation.methodName().equals("")) {

                        Method method = action.getClass().getMethod(annotation.methodName());

                        resultName = (String) method.invoke(action);

                    } else {

                        resultName = annotation.resultName();

                    }

                }

                //就是这里啦 返回的input!

                return resultName;

            }

        }

     //不出意外的话这里invoke的是execute()方法嗯,我们的例子没能到这一步

     return invocation.invoke();

  }

}

一些零碎的知识:

  • 在使用<s:form>的时候可以指定theme:<s:form action="register" theme="simple"> Struts2为每个表单显示都定义了一个主题,默认是HTML主题,其它的还有Ajax和Simple ,我们可以把它改成Simple 即可以自己定义布局的主题,是这样,一旦改成了theme=”simple” 它的错误信息就不会显示了。这也是我们使用这个主题的原因。
  • 这是因为Struts2标签默认只会显示Field级别的错误信息。要想显示Action级别的信息,需要在表单一加上一句;<s:actionerror cssStyle="color:red;"/>
  • Struts2提供了一个Action中多个方法,处理多种请求的机制,可以通过struts.xml 配置action中,加一个method属性来实现:
    <action name="register" class="test.RegisterAction"
    
    
    	method="registerPeople">
    
    
    	<result name="success">/test/Thankyou.jsp</result>
    
    
    	<result name="input">/test/Register.jsp</result>
    
    
    </action>
    这样的话validate方法还是运行在registerPeople之前的,可是如果有有一个情景要求在一个registerAction里面为两种不同的角色进行注册和验证的时候怎么办呢?可以把execute方法和validate方法留空,分别指定两个执行方法如:registerA()和registerB(),然后再这两个方法中显示调用各自的validate方法,类似于:
    public String registerPeople() {
    
    
    	validateRegister();
    
    
       /*do some thing, such as DB storage */
    
    
    	return SUCCESS;
    
    
    }

关于采用XML配置的校验方式,偶还木有学……标记一下Struts2官网的教程,以后用空了去研究一下!

如有理解错误,敬请指正!

你可能感兴趣的:(struts2)