Struts2 Bean 验证
Struts2 Bean Validation
我目前正在设置 Stuts2 应用程序,它使用休眠 bean 验证来验证登录页面上的表单字段。我已经添加了所有必要的插件和依赖项,并配置了 struts.xml 以包含调用 beanValidation 拦截器的自定义堆栈。 /logon 路径被排除在 authInterceptor 之外。不幸的是,即使填写了电子邮件和密码的表单字段,return 消息仍然是空白。我可以在调试器中看到在 LoginAction class 中设置了电子邮件和密码,但好像 beanValidation 没有此信息。如果我将拦截器的顺序切换为最后有 beanValidation,它永远不会被调用。
<?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>
HTML
<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>
操作Class
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;
}
编辑 2016 年 6 月 10 日
我更改了拦截器的执行顺序,因此 defaultStack
将首先执行,因为我的理解是它负责填充 ActionClass
中的 bean。现在,验证正在按预期进行。但是,如果我将任何字段留空,正确的错误消息是 returned 但 ActionClass 方法 doLogon
仍在被调用.我现在想弄清楚如何让 beanValidation
短路,这样 ActionClass
就不会被调用。
所以看来org.apache.struts.beanvalidation.validation.interceptor。
BeanValidationInterceptor 并不意味着短路其他拦截器的执行。在 struts bean 验证插件的 2.5 版本中,doIntercept 方法简单地 returns 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。新的 class 有一个实例变量,用于存储 ConstraintViolations 和 doIntercept 方法 returns "input" 如果有错误。
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";
}
我目前正在设置 Stuts2 应用程序,它使用休眠 bean 验证来验证登录页面上的表单字段。我已经添加了所有必要的插件和依赖项,并配置了 struts.xml 以包含调用 beanValidation 拦截器的自定义堆栈。 /logon 路径被排除在 authInterceptor 之外。不幸的是,即使填写了电子邮件和密码的表单字段,return 消息仍然是空白。我可以在调试器中看到在 LoginAction class 中设置了电子邮件和密码,但好像 beanValidation 没有此信息。如果我将拦截器的顺序切换为最后有 beanValidation,它永远不会被调用。
<?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>
HTML
<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>
操作Class
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;
}
编辑 2016 年 6 月 10 日
我更改了拦截器的执行顺序,因此 defaultStack
将首先执行,因为我的理解是它负责填充 ActionClass
中的 bean。现在,验证正在按预期进行。但是,如果我将任何字段留空,正确的错误消息是 returned 但 ActionClass 方法 doLogon
仍在被调用.我现在想弄清楚如何让 beanValidation
短路,这样 ActionClass
就不会被调用。
所以看来org.apache.struts.beanvalidation.validation.interceptor。 BeanValidationInterceptor 并不意味着短路其他拦截器的执行。在 struts bean 验证插件的 2.5 版本中,doIntercept 方法简单地 returns 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。新的 class 有一个实例变量,用于存储 ConstraintViolations 和 doIntercept 方法 returns "input" 如果有错误。
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";
}