简体   繁体   English

在Spring Boot App中使用@Valid和BindingResult进行表单输入验证时出现问题

[英]Problem with form input validation in using @Valid and BindingResult in a Spring Boot App

I am trying to add code-side validation to my form. 我正在尝试向我的表单添加代码端验证。 I am basing on this tutorial: https://www.javacodegeeks.com/2017/10/validation-thymeleaf-spring.html - but without effort. 我基于此教程: https//www.javacodegeeks.com/2017/10/validation-thymeleaf-spring.html-但无需付出任何努力。

I have an entity InvoiceData: 我有一个实体InvoiceData:

@Data
@Document
@NoArgsConstructor
public class InvoiceData {

    @Id private String id;
    private ContractorData data;
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date receptionDate;
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date orderDate;
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date invoiceIssueDate;
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @NotNull
    private Date contractDate;
    @NotBlank
    private String invoiceNumber;
    private String additionalCosts;
    private String contractorComment;
    @NotEmpty
    private List<InvoiceTask> invoiceTasks = new ArrayList<>();

And a Controller method: 和Controller方法:

@RequestMapping(value = "/addinvoice/{contractorId}", method = RequestMethod.POST, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String addInvoice(@PathVariable("contractorId") String contractorId, @ModelAttribute @Valid InvoiceData data, Model model, BindingResult result, RedirectAttributes attr, HttpSession session) {
        if (result.hasErrors()) {
            System.out.println("BINDING RESULT ERROR");
            attr.addFlashAttribute("org.springframework.validation.BindingResult.data", result);
            attr.addFlashAttribute("register", result);
            return "redirect:/add";
        } else {
            Contractor contractor = contractorRepository.findById(contractorId).get();
            data.setData(contractor.getContractorData());
            if (contractor.getInvoices() == null) {
                contractor.setInvoices(new ArrayList<InvoiceData>());
            }
            contractor.getInvoices().add(data);
            invoiceDataRepository.save(data);
            contractorRepository.save(contractor);
            model.addAttribute("contractor", contractor);
            return "index";
        }
    }

And a small piece of the Thymeleaf for clearness (all other fields look alike this one) 还有一小块胸腺,以保持清晰(其他所有字段看起来都与此相似)

<form action="#" th:action="@{addinvoice/{id}(id=${contractorid})}" th:object="${invoicedata}" method="post">
    <ul class="form-style-1">
        <li>
            <label>Reception date<span class="required">*</span></label>
            <input type="date" th:field="*{receptionDate}" id="receptionDate">
        </li>

The problem is that when I am trying to send an invalid form, I am not redirected to /add , but I get an error page saying: 问题是,当我尝试发送无效的表单时,我没有重定向到/add ,但是出现错误页面,提示:

There was an unexpected error (type=Bad Request, status=400). 发生意外错误(类型=错误的请求,状态= 400)。 Validation failed for object='invoiceData'. 对象=“ invoiceData”的验证失败。 Error count: 6 错误计数:6

And the stacktrace (from just one field, for clearness): 和stacktrace(出于清晰起见,仅来自一个字段):

Field error in object 'invoiceData' on field 'invoiceIssueDate': rejected value [null]; 字段'invoiceIssueDate'上的对象'invoiceData'中的字段错误:拒绝的值[null]; codes [NotNull.invoiceData.invoiceIssueDate,NotNull.invoiceIssueDate,NotNull.java.util.Date,NotNull]; 代码[NotNull.invoiceData.invoiceIssueDate,NotNull.invoiceIssueDate,NotNull.java.util.Date,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [invoiceData.invoiceIssueDate,invoiceIssueDate]; 参数[org.springframework.context.support.DefaultMessageSourceResolvable:代码[invoiceData.invoiceIssueDate,invoiceIssueDate]; arguments []; 参数[]; default message [invoiceIssueDate]]; 默认消息[invoiceIssueDate]]; default message [must not be null] 默认消息[不得为空]

So I presume that this is one of the behaviours that I can exptect from the validator. 因此,我认为这是我可以从验证程序中防止的行为之一。

But there is one thing, when I set a breakpoint in the controller, at the beginning of the method where the if statement begins, AND I send an invalid form, the debugger never stops there, so it seems that this code is never reached... 但是有一件事,当我在控制器中设置一个断点时,在方法语句的开始处( if语句开始),并且我发送了一个无效的表单,调试器从不在那里停止,因此似乎从未到达此代码。 ..

But when I send a correctly filled form - everything goes fine, the code works, data is sent to the database etc... 但是当我发送正确填写的表格时-一切正常,代码正常运行,数据发送到数据库等。

My question is: is this a normal behaviour of the validator? 我的问题是:这是验证程序的正常行为吗? What can I do make the code run when form is invalid, so I can get the BindingResult and show some error output to the user? 当表单无效时,如何使代码运行,以便获得BindingResult并向用户显示错误输出?

You need to move the BindingResult parameter right next to parameter having @Valid annotation. 您需要将BindingResult参数移到带有@Valid批注的参数旁边。

@RequestMapping(value = "/addinvoice/{contractorId}", method = RequestMethod.POST, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String addInvoice(@PathVariable("contractorId") String contractorId, @ModelAttribute @Valid InvoiceData data, BindingResult result, Model model , RedirectAttributes attr, HttpSession session) {
    if (result.hasErrors()) {
        System.out.println("BINDING RESULT ERROR");
        attr.addFlashAttribute("org.springframework.validation.BindingResult.data", result);
        attr.addFlashAttribute("register", result);
        return "redirect:/add";
    } else {
        Contractor contractor = contractorRepository.findById(contractorId).get();
        data.setData(contractor.getContractorData());
        if (contractor.getInvoices() == null) {
            contractor.setInvoices(new ArrayList<InvoiceData>());
        }
        contractor.getInvoices().add(data);
        invoiceDataRepository.save(data);
        contractorRepository.save(contractor);
        model.addAttribute("contractor", contractor);
        return "index";
    }
}

Now the BindingResult variable will be attached to InvoiceData variable. 现在,BindingResult变量将附加到InvoiceData变量。 Also if you are Validating multiple parameters in a API, you would require to declare its corresponding BindingResult variable right next to all of these. 同样,如果要验证API中的多个参数,则需要在所有这些参数旁边声明其对应的BindingResult变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM