1、转换器的概述
实际上在SpringMVC框架中,框架本身就内置了很多类型转换器,这些默认的类型转换器,可以将String类型的数据,自动转换为相应类型的数据。比如在前面的各种演示案例中,表单提交的无论是int还是double类型的请求参数,通过默认转换器均可直接接收到相应类型的相应数据,而非接收到String再手动转换,都是会自动帮你转换。这些默认的转换器就在包 org.springframework.core.convert.converter 下,如图所示:
但是有的时候内置的类型转换器不足够满足业务需求,因为默认转换器并不是可以将用户提交的String转换为所有用户需要的类型。此时,就需要自定义类型转换器了。例如,在Spring MVC的默认类型转换器中,没有日期类型的转换器,因为日期的格式太多。若要使表单中提交的日期字符串,被处理器方法形参直接接收为日期类型,则需要自定义类型转换器了,否则肯定会报错。下面就来学习一下怎么操作的。
2、实现Converter接口
依旧使用前面的提交Book举例,首先创建一个实现Converter接口的DateConverter实现类,代码如下:
package com.thr.convert;
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* 自定义转换器
*/
//@Component
public class DateConverter implements Converter<String, LocalDate> {
//Java8 的日期格式化器
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd");
public LocalDate convert(String source) {
// 根据格式化器将String类型解析为LocalDate类型
return LocalDate.parse(source, formatter);
}
}
上面是在自定义的参数类型转换器中,将一个前台传来的 String 转为 LocalDate 对象。
然后我们在Book类添加一个日期类型的属性,用来表示图书的出版日期,Book实体类代码如下:
public class Book {
//书的ID
private Integer id;
//书名
private String name;
//出版社
private String publisher;
//图书出版日期
private LocalDate publishDate;
//getter,setter和toString省略
}
接下来,在 SpringMVC 的配置文件(spring-mvc.xml)中配置相关的 Bean使之生效。
<!-- 注册自定义转换器 -->
<bean id="dateConverter" class="com.thr.convert.DateConverter"/>
<!-- 注册类型转换服务bean -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
</bean>
<!-- 配置MVC注解驱动。-->
<mvc:annotation-driven conversion-service="conversionService"/>
创建用于提交图书信息的index.jsp页面,具体代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/book" method="post">
<table>
<tr>
<td>图书ID:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>图书名称:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>出版社:</td>
<td><input type="text" name="publishingHouse"></td>
</tr>
<tr>
<td>图书出版日期:</td>
<td><input type="date" name="publishDate"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
</body>
</html>
3、使用@InitBinder注解(推荐)
当然也可以不在XML中配置类型转换服务,而是使用@InitBinder注解来实现,推荐这种方式。在需要日期转换的 Controller 中使用 SpringMVC 的注解 @InitBinder 和 Spring 自带的 WebDateBinder 类来操作,WebDataBinder 是用来绑定请求参数到指定的属性编辑器。由于前端传到 Controller 里的值是 String 类型的,当往 Model 里 Set这个值的时候,如果 set 的这个属性是个对象,Spring 就会去找到对应的 editor 进行转换,然后再 SET 进去。注意:@InitBinder用于在@Controller中标注的方法,表示为当前控制器注册一个属性编辑器,只对当前的Controller有效。这个方法会在控制器中其他方法之前调用,这样就可以预先处理数据。
//@Controller:表示一个Controller实例,该实例由Spring容器管理
@Controller
public class BookController {
//添加initBinder注解
@InitBinder
public void initBinder(WebDataBinder binder) {
//注册原类型和目标类型的转换格式
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
System.out.println("-----进入了initBinder()----");
setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
});
}
//配置请求的地址
@RequestMapping(value = "book", method = RequestMethod.POST)
public String getInfo(Book book) {
System.out.println(book.getId());
System.out.println(book.getName());
System.out.println(book.getPublisher());
System.out.println(book.getPublishDate());
//成功后跳转的页面
return "success";
}
}