Appearance
SpringMVC中不常用注解使用
@InitBinder
在参数绑定时进行可以针对复杂对象自定义参数绑定逻辑,比如:
java
@GetMapping("/testInitBinder")
public String testInitBinder(Date date){
return date.toString();
}此时如果访问:http://localhost:8080/tuling-web/app/testInitBinder?date=1111-1-1,会报错:
java
Failed to convert value of type 'java.lang.String' to required type 'java.util.Date';
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [java.util.Date] for value '1111-1-1';
nested exception is java.lang.IllegalArgumentException]此时可以在当前Controller中添加:
java
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}有了这个就相当于添加了一个自定义的日期格式转换器,这样就能正常访问了。
注意,如果我们想把String类型转成我们自定义的User类,那么在User类中得提供一个String类型的构造方法
关键类为:ObjectToObjectConverter、TypeConverterDelegate:
- 在处理请求时,在调用方法之前,会把方法参数类型作为target类型,String类型作为source类型
- 会先匹配到ObjectToObjectConverter,除非你自定定义了一个String类型->target类型的Converter
- 在ObjectToObjectConverter中会需要target类型中有一个String参数的构造方法才算匹配到,不然ObjectToObjectConverter都不给你匹配,就不能完成转换了
- 匹配到ObjectToObjectConverter后,会先调用TypeConverterDelegate的convertIfNecessary()方法
- 在这个方法中就会找到我们注册的CustomEditor,并且利用它把String类型转成target类型
在Controller中定义的InitBinder只会在本Controller中生效,我们可以通过ControllerAdvice来定义一个全局的:
java
@ControllerAdvice
public class ZhouyuControllerAdvice {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
}@SessionAttributes
只能写在类上,通过@SessionAttributes注解指定model中哪些key的value存到session中。
java
@RestController
@SessionAttributes(names = {"user"})
public class ZhouyuController {
@GetMapping("/test")
public String test(Model model) {
model.addAttribute("user", "xxxx");
return null;
}
@GetMapping("/testSession")
public String testSession(HttpServletRequest httpServletRequest){
Object user = httpServletRequest.getSession().getAttribute("user");
return (String) user;
}
}@RequestAttribute 与 @SessionAttribute
都只能写在方法参数前面,表示从相对应request.getAttribute()、session.getAttribute()中获取值传递给方法参数
@ModelAttribute
可以写在某个方法上,@ModelAttribute可以定义在一个Controller中,当请求这个Controller中的方法时,会先调用@ModelAttribute所修饰的方法,方法返回的值会添加到model中,比如以下代码就会向model中添加一个key为user,values为请求中user参数所传递的值。
在访问以下两个GetMapping时,都会先执行addString方法,向model中添加值,有点类似切面的作用了。
java
@ModelAttribute("user")
public String addString(@RequestParam("user") String value){
return value;
}
@GetMapping("/testModelAttribute")
public String testModelAttribute(Model model){
return (String) model.getAttribute("user");
}
@GetMapping("/testModelAttributev2")
public String testModelAttributeV2(Model model){
return (String) model.getAttribute("user");
}我们同样可以定义在ControllerAdvice中,从而变成全局的:
java
@ControllerAdvice
public class ZhouyuControllerAdvice {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(User.class, new UserEditor());
}
@ModelAttribute("user")
public String addString(@RequestParam("user") String value){
return value;
}
}也可以写在方法参数前,会将model中的参数值传递给方法参数,或者model中如果没有则会从request.getParameter()中获取对应的值设置给model
更新: 2022-12-11 16:30:14
原文: https://www.yuque.com/renyong-jmovm/spring/lezs4zrkv4sadn15