Validation Struts2在单个文本字段上验证3次
我对Struts(2.2.3)有一个非常令人不安的问题。下面是我对ActionName-validation.xml的字段验证Validation Struts2在单个文本字段上验证3次,validation,struts2,interceptor,interceptorstack,Validation,Struts2,Interceptor,Interceptorstack,我对Struts(2.2.3)有一个非常令人不安的问题。下面是我对ActionName-validation.xml的字段验证 <field name="txtRequestDateFrom"> <field-validator type="conversion"> <param name="repopulateField">false</param> <message>${getText("E011",
<field name="txtRequestDateFrom">
<field-validator type="conversion">
<param name="repopulateField">false</param>
<message>${getText("E011", {"Date from"})}</message>
</field-validator>
</field>
当我在txtRequestDateFrom字段中输入字母时,我在上收到3条验证消息
<s:fielderror fieldName="txtRequestDateFrom"/>
我有自己的自定义主题,我相信简单主题不会有太多修改。我的拦截器堆栈与默认值堆栈几乎相同
<interceptor-stack name="defaultStack">
<interceptor-ref name="security"/>
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUploadStack" />
<interceptor-ref name="fileUpload" >
<param name="maximumSize">4000000</param>
</interceptor-ref>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">execute, complete ...</param>
</interceptor-ref>
<interceptor-ref name="workflow"/>
</interceptor-stack>
4000000
执行,完成。。。
我发现通过从堆栈中删除conversionError拦截器可以删除一个字段错误。但我不认为这会导致这个问题。Struts应该只能显示由开发人员定义的错误,对吗
请在这方面帮助我,你需要理解
在类型转换期间发生的任何错误都可能需要报告,也可能不希望报告。例如,报告输入“abc”无法转换为数字可能很重要。另一方面,报告无法将空字符串“”转换为数字可能并不重要,尤其是在web环境中,很难区分用户未输入值和输入空白值
重要的是要知道这些错误实际上都不是直接报告的。相反,它们被添加到ActionContext中名为conversionErrors的映射中。有几种方法可以访问此映射,并相应地报告错误
错误报告有两种方式:
您正在使用这两种机制,从而重复发现的错误。正如文档所述,通常您不想报告所有转换错误,因此应该从堆栈中删除。现在,您可以使用
转换
验证程序有选择地将转换错误作为字段错误引发。我发现我的自定义日期时间转换器
导致了异常和额外的错误消息。因为我从Struts2书中找到了下面的代码,以便更改日期的正常格式。当它抛出异常时,它在控制台上显示异常,在字段error上显示错误消息,而不是将异常传递给验证器。我认为这是一种bug,因为这个类扩展了strutstypecoverter
,它应该像普通的转换器一样工作
public class StringToDateTimeConverter extends StrutsTypeConverter {
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd");
public Object convertFromString(Map context, String[] strings, Class toClass) {
if (strings == null || strings.length == 0 || strings[0].trim().length() == 0) {
return null;
}
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(DATETIME_FORMAT.parse(strings[0]));
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
return calendar.getTime();
} catch (ParseException e) {
throw new TypeConversionException(e);
}
}
public String convertToString(Map context, Object date) {
if (date != null && date instanceof Date) {
return DATETIME_FORMAT.format(date);
} else {
return null;
}
}
}
无论如何,我改变了抛出新的TypeConversionException(e)
to返回null代码>并在验证XML上添加了必需的
验证器。现在,当我在日期字段中输入无效日期时,它显示了一个错误
PS:还有其他方法来更改Struts全局日期格式吗?谢谢我昨天遇到了一个类似的问题,最终找到了一个我愿意分享的解决方案。我在操作中使用注释进行验证,因此我更改了默认struts拦截器堆栈,并将SensibleVersionErrorInterceptor而不是StrutsConversionErrorInterceptor放入。这一个完全相同,但不会产生任何验证错误。相反,它们是通过在“我的操作”的注释中配置的验证生成的
这是我的转换器:
public class SensibleConversionErrorInterceptor extends StrutsConversionErrorInterceptor {
private static final long serialVersionUID = 8186282792289268544L;
@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)) {
// removed cause error messages are generated from annotations in actions
// 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);
}
}
});
}
return invocation.invoke();
}
感谢您的回答,但正如我之前在删除ConversionError拦截器时所说的,它只删除1条错误消息。剩下的两条消息中有一条来自Action-validation.xml。即使删除Action-validation.xml,也始终会保留一条错误消息。我不知道它是从哪里来的。此外,当转换错误发生时,它总是在控制台上给出异常。若它正在处理错误,为什么它会在控制台上显示异常?我认为是其他原因导致了这个错误异常,它给我的是:java.lang.NoSuchMethodException:com.*********.client.CEST01.setTxtRequestDateFrom([Ljava.lang.String;)@batbaatar看起来您已打开,这将引发通常忽略的转换错误。关于附加消息的问题,我怀疑您的堆栈中仍然存在conversionError
拦截器。您能否检查defaultStack
定义中引用的任何堆栈是否具有offen拦截程序?另一种确保conversionError
拦截程序不在堆栈中的方法是,尝试从struts.xml
中注释拦截程序定义
。我的devMode为false。我发现了我的问题,我想Struts2在错误处理方面做得不太好。
public class StringToDateTimeConverter extends StrutsTypeConverter {
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd");
public Object convertFromString(Map context, String[] strings, Class toClass) {
if (strings == null || strings.length == 0 || strings[0].trim().length() == 0) {
return null;
}
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(DATETIME_FORMAT.parse(strings[0]));
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
return calendar.getTime();
} catch (ParseException e) {
throw new TypeConversionException(e);
}
}
public String convertToString(Map context, Object date) {
if (date != null && date instanceof Date) {
return DATETIME_FORMAT.format(date);
} else {
return null;
}
}
public class SensibleConversionErrorInterceptor extends StrutsConversionErrorInterceptor {
private static final long serialVersionUID = 8186282792289268544L;
@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)) {
// removed cause error messages are generated from annotations in actions
// 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);
}
}
});
}
return invocation.invoke();
}
@Conversion
public class ProductAction extends ActionSupport {
private Product product;
// getter, setter and so on...
@Action(...)
@Validations(
requiredFields = {
@RequiredFieldValidator(
type = ValidatorType.FIELD,
fieldName = "product.validFrom",
message = "required.product.validFrom",
shortCircuit = true
)
},
conversionErrorFields = {
@ConversionErrorFieldValidator(
fieldName = "product.validFrom",
key = "invalid.fieldvalue.product.validFrom'",
shortCircuit = true
)
}
)
public String saveOrUpdate() {
// do something here...
}
}