spring mvc 是基于 Servlet API 构建的 Web 框架,围绕一个 DispatcherServlet
设计的,这个 Servlet 将请求分发给各个处理器,支持可配置的处理器映射、视图渲染、地区、时区和主题解析,以及对文件上传。默认处理程序基 于@Controller
和 @RequestMapping
注释,Spring为处理器方法提供了极其多样灵活的配置。Spring 3.0以后提供了@Controller注解机制、@PathVariable注解以及一些其他的特性,你可以使用它们来进行RESTful web站点和应用的开发。
spring mvc 流程图
流程说明
DispatcherServlet 要使用 Java 配置或在 web.xml 根据 Servlet 规范进行声明和映射。然后 DispatcherServlet 使用 Spring 配置来发现它需要的用于请求映射、视图解析、异常处理等的组件。
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:conf/spring/applicationContext*.xmlparam-value>
context-param>
<servlet>
<servlet-name>spring-mvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:conf/spring/applicationContext-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>spring-mvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
在这里存在两个 contextConfigLocation,一个是给ContextLoadrListener,一个是给DispatcherServlet
都是用于加载上下文,一个是spring的,一个是springMVC的,其中ContextLoadrListener先加载,然后才是DispatcherServlet。
也就是如果我把 @Controller 的注解声明放到 ContextLoadrListener 中的配置文件去加载是不可以的,DispatcherServlet 到时对这个 controller 会无感知。
DispatcherServlet 的上下文仅仅是 Spring MVC 的上下文, 而 ContextLoaderListener 的上下文则对整个Spring都有效. 也就是 DispatcherServlet 可以使用 spring 的上下文,但是 spring 不能使用 DispatcherServlet 的上下文,一般 Spring web 项目中同时会使用这两种上下文
url-pattern 路径匹配问题
路径匹配的优先级为
/*
(如:/* 、/app/*)*.
(如:*.jsp 不能直接用 *
)/
/
与/*
的区别
/*
是路径匹配,像是模糊匹配,会匹配到该路径下所有的 URL 请求,包括带扩展名的文件如 *.jsp、*.css、*.js 等等
而/
的优先级是低于扩展名匹配的,它只能匹配到如 /toIndex 这样的路径
Spring MVC 提供基于注释的编程模型,使用 @Controller 和 @RestController 注解标记控制器来表达请求映射,请求输入,异常处理等。带注解的控制器具有灵活的方法签名,不必扩展基类,也不必实现特定的接口
要使用 @Controller 和 @RestController 注解,你得要告诉 spring mvc 要扫描解析的位置,可以将组件扫描添加到 Java 配置中
@Configuration
@ComponentScan("com.example.web")
public class WebConfig {
// ...
}
或者是在 spring mvc 的bean配置xml文件中声明组件扫描
<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
使用 @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) {
// ...
}
}
请求路径还能使用 通配符
?
匹配一个字符*
匹配路径段中的零个或多个字符**
匹配零个或多个路径段另外,还可声明 URI变量并通过 @PathVariable 访问它们的值
@GetMapping("/owners/{owner}/pets/{petId}")
public Pet findPet(@PathVariable("owner") Long ownerId, @PathVariable Long petId) {
// ...
}
其正则表达式的语法为{varName:regex}