如何使用Javax验证(百里香与Spring Boot)验证另一个对象内的对象列表元素?

时间:2019-04-19 17:31:22

标签: java spring spring-boot validation thymeleaf

我在使用ThymeLeaf和javax验证来验证另一个对象内的对象列表时遇到问题。

从代码方面看,它看起来像这样。对于豆:

public class InvoiceData {

    @Id private String id;
    private ContractorData data;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date receptionDate;
    private String invoiceNumber;
    @NotEmpty(message = "Lista zadań nie może być pusta!")
    private List<InvoiceTask> invoiceTasks = new ArrayList<>();

    // getters, setters below

}

然后使用自定义验证程序:

@Component
public class InvoiceFormValidator implements Validator {

    Logger logger = LoggerFactory.getLogger(InvoiceFormValidator.class);

    @Override
    public boolean supports(Class<?> clazz) {
        return InvoiceData.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "receptionDate", "empty");
        ValidationUtils.rejectIfEmpty(errors, "invoiceNumber", "empty");
        ValidationUtils.rejectIfEmpty(errors, "invoiceTasks", "empty");
    }
}

现在使用InvoiceTask类:

@Data
@Builder
@Document
@AllArgsConstructor
public class InvoiceTask {

    private String taskName;
    private String project;
    private BigDecimal hoursCount;

}

messages.properties中的某些消息与此处无关。

最后但并非最不重要的,控制器:

@RequestMapping(value = "/addinvoice", method = RequestMethod.POST, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String addInvoice(@CurrentUser Contractor contractor, @ModelAttribute("invoicedata") @Validated InvoiceData invoicedata, BindingResult result, Model model, RedirectAttributes attr) {
        if (result.hasErrors()) {
            return "add";
        } else {
            invoicedata.setData(contractor.getContractorData());
            // TODO check if we can remove the next 3 lines of code.
            if (contractor.getInvoices() == null) {
                contractor.setInvoices(new ArrayList<InvoiceData>());
            }
            contractor.getInvoices().add(invoicedata);
            invoiceDataRepository.save(invoicedata);
            contractorRepository.save(contractor);
            model.addAttribute("contractor", contractor);
            logger.info("Invoice number "+ invoicedata.getInvoiceNumber() +" with ID " + invoicedata.getId() + " created for Contractor with ID " + contractor.getId());
            return "index";
        }
    }

现在可以使用Thymeleaf模板:它是基于<ul>的{​​{1}},因此在这里我将为您提供有趣的片段以提高可读性:

<form>

现在,当我尝试向<li id="items"> <fieldset> <div th:each="task, rowStat : ${invoicedata.invoiceTasks}"> <input th:field="${invoicedata.invoiceTasks[__${rowStat.index}__].taskName}" placeholder="Nazwa zadania" required> <input th:field="${invoicedata.invoiceTasks[__${rowStat.index}__].project}" placeholder="Projekt" required> <input type="number" th:field="${invoicedata.invoiceTasks[__${rowStat.index}__].hoursCount}" placeholder="Liczba godzin" required> <button type="button" name="removeItem" th:value="${rowStat.index}">Remove task</button> </div> </fieldset> <button type="button" name="addItem">Add task</button> <script type="text/javascript"> function replaceItems (html) { // Replace the <fieldset id="items"> with a new one returned by server. $('#items').replaceWith($(html)); } $('button[name="addItem"]').click(function (event) { event.preventDefault(); var data = $('form').serialize(); // Add parameter "addItem" to POSTed form data. Button's name and value is // POSTed only when clicked. Since "event.preventDefault();" prevents from // actual clicking the button, following line will add parameter to form // data. data += '&addItem'; $.post('/add', data, replaceItems); }); $('button[name="removeItem"]').click(function (event) { event.preventDefault(); var data = $('form').serialize(); // Add parameter and index of item that is going to be removed. data += '&removeItem=' + $(this).val(); $.post('/add', data, replaceItems); }); </script> </li> <li> <input type="submit" value="Save protocol" /> </li> </ul> 添加这样的内容时:

<fieldset>

只是为了证明列表不为空,我什么也没有得到,也没有消息,并且得到这样的错误:

  

java.lang.IllegalStateException:既不绑定结果也不简单   可根据请求提供bean名称“ invoiceTasks”的目标对象   属性

更有趣的是,JavaScript停止正常运行。 “删除任务”按钮仍然可以正常工作,但是“添加任务”按钮完全停止工作...

尝试

<span class="error" th:if="${#fields.hasErrors('invoiceTasks')}" th:errors="*{invoiceTasks}">Generic error</span>

得到我:

<span class="error" th:if="${#fields.hasErrors('invoicedata.invoiceTasks')}" th:errors="*{invoicedata.invoiceTasks}">Generic error</span>

There was an unexpected error (type=Internal Server Error, status=500).
Exception evaluating SpringEL expression: "#fields.hasErrors('invoicedata.invoiceTasks')" (template: "add" - line 60, col 49)

是的,我还没有设置/ error页面。

所有其他验证器运行正常。

目标是能够验证org.springframework.beans.NotReadablePropertyException: Invalid property 'invoicedata' of bean class [com.look4app.generator.entity.InvoiceData]: Bean property 'invoicedata' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? 对象内的3个字段,并验证InvoiceTask列表,使其不为空。

是否有可能实现这一目标?

0 个答案:

没有答案