Spring MVC 「1」初识Spring MVC

184 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

01-DispatcherServlet

与其他的Web框架一样,Spring MVC也基于前端控制器模式设计。DispatcherServlet是Spring MVC的核心。

从[1]文中了解到,前端控制器模式的UML图如左图所示:

Handler负责将不同的请求委托给不同的Command类去处理。

Spring MVC中,DispatcherServlet的角色就是Handler类。

图1. 前端控制器模式

图1. 前端控制器模式

[1] A Guide to the Front Controller Pattern in Java

01.1-前端控制器模式在Spring MVC中的实现

  1. DispatcherServlet的角色是图1中的Handler
  2. HandlerMapping接口是AbstractCommand,负责将请求映射到处理器和一系列关联的pre-/post-拦截器。
  3. 为了屏蔽Handler的具体实现,方便DispatcherServlet调用,定义了HandlerAdapter接口。

图2. 前端控制器模式在Spring MVC中的实现

图2. 前端控制器模式在Spring MVC中的实现

01.2-处理请求的流程

DispatcherServlet处理请求的大致流程如下:

  1. WebApplicationContext绑定到请求的某个属性上,以便在后续处理过程中控制器或其他元素(例如拦截器)可以访问到。
  2. locale处理器绑定到请求上。「可选」
  3. theme处理器绑定到请求上。「可选」
  4. 检查请求中是否包含multiparts,若是,则将请求包装成MultipartHttpServletRequest。「可选」
  5. 查找合适的handler。若能找到匹配的,其关联的执行链(预处理、后置处理、控制器)会执行,并生成一个model用于渲染。
  6. 若handler返回了一个model,则渲染view。否则,则不渲染,说明请求已被满足。

除了上述步骤外,可能还需要进行:

  • 异常处理,HandlerExceptionResolver负责处理。
  • HTTP caching。

02-请求路径匹配

@RequestMapping注解把请求映射到控制器中的某个方法上,并可以指定匹配映射的方式:基于URL、HTTP方法、请求中的参数、消息头、媒体类型。

02.1-URI pattern

基于URL的匹配分为两种:PathPattern和AntPathMatcher。

  • 前者基于预解析的模式匹配,PathContainer,更高效,推荐使用。
  • 后者基于字符串模式匹配,效率不高,且难以解决URL存在的一些问题。

PathPattern的一些示例:

"/resources/ima?e.png" - ?匹配一个字符
"/resources/*.png" - *匹配0或多个字符
"/resources/**" - **匹配多层路径
"/projects/{project}/versions" - 匹配一层路径,并将匹配部分赋值给变量project
"/projects/{project:[a-z]+}/versions" - 匹配包含[a-z]的一段字符,并将匹配部分赋值给变量project

02.2-HTTP方法

@GetMapping / @PostMapping / @PutMapping / @DeleteMapping / @PatchMapping等注解等价于@RequestMapping(method=HttpMethod.GET / POST / PUT / etc.)

02.3-请求参数和消息头

可通过请求参数params和消息头headers,缩小请求匹配的范围。

例如:

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String petId) {
    // ...
}
// 等价于
@GetMapping(path = "/pets", headers = "myHeader=myValue") 
public void findPet(@PathVariable String petId) {
    // ...
}

02.4-媒体类型

通过consumes(对应请求中的Content-Type)来限定请求匹配的范围。

通过produces(对应请求中的Accept)来限定请求匹配的范围。

例如:

@GetMapping(path = "/pets/{petId}", produces = "application/json") 
@ResponseBody
public Pet getPet(@PathVariable String petId) {
    // ...
}