如何使用BindingResult检查特定行是否在Spring中进行多行验证时出现验证错误

时间:2016-08-27 14:40:19

标签: spring validation spring-mvc bean-validation

当前逻辑将检查BindingResult是否有错误并在jsp中显示数据和错误。 需要的逻辑是检查每行的错误并仅显示包含验证错误的行,并更新没有验证错误的行。     @Autowired      private IncidentExtractStgService incidentExtractStgService;

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        this.DataContext = new List<String>{ "Item 1", "Item 2", "Item 3"};
    }

    private string ListViewItemString;

    private void ChoiceA_Click(object sender, RoutedEventArgs e)
    {
        // What was clicked?
        var clickedItem = ListViewItemString;
    }

    private void ListView_Opening(object sender, object e)
    {
        ListViewItemString = ((sender as MenuFlyout)?.Target as ListViewItem)?.Content as string;
    }
}

下面的代码片段将检查模型是否包含属性&#34; incidetsForm&#34;如果是,则将相同的内容发送到example.jsp,而example.jsp将显示数据和验证错误。

function implementsInterface(object: Object, target: Interface) {
    const objClass: Class = object.constructor && object.constructor.getClass();
    if (objClass && objClass.implements) { 
        let found = false;
        for (let base of objClass.implements) {
            let found = interfaceExtends(base, target);
            if (found) {
                return true;
            }
        }
    }
    return false;
}

// recursive interface inheritance check
function interfaceExtends(i: Interface, target: Interface) {
    if (i === target) { 
        return true;
    }
    if (i.extends) {
        let found = false;
        for (let base of i.extends) {
            // do a recursive check on base interface...
            found = interfaceExtends(base, target);
            if (found) {
                return true;
            }
        }
    }
    return false;
}

Example.jsp代码段

@RequestMapping(value = "/validatingIncidentList", method = RequestMethod.POST)
public String ValidateIncidentList( @Valid @ModelAttribute("incidentsForm") IncidentsForm incidentsForm,
        BindingResult bindingResult,RedirectAttributes redirectAttributes) {
    if (bindingResult.hasErrors()) {


        for(ObjectError error: bindingResult.getAllErrors()){

            System.out.println(error);
        }

        redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.incidentsForm", bindingResult);
        redirectAttributes.addFlashAttribute("incidentsForm", incidentsForm);

        return "redirect:/validateIncidentList";
    }
    else
    {
        for(IncidentExtractStg ie : incidentsForm.getIncidents()) {

            ie.setValidated(1);
            incidentExtractStgService.update(ie);

            System.out.println(ie.getNumber()+"     "+ie.getWaitTime());
        }


    return  "redirect:/validateIncidentList";

    }

IncidentsForm.java:

@RequestMapping(value = "/validateIncidentList", method = RequestMethod.GET)
 public String incidentList(Model model) {
    if (!model.containsAttribute("incidentsForm")) {
            List<IncidentExtractStg> incidents = incidentExtractStgDao.validateList();
            incidentsForm.setIncidents(incidents);
            model.addAttribute("incidentsForm", incidentsForm);
            return "example";
    }

     model.addAttribute("errormessage","Please Check the Validation Errors column for Errors");
     return "example";
}

IncidentExtractStg.java片段

<c:forEach var="ie" items="${incidentsForm.incidents}" varStatus="status">
             <tr>
                  <td><form:input path="incidents[${status.index}].id" value="${ie.id}" readonly ="true"/></td>
                 <td><form:errors path="incidents[${status.index}].id" cssClass="error" /></td> 

                <td><form:input path="incidents[${status.index}].number" value="${ie.number}"/></td>
                <td><form:errors path="incidents[${status.index}].number" cssClass="error" /></td> 
            </tr>

2 个答案:

答案 0 :(得分:1)

首先,如果我是你,我将提取服务层内的所有逻辑。要继续,您可以创建一个接口IncidentService和它自己的具体实现IncidentServiceImpl,您可以在其中安全地处理您的需求。控制器肯定没有完成所有事情。

那么,您的需求是什么? &#34;检查每行的错误并仅显示包含验证错误的行,并更新没有验证错误的行&#34;

服务层内的方法可能是这样的:

public void handleErrors(IncidentsForm incidentsForm, BindingResult bindingResult){ 

    List<String> fieldsInErrorState = new ArrayList<String>(10);

    if (bindingResult.hasErrors()) { //
        Map<String, Object> bindingModel = bindingResult.getModel();

        for (Map.Entry<String, Object> entry : bindingModel.entrySet()) {
            String key = entry.getKey();
            //Object value = entry.getValue(); you don't need to parse that unless you want specific domain model handlers to run

            //you need to store the key as a form field which is in error state
            fieldsInErrorState.add(key);

            //you already have all the stuff to parse and display errors in your JSP
            //thanksfully to bindingResult and JSTL tags.
        }

        ContactMessageForm cmForm2 = new ContactMessageForm();
        // get the list of the fields inside your form
        Field[] declaredFields = ContactMessageForm.class.getDeclaredFields();
        for (Field field : declaredFields) {
            if (!fieldsInErrorState.contains(field.getName())) {
                if (field.getName().equalsIgnoreCase("firstname")) {
                    cmForm2.setFirstname(contactMessageForm.getFirstname());
                }
                if (field.getName().equalsIgnoreCase("lastname")) {
                    cmForm2.setLastname(contactMessageForm.getLastname());
                }

                //etc for each properties of your form object.
            }

            // then store your dbmodel object
            // BUT i think you must be carefull to your data integrity... It is maybe not safe to save an object like that with bypassing some stuff... 
            // Your form was built like that maybe for a good reason looking at your objects graph.
            // If your form is too big, then split it in small parts, it will be much easy to handle, to update, and to work with daily.
        }

    }


}

当然,您需要自定义该代码,不要忘记将throws IntrospectionException添加到您的服务方法中,并且您处于良好的状态。

干杯!

答案 1 :(得分:0)

由于逻辑是仅显示包含验证错误的行,因此会创建一个新的List来存储至少有一个验证错误的行。

创建一个新的BindingResult来将错误存储在新List的索引中。(如果没有这样做,那么错误信息将不会显示在显示的行上)。

以下逻辑是针对行的每个字段检查字段错误,并且从jsp可以看到归档名称具有“事件[$ {status.index}]。id”。   - 计数器i获取行数   - 计数器j用于设置BindingResult的索引。

join

例如:如果在第30行,事件[30] .number字段有验证错误。然后i = 30并且计数> 0且j = 0。

因此整个行事件[30]将保存在新初始化列表的索引0处,并且bindingresult也将在索引0处添加。如果J未被设置为result2并且使用了bindingresult,那么它将仍然指向索引30,并且不会对现在存储在索引0的字段显示错误消息。

现在,这个更新的IncidentsForm和result2将被发送到jsp页面,该页面将仅显示那些具有验证错误的行以及各自的错误消息。