掌握SpringMVC中@InitBinder的实际应用
作者:一户董
1: 注册属性编辑器
我们在接收参数的时候,对于基础的数据类型,比如接收string,int等类型,springmvc是可以直接处理的,但是对于其他复杂的对象类型,有时候是无法处理的,这时候就需要属性编辑器来进行处理(源数据为string),过程一般就是 String->属性编辑器->目标类型 。spring为我们提供了一些默认的属性编辑器,如 org.springframework.beans.propertyeditors.CustomDateEditor 就是其中一个,我们也可以通过继承 java.beans.PropertyEditorSuppotr 来根据具体的业务来定义自己的属性编辑器。
1.1: 使用系统默认提供的属性编辑器
- 定义controller并使用@InitBinder注册属性编辑器
这里注册的属性编辑器为 org.springframework.beans.propertybeans.CustomDateEditor ,作用是根据提供的 java.text.SimpleDateFormat 将输入的字符串数据转换为 java.util.Date 类型的数据,核心源码如下:
org.springframework.beans.propertyeditors.CustomDateEditor#setAsText public void setAsText(@Nullable String text) throws IllegalArgumentException { ... else { try { // 使用用户提供的java.text.SimpeDateFormat来将目标字符串格式化为java.util.Date类型,并通过SetValue方法设置最终值 setValue(this.dateFormat.parse(text)); } ... } }
接下来定义类:
@RequestMapping("/myInitBinder0954") @Controller public class MyInitBinderController { /* 注册将字符串转换为Date的属性编辑器,该编辑器仅仅对当前controller有效 */ @InitBinder public void initBinderXXX(WebDataBinder binder) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); CustomDateEditor dateEditor = new CustomDateEditor(df, true); binder.registerCustomEditor(Date.class, dateEditor); } // http://localhost:8080/myInitBinder0954/test?date=2020-09-03%2010:17:17会使用在 // dongshi.controller.initbinder.MyInitBinderController.initBinderXXX注册的属性编辑器转换为, // Date类型的 @RequestMapping(value = "/test", method = RequestMethod.GET) @ResponseBody public String testFormatData(Date date) { Map<String, Object> map = new HashMap<>(); map.put("date", date); return map.toString(); } }
访问测试
看到返回了Date的toString的结果,就是说明成功了。
1.2: 使用自定义的属性编辑器
假设我们的需求是这样的,调用方传过来的值是一个 _ 竖线分割的字符串,但是处理的过程使用的是通过 _ 号分割得到的一个 String[] ,我们当然可以在接口内部去处理,但是我们作为 专业的屌丝程序员,哈哈哈 ,还是要用专业一些的手段,这里就可以定义一个 将竖线分割的多个字符串转换为String[] 的自定义属性编辑器来实现。
- 自定义属性编辑器
通过继承 java.beans.PropertyEditorSupport 类并重写其 setAdText(String text) 方法完成,最后调用 setValue(Object Value) 方法完成转换后的值的设置。
public class StringToListPropertyEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { String[] resultArr = null; if (!StringUtils.isEmpty(text)) { resultArr = text.split("_"); } setValue(resultArr); } }
使用
@RequestMapping("/myStringToList") @Controller public class StringToListController { @InitBinder public void myStringToListBinder(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(String[].class, new StringToListPropertyEditor()); } @RequestMapping(value = "/test", method = RequestMethod.GET) @ResponseBody public String myStringToListTest(String[] strToListArr, HttpServletResponse response) { response.setCharacterEncoding("UTF-8"); String result = "_分割字符串转String[]不成功!"; if (strToListArr != null && strToListArr.length > 0) { result = Arrays.asList(strToListArr).toString(); } return result; } }
访问测试
2: 处理带有前缀的form字段
比如这样的场景,在People,Address两个类中都有name字段,但是我们需要在一个表单中录入People和Address的信息,然后在接口中直接通过People,Address两个对象来接收页面的表单数据,但是 两个name 是无法区分的,一般的做法就是指定一个前缀,然后通过@InitBinder通过调用 org.springframework.web.bind.WebDataBinder 的 setFieldDefaultPrefix(@Nullable String fieldDefaultPrefix) 方法,然后在接口中使用注解 public @interface ModelAttribute 设置要接收的参数的前缀,就可以区分并接收对应的参数了。
2.1: 定义用到的实体
Person
public class People { private String name; private String age; // getter setter toString }
Address
public class Address { private String name; private String city; // getter setter toString }
2.2: 定义测试使用的表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> <form action="${pageContext.request.contextPath}/myInitBinder0954/test0942" method="post" enctype="multipart/form-data"> <input type="text" name="people.name" placeholder="人名"><br><br> <input type="text" name="people.age" placeholder="人年龄"><br><br> <input type="text" name="address.name" placeholder="地址名称"><br><br> <input type="text" name="address.city" placeholder="地址所在城市"><br><br> <input type="submit" value="提交"/> </form> </body> </html>
2.3: 定义接口
@RequestMapping("/myInitBinder0954") @Controller public class MyInitBinderController { @InitBinder(value = "people") public void initBinderSetDefaultPreifixPeople(WebDataBinder dataBinder) { dataBinder.setFieldDefaultPrefix("people."); } @InitBinder(value = "address") public void initBinderSetDefaultPreifixAddress(WebDataBinder dataBinder) { dataBinder.setFieldDefaultPrefix("address."); } @RequestMapping(value = "/test0942", method = RequestMethod.POST) @ResponseBody public String test0942(@ModelAttribute("people") People people, @ModelAttribute("address") Address address) { StringBuffer sb = new StringBuffer(); sb.append(people.toString()); sb.append("---"); sb.append(address.toString()); return sb.toString(); } }
2.4: 访问测试 录入表带数据
访问返回结果
3:注册校验器
3.1:定义测试实体
package dongshi.controller.initbinder; public class User { private String userName; // getter setter toString }
3.2:自定义校验器
直接实现 org.springframework.validation.Validator ,该接口只有两个方法,一个是校验是否支持校验的 support(Class<?> clazz) 方法,一个是进行具体校验的 validate(Object target, Errors errors) 方法,源码如下:
public interface Validator { boolean supports(Class<?> clazz); void validate(Object target, Errors errors); }
定义一个校验器:
@Component public class UserValidator implements Validator { @Override public boolean supports(Class<?> clazz) { // 只支持User类型对象的校验 return User.class.equals(clazz); } @Override public void validate(Object target, Errors errors) { User user = (User) target; String userName = user.getUserName(); if (StringUtils.isEmpty(userName) || userName.length() < 8) { errors.rejectValue("userName", "valid.userNameLen", new Object[] { "minLength", 8 }, "用户名不能少于{1}位"); } } }
该校验器校验用户录入的userName长度是否大于8,并给出响应的错误信息,错误信息直接设置到errors中,最终会设置到 org.springframework.validation.BindingReuslt ,在接口中直接定义该对象则会自动注入对象值,从而可以获取到对应的错误信息。
3.3:定义控制器
@Controller @RequestMapping("/valid") public class ValidatorController { @Autowired private UserValidator userValidator; @InitBinder private void initBinder(WebDataBinder binder) { binder.addValidators(userValidator); } @RequestMapping(value = { "/index", "" }, method = { RequestMethod.GET }) public String index(ModelMap m) throws Exception { m.addAttribute("user", new User()); return "initbinder/user.jsp"; } @RequestMapping(value = { "/signup" }, method = { RequestMethod.POST }) public String signup(@Validated User user, BindingResult br, RedirectAttributes ra) throws Exception { // 携带用户录入的信息方便回显 ra.addFlashAttribute("user", user); return "initbinder/user.jsp"; } }
3.4:定义user.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>validate user</title> </head> <body> <form:form modelAttribute="user" action="/valid/signup" method="post"> <!-- 显示所有的错误信息 --> <form:errors path="*"></form:errors> 用户名:<form:input path="userName"/><form:errors path="userName"/> </form:form> </body> </html>
3.5:访问user.jsp
录入一个不合法的字符,并回车:
到此这篇关于掌握SpringMVC中@InitBinder的实际应用的文章就介绍到这了,更多相关SpringMVC中@InitBinder内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!