目前方法执行的核心,无非就是对参数的解析、封装,也就是对HandlerMethodArgumentResolver
的理解。强烈推荐你可以参考 这个系列的所有文章~
有了这些基础理论的支撑,接下来当然就是它的使用Demo Show
了
@InitBinder的使用案例
我抛出两个需求,借助@InitBinder来实现:
- 请求进来的所有字符串都trim一下
- yyyy-MM-dd这种格式的字符串能直接用Date类型接收(不用先用String接收再自己转换,不优雅)
为了实现如上两个需求,我需要先自定义两个属性编辑器:
1、StringTrimmerEditor
public class StringTrimmerEditor extends PropertyEditorSupport { // 将属性对象用一个字符串表示,以便外部的属性编辑器能以可视化的方式显示。缺省返回null,表示该属性不能以字符串表示 //@Override //public String getAsText() { // Object value = getValue(); // return (value != null ? value.toString() : null); //} // 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入 // 处理请求的入参:test就是你传进来的值(并不是super.getValue()哦~) @Override public void setAsText(String text) throws IllegalArgumentException { text = text == null ? text : text.trim(); setValue(text); } }
说明:Spring内置有org.springframework.beans.propertyeditors.StringTrimmerEditor,默认情况下它并没有装配进来,若你有需要可以直接使用它的(此处为了演示,我就用自己的)。Spring内置注册了哪些?参照PropertyEditorRegistrySupport#createDefaultEditors方法
Spring的属性编辑器和传统的用于IDE开发时的属性编辑器不同,它们没有UI界面,仅负责将配置文件中的文本配置值转换为Bean属性的对应值,所以Spring的属性编辑器并非传统意义上的JavaBean属性编辑器。
2、CustomDateEditor
关于这个属性编辑器,你也可以像我一样自己实现。本文就直接使用Spring提供了的,参见:org.springframework.beans.propertyeditors.CustomDateEditor
// @since 28.04.2003 // @see java.util.Date public class CustomDateEditor extends PropertyEditorSupport { ... @Override public void setAsText(@Nullable String text) throws IllegalArgumentException { ... setValue(this.dateFormat.parse(text)); ... } ... @Override public String getAsText() { Date value = (Date) getValue(); return (value != null ? this.dateFormat.format(value) : ""); } }
定义好后,如何使用呢?有两种方式:
- API方式WebBindingInitializer ,关于它的使用,请参阅这里,本文略。1. 重写initBinder注册的属性编辑器是全局的属性编辑器,对所有的Controller都有效(全局的)
- @InitBinder注解方式
在Controller本类上使用@InitBinder,形如这样:
@Controller @RequestMapping public class HelloController { @InitBinder public void initBinder(WebDataBinder binder) { //binder.setDisallowedFields("name"); // 不绑定name属性 binder.registerCustomEditor(String.class, new StringTrimmerEditor()); // 此处使用Spring内置的CustomDateEditor DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); } @ResponseBody @GetMapping("/test/initbinder") public String testInitBinder(String param, Date date) { return param + ":" + date; } }
请求:/test/initbinder?param= ds&date=2019-12-12。结果为:ds:Thu Dec 12 00: 00: 00 CST 2019,符合预期。
注意,若date为null返回值为ds: null(因为我设置了允许为null)
但若你不是yyyy-MM-dd格式,那就抛错喽(格式化异常)
本例的@InitBinder方法只对当前Controller生效。要想全局生效,可以使用@ControllerAdvice/WebBindingInitializer。
通过@ControllerAdvice可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler,@InitBinder,@ModelAttribute等注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效(关于全局的方式本文略,建议各位自己实践~)