1.SpringMvc是什么
Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框 架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
Spring Web MVC也是服务到工作者模式的实现,但进行可优化。前端控制器是DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;页面控制器/动作/处理器为Controller接口(仅包含ModelAndView handleRequest(request, response) 方法)的实现(也可以是任何的POJO类);支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。
2.Spring Web MVC 能干什么
√让我们能非常简单的设计出干净的Web层和薄薄的Web层;
√进行更简洁的Web层的开发;
√天生与Spring框架集成(如IoC容器、AOP等);
√提供强大的约定大于配置的契约式编程支持;
√能简单的进行Web层的单元测试;
√支持灵活的URL到页面控制器的映射;
√非常容易与其他视图技术集成,如Velocity、Thymeleaf、FreeMarker等等,因为模型数据不放在特定的API里,而是放在一个Model里(Map 数据结构实现,因此很容易被其他框架使用);
√非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的API;
√提供一套强大的JSP标签库,简化JSP开发;
√支持灵活的本地化、主题等解析;
√更加简单的异常处理;
√对静态资源的支持;
√支持Restful风格。
3.Spring Web MVC 核心架构
核心架构的具体流程步骤如下:
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个 HandlerInterceptor拦截器)对象,通过这种策略模式,很容 易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
@PathVariable
取得 URL 路径中匹配的内容,适合 RESTful 的风格。
package com.toltech.controller;
/**
* @author Wgs
* @version 1.0
* @create:2018/05/09
* @PathVariable 取得 URL 路径中匹配的内容,适合 RESTful 的风格。
*/
@Controller
public class ParameterController {
// {userId} 是 placeholder,里面的内容可以用 @PathVariable 取到
@RequestMapping("/users/{userId}")
@ResponseBody
public String one(@PathVariable Integer userId) {
return userId + "";
}
// 如果变量名和 {} 中的名字不一样,
// 需要用 @PathVariable("nameInPath") 来指定变量要使用路径中的哪一个变量
@RequestMapping("/categories/{categoryName}/products/{productId}")
@ResponseBody
public String two(@PathVariable String categoryName,
@PathVariable("productId") Integer pId) {
return "categoryName: " + categoryName + ", productId: " + pId;
}
// 还支持正则表达式的方式
@RequestMapping("/regex/{text:[a-z]+}-{number:\\d+}")
@ResponseBody
public String three(@PathVariable String text, @PathVariable Integer number) {
return "Text: " + text + ", Number: " + number;
}
// 路径中有 . 时需要用正则,如http://localhost:8080//ion-i/2.jpg
@GetMapping("/question-img/{subjectCode}/{imageName:.+}")
public void readQuestionImage(@PathVariable String subjectCode, @PathVariable String imageName) {
System.out.println(subjectCode+"----"+imageName);
}
}
测试:
- http://localhost:8080/users/1234
- http://localhost:8080/categories/xbox/products/1234
- http://localhost:8080/regex/part-1234
@RequestParam
取得 HTTP 请求 中的参数(GET 和 POST 都可以)。
package com.toltech.controller;
/**
* @author Wgs
* @version 1.0
* @create:2018/05/09
* @PathVariable 取得 URL 路径中匹配的内容,适合 RESTful 的风格。
*/
@Controller
public class ParameterController {
// 取得名字为 id 的参数的值
@RequestMapping("/user1")
@ResponseBody
public String findUser(@RequestParam Integer id) {
return "ID: " + id;
}
// required 默认是 true,参数是必要的,如果没有提供需要的参数,则报错
// required 为 false 表示参数是可选的
@RequestMapping("/product1")
@ResponseBody
public String findProduct(@RequestParam(value="productId", required=true) Integer id,
@RequestParam(value="productName", required=false) String name) {
return "ID: " + id + ", Name: " + name;
}
}
测试:
- http://localhost:8080/user?id=1234
- http://localhost:8080/product?productId=1234&productName=PS4
@Controller
@RequestMapping("/customer")
public class CustomerController {
@GetMapping
public String list(Model model,
@RequestParam(name = "p",defaultValue = "1") Integer pageNo) {
System.out.println("PageNO: " + pageNo);
model.addAttribute("pageNo",pageNo);
return "customer/list";
}
SpringMVC 数据绑定
SpringMVC 中提供了多种数据绑定,可以把请求中的数据绑定为简单类型,简单数组,对象,对象的数组等。
简单数组
- http://localhost:8080/array?name=Tom&name=Lucy
- URL 中多个同名的参数映射为同一个数组的元素,例如 name
- 数组是 primitive, String 等简单类型的数
@RequestMapping("/array")
@ResponseBody
public String[] array(@RequestParam("name") String[] names) {
return names;
}
@RequestMapping("/list")
@ResponseBody
public List list(@RequestParam("name") List names) {
return names;
}
显示
[“Tom”,”Lucy”]
简单对象
- http://localhost:8080/object?username=Tom&age=10
- URL 中参数名和对象中的属性名一样的会自动映射
- 对 User 进行映射
@RequestMapping("/object")
@ResponseBody
public User object(User user) {
return user;
}
显示
{
"username": "Tom",
"age": 10,
"address": null
}
复杂对象
- http://localhost:8080/object?username=Tom&password=Passw0rd&address.city=Beijing&address.street=SCI
- 可以使用级连映射,URL 的参数名为属性的级连,例如 address.city,映射的是 user 的 address 的 city 属性
@RequestMapping("/nested-object")
@ResponseBody
public User object(User user) {
return user;
}
显示
{
"username": "Tom",
"age": 10,
"address": {
"city": "Beijing",
"street": "SCI"
}
}
同属性多对象
- http://localhost:8080/intersect-object?user.username=Tom&admin.username=Jim&age=10
- User 和 Admin 都有同名的属性 username, age,可以使用 WebDataBinder 对其区分
- 映射的参数名 user 和 @InitBinder 中的 value user 要一样
如果 URL 都使用 username 和 age 的话,会同时作用于 user 和 admin,使用 WebDataBinder 可对其加前缀,就能在映射的时候区分开是给谁使用的。
user.username and admin.username 分别映射到对象 user 和 admin,age 同时映射到他们的 age 属性上。
@RequestMapping("/intersect-object")
@ResponseBody
public Map intersectObject(User user, Admin admin) {
Map map = new HashMap();
map.put("user", user);
map.put("admin", admin);
return map;
}
@InitBinder("user")
public void initUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
@InitBinder("admin")
public void initAdmin(WebDataBinder binder) {
binder.setFieldDefaultPrefix("admin.");
}
显示:
{
"admin": {
"username": "Jim",
"age": 10
},
"user": {
"username": "Tom",
"age": 10,
"address": null
}
}
对象数组
- http://localhost:8080/object-list?users[0].username=Tom&users[1].username=Lucy
- 不能直接使用 List
users 来映射 - 需要创建一个类 UserList,其属性为 List
users,然后使用级连映射相似的方式来映射,但是要有数组的下标
@RequestMapping("/object-list")
@ResponseBody
public UserList objectList(UserList userList) {
return userList;
}
显示:
{
"users": [{
"username": "Tom",
"age": 0,
"address": null
}, {
"username": "Lucy",
"age": 0,
"address": null
}]
}
对象的 Map
http://localhost:8080/object-map?users['x'].username=Tom&users['y'].username=Lucy
http://localhost:8080/object-map?users["x"].username=Tom&users["y"].username=Lucy
不能直接使用 Map
users 来映射 需要创建一个类 UserMap,其属性为 Map
users,然后使用级连映射相似的方式来映射,但是要有 Map 的 key
@RequestMapping("/object-map")
@ResponseBody
public UserMap objectMap(UserMap users) {
return users;
}
显示:
{
"users": {
"x": {
"username": "Tom",
"age": 0,
"address": null
},
"y": {
"username": "Lucy",
"age": 0,
"address": null
}
}
}
AJAX 数据绑定
如果是 AJAX 传递数据给服务器端,然后要绑定为对象,那么 AJAX 不能是 GET 操作,如果只是使用 AJAX 从服务器端获取数据,则可以是 GET,POST 等。
接受 AJAX 传递过来的数据,映射为对象时必须要有 @RequestBody 修饰方法的参数
@RequestMapping("/json-bind")
@ResponseBody
public User json(@RequestBody User user) {
System.out.println(user.getUsername());
return user;
}
浏览器控制台输出
{
username: "Biao",
age: 111,
address: null
}
需要的类
User:
public class User {
private String username;
private int age;
private Address address;
// Setters and getters
}
Address:
public class Address {
private String city;
private String street;
// Setters and getters
}
Admin:
public class Admin {
private String username;
private int age;
// Setters and getters
}
UserList:
public class UserList {
private List users;
// Setters and getters
}
UserMap:
public class UserMap {
private Map users;
// Setters and getters
}
@ModelAttribute
把 HTTP 请求的参数映射到对象,参数名和对象中的属性名匹配的就做映射,不匹配的就不管,此注解可以省略。
package com.xtuer.controller;
@Controller
public class ParameterController {
// 表单中的参数被映射到对象 user
@RequestMapping("/user")
@ResponseBody
public String findUser(@ModelAttribute User user,
@RequestParam(required=false) Integer age) {
System.out.println("Age: " + age);
return user.toString();
}
}
package com.xtuer.domain;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class User {
private int id;
private String username;
private String password;
}
测试:
- http://localhost:8080/user?id=1234&username=biao
- http://localhost:8080/user?id=1234&username=biao&password=Secret
- http://localhost:8080/user?id=1234&username=biao&password=Secret&age=12
Forward and Redirect
Forward 在 url 前面加上字符串 forward: 即可
Redirect 在 url 前面加上字符串 redirect: 即可
package com.xtuer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ParameterController {
@RequestMapping("/forward-test")
public String forward() {
return "forward:/helloworld-springmvc";
}
@RequestMapping("/redirect-test")
public String redirect() {
return "redirect:/helloworld-springmvc";
}
}
测试:
- http://localhost:8080/forward-test
- http://localhost:8080/redirect-test
RedirectAttributes
表单提交后一般都会 redirect 到另一个页面,防止表单重复提交。RedirectAttributes 的作用就是把处理 PageA 的结果存储起来,当 redirect 到 PageB 的时候显示 PageA 的结果。
Request 中的参数不能被传递给 redirect 的页面,因为 redirect 是从浏览器端发起一个新的请求。
防止表单重复提交的流程:
Update User
Result: ${result}
package com.xtuer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class ParameterController {
// 显示表单
@RequestMapping("/user-form")
public String showUserForm() {
return "user-form.html";
}
// 更新 User,把结果保存到 RedirectAttributes
@RequestMapping("/update-user")
public String updateUser(@RequestParam String username,
@RequestParam String password,
final RedirectAttributes redirectAttributes) {
// Update user in database...
System.out.println("Username: " + username + ", Password: " + password);
// 操作结果显示给用户
redirectAttributes.addFlashAttribute("result", "The user is already successfully updated");
return "redirect:/result";
}
// 显示表单处理结果
@RequestMapping("/result")
public String result() {
return "result.html";
}
}
测试:
访问 http://localhost:8080/user-form,填写信息,提交表单,处理好后页面被 redirect 到 http://localhost:8080/result 显示操作结果。
Redirect 到另一个 Controller 时获取 RedirectAttributes 里的属性使用 @ModelAttribute
@RequestMapping("/flash")
public String flash(RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("username", "Biao");
return "redirect:flash2";
}
@RequestMapping("/flash2")
@ResponseBody
public String flash2(@ModelAttribute("username") String username) {
return "username: " + username;
}
获取 Request and Response
想取得 HttpServletRequest 和 HttpServletResponse 很容易,只要在方法的参数里定义后,Spring MVC 会自动的注入它们到参数里。
package com.xtuer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class ParameterController {
@RequestMapping("/request-response")
@ResponseBody
public String foo(HttpServletRequest request, HttpServletResponse response) {
System.out.println(request);
return "WoW";
}
}
测试:
- http://localhost:8080/request-response
Header
读取 header: The @RequestHeader annotation allows a method parameter to be bound to a request header
写入 header: Header 直接写入到 HttpServletResponse,没有注解用来写 header
下面是浏览器发送请求后的 header 信息:
Header Value
Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
package com.xtuer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
@Controller
public class ParameterController {
@RequestMapping("/read-header")
@ResponseBody
public String readHeader(@RequestHeader("Host") String host,
@RequestHeader(value="Accept-Encoding", required=false) String encoding,
@RequestHeader(value="Accept-Charset", required=false) String charset) {
return "Host: " + host + ", Encoding: " + encoding + ", Charset: " + charset;
}
@RequestMapping("/read-header-error")
@ResponseBody
public String readHeaderError(@RequestHeader("Host") String host,
@RequestHeader("Accept-Charset") String charset) {
return "Host: " + host + ", Charset: " + charset;
}
@RequestMapping("/write-header")
@ResponseBody
public String writeHeader(HttpServletResponse response) {
response.setHeader("token", "D4BFCEC2-89E6-40CB-AF9A-B5513CB30FED");
return "Header is wrote.";
}
}
测试:
- http://localhost:8080/read-header
- http://localhost:8080/read-header-error
- http://localhost:8080/write-header
访问 http://localhost:8080/read-header 成功访问
访问 http://localhost:8080/read-header-error 提示错误,因为 charset 是 required=true 的,在 header 信息里没有 charset,所以报错。但是这个错误如果不了解的话会一头雾水,因为在控制台中没有输出错误的原因
参数错误,类型转换错误等默认在控制台中看不到,也不会返回给浏览器端,要看到错误原因,需要把 Spring MVC 的日志调到 Debug 级别。
Cookie
- 读取 cookie: The @CookieValue annotation allows a method parameter to be bound to the value of an HTTP cookie
- 写入 cookie: Cookie 直接写到 HttpServletResponse,没有注解用来写 cookie
package com.xtuer.controller;
import javax.servlet.http.HttpServletResponse
@Controller
public class ParameterController {
@RequestMapping("/read-cookie")
@ResponseBody
public String readCookie(@CookieValue("username") String cookie) {
return "Cookie for username: " + cookie;
}
@RequestMapping("/write-cookie")
@ResponseBody
public String writeCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", "Don't tell you");
cookie.setMaxAge(1000);
response.addCookie(cookie); // Put cookie in response.
return "Cookie is wrote.";
}
}
测试:
- 访问 http://localhost:8080/read-cookie 报错,因为还没有 cookie,
可以给 cookie 一个默认值,这样即使没有 cookie 也不会报错了:
@CookieValue(value="username", defaultValue="") String cookie
访问 http://localhost:8080/write-cookie 写入 cookie
访问 http://localhost:8080/read-cookie 输出 cookie
package com.kaishengit.controller;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@Controller
public class FileUploadController {
@GetMapping("/upload")
public String uploadFile(@RequestHeader(name = "User-Agent") String userAgent,
HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println("userAgent:" + userAgent);
Cookie cookie = new Cookie("userLevel","SVIP");
cookie.setHttpOnly(true);
cookie.setMaxAge(60 * 60 * 24);
cookie.setDomain("localhost");
response.addCookie(cookie);
return "upload";
}
@PostMapping("/upload")
public String uploadFile(@CookieValue(name = "userLevel") String userLevel, String name, MultipartFile photo, RedirectAttributes redirectAttributes) throws IOException {
System.out.println("cookieValue: " + userLevel);
if(!photo.isEmpty()) {
System.out.println("表单中的元素名字:" + photo.getName());
System.out.println("原始文件名称:" + photo.getOriginalFilename());
System.out.println("ContentType:" + photo.getContentType());
System.out.println("文件大小:" + photo.getSize() + " -> " + FileUtils.byteCountToDisplaySize(photo.getSize()));
//byte[] bytes = photo.getBytes();
/*InputStream inputStream = photo.getInputStream();
OutputStream outputStream = new FileOutputStream("D:/temp/upload/"+photo.getOriginalFilename());
IOUtils.copy(inputStream,outputStream);
outputStream.flush();
outputStream.close();
inputStream.close();*/
photo.transferTo(new File("X:/temp/upload/"+photo.getOriginalFilename()));
} else {
System.out.println("请选择文件");
redirectAttributes.addFlashAttribute("message","请选择文件");
}
return "redirect:/upload";
}
@ExceptionHandler(IOException.class)
public String ioExceptionHandler() {
return "error/500";
}
}
Session
- 可以使用 HttpSession 来直接操作 session
- 同时也提供了操作 session 的注解 @SessionAttributes
HttpSession 的方式什么时候都生效,但是 @SessionAttributes 有时候就不行,如返回 AJAX 请求时设置的 session 无效。所以推荐使用注入 HttpSession 来读写 session。
package com.xtuer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
@Controller
@SessionAttributes({"result"})
public class SessionController {
@RequestMapping("/write-session")
@ResponseBody
public String writeSession(HttpSession session) {
session.setAttribute("username", "座山雕");
session.setAttribute("password", "天王盖地虎");
return "Session wrote...";
}
@RequestMapping("/read-session")
public String readSession() {
return "helloworld-freemarker.htm";
}
@RequestMapping("/write-session2")
public ModelAndView writeSession2() {
ModelAndView mav = new ModelAndView();
mav.addObject("result", "Save session");
mav.setViewName("user-form.htm");
return mav;
}
@RequestMapping("/read-session2")
public String readSession2() {
return "result.htm";
}
}
测试:
- 访问 http://localhost:8080/write-session
- 访问 http://localhost:8080/read-session
Spring MVC 的处理流程
用户向服务器发送请求,请求被 Spring 前端控制 Servelt DispatcherServlet 捕获
DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回
DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。(附注:如果成功获得HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…)方法)
提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换,如 String 转换成 Integer、Double 等
格式化:对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象
根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的ViewResolver)返回给 DispatcherServletViewResolver 结合 Model 和 View,来渲染视图
将渲染结果返回给客户端
Spring MVC 教程, 快速入门, 深入分析
SpringMVC 获取 Request 和 Response
SpringMVC 中在任意地方取得 HttpServletRequest 和 HttpServletResponse
- 在 web.xml 中注册 RequestContextListener (SpringMVC 4 不需要这一步)
org.springframework.web.context.request.RequestContextListener
- 获取 HttpServletRequest 和 HttpServletResponse
public static String testRequestAndResponse() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
return request.getParameter("name");
}
SpringMVC 接收日期参数
SpringMvc 的请求中的参数(字符串)默认是不能自动地转换为日期的,需要使用 Converter, InitBinder 或者 Formatter 来把请求中的参数转换为日期。
使用 Converter
- 定义字符串转换为日期的类 DateConverter
package com.xtuer.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter {
@Override
public Date convert(String source) {
String pattern = source.length()==10 ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat format = new SimpleDateFormat(pattern);
try {
return format.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
- SpringMvc 的配置文件中注册 Converter
- 处理请求
@GetMapping("/to-date")
@ResponseBody
public Date toDate(Date date) {
System.out.println("=========>" + date);
return date;
}
- 访问 http://localhost:8080/to-date?date=2016-04-12 或者 http://localhost:8080/to-date?date=2016-04-12%2012:12:12 能得到日期2016-04-12 和 2016-04-12 12:12:12
Converter 是全局的,可以在所有 Controller 中使用。
使用 InitBinder
- Controller 中定义 InitBinder
@InitBinder("date")
public void initDate(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
- 处理请求
@GetMapping("/to-date")
@ResponseBody
public Date toDate(Date date) {
System.out.println("=========>" + date);
return date;
}
注意: @InitBinder(“date”) 中 date 必须和 toDate(Date date) 中的 date 名字一样,当然,请求的参数中也必须有名为 date 的参数。
@InitBinder 只能在当前 Controller 中使用,当有多个地方都需要把参数转换为日期对象,则使用 Converter 更适合。