简体   繁体   English

如何将通用对象发布到Spring控制器?

[英]How to post generic objects to a Spring controller?

I want to create a website that displays a form. 我想创建一个显示表单的网站。 The fields of the form depend on a request parameter (and also the form backing bean). 表单的字段取决于请求参数(以及表单支持bean)。 This is my controller that renders the different forms: 这是我的控制器,呈现不同的形式:

@Controller
public class TestController {

    @Autowired
    private MyBeanRegistry registry;

    @RequestMapping("/add/{name}")
    public String showForm(@PathVariable String name, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("bean", registry.lookup(name));

        return "add";
    }

}

The corresponding view looks like this: 相应的视图如下所示:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
    <form method="post" th:action="@{|/add/${name}|}" th:object="${bean}">
        <th:block th:replace="|${name}::fields|"></th:block>
        <button type="submit">Submit</button>
    </form>
</body>
</html>

Following is an example fragment that displays the form fields: 以下是显示表单字段的示例片段:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
    <th:block th:fragment="fields">
        <label for="firstName">First name</label><br />
        <input type="text" id="firstName" th:field="*{firstName}" /><br />
        <label for="lastName">Last name</label><br />
        <input type="text" id="lastName" th:field="*{lastName}" />
    </th:block>
</body>
</html>

The looked up bean would be like this: 查找的bean将如下所示:

public class MyExampleBean {

    private String firstName;

    private String lastName;

    // Getters & setters

}

The form is rendered correctly, but how can I receive the form back in the controller? 表单呈现正确,但是如何才能在控制器中重新收到表单? And how can I validate the submitted bean? 我如何验证提交的bean? I tried the following method, but obviously it can not work: 我尝试了以下方法,但显然无法正常工作:

@RequestMapping(value = "/add/{name}", method = RequestMethod.POST)
public String processForm(@PathVariable String name, @Valid Object bean) {
    System.out.println(bean);

    return "redirect:/add/" + name;
}

Spring creates a new instance of Object but the submitted values are lost. Spring创建了Object的新实例,但是提交的值丢失了。 So how can I accomplish this task? 那么我该如何完成这项任务呢?

If you only wanted to deal with a limited number of beans, you could have one @RequestMapping method for each bean, all delegating to a private method that would do the job . 如果您只想处理有限数量的Bean,则可以为每个Bean使用一个@RequestMapping方法,所有方法都委派给可以完成此工作的私有方法。 You can find an example here . 您可以在此处找到示例。

If you want to be able to accept bean dynamically, you will have to do by hand what Spring does automagically : 如果您希望能够动态接受bean,则必须手动执行 Spring自动执行的操作:

  • only use the request and not a model attribute 仅使用请求,而不使用模型属性
  • find the bean in registry by the PathVariable name 通过PathVariable名称在注册表中找到bean
  • do explicitely the binding 明确地进行绑定

But hopefully Spring offers the subclasses of WebDataBinder as helpers : 但是希望Spring提供WebDataBinder的子类作为助手:

@RequestMapping(value = "/add/{name}", method = RequestMethod.POST)
public String processForm(@PathVariable String name, WebRequest request) {
    //System.out.println(bean);

    Object myBean = registry.lookup(name);
    WebRequestDataBinder binder = new WebRequestDataBinder(myBean);
    // optionnaly configure the binder
    ...
    // trigger actual binding of request parameters
    binder.bind(request);
    // optionally validate
    binder.validate();
    // process binding results
    BindingResult result = binder.getBindingResult();
    ...

    return "redirect:/add/" + name;
}

As for validation i don't know, but for retrieving the values, you could try the below 至于验证我不知道,但是要获取值,您可以尝试以下操作

(WARNING: i didn't try this code, as i couldn't at the time of writing). (警告:我没有尝试这段代码,因为在撰写本文时无法这样做)。

Change the processForm handler to handle HttpServletRequest insead of type Object , and get the sumbitted values from the paramters map, example : 更改processForm处理程序以处理类型为Object HttpServletRequest insead,并从paramters映射中获取汇总值,例如:

@RequestMapping(value="/add/{name}", method=RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String processForm(@PathVariable String name, HttpServletRequest request) {
    Map<String, String[]> parameterMap = request.getParameterMap();
    ...
}

You should make two changes to your code, 您应该对代码进行两项更改,

  1. Annotate your TestController with @SessionAttributes("bean") it will keep your model attribute with the name bean stored in the session @SessionAttributes("bean")注释您的TestController ,它将使用存储在会话中的名称bean保留模型属性

  2. Add @ModelAttribute("bean") to your processForm method, so processForm(@PathVariable String name, @Valid @ModelAttribute("bean") Object bean) . @ModelAttribute("bean")添加到您的processForm方法中,以便添加processForm(@PathVariable String name, @Valid @ModelAttribute("bean") Object bean) As the model attribute bean is registered as session attribute as well it will retrieve it from session, and will keep the values 由于模型属性bean也注册为会话属性,因此它将从会话中检索它,并保留值

If your processForm method is residing in a different controller, make sure to annotate that controller with @SessionAttributes("bean") as well 如果您的processForm方法位于其他控制器中,请确保也使用@SessionAttributes("bean")注释该控制器。

The following should be an example of the working controller 以下应为工作控制器的示例

@SessionAttributes("bean")
@Controller
public class TestController {

    @Autowired
    private MyBeanRegistry registry;

    @RequestMapping("/add/{name}")
    public String showForm(@PathVariable String name, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("bean", registry.lookup(name));

        return "add";
    }

    @RequestMapping(value = "/add/{name}", method = RequestMethod.POST)
    public String processForm(@PathVariable String name, @Valid @ModelAttribute("bean") Object bean) {
       System.out.println(bean);
       return "redirect:/add/" + name;
   }
}

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

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