前面进行短路验证时,我们发现短路验证虽然成功了,但是还有不完善的地方,如:
其他配置和类与短路验证中的一致
如何解决这个问题呢?
经过分析,我们知道,若类型转换失败, 默认情况下还会执行后面的拦截器, 还会进行后面的验证. 可以通过修改 ConversionErrorInterceptor 源代码的方式,使当类型转换失败时, 不再执行后续的验证拦截器, 而直接返回 input 的 result ,具体如何操作呢?
1. 在src 下创建一个和ConversionErrorInterceptor 所在包同名的包 com.opensymphony.xwork2.interceptor
2. 在包 com.opensymphony.xwork2.interceptor下创建一个和 ConversionErrorInterceptor 拦截器同名的类
3. 把原ConversionErrorInterceptor 拦截器中的代码复制到新创建的 ConversionErrorInterceptor 拦截器中
4. 修改新创建的 ConversionErrorInterceptor 拦截器中的代码,使其如果类型转换出错的情况下,就不在执行其后的拦截器链
其他配置和类与短路验证中的一致
~~~~~~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
项目结构
/*
* Copyright 2002-2007,2009 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.interceptor;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.lang3.StringEscapeUtils;
import java.util.HashMap;
import java.util.Map;
/**
* <!-- START SNIPPET: description -->
* ConversionErrorInterceptor adds conversion errors from the ActionContext to the Action's field errors.
*
* <p/>
* This interceptor adds any error found in the {@link ActionContext}'s conversionErrors map as a field error (provided
* that the action implements {@link ValidationAware}). In addition, any field that contains a validation error has its
* original value saved such that any subsequent requests for that value return the original value rather than the value
* in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to
* display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to
* the user).
*
*
* <!-- END SNIPPET: description -->
*
* <p/> <u>Interceptor parameters:</u>
*
* <!-- START SNIPPET: parameters -->
*
* <ul>
*
* <li>None</li>
*
* </ul>
*
* <!-- END SNIPPET: parameters -->
*
* <p/> <u>Extending the interceptor:</u>
*
* <p/>
*
* <!-- START SNIPPET: extending -->
*
* Because this interceptor is not web-specific, it abstracts the logic for whether an error should be added. This
* allows for web-specific interceptors to use more complex logic in the {@link #shouldAddError} method for when a value
* has a conversion error but is null or empty or otherwise indicates that the value was never actually entered by the
* user.
*
* <!-- END SNIPPET: extending -->
*
* <p/> <u>Example code:</u>
*
* <pre>
* <!-- START SNIPPET: example -->
* <action name="someAction" class="com.examples.SomeAction">
* <interceptor-ref name="params"/>
* <interceptor-ref name="conversionError"/>
* <result name="success">good_result.ftl</result>
* </action>
* <!-- END SNIPPET: example -->
* </pre>
*
* @author Jason Carreira
*/
public class ConversionErrorInterceptor extends AbstractInterceptor {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";
protected Object getOverrideExpr(ActionInvocation invocation, Object value) {
return escape(value);
}
protected String escape(Object value) {
return "\"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "\"";
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext invocationContext = invocation.getInvocationContext();
Map<String, Object> conversionErrors = invocationContext.getConversionErrors();
ValueStack stack = invocationContext.getValueStack();
HashMap<Object, Object> fakie = null;
for (Map.Entry<String, Object> entry : conversionErrors.entrySet()) {
String propertyName = entry.getKey();
Object value = entry.getValue();
if (shouldAddError(propertyName, value)) {
String message = XWorkConverter.getConversionErrorMessage(propertyName, stack);
Object action = invocation.getAction();
if (action instanceof ValidationAware) {
ValidationAware va = (ValidationAware) action;
va.addFieldError(propertyName, message);
}
if (fakie == null) {
fakie = new HashMap<Object, Object>();
}
fakie.put(propertyName, getOverrideExpr(invocation, value));
}
}
if (fakie != null) {
// if there were some errors, put the original (fake) values in place right before the result
stack.getContext().put(ORIGINAL_PROPERTY_OVERRIDE, fakie);
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation, String resultCode) {
Map<Object, Object> fakie = (Map<Object, Object>) invocation.getInvocationContext().get(ORIGINAL_PROPERTY_OVERRIDE);
if (fakie != null) {
invocation.getStack().setExprOverrides(fakie);
}
}
});
}
Object action = invocation.getAction();
if (action instanceof ValidationAware) {
ValidationAware va = (ValidationAware) action;
//如果 字段类型转换有错误 或者 action请求 有错误 直接返回不在调用下面的 invocation.invoke(),
//这样就阻止了拦截器链的运行,使程序更有效率
if(va.hasFieldErrors() || va.hasActionErrors()){
return "input";
}
}
return invocation.invoke();
}
protected boolean shouldAddError(String propertyName, Object value) {
return true;
}
}
修改后的效果: