Spring MVC 中 Bean 集合的自定义绑定错误消息

2024-04-25

我们使用的是 Spring MVC 3.0.6,但我们没有使用 JSR 303 验证,仅在处理模型表单 bean 的控制器方法中使用 BindingResult 进行绑定错误。我将尝试简化下面的示例,因为问题不在于如何构建事物,因为这些决定是在我到达之前做出的。我只是想让事情在我所拥有的参数范围内正常工作。

在我正在处理的这个特定表单中,我有一个表单 bean,它是子 bean 的列表,其中的视图允许用户添加/删除一堆这些子 bean。

表单 bean 看起来像:

public class FormBean {
    private List<SubBean> subBeans;
    ...
}

和子 bean:

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!!!"

但是,当您像我一样有一个列表时,如何控制错误消息呢?


我也不喜欢默认消息,因此自定义了自己的 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}"

这个区域不是很清楚..整个绑定 - >错误处理 - >消息解析系统相当复杂,并且(据我所知)陷入了消息代码通常是这样的问题太具体了.

关于这方面的资料很少(我在谷歌上没有找到任何直接相关的内容),所以我希望这对人们有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring MVC 中 Bean 集合的自定义绑定错误消息 的相关文章

随机推荐