Struts2 Bean验证

时间:2016-06-10 21:54:01

标签: struts2 bean-validation hibernate-validator

我目前正在设置一个使用hibernate bean验证的Stuts2应用程序来验证登录页面上的表单字段。我添加了所有必需的插件和依赖项,并配置了struts.xml以包含一个调用beanValidation拦截器的自定义堆栈。 / logon路径从 authInterceptor 中排除。不幸的是,即使填充了电子邮件和密码的表单字段,返回消息也是空白。我可以在调试器中看到电子邮件和密码是在LoginAction类中设置的,但它好像 beanValidation 没有这个信息。如果我最后将拦截器的顺序切换为 beanValidation ,则永远不会调用它。

Extension

HTML

  <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <constant name="struts.devMode" value="false" />
    <constant name="struts.action.extension" value="," />
    <constant name="struts.custom.i18n.resources" value="login,signup" />
    <constant name="struts.mapper.alwaysSelectFullNamespace"
        value="false" />
    <constant name="struts.beanValidation.providerClass" value="org.hibernate.validator.HibernateValidator" />
    <constant name="struts.beanValidation.ignoreXMLConfiguration"
        value="false" />
    <constant name="struts.beanValidation.convertMessageToUtf"
        value="false" />
    <constant name="struts.beanValidation.convertMessageFromEncoding"
        value="ISO-8859-1" />
    <constant name="struts.enable.SlashesInActionNames" value="true" />
    <package name="defaultPackage" namespace="/" extends="struts-default">
        <interceptors>
            <interceptor name="authInterceptor"
                class="com.mypackage.interceptor.AuthenticationInterceptor">
            </interceptor>
            <interceptor name="beanValidation"
                class="org.apache.struts.beanvalidation.validation.interceptor.BeanValidationInterceptor" />
            <interceptor-stack name="authStack">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="beanValidation">
                    <param name="validateAnnotatedMethodOnly">true</param>
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="authInterceptor" />
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="authStack"></default-interceptor-ref>
        <global-results>
            <result name="login">/jsp/login.jsp</result>
        </global-results>
        <action name="login" class="com.mypackage.action.LoginAction"
            method="login">
            <interceptor-ref name="authStack">
                <param name="excludeMethods">login</param>
            </interceptor-ref>
            <result name="login">/jsp/login.jsp</result>
            <result name="input">/jsp/login.jsp</result>
        </action>
        <action name="logon" class="com.mypackage.action.LoginAction"
            method="doLogon">
            <interceptor-ref name="authStack">
                <param name="authInterceptor.excludeMethods">doLogon</param>
            </interceptor-ref>
            <result name="input">/jsp/login.jsp</result>
            <result name="success">/jsp/login.jsp</result>
        </action>
        <action name="password/reset" class="com.mypackage.action.PasswordResetAction"
            method="resetPassword">
            <interceptor-ref name="authInterceptor">
                <param name="excludeMethods">resetPassword</param>
            </interceptor-ref>
            <result name="reset-password">/jsp/password_reset_html.jsp</result>
        </action>
        <action name="register" class="com.mypackage.action.RegisterAction"
            method="register">
            <interceptor-ref name="authInterceptor">
                <param name="excludeMethods">register</param>
            </interceptor-ref>
            <result name="register">/jsp/register_html.jsp</result>
        </action>
        <action name="doRegistration" class="com.mypackage.action.RegisterAction">
            <interceptor-ref name="authInterceptor">
                <param name="excludeMethods">resetPassword</param>
            </interceptor-ref>
        </action>
    </package>
</struts>

行动类

         <div class="fields-container">
            <div class="field-div">
                <div>
                    <span><s:text name="login.email" /></span>
                </div>
                <label class="form-label"> <input type="text" name="email"
                    value="" />
                </label>
            </div>
            <div class="field-div">
                <div>
                    <span><s:text name="login.password" /></span>
                </div>
                <label class="form-label"> <input type="text"
                    name="password" value="" />
                </label>
            </div>
        </div>

编辑6/10/16

我更改了拦截器的执行顺序,以便public class LoginAction extends BaseAction { /** * */ private static final long serialVersionUID = 1L; private static final Logger log = LoggerFactory.getLogger(LoginAction.class); @NotNull(message = "{login.error.email.empty}") private String email; @NotNull(message = "{login.error.password.empty}") private String password; public String login() { return ActionConstants.LOGIN; } /** * Perform the authentication of the user. * * @return The result string which maps to a jsp page. */ public String doLogon() { String result = null; return result; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } 先行,因为我的理解是它负责填充defaultStack中的bean。现在,验证正在进行中。但是,如果我将任何字段留空,则会返回正确的错误消息,但仍会调用ActionClass方法 ActionClass 。我现在想弄清楚如何让doLogon短路,以便不调用beanValidation

1 个答案:

答案 0 :(得分:1)

所以看来 org.apache.struts.beanvalidation.validation.interceptor。 BeanValidationInterceptor 并不意味着短路其他拦截器的执行。在struts bean验证插件的2.5版本中,doIntercept方法只返回invocation.invoke(),这表明即使有错误,执行仍将继续。

    protected String doIntercept(ActionInvocation invocation)
    throws Exception
  {
    Validator validator = this.beanValidationManager.getValidator();
    if (validator == null)
    {
      LOG.debug("There is no Bean Validator configured in class path. Skipping Bean validation..");
      return invocation.invoke();
    }
    LOG.debug("Starting bean validation using validator: {}", new Object[] { validator.getClass() });

    Object action = invocation.getAction();
    ActionProxy actionProxy = invocation.getProxy();
    String methodName = actionProxy.getMethod();
    if (LOG.isDebugEnabled()) {
      LOG.debug("Validating [{}/{}] with method [{}]", new Object[] { invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), methodName });
    }
    Collection<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethods(action.getClass(), new Class[] { SkipValidation.class });
    if (!annotatedMethods.contains(getActionMethod(action.getClass(), methodName))) {
      performBeanValidation(action, validator);
    }
    return invocation.invoke();
  }

因为如果有错误我不想调用ActionClass方法,我创建了BeanValidationInterceptor.class的副本并将其添加到struts.xml。新类有一个用于存储ConstraintViolations的实例变量,而doIntercept方法返回&#34; input&#34;如果有错误。

private Set<ConstraintViolation<Object>> constraintViolations;

protected String doIntercept(ActionInvocation invocation) throws Exception {
    Validator validator = this.beanValidationManager.getValidator();
    if (validator == null) {
        LOG.debug("There is no Bean Validator configured in class path. Skipping Bean validation..");
        return invocation.invoke();
    }
    LOG.debug("Starting bean validation using validator: {}", new Object[] { validator.getClass() });

    Object action = invocation.getAction();
    ActionProxy actionProxy = invocation.getProxy();
    String methodName = actionProxy.getMethod();
    if (LOG.isDebugEnabled()) {
        LOG.debug("Validating [{}/{}] with method [{}]", new Object[] { invocation.getProxy().getNamespace(),
                invocation.getProxy().getActionName(), methodName });
    }
    Collection<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethods(action.getClass(),
            new Class[] { SkipValidation.class });
    if (!annotatedMethods.contains(getActionMethod(action.getClass(), methodName))) {
        performBeanValidation(action, validator);
    }
    return this.constraintViolations.isEmpty() ? invocation.invoke() : "input";
}