Spring MVC 入门教程
一张图简要描述 Spring MVC 的处理流程:

- Spring MVC 的核心前端控制器
DispatcherServlet接收 HTTP 请求并询问Handler mapping该请求应该转发到哪个Controller方法。 Controller业务处理完毕,返回 逻辑视图名(通常是一个字符串) 。- 最后
viewResolver解析逻辑视图名并返回相应的View,如 JSP、FreeMarker。
实现一个 Controller
下面介绍编写控制器过程中常用的注解:
定义一个控制器
@Controller
Traditional MVC controller relying on a view technology to perform server-side rendering.
@RestController
RESTful web service controller simply populates and returns a object that will be written directly to the HTTP response as JSON. Thanks to Spring’s HTTP message converter support, you don’t need to do this conversion manually. Because Jackson 2 is on the classpath, Spring’s MappingJackson2HttpMessageConverter is automatically chosen to convert the object to JSON.
It’s shorthand for @Controller and @ResponseBody rolled together.
映射请求
@RequestMapping
@RequestMapping 用于将 HTTP 请求映射到指定的 Controller 类或方法。
一、可匹配的请求属性如下:
value用于匹配指定的请求路径,例如:value = "/index"。method用于匹配指定的请求方法,例如:method = RequestMethod.POST。consumes用于匹配指定的请求头Content-Type,例如:consumes = MediaType.APPLICATION_JSON_UTF8_VALUE。produces用于匹配指定的请求头Accept,例如:produces = MediaType.APPLICATION_JSON_UTF8_VALUE。params用于匹配指定的请求参数,例如:- 匹配存在:
params = "myParam" - 匹配不存在:
params = "!myParam" - 匹配指定参数值:
params = "myParam=myValue"
- 匹配存在:
headers用于匹配指定的请求头,例如:- 匹配存在:
headers = "myHeader" - 匹配不存在:
headers = "!myHeader" - 匹配指定值:
headers = "myHeader=myValue"
- 匹配存在:
尽管你可以使用媒体类型通配符(例如:content-type=text/* 或 accept=xxx)去匹配 Content-Type 或 Accept 请求头,但还是更推荐使用 consumes 或 produces 属性。因为它们专门用于此目的。
二、Spring Framework 4.3 还引入了五个等价的变体注解,相当于 @RequestMapping 注解与 method 属性的组合使用:
1 | @GetMapping |
三、标注了 @RequestMapping 注解的方法可以拥有非常灵活的方法签名。支持以下参数类型/注解、返回类型/注解:
方法参数类型
@RequestMapping 注解的方法,参数可以是下列任一类型:
Request / Response
用于访问当前 javax.servlet.http.HttpServletRequest / javax.servlet.http.HttpServletResponse。
1 |
|
使用这类方法参数有点类似于传统的 Servlet 编程。
InputStream / Reader
用于访问当前请求内容的 java.io.InputStream / java.io.Reader
OutputStream / Writer
用于生成当前响应内容的 java.io.OutputStream / java.io.Writer
1 |
|
Session
用于访问当前 javax.servlet.http.HttpSession
1 |
|
HttpEntity<?>
HttpEntity<?> 用于同时访问 HTTP 请求头和请求体(HTTP request headers and contents) 。
1 |
|
Map / Model / ModelMap
Map / Model / ModelMap 用于在 Controller 层填充将会暴露给 View 层的 Model 对象。
方法参数注解
尽管使用常规类型的方法参数更接近于人们所熟悉的传统 Servlet 编程,但在 Spring 编程中却不建议这么做。因为这样会导致 JavaBean 与 Servlet 容器耦合,侵入性强,难以进行单元测试(如 Mock 测试)。最佳实践应当是传入注解后被解析好的数据类型,下面介绍这些常用的注解:
@PathVariable
@PathVariable 用于标注某个方法参数与某个 URI 模板变量(URI template variable) 的绑定关系,常用于 RESTful URL,例如 /hotels/{hotel}。
@RequestParam
@RequestParam 用于标注某个方法参数与某个 HTTP 请求参数(HTTP request parameter) 的绑定关系。
Annotation which indicates that a method parameter should be bound to a web request parameter.
Supported for annotated handler methods in Spring MVC and Spring WebFlux as follows:
- In Spring MVC, “request parameters” map to query parameters, form data, and parts in multipart requests. This is because the Servlet API combines query parameters and form data into a single map called “parameters”, and that includes automatic parsing of the request body.
- In Spring WebFlux, “request parameters” map to query parameters only. To work with all 3, query, form data, and multipart data, you can use data binding to a command object annotated with
ModelAttribute.If the method parameter type is
Mapand a request parameter name is specified, then the request parameter value is converted to aMapassuming an appropriate conversion strategy is available.If the method parameter is
MaporMultiValueMapand a parameter name is not specified, then the map parameter is populated with all request parameter names and values.
例子 1:POST with form data
1 | POST /test HTTP/1.1 |
例子 2:GET with query string parameters
1 | GET /test?data=123,234 HTTP/1.1 |
代码:
1 |
|
Type conversion is applied automatically if the target method parameter type is not String. See the section called “Method Parameters And Type Conversion”.
1 |
|
When an @RequestParam annotation is used on a Map<String, String> or MultiValueMap<String, String> argument, the map is populated with all request parameters.
1 |
|
使用时需要注意 required 这个属性:
- 方法参数不写
@RequestParam,默认的required为false - 方法参数写了
@RequestParam,默认的required为true - 方法参数同时写了
@RequestParam+defaultValue,默认的required为false
@RequestBody
@RequestBody 用于标注某个方法参数与某个 HTTP 请求体(HTTP request body) 的绑定关系。 @RequestBody 会调用合适的 message converters 将 HTTP 请求体(HTTP request body) 写入指定对象,默认的 HttpMessageConverter 如下:
content-type |
Description |
|---|---|
ByteArrayHttpMessageConverter converts byte arrays. |
|
StringHttpMessageConverter converts strings. |
|
application/x-www-form-urlencoded |
FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>. |
application/json |
MappingJackson2HttpMessageConverter converts JSON. |
例子:
1 | POST /test HTTP/1.1 |
1 |
|
An @RequestBody method parameter can be annotated with @Valid, in which case it will be validated using the configured Validator instance. When using the MVC namespace or the MVC Java config, a JSR-303 validator is configured automatically assuming a JSR-303 implementation is available on the classpath.
@RequestHeader
@RequestHeader 用于标注某个方法参数与某个 HTTP 请求头(HTTP request header) 的绑定关系。
@CookieValue
@CookieValue 用于标注某个方法参数与某个 HTTP cookie 的绑定关系。方法参数可以是 javax.servlet.http.Cookie,也可以是具体的 Cookie 值(如字符串、数字类型等)。
举个例子:
1 |
|
方法参数验证
Spring MVC 可以快速整合 JSR 303 - Bean Validation 实现方法参数校验,用法如下:
1 |
|
用到:
org.springframework.validation.annotation.Validated 注解
org.springframework.validation.BindingResult 接口
参考:
《Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC》
方法返回类型
@RequestMapping 注解的方法,返回类型可以是下列任一常规类型:
HttpEntity<?>
org.springframework.http.HttpEntity
Represents an HTTP request or response entity, consisting of headers and body.
Typically used in combination with the RestTemplate, like so:
1 | HttpHeaders headers = new HttpHeaders(); |
or
1 | HttpEntity<String> entity = template.getForEntity("http://example.com", String.class); |
Can also be used in Spring MVC, as a return value from a @Controller method:
1 |
|
ResponseEntity<?>
org.springframework.http.ResponseEntity
Extension of HttpEntity that adds a HttpStatus status code. Used in RestTemplate as well @Controller methods.
In RestTemplate, this class is returned by getForEntity() and exchange():
1 | ResponseEntity<String> entity = template.getForEntity("http://example.com", String.class); |
Can also be used in Spring MVC, as the return value from a @Controller method:
1 |
|
Or, by using a builder accessible via static methods:
1 |
|
ModelAndView
org.springframework.web.servlet.ModelAndView
Holder for both Model and View in the web MVC framework.
String
表示直接返回视图名。
方法返回注解
@ResponseBody
用于标注某个方法返回值与 WEB 响应体(response body) 的绑定关系。 @ResponseBody 会跳过 ViewResolver 部分,调用合适的 message converters,将方法返回值作为 WEB 响应体(response body) 写入输出流。
1 |
|
@ResponseStatus
@ResponseStatus 用于返回 HTTP 响应码,例如返回 404:
1 |
|
视图处理
统一异常处理
Classes annotated with @ControllerAdvice can contain @ExceptionHandler, @InitBinder, and @ModelAttribute annotated methods, and these methods will apply to @RequestMapping methods across all controller hierarchies as opposed to the controller hierarchy within which they are declared.
@RestControllerAdvice is an alternative where @ExceptionHandler methods assume @ResponseBody semantics by default.
Both @ControllerAdvice and @RestControllerAdvice can target a subset of controllers:
1 | // Target all Controllers annotated with @RestController |
例子:
1 |
|
CORS 支持
核心配置
参考
《Serving Web Content with Spring MVC》
《Building a RESTful Web Service》