java - 两个对象的 Spring 表单验证

标签 java spring validation thymeleaf

有一个 Spring Boot 应用程序的复杂问题,我已经尝试解决了一段时间,我希望有人能帮助我。我已经删除了项目的所有其他部分,并试图使其尽可能简单。如果您转到 localhost:8080,将会出现一个带有两个文本框(用于输入两个名称)和一个提交按钮的表单。第一个姓名将存储在 Nominee 对象中,第二个姓名将存储在 Submitter 对象中。当您单击提交时,它将对字段执行验证以确保它们都不为空。我将在下面发布代码并在最后解释我的问题。

应用程序.java

@SpringBootApplication
@EnableJms
@EnableWebMvc
public class Application {

    public static void main(String[] args) throws Exception {
        // Launch the application
        SpringApplication.run(Application.class, args);
    }
}

WebController.java

@Controller
public class WebController extends WebMvcConfigurerAdapter {
    protected static final Logger LOG = LoggerFactory.getLogger(WebController.class);

    @InitBinder("nominee")
    protected void initNomineeBinder(WebDataBinder binder) {
        binder.setValidator(new NomineeValidator());
    }

    @InitBinder("submitter")
    protected void initSubmitterBinder(WebDataBinder binder) {
        binder.setValidator(new SubmitterValidator());
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/success").setViewName("success");
    }

    @RequestMapping(value="/", method=RequestMethod.GET)
    public String showForm(Model model) {
        model.addAttribute("nominee", new Nominee());
        model.addAttribute("submitter", new Submitter());
        return "form";
    }

    @RequestMapping(value="/", method=RequestMethod.POST)
    public String checkPersonInfo(@ModelAttribute(value="nominee") @Valid Nominee nominee,
                                  @ModelAttribute(value="submitter") @Valid Submitter submitter,
                                  BindingResult bindingResult, @Valid Model model) {
        LOG.info("Nominee to string: " + nominee.toString());
        LOG.info("Submitter to string: " + submitter.toString());
        LOG.info("bindingResult to string: " + bindingResult.toString());
        if (bindingResult.hasErrors()) {
            return "form";
        }

        return "redirect:/success";
    }
}

Nominee.java

import lombok.Data;

@Data
public class Nominee {
    private String name;
}

NomineeValidatior.java

public class NomineeValidator implements Validator {

    public boolean supports(Class clazz) {
        return Nominee.class.equals(clazz);
    }

    public void validate(Object object, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "name", "name", "This field is empty.");
    }
}

Submitter.java

import lombok.Data;

@Data
public class Submitter {
    private String sname;
}

SubmitterValidator.java

public class SubmitterValidator implements Validator {

    public boolean supports(Class clazz) {
        return Submitter.class.equals(clazz);
    }

    public void validate(Object object, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "sname", "sname", "This field is empty.");
    }
}

form.html

<html>
<body>
<form role="form" th:action="@{/}" method="post">
    <h2>Nominee details</h2>
    <table>
        <tr>
            <td>Name:</td>
            <td>
                <input type="text" th:field="${nominee.name}"/>
            </td>
            <td><p th:if="${#fields.hasErrors('nominee.name')}" th:errors="${nominee.name}">Empty field</p></td>
        </tr>
    </table>
    <h2>Your details</h2>
    <table>
        <tr>
            <td>Your name:</td>
            <td>
                <input type="text" th:field="${submitter.sname}"/>
            </td>
            <td><p th:if="${#fields.hasErrors('submitter.sname')}" th:errors="${submitter.sname}">Empty field</p></td>
        </tr>
    </table>
    <div>
        <button type="submit">Submit nomination</button>
    </div>
</form>
</body>
</html>

成功.html

<html><body>Form successfully submitted.</body></html>

如果我将第一个文本字段留空(并填写或不填写第二个文本字段),屏幕上会显示一条错误消息:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback. Tue May 12 13:10:17 AEST 2015 There was an unexpected error (type=Bad Request, status=400). Validation failed for object='nominee'. Error count: 1

我不知道如何修复它,以便将第一个文本框留空不会导致白色标签错误页面。如果我将第二个文本字段留空但填写第一个文本字段,它的行为完全正常,所以我不确定如果我以相反的方式尝试它为什么会导致错误。非常感谢任何解决此问题的帮助。

此外,您可能已经注意到我必须在 Nominee 和 Submitter 中使用 'name' 和 'sname' 作为我的变量,如果我将它们都设置为 'name' 那么它就不能正常工作。如果有任何方法可以编辑它以便他们都可以使用“名称”,我很想知道如何做。

编辑:找到解决方案。在 WebController 中,checkPersonInfo 需要为每个被验证的对象提供一个单独的 BindingResult。 BindingResult 需要紧跟在每个 @Valid 对象之后的方法参数中。

因此,在 WebController.java 中,这是:

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@ModelAttribute(value="nominee") @Valid Nominee nominee,
                              @ModelAttribute(value="submitter") @Valid Submitter submitter,
                              BindingResult bindingResult, @Valid Model model) {
    LOG.info("Nominee to string: " + nominee.toString());
    LOG.info("Submitter to string: " + submitter.toString());
    LOG.info("bindingResult to string: " + bindingResult.toString());
    if (bindingResult.hasErrors()) {
        return "form";
    }

    return "redirect:/success";
}

需要变成这样:

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@ModelAttribute(value="nominee") @Valid Nominee nominee,
                              BindingResult bindingResultNominee,
                              @ModelAttribute(value="submitter") @Valid Submitter submitter,
                              BindingResult bindingResultSubmitter) {
    LOG.info("Nominee to string: " + nominee.toString());
    LOG.info("Submitter to string: " + submitter.toString());
    if (bindingResultNominee.hasErrors() || bindingResultSubmitter.hasErrors()) {
        return "form";
    }

    return "redirect:/success";
}

(模型对象已被删除,因为它实际上从未在任何地方使用过,如果您需要使用 @Valid 验证它,那么您将添加第三个 BindingResult 对象。)

最佳答案

找到解决方案。在 WebController 中,checkPersonInfo 需要为每个被验证的对象提供一个单独的 BindingResult。 BindingResult 需要紧跟在每个 @Valid 对象之后的方法参数中。

因此,在 WebController.java 中,这是:

    @RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@ModelAttribute(value="nominee") @Valid Nominee nominee,
                              @ModelAttribute(value="submitter") @Valid Submitter submitter,
                              BindingResult bindingResult, @Valid Model model) {
    LOG.info("Nominee to string: " + nominee.toString());
    LOG.info("Submitter to string: " + submitter.toString());
    LOG.info("bindingResult to string: " + bindingResult.toString());
    if (bindingResult.hasErrors()) {
        return "form";
    }

    return "redirect:/success";
}

需要变成这样:

    @RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@ModelAttribute(value="nominee") @Valid Nominee nominee,
                              BindingResult bindingResultNominee,
                              @ModelAttribute(value="submitter") @Valid Submitter submitter,
                              BindingResult bindingResultSubmitter) {
    LOG.info("Nominee to string: " + nominee.toString());
    LOG.info("Submitter to string: " + submitter.toString());
    if (bindingResultNominee.hasErrors() || bindingResultSubmitter.hasErrors()) {
        return "form";
    }

    return "redirect:/success";
}

(模型对象已被删除,因为它实际上从未在任何地方使用过,如果您需要使用 @Valid 验证它,那么您将添加第三个 BindingResult 对象。)

关于java - 两个对象的 Spring 表单验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30181245/

相关文章:

java - 在 spring security 中使用 session id 检索身份验证对象

Java Component.show()/hide() 已弃用……为什么?

java - jpa 和 struts 项目中持久性提供程序的问题

mysql - 如何使用 Java 和 spring/hibernate 在我的数据库中正确插入日期(在我的数据库中得到错误的时间)?

java - 如何在 Spring 中正确关闭 ApplicationContext?

java - Spring通过子类的方法名来声明事务语义

java - 如何在 Java 中等待线程完成后再开始更多操作

javascript - 使用 Backbone 验证表单

spring - 我应该在哪一侧验证表单数据,客户端还是服务器端?

java - 如何检查给定数字中是否存在有效的组分隔符?