我们知道无论是 Get 请求还是 Post 请求,Controller 这边都可以定义一个实体类来接收这些参数。而 @ControllerAdvice 结合 @InitBinder 还能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理。
三、请求参数预处理(搭配 @InitBinder)
1,问题描述
(1)假设我们有如下两个实体类 User 和 Book:
public class User { private String name; private Integer age; // 省略getter/setter } public class Book { private String name; private Float price; // 省略getter/setter }
(2)如果在 Contoller 上需要接收两个实体类的数据,接收方法可以这么定义:
package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(User user, Book book) { return "name:" + user.getName() + " | age:" + user.getAge() + "<br>" + "name:" + book.getName() + " | price:" + book.getPrice(); } }
(3)但由于两个实体类中都有 name 属性,那么参数传递时就会发生混淆。
2、解决办法
(1)使用 @ControllerAdvice 结合 @InitBinder 即可解决上面的问题,这里我们创建一个全局的参数预处理配置。
代码说明:
- 第一个 @InitBinder("user") 表示该方法是处理 Controller 中 @ModelAttribute("user") 对应的参数。
- 第二个 @InitBinder("book") 表示该方法是处理 Controller 中 @ModelAttribute("book") 对应的参数。
- 这两个方法中给相应的 Filed 设置一个前缀。
补充说明:在 WebDataBinder 对象中,除了可以设置前缀,还可以设置允许、禁止的字段、必填字段以及验证器等等。
package com.example.demo; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.InitBinder; @ControllerAdvice public class GlobalConfig { @InitBinder("user") public void init1(WebDataBinder binder) { binder.setFieldDefaultPrefix("user."); } @InitBinder("book") public void init2(WebDataBinder binder) { binder.setFieldDefaultPrefix("book."); } }
(2)然后 Controller 中方法的参数添加 @ModelAttribute 注解:
package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(@ModelAttribute("user") User user, @ModelAttribute("book") Book book) { return "name:" + user.getName() + " | age:" + user.getAge() + "<br>" + "name:" + book.getName() + " | price:" + book.getPrice(); } }
(3)最后浏览器请求参数中添加相应的前缀,即可成功区分出 name 属性:
当然也可以在 Cotroller 里面使用 @InitBinder 来单独定义预处理方法,具体参考我写的另一篇文章: