spring mvc 使用
spring mvc 是基于 Servlet API 构建的 Web 框架,围绕一个 DispatcherServlet
设计的,这个 Servlet 将请求分发给各个处理器,支持可配置的处理器映射、视图渲染、地区、时区和主题解析,以及对文件上传。默认处理程序基 于@Controller
和 @RequestMapping
注释,Spring为处理器方法提供了极其多样灵活的配置。Spring 3.0以后提供了@Controller注解机制、@PathVariable注解以及一些其他的特性,你可以使用它们来进行RESTful web站点和应用的开发。
一、spring mvc 的处理流程
spring mvc 流程图
流程说明
- 用户发送请求至 前端控制器DispatcherServlet
- DispatcherServlet 收到请求后调用 处理器映射HandlerMapping
- HandlerMapping 根据请求的 url 找到具体的处理器,生成处理器对象Handler 及处理器拦截器HandlerIntercepter(如果有则生成)一并返回给前端控制器DispatcherServlet
- DispatcherServlet 通过处理器适配器 HandlerAdapter 调用具体的处理器Controller
- 处理器 Controller 执行完后返回模型和视图 ModelAnView
- DispatcherServlet 将 ModelAnView 传给视图解析器 ViewResolver,ViewResolver 解析后返回具体的视图 View
- 前端控制器 DispatcherServlet对视图View进行渲染视图(将模型数据填充至视图中)并响应用户
二、DispatcherServlet
DispatcherServlet 要使用 Java 配置或在 web.xml 根据 Servlet 规范进行声明和映射。然后 DispatcherServlet 使用 Spring 配置来发现它需要的用于请求映射、视图解析、异常处理等的组件。
<web-app>
<!-- 在启动Web容器时,自动装配spring的配置信息 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 需要加载的上下文配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring/applicationContext*.xml</param-value>
</context-param>
<!-- DispatcherServlet -->
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring/applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在这里存在两个 contextConfigLocation,一个是给ContextLoadrListener,一个是给DispatcherServlet
都是用于加载上下文,一个是spring的,一个是springMVC的,其中ContextLoadrListener先加载,然后才是DispatcherServlet。
- DispatcherServlet 一般会加载MVC相关的bean配置管理(如: ViewResolver, Controller, MultipartResolver, ExceptionHandler)
- ContextLoaderListener一般会加载整个Spring容器相关的bean配置管理(如: Log, Service, Dao, PropertiesLoader)
也就是如果我把 @Controller 的注解声明放到 ContextLoadrListener 中的配置文件去加载是不可以的,DispatcherServlet 到时对这个 controller 会无感知。
DispatcherServlet 的上下文仅仅是 Spring MVC 的上下文, 而 ContextLoaderListener 的上下文则对整个Spring都有效. 也就是 DispatcherServlet 可以使用 spring 的上下文,但是 spring 不能使用 DispatcherServlet 的上下文,一般 Spring web 项目中同时会使用这两种上下文
url-pattern 路径匹配问题
路径匹配的优先级为
- 完全匹配(如:/test/test.do)
- 路径匹配
/*
(如:/* 、/app/*) - 扩展名匹配
*.
(如:*.jsp 不能直接用*
) - 另外还有一个
/
/
与/*
的区别/*
是路径匹配,像是模糊匹配,会匹配到该路径下所有的 URL 请求,包括带扩展名的文件如 *.jsp、*.css、*.js 等等
而/
的优先级是低于扩展名匹配的,它只能匹配到如 /toIndex 这样的路径
三、使用注解的控制器
Spring MVC 提供基于注释的编程模型,使用 @Controller 和 @RestController 注解标记控制器来表达请求映射,请求输入,异常处理等。带注解的控制器具有灵活的方法签名,不必扩展基类,也不必实现特定的接口
1、声明
要使用 @Controller 和 @RestController 注解,你得要告诉 spring mvc 要扫描解析的位置,可以将组件扫描添加到 Java 配置中
@Configuration
@ComponentScan("com.example.web")
public class WebConfig {
// ...
}
或者是在 spring mvc 的bean配置xml文件中声明组件扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.web"/>
<!-- ... -->
</beans>
@RestController 是 @Controller 和 @ResponseBody 的组合,相当于在这个控制器的每个方法上都注解了 @ResponseBody
2、请求映射
1)@RequestMapping
使用 @RequestMapping 注解能将请求映射到控制器的方法。可以在类级别使用它来表示共享映射,或者在方法级别使用它来缩小到特定的端点映射
另外还有与 HTTP方法匹配的映射注解: @GetMapping,@PostMapping,@PutMapping,@DeleteMapping,和@PatchMapping。(@GetMapping 等效@RequestMapping(method=HttpMethod.GET))
虽然默认情况下,@RequestMapping 与所有HTTP方法匹配,但大多数控制器方法应该映射到特定的HTTP方法而不是使用@RequestMapping
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
2)路径匹配
请求路径还能使用 通配符
-
?
匹配一个字符 -
*
匹配路径段中的零个或多个字符 -
**
匹配零个或多个路径段
另外,还可声明 URI变量并通过 @PathVariable 访问它们的值
@GetMapping("/owners/{owner}/pets/{petId}")
public Pet findPet(@PathVariable("owner") Long ownerId, @PathVariable Long petId) {
// ...
}
其正则表达式的语法为{varName:regex}