这篇博客主要了解 SpringMVC 中 Controller 类的编写,主要了解的是请求地址与 Controller 类中方法的映射。
1、SpringMVC的工作流程
具体的工作流程图:
这张流程图有点复杂,我们一点点进行解读:
- 客户端用户发送请求至DispatcherServlet(前端控制器)。该控制器会过滤出哪些请求可以访问Servlet、哪些不能访问,并且会加载 XML 配置文件。
- DispatcherServlet(前端控制器)根据请求地址寻找对应的处理器映射。如果不存在映射,则判断是否有对应的资源,如果没有则返回404错误代码页面,如果有则返回对应的资源。如果存在映射,则通过HandlerMapping(处理器映射器)生成Handler(处理器)及(处理器拦截器)(拦截器如果有则生成),然后返回给 DispatcherServlet(前端控制器)
- DispatcherServlet(前端控制器)拿到Handler(处理器)后,找到HandlerAdapter(处理器适配器),经过适配调用具体的Handler(处理器)(Controller,也叫后端控制器)。
- Handler(处理器controller)执行
- HandlerAdapter(处理器适配器)将 Handler(处理器controller) 执行后的结果 ModelAndView 对象返回给DispatcherServlet(前端控制器)。
- DispatcherServlet(前端控制器)前端控制器将 ModelAndView 对象传给ViewReslover视图解析器。
- ViewReslover视图解析器解析后返回具体 View。
- DispatcherServlet(前端控制器)根据 View 进行渲染视图(即将模型数据填充至视图中),并返回给客户端用户。
在上述几个流程中,提到几个组件,它们的具体作用:
-
前端控制器
DispatcherServlet
:由框架提供,作用是接收请求,响应结果,相当于转发器,中央处理器。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。 -
处理器映射器
HandlerMapping
:由框架提供,作用是负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
等。 -
处理器适配器
HandlerAdapter
:作用是按照特定规则去执行Handler。通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。 -
处理器
Handler
:需要自己开发,在编写Handler时按照 HandlerAdapter 的要求去做,这样适配器才可以去正确执行Handler。Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下 Handler 对具体的用户请求进行处理。 -
视图解析器
View resolver
:由框架提供,作用是将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等 -
视图
View
:View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
2、DispathcerServlet
从工作流程中可以看出,SpringMVC 中有两个核心,其中一个就是DispathcerServlet——前端控制器,还有一个是Controller——后端控制器。
前端控制器不需要我们去编写,这个由 SpringMVC 提供,但是需要进行一定的配置,具体的配置在之前已经讲解过了。
3、Controller
Controller是后端控制器,也是具体的需要编写代码的地方。它主要是获取 DispathcerServlet 传递的请求参数,调用具体的业务,然后进行相应的数据响应。如下就是一个简单的 Controller类
//创建一个简单的Controller类
@Controller
public class UserController {
@RequestMapping("/user")
public String user(){
//具体操作
return "/user.html";
}
}
4、请求映射
DispathcerServlet
获取到请求信息之后,调用 HandlerMapping 处理器映射器,其目的是通过根据请求地址找到对应的 Controller 类和 Controller 中具体的方法。
而@RequestMapping
注解的作用就是请求和处理请求的控制器方法关联起来,建立映射关系。@RequestMapping
注解有多种属性可以通过请求地址、请求方式、请求参数、标头进行映射,既通过属性设置来完成具体的请求映射:
4.1、注解的位置
当 @RequestMapping
标识一个类时,表示设置映射请求的请求路径的初始信息;当 @RequestMapping
标识一个方法时,表示设置映射请求的请求路径的具体信息。
当注解设置在整个类,请求URL 的第一级访问目录。当注解设置方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping
标注的一级目录一起组成访问虚拟路径。
@Controller
@RequestMapping("/user")
public class UserController {
//请求地址必须是localhost://user/user_name
@RequestMapping("/user_name")
public String user_name(){
//....
}
}
4.2、注解的属性
注解在使用过程中,可以设置一些属性完成具体的映射。
-
value
属性用于映射请求地址,是一个字符串数组,可以同时映射多个请求地址:@RequestMapping (value = {"/user_name","/user_names"}) public void user_name() { // ... }
在匹配请求路径时,除了可以直接设置请求地址,还可以使用ant风格的路径
- ?:表示任意的单个字符
- *:表示任意的0个或多个字符
- **:表示任意的一层或多层目录
@RequestMapping (value = {"/user_?ame","/user_names/*","/user_names/**"}) public void user_name() { // ... }
在匹配请求路径是,还可以使用占位符,然后通过
@PathVariable
注解将占位符表示的数据赋值给控制方法的形参。//@PathVariable("userId") 中的 userId 表示将占位符中的userId赋值形参,如果形参的参数和占位符中的相同可以省略("userId") @RequestMapping ("/user/{userId}/photos/{photoId}") public void findPet(@PathVariable("userId") Long userId, @PathVariable("photoId") Long photoId) { // ... }
-
method
属性用于设置请求方式,是一个字符串数组,可以同时映射多个请求方式。如果当前请求地址瞒住,但是请求方式不满足条件,会返回 405 错误。当不设置该属性时,表示不以请求方式为条件,既可以匹配到任何请求方式的请求。@RequestMapping(value = {"/user_name","/user_names"},method={HttpMethod.GET,HttpMethod.POST}) public void user_name() { // ... }
SpringMVC 还提供了一些
@RequestMapping
和请求方式结合的派生注解,@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping
。//等价与 @RequestMapping(value = {"/user_name","/user_names"},method=HttpMethod.GET) @PostMapping(value = {"/user_name","/user_names"}) //等价与 @RequestMapping(value = {"/user_name","/user_names"},method=HttpMethod.POST) @PutMapping(value = {"/user_name","/user_names"}) @DeleteMapping(value = {"/user_name","/user_names"}) @PatchMapping(value = {"/user_name","/user_names"}) public void user_name() { // ... }
-
params
属性通过请求参数匹配请求映射,是一个字符串数组,可以同时映射多个请求参数。有下列四种表达式用于设置请求参数和请求映射的匹配关系。//表示必须携带 accountName 参数,不能携带 accountName2 参数 //myParam参数的值必须为 myValue,myParam2参数的值不能为 100 @RequestMapping(value = {"/user_name","/user_names"},method={HttpMethod.GET,HttpMethod.POST},params = {"accountName","!accountName2","myParam=myValue","myParam2!=100"}) public void user_name() { // ... }
SpringMVC的工作流程只是稍作了解,不需要记忆。而给 Controller 类添加请求映射主要用于将 Controller 类中的方法与请求地址进行映射是必须要掌握的。
5、处理 PUT 和 DELETE 请求方式
由于浏览器只支持发送 GET 和 POST 方式的请求,那么当我们想要发送 PUT 和 DELETE 请求时,有两种解决方法:
- 通过 Ajax 发送请求时设置请求方式为 PUT 或 DELETE。
- 通过 SpringMVC 提供了 HiddenHttpMethodFilter 将 POST 请求转换为 DELETE 或 PUT 请求
那么我们主要来了解一下第二种方式:想要 HiddenHttpMethodFilter 处理 PUT 和 DELETE 请求必须满足两个条件,当前请求的请求方式必须为post和当前请求必须传输请求参数_method。
在 web.xml 中注册HiddenHttpMethodFilter :
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
想要发送 POST 请求且必须存在 _method 参数可以使用如下方法:
<form action="请求地址" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="提交">
</form>