spring中的@InitBinder注解使用
一、概述
@InitBinder
用于在控制器(Controller)
中标注于方法上,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。@InitBinder
标注的方法必须有一个参数WebDataBinder
。webDataBinder是用于表单到方法的数据绑定的。所谓的属性编辑器可以理解就是帮助我们完成参数绑定。
@InitBinder只在@Controller中注解方法来为这个控制器注册一个绑定器初始化方法,方法只对本控制器有效。
二、实例解析
1、对数据绑定进行设置
WebDataBinder中有很多方法可以对数据绑定进行具体的设置:比如我们设置name属性为非绑定属性(也可以设置绑定值setAllowedFields):
在Controller中添加一个方法:
@InitBinder public void initBinder(WebDataBinder binder) { binder.setDisallowedFields("name"); }
然后运行:
添加:
看后面那个name值就没有绑定成功!
该使用场景应该并不多,大家可以灵活运用。
2、注册已有封装好的编辑器
WebDataBinder是用来绑定请求参数到指定的属性编辑器。由于前台传到controller里的值是String类型的,当往Model里Set这个值的时候,如果set的这个属性是个对象,Spring就会去找到对应的editor进行转换,然后再set进去!Spring自己提供了大量的实现类(如下图所示的在org.springframwork.beans.propertyEditors下的所有editor),诸如CustomDateEditor ,CustomBooleanEditor,CustomNumberEditor等许多,基本上够用。 在平时使用SpringMVC时,会碰到javabean中有Date类型参数,表单中传来代表日期的字符串转化为日期类型,SpringMVC默认不支持这种类型的转换。我们就需要手动设置时间格式并在webDateBinder上注册这个编辑器!
@ResponseBody @RequestMapping(value = "/test") public String test(@RequestParam String name,@RequestParam Date date) throws Exception { System.out.println(name); System.out.println(date); return name; } @InitBinder public void initBinder(WebDataBinder binder){ binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false)); }
上面例子中,@InitBinder
方法会帮助我们把String类型的参数先trim再绑定,而对于Date类型的参数会先格式化在绑定。例如当请求是/test?name=%20zero%20&date=2018-05-22
时,会把zero绑定到name,再把时间串格式化为Date类型,再绑定到date。
这里的@InitBinder
方法只对当前Controller生效,要想全局生效,可以使用@ControllerAdvice
。通过@ControllerAdvice
可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice
的类的方法可以使用@ExceptionHandler
,@InitBinder
,@ModelAttribute
注解到方法上,这对所有注解了@RequestMapping
的控制器内的方法有效。
@ControllerAdvice public class GlobalControllerAdvice { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false)); } }
除了使用@ControllerAdvice
来配置全局的WebDataBinder
,还可以使用RequestMappingHandlerAdapter
:
@Bean public RequestMappingHandlerAdapter webBindingInitializer() { RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter(); adapter.setWebBindingInitializer(new WebBindingInitializer(){ @Override public void initBinder(WebDataBinder binder, WebRequest request) { binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false)); } }); return adapter; }
如上示例,可以实现同样的效果。或者你写个BaseController,让其他controller继承该类。
@ControllerAdvice
中除了配置@InitBinder
,还可以有@ExceptionHandler
用于全局处理控制器里面的异常;@ModelAttribute
作用是绑定键值对到Model里,让全局的@RequestMapping
都能获得在此处设置的键值对。
补充:如果 @ExceptionHandler
注解中未声明要处理的异常类型,则默认为方法参数列表中的异常类型。示例:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody String handleException(Exception e){ return "Exception Deal! " + e.getMessage(); } }
3、注册自定义编辑器
使用自定义编辑器就是在第二个的基础上添加个自定义编辑器就行了,自定义的编辑器类需要继承
org.springframework.beans.propertyeditors.PropertiesEditor;
并重写其setAsText和getAsText两个方法就行了!
比如下面这个DoubleEditor:
public class DoubleEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Double.parseDouble(text)); } @Override public String getAsText() { return getValue().toString(); } }
然后在InitBinder方法中注册就行。
这里提供给大家一个Demo
public class BaseController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Date.class, new MyDateEditor()); binder.registerCustomEditor(Double.class, new DoubleEditor()); binder.registerCustomEditor(Integer.class, new IntegerEditor()); } private class MyDateEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = null; try { date = format.parse(text); } catch (ParseException e) { format = new SimpleDateFormat("yyyy-MM-dd"); try { date = format.parse(text); } catch (ParseException e1) { } } setValue(date); } } public class DoubleEditor extends PropertiesEditor { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Double.parseDouble(text)); } @Override public String getAsText() { return getValue().toString(); } } public class IntegerEditor extends PropertiesEditor { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Integer.parseInt(text)); } @Override public String getAsText() { return getValue().toString(); } } }
4、利用@InitBinder实现表单多对象传递小技巧
@InitBinder("user") public void init1(WebDataBinder binder) { binder.setFieldDefaultPrefix("u."); } @InitBinder("stu") public void init2(WebDataBinder binder) { binder.setFieldDefaultPrefix("s."); } @RequestMapping("/testBean") public ModelAndView testBean(User user, @ModelAttribute("stu") Student stu) { System.out.println(stu); System.out.println(user); String viewName = "success"; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("user", user); modelAndView.addObject("student", stu); return modelAndView; }
@InitBinder("user")
括号内的参数为类的首字母小写(默认命名规则),也可以用@ModelAttribute("stu")
做限定。
文章整理自:
https://blog.csdn.net/qq_38016931/article/details/82080940
https://www.cnblogs.com/heyonggang/p/6186633.html