[Study]SpringMVC
Posted Spring-_-Bear
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Study]SpringMVC相关的知识,希望对你有一定的参考价值。
文章目录
一、概述及示例
1.1 MVC 思想介绍
-
MVC 是一种软件架构的思想,将软件按照模型(
model
)、视图(view
)、控制器(controller
)来划分 -
M(
Model
):模型层,指工程中的 JavaBean,作用是处理数据。JavaBean分为以下两类- 一类称为实体 Bean:用于存储业务数据,如 Student、User 等
- 一类称为业务 Bean:指
Service
或Dao
对象,专门用于处理业务逻辑和数据访问
-
V(
View
):视图层,指工程中的html
或JSP
等页面,作用是与用户进行交互,展示数据 -
C(
Controller
):控制层,指工程中的 Servlet,作用是接收请求和响应浏览器 -
MVC 的工作流程
- 用户通过视图层(
view
)发送请求到服务器,在服务器中请求被Controller
接收 Controller
调用相应的Model
层处理请求- 模型层处理完毕后将结果返回到
Controller
Controller
根据请求处理的结果找到相应的View
- 由视图层渲染数据后最终响应给浏览器
- 用户通过视图层(
1.2 SpringMVC 概述
SpringMVC
是 Spring
的一个后续产品,是 Spring
的一个子项目。SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案,在表述层框架历经 Strust
、WebWork
、Strust2
等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 JavaEE 项目表述层开发的首选方案。相比其它框架,SpringMVC 具有以下显著特点
- Spring 家族原生产品,与
IOC
容器等基础组件无缝对接- 基于原生的
Servlet
,通过功能强大的前端控制器DispatcherServlet
对请求和响应进行统一处理- 可插拔式组件即插即用,内部组件化程度高,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
1.3 HelloWorld
-
新建 maven 工程,给普通的 maven 工程添加 web 模块(添加
web.xml
、指定工程上下文路径到webapp
) -
在
pom.xml
中修改 maven 工程的打包方式为war
包并引入 SpringMVC 相关依赖<!-- 修改 maven 工程打包方式为 war 包 --> <packaging>war</packaging> <!-- 引入 springmvc 相关所需依赖 --> <dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <!-- 日志 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- ServletAPI --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- Spring5 和 Thymeleaf 整合包 --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> </dependencies>
-
在
web.xml
中注册前端控制器DispatcherServlet
<!-- 配置前端控制器,对浏览器发送的请求统一进行处理 --> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定 SpringMVC 配置文件路径,若不指定则 mvc.xml 应位于 WEB-INF 目录下且名称为 <servlet-name>-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mvc.xml</param-value> </init-param> <!-- 将前端控制器初始化时间提前到服务器启动时,减少第一次访问的等待时间 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <!-- / 不能匹配 .jsp 请求路径的请求(避免在访问 jsp 页面时,该请求被 DispatcherServlet 处理,从而找不到相应的页面) /* 能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用 /* 的写法 --> <url-pattern>/</url-pattern > </servlet-mapping>
-
在
resources
目录下新建 SpringMVC 的配置文件(需与第四步init-parame
中配置的文件名相同)<!-- 开启组件扫描,只扫描 Controller 组件 --> <context:component-scan base-package="com.bear.mvc.controller"/> <!-- 配置 Thymeleaf 视图解析器 --> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"/> <property name="characterEncoding" value="UTF-8"/> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <!-- 视图前缀 --> <property name="prefix" value="/WEB-INF/templates/"/> <!-- 视图后缀 --> <property name="suffix" value=".html"/> <property name="templateMode" value="HTML5"/> <property name="characterEncoding" value="UTF-8"/> </bean> </property> </bean> </property> </bean>
-
创建请求控制器
Controller
/** * @author Spring-_-Bear * @datetime 2022/4/9 20:52 */ @Controller public class HelloController /** * @RequestMapping:处理请求和控制器方法之间的映射关系 * @RequestMapping 注解的 value 属性可以通过请求地址匹配请求, * / 表示的当前工程的上下文路径:http://localhost:8080/project/ * / 被服务器解析为 http://localhost:8080/project/ * / 被浏览器解析地址为 http://localhost:8080/ * / 重定向是将新的访问地址发送给浏览器解析,所以重定向是 / 解析的地址为 */ @RequestMapping("/") public String toIndex() // 返回视图名称即 hello.html,返回 hello 后由 Thymeleaf 视图解析器解析 return "hello";
-
创建前端页面
hello.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello World</title> </head> <body> <h1>Hello World</h1> </body> </html>
-
部署 Tomcat 访问
-
项目结构如下
-
访问成功
1.4 请求响应流程
- 浏览器发送请求,若请求地址符合前端控制器的
url-pattern
,该请求就会被前端控制器DispatcherServlet
捕获 - 前端控制器会读取
SpringMVC
的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping
注解的value
属性值进行匹配 - 若匹配成功,该注解所标识的控制器方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析
- 视图解析器加上前缀和后缀组成视图的路径,通过
Thymeleaf
对视图进行渲染,最终转发到视图所对应页面
二、请求映射
2.1 注解的使用位置
@RequestMapping
标识一个类:设置映射请求路径初始信息@RequestMapping
标识一个方法:设置映射请求路径的具体信息
@Controller
@RequestMapping("/test")
public class RequestMappingController
// 此时浏览器具体请求路径为:/test/testRequestMapping
@RequestMapping("/testRequestMapping")
public String testRequestMapping()
return "success";
2.2 value、method 属性
-
@RequestMapping
注解的value
属性通过请求的请求地址匹配请求映射(value 属性必不可少)。value
属性是一个String
类型的数组,表示该控制器方法可以响应多个对应的请求地址@RequestMapping(value = "/testRequestMapping", "/test") public String testRequestMapping() return "success";
<!DOCTYPE html> <!-- 需要引入 thymeleaf 的 th 名称空间 --> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <a th:href="@/test">get request</a><br> <!-- 使用 Thymeleaf @/ 的形式可动态获取当前工程的上下文路径 --> <form th:action="@/testRequestMapping" method="post"> <input type="submit"> </form> </body> </html>
-
@RequestMapping
注解的method
属性是通过请求的请求方式来匹配请求映射。method 属性是一个RequestMethod
类型的数组,表示该请求映射能够匹配多种请求方式的请求(不配置 method 属性的时表示当前控制器方法可以匹配所有请求方式的请求)@RequestMapping(value = "/testRequestMapping", "/test", method = RequestMethod.GET, RequestMethod.POST) public String testRequestMapping() return "success";
-
若当前请求的请求地址满足请求映射的
value
属性,但是请求方式不满足method
属性,则浏览器报错405:Request method 'POST' not supported
-
method 的派生注解:目前浏览器只支持 get 和 post,若在 form 表单提交时,为 method 设置了其他请求方式的字符串(put 或 delete),则按照默认的请求方式 get 进行处理
@PostMapping
:处理post
请求的映射(增)@DeleteMapping
:处理delete
请求的映射(删)@PutMapping
:处理put
请求的映射(改)@GetMapping
:处理get
请求的映射(查)
2.3 params、headers 属性
-
@RequestMapping
注解的params
属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系param
:请求必须携带 param 参数!param
:请求不能携带 param 参数param=value
:请求必须携带 param 参数且 param=valueparam!=value
:请求必须携带 param 参数且 param!=value
// 请求必须携带 username 和 password 参数且值为 bear(否则报错 400参数不匹配) // 请求头中必须携带 Connection 和 Host 参数且值为指定值(否则报错 404) @RequestMapping( value = "/testParamsAndHeaders", params = "username=bear", "password=bear", headers = "Connection=keep-alive", "Host=localhost:8080") public String testParamsAndHeaders() return "success";
<a th:href="@/testParamsAndHeaders(username='bear',password='bear')">1. testParamsAndHeaders</a>
-
headers 属性的使用方法与 params 一致
2.4 Ant 风格编程
// 1. ? 匹配任意单个字符
@RequestMapping("/?testAnt")
// 2. * 零到多个字符
@RequestMapping("/*testAnt")
// 3. ** 零到多层目录,** 前后不能添加内容
@RequestMapping("/**/testAnt")
<!-- 1. 任意单个字符 -->
<a th:href="@/0testAnt">1. testAnt -> ?</a>
<!-- 2. 零到多个字符 -->
<a th:href="@/gsfgrtestAnt">2. testAnt -> *</a>
<!-- 3. 零到多层目录 -->
<a th:href="@/123/dfa/testAnt">3. testAnt -> **</a><hr/>
2.5 路径中的占位符
/**
* 原始方式:/deleteUser?id=1 REST 方式:/deleteUser/1
* 通过 占位符占据请求参数的位置
* @param username 通过 @PathVariable 注解将占位符所表示的数据赋值给控制器方法的形参
*/
@RequestMapping("/testPath/username/password")
public String testPath(@PathVariable("username") String username, @PathVariable("password") String password)
System.out.println("username:" + username);
System.out.println("password:" + password);
return "success";
<!-- 以路径方式传输数据到服务器 -->
<a th:href="@/testPath/Spring-_-Bear/springbear">测试 RequestMapping 中的占位符</a>
三、请求参数获取
3.1 原生 Servlet
// 不推荐(侮辱 SpringMVC?)
@RequestMapping("/testServletApi")
public String testServletApi(HttpServletRequest request)
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username + " " + password);
return "success";
<a th:href="@/testServletApi(username='Spring-_-Bear',password='bear')">测试 Servlet Api 获取请求参数</a>
3.2 形参列表
/**
* 当通过形参获取一个 name 对应多个 value 属性时,
* 可以用 String[] 接收,也可以直接用 String 接收,此时各 value 之间使用 , 间隔
*/
@RequestMapping("/testParam")
public String testParam(String username, String password, String[] hobby)
System.out.println(username + " " + password);
System.out.println(Arrays.toString(hobby));
return "success";
3.3 @RequestParam
/**
* 通过 @RequestParam 注解的 value 属性可映射浏览器请求请求参数名(name 属性)与控制器方法形参的关系,
* required 属性可指定浏览器请求参数是否必须携带此参数,为 true 且浏览器请求中未携带且未设置默认值则报错 400
* defaultValue 属性不管 required 属性值为 true 或 false,当 value 所指定的请求参数没有传输或传输的值为 "" 时,则使用默认值为形参赋值
*/
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "user_name", required = false, defaultValue = "bear") String username)
System.out.println(username);
return "success";
3.4 @RequestHeader
@RequestHeader
是将请求头信息和控制器方法的形参创建映射关系- @RequestHeader 注解一共有三个属性:value、required、defaultValue,用法同 @RequestParam
3.5 @CookieValue
@CookieValue
是将cookie
数据和控制器方法的形参创建映射关系- @CookieValue 注解一共有三个属性:value、required、defaultValue,用法同 @RequestParam
- 第一次创建
session
会话时,服务器创建Cookie
并响应给浏览器(浏览器 Cookie 信息存在于响应报文中),此后的请求Cookie
存在于请求报文中
3.6 POJO 对象
// 若请求参数中不存在的 POJO 对象中的字段时则对应字段值为 null
@RequestMapping("/testPojo")
public String testPojo(User user)
System.out.println(user);
return "success";
3.7 中文乱码
-
在 web.xml 中配置编码过滤器
CharacterEncodingFilter
,需将其配置为第一个过滤器,因为过滤器的拦截顺序安装配置的顺序依次拦截<!--配置 springMVC 的编码过滤器--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> 以上是关于[Study]SpringMVC的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring MVC 中的不同类中创建动态 bean