我们正在使用Spring MVC 3.0.6,但我们没有使用JSR 303验证,只使用我们的Controller方法中使用BindingResult的Binding错误来处理我们的模型表单bean。我将尝试简化下面的示例,因为问题不在于如何构建事物,因为这些决定是在我到达之前做出的。我只是想在我拥有的参数范围内使事情正常工作。
在我正在处理的这个特定形式中,我有一个表bean,它是一个子bean列表,视图允许用户添加/删除一堆这些子bean。
表单bean看起来像:
public class FormBean {
private List<SubBean> subBeans;
...
}
子豆:
public class SubBean {
private Integer value1;
private Date value2;
private String value3;
}
在视图JSP中,我们正在做类似的事情:
<form:form modelAttribute="formBean">
<spring:hasBindErrors name="formBean">
<div class="error-box">
<div class="error-txt">
<form:errors path="*" cssClass="error" />
</div>
</div>
</spring:hasBindErrors>
<c:forEach items="${formBean.subBeans}" var="subBean" varStatus="subBeanStatus">
...
<form:input path="subBeans[${subBeanStatus.index}].value1" />
<form:input path="subBeans[${subBeanStatus.index}].value2" />
<form:input path="subBeans[${subBeanStatus.index}].value3" />
...
</c:forEach>
...
</form:form>
当我提交一个没有通过Binding-mustard的值的表单时,会出现问题。例如,如果我为value1添加一个无效的int值,我会收到如下错误消息:
Failed to convert property value of type java.lang.String to required type java.lang.Integer for property subBeans[0].value1; nested exception is java.lang.NumberFormatException: For input string: "sdfs"
我知道使用非嵌套bean,你只需在表格中向Resource Bunder添加一条消息:
typeMismatch.beanName.fieldName="This is my custom error message!!!"
但是,如果你有一个List,你如何控制错误信息呢?
答案 0 :(得分:3)
我也不喜欢默认消息,并自定义了我自己的BindingErrorProcessor。
基本上我想要的只是“最后字段”名称 - 我想说日期的值无效,或者员工的值无效,或者其他什么。我还包括被拒绝的字段文本,标准的Spring错误处理器不会为消息提供这些文本。
public class SimpleMessage_BindingErrorProcessor
extends DefaultBindingErrorProcessor
{
@Override
public void processPropertyAccessException(PropertyAccessException ex, BindingResult bindingResult) {
// Create field error with the exceptions's code, e.g. "typeMismatch".
String field = ex.getPropertyName();
String[] codes = bindingResult.resolveMessageCodes(ex.getErrorCode(), field);
Object rejectedValue = ex.getValue();
if (rejectedValue != null && rejectedValue.getClass().isArray()) {
rejectedValue = StringUtils.arrayToCommaDelimitedString(ObjectUtils.toObjectArray(rejectedValue));
}
Object[] arguments = getArgumentsForBindError( bindingResult.getObjectName(), field, rejectedValue);
FieldError fieldError = new FieldError(
bindingResult.getObjectName(), field, rejectedValue, true,
codes, arguments, ex.getLocalizedMessage());
bindingResult.addError( fieldError);
}
/**
* Return FieldError arguments for a binding error on the given field.
* <p>TW's implementation returns {0} simple field title, {1} rejected value, {2} FQ field resolvable as per Spring DefaultBindingErrorProcessor
* (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes).
* @param objectName the name of the target object
* @param propPath the field that caused the binding error
* @param rejectedValue the value that was rejected
* @return the Object array that represents the FieldError arguments
* @see org.springframework.validation.FieldError#getArguments
* @see org.springframework.context.support.DefaultMessageSourceResolvable
*/
protected Object[] getArgumentsForBindError (String objectName, String propPath, Object/*String*/ rejectedValue) {
// just the Simple Name of Field;
// (last field in path).
//
String lastField = getLastField_Title( propPath);
// create Resolvable for "Fully-Qualified" Field;
// -- Spring standard, too specific/ would require defining hundreds of distinct messages; we don't use these.
//
String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + propPath, propPath};
DefaultMessageSourceResolvable fqField_resolvable = new DefaultMessageSourceResolvable(codes, propPath);
// return Args; {0} simple name, {1} rejected text, {2} FQ complex name.
return new Object[]{
lastField, rejectedValue, fqField_resolvable
};
}
/**
* Return FieldError arguments for a binding error on the given field.
* <p>TW's implementation returns {0} simple field title, {1} FQ field resolvable as per Spring DefaultBindingErrorProcessor
* (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes).
* @param objectName the name of the target object
* @param propPath the field that caused the binding error
* @return the Object array that represents the FieldError arguments
* @see org.springframework.validation.FieldError#getArguments
* @see org.springframework.context.support.DefaultMessageSourceResolvable
*/
@Override
protected Object[] getArgumentsForBindError (String objectName, String propPath) {
// just the Simple Name of Field;
// (last field in path).
//
String lastField = getLastField_Title( propPath);
// create Resolvable for "Fully-Qualified" Field;
// -- Spring standard, too specific/ would require defining hundreds of distinct messages; we don't use these.
//
String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + propPath, propPath};
DefaultMessageSourceResolvable fqField_resolvable = new DefaultMessageSourceResolvable(codes, propPath);
// return Args; {0} simple name, {2} FQ complex name.
return new Object[]{
lastField, fqField_resolvable
};
}
protected String getLastField_Title (String propPath) {
int index = propPath.lastIndexOf('.');
String title = (index >= 0) ? propPath.substring(index+1) : propPath;
return StrUtil.capitalize( title);
}
}
这很好用!现在你所有的messages.properties都说是:
# Type Mismatch generally;
# INCOMING 21/8/13 -- use {0} as 'Simple Name' of field, when using SimpleMessage_BindingErrorProcessor; {1} is 'resolvable' FQN of field.
#
typeMismatch=Invalid value for {0}: "{1}"
# Method Invocation/ value conversion;
# INCOMING 21/8/13 -- only expected for certain 'Value Converting'/ self-parsing properties; SPEC.
#
methodInvocation.machine=Invalid value for {0}: "{1}"
这个区域不是很清楚..整个绑定 - &gt;错误处理 - &gt;消息解析系统相当复杂,并且(据我所见)坚持消息代码通常太具体的问题。
这方面几乎没有(我没有发现任何与谷歌直接相关的内容),所以我希望这有助于人们。
答案 1 :(得分:2)
如果要获取资源包提供的消息,首先需要注册的messageSource实例:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="ValidationMessages"/>
</bean>
然后,
@Autowired
private MessageSource messageSource;
要从资源包中获取您的消息,
for (Object object : bindingResult.getAllErrors()) {
if(object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
// Use null for second parameter if you do not use i18n
String message = messageSource.getMessage(fieldError, null);
}
}
您的验证器应如下所示:
errors.rejectValue("<FIELD_NAME>", "typeMismatch.beanName.fieldName", new Object [] {"123"}, null);
这将让您了解如何实现目标。
答案 2 :(得分:1)
我解决这个问题的方法是添加一个像'typeMismatch.fieldName'这样的消息,基本上只指定结束字段名而不是bean /列表名。专家是它的工作原理,con是它为任何具有相同名称的bean设置所有字段的消息。因为我们正在开发门户网站,并且在同一个WAR中部署了数百个小小的应用程序,这可能是一个问题。现在,它有效。
答案 3 :(得分:1)
您应该查看DefaultMessageCodesResolver
课程的文档。在那里,您可以找到在使用List
或Map
类型的字段时可能使用的错误代码。