学习资源
学习笔记
一、SpringMVC概述
- 轻量级基于MVC的web层应用框架
- 与Spring框架集成(IOC、AOP)
- 支持Restful风格
- 支持灵活的URL到页面控制器的映射
1. IDEA2020.2dds创建SpringMVC项目
1.1 新建项目
1.2 添加框架支持



- 实际引用的jar包
1.3 配置xml
1.3.1 配置 web.xml
<!-- servlet标签 --><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--标记容器是否在启动的时候就加载这个servlet。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><!--访问路径以 form 结尾的才会被 dispatcher 拦截<url-pattern>*.form</url-pattern>--><!--/ 和 /* 区别是 / 仅包含请求访问,而 /* 是全局页面和请求都会被当前servlet拦截--><url-pattern>/</url-pattern></servlet-mapping>
1.3.2 配置 DispatcherServlet.xml
配置完成 DispatcherServlet 会自动加载配置文件,
- 配置文件有默认路径(web/WEB-INF/)
- 默认名称(
-servlet.xml),例如上图配置方式那么配置文件名为 dispatcher-servlet.xml <!-- dispatcher-servlet.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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描组件,将 @Controller 注解的类作为SpringMVC的控制层 --><context:component-scan base-package="xyz.simorel" /><!-- 配置视图解析器作用:将 prefix + 视图名称 + suffix 确定最终跳转页面/WEB-INF/view/success.jsp--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/"></property><property name="suffix" value=".jsp"></property></bean></beans>
1.4 创建一个 POJO
在类上添加注解 @Controller,SpringMVC就可以将此类作为控制层加载,使其处理请求响应
- Controller
- RequestMapping(value = “xxx”)
- 返回一个字符串这个字符串是视图名称,跳转到指定页面 ```java package xyz.simorel; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class SpringMVCController { /* 假设客户端请求路径为:localhost:8080/spingmvc/hello / @RequestMapping(“hello”) // 请求映射,最佳实践 方法名和映射名 保持一致 public String helloTest() { System.out.println(“success”); return “success”; // 实际返回的是 视图名称 } }
- 最终跳转到 web/WEB-INF/view/success.jsp 中<a name="0sCDj"></a>## 二、@RequestMapping注解- 当注解只有一个属性时可以省略 `(value = "xxx")` 直接写 `("xxx")`- `@RequestMapping` 设置请求映射,把请求和控制层方法设置映射关系,当请求路径和 `@RequestMapping` 中的value属性一致时,则该注解所标注的方法即为处理请求的方法<a name="kEnRl"></a>### 1. 注解属性<a name="lemNi"></a>#### 1.1 method设置请求方式,只有请求方式和method一致,才能处理请求- 可用值- RequestMethod.GET- RequestMethod.POST- RequestMethod..PUT- RequestMethod.DELETE<a name="2zmw4"></a>#### 1.2 params设置客户端传递到客户端参数,支持表达式- `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"age!=12"``})`请求参数中age不能为12,或者不写age参数也是可以的- `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"!age"``})``!age` 请求参数中不能包含 age- `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"age=12"``})` <br /> 请求参数中必须包含age参数,且其值必须为12,否则请求失败<a name="MZ5CV"></a>#### 1.3 headers设置请求头信息,所发送请求请求头信息必须和设置的请求头一致<br />`headers = {"Accept-Language=zh-CN,zh;"}`<a name="woBFO"></a>### 2. RequestMapping 注解位置- 当RequestMapping 注解位于类顶部时,代表类内所有方法都可以作为请求处理方法,但是这个时候路径就要由之前直接 `/[``方法注解value]` 变为 `/[类注解value]/[方法注解value]`- 作用是切分不同模块,看一眼就知道这个请求属于哪个模块<a name="Ge4lH"></a>### 3. Ant路径风格- Ant 风格资源地址支持 3 种通配符:- ? : 匹配文件名中的一个字符- * : 匹配文件名中的任意字符- ** : 匹配多层路径```javapackage xyz.simorel;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class SpingMVCControllerAnt {/** http://localhost:8080/springmvc/mvc/testant */@RequestMapping("/*/testant")public String test() {System.out.println("/*/testant");return "success";}/** http://localhost:8080/springmvc/mvc/ant12/testant */@RequestMapping("/*/ant??/testant")public String test1() {System.out.println("/*/ant??/testant");return "success";}/** http://localhost:8080/springmvc/mvc/ant12/a/b/c/testant */@RequestMapping("/*/ant??/**/testant")public String test2() {System.out.println("/*/ant??/**/testant");return "success";}}
4. 解析占位符
为了解析原先 user?id=1001 改变为 user/1001 , 这个时候就要用到占位符了
路径使用 /{xxx}/{yyy} 方式匹配
@PathVariable(“xxx”) 此注解用于获取请求路径上的参数并装欢类型为指定形参类型
package xyz.simorel;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class SpringMVCControllerPlaceholder {@RequestMapping("/placeholder/{id}/{username}")// 通过 @PathVariable 注解获取请求链接上的属性值,赋给对应的形参public String test(@PathVariable("id")Integer id, @PathVariable("username")String username) {System.out.println("placeholder");System.out.println(id + " --> " + username);return "success";}}
三、RESTful
| 方法 | 过去 | RESTful |
|---|---|---|
| 添加 add | insertUser POST | /user POST |
| 修改 update | getUserById GET —> updateUser POST | /user PUT |
| 删除 delete | deleteUser POST | /user/1001 DELETE |
| 查找 find | findAll GET | /user/1001 GET |
1. 方法转换
- 作用:方便 PUT / DELETE 请求可以不用配置请求方式,利用传参的方式区分
配置 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
- 结果
- 若不符合条件 —> 仍是 post 请求
- 符合条件,经过转换后,变为真正的 _method 设定的请求方式
四、处理请求数据
- 复习
- JavaWEB: HttpServletRequest
- Request.getParamter(参数名)
- Request.getParamterMap()
- Request.getCookies()
- Request.getHeader()
- JavaWEB: HttpServletRequest
1. 获取POST请求参数
1.1 通过形参获取POST请求参数
保持 形参参数名 和 请求参数的参数名 一致,来自动赋值
1.2 通过 @RequestParam 注解获取POST请求参数
@RequestParam注解参数- value 配置请求参数名,映射关系
- required 是否必填,默认true(必填)
- defaultValue 默认参数,当未传此参数时,使用默认参数
@RequestMapping(method = RequestMethod.POST)public String param(@RequestParam(value = "name", required = false, defaultValue = "admin") String username, String password, String age) {}
2. 获取请求头数据
@RequestHeader注解参数,获取请求头数据- value 配置请求参数名,映射关系
- required 是否必填,默认true(必填)
- defaultValue 默认参数,当未传此参数时,使用默认参数
3. 获取Cookie数据
@CookieValue获取请求中的Cookie数据- value 配置请求参数名,映射关系
- required 是否必填,默认true(必填)
- defaultValue 默认参数,当未传此参数时,使用默认参数
4. 使用POJO作为参数
- 当使用嵌套类时,可以使用级联选项
- 要求实体类对象中的属性名一定要和页面表单元素的name属性值一致,且支持级联关系
<form action="pojo" method="post">username:<input name="username">password:<input name="password">age:<input name="age">province:<input name="address.province">city:<input name="address.city">country:<input name="address.country"><input type="submit" value="提交pojo参数"></form>
5. 使用Servlet原生API作为参数

五、处理响应数据
1. ModelAndView重要属性和方法
/** 描述视图信息 */private Object view;/** 描述模型数据(响应数据) */private ModelMap model;/** 设置视图名字 */public void setViewName(String viewName){}/** 设置模型数据 */public ModelAndView addObject(String attributeName, Object attributeValue){return null;}/** 返回模型数据 */protected Map<String, Object> getModelInternal(){return null;}/** 返回模型数据 */public ModelMap getModelMap(){return null;}/** 返回模型数据 */public Map<String, Object> getModel(){return null;}
2. 处理模型数据源码调试
2.1 调用请求处理器中的请求处理方法
[DispatcherServlet.java] 1040L
// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
2.2 返回一个ModelAndView对象
执行请求处理器中的请求处理方法,方法执行完成后,返回一个ModelAndView对象,最终将ModelAndView对象返回到 DispatcherServlet 的1040行。
2.3 准备ModelAndView
[DispatcherServlet.java] 1057L
2.4 准备ModelAndView的视图信息还有模型
步入processDispatchResult方法中
[DispatcherServlet.java] 1118L
2.5 根据ModelAndView中视图信息通过视图解析器得到view视图对象
步入render方法中
[DispatcherServlet.java] 1350L
2.6 视图对象开始处理模型数据
继续往下执行
[DispatcherServlet.java] 1373L
render() 方法是 View 接口中定义的,在 AbstractView 类中进行了实现。所有具体的视图类都使用 AbstractView 中实现的 render 方法。
2.7 AbstractView整合输出模型数据
步入view.render方法中
[AbstractView.java] 316L
renderMergedOutputModel方法是 AbstractView 中定义的抽象方法,在每个具体的视图实现类中进行实现
2.8 InternalResourceView中将模型数据设置到Request域对象中
步入renderMergedOutputModel方法中
[InternalResourceView.java] 142L

设置模型数据
2.9 获取转发器
继续向下执行
[InternalResourceView.java] 151L
2.10 转发
继续向下执行
[InternalResourceView.java] 171L
3. 使用 ModelAndView
// 方式一:@RequestMapping(method = RequestMethod.POST)public ModelAndView test() {ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("username", "admin"); // 向request作用域中设置值modelAndView.setViewName("success"); // 设置视图名称,实现页面跳转return modelAndView;}// 方式二:@RequestMapping(value = "/map", method = RequestMethod.POST)public String test1(Map<String, Object> map) {map.put("username", "admin test"); // 向作用域中存放值return "success"; // 返回视图名称}// 方式三:@RequestMapping(value = "/model", method = RequestMethod.POST)public String test2(Model model) {model.addAttribute("username", "model admin");return "success"; // 返回视图名称}
@SessionAttributes 将模型中的某个属性暂存到HttpSession中,以便多个请求共享这个属性
@ModelAttribute 方法入参标注该注解后,入参的对象就会放到数据模型中
六、 视图解析
- 无论控制器返回一个 String、ModelAndView、View 都会转换为 ModelAndView 对象,由视图解析器解析视图,然后进行页面跳转
1. View
- 处理模型数据,实现页面跳转(转发,重定向)
- view类型
- InternalResourceView 转发视图
- JstlView 转发视图(extends InternalResourceView,主要补充了对于 Jstl 的支持)
- RedirectView 重定向视图
@RequestMapping("/redirect")public String test3() {return "redirect:/index.jsp";}
2. 设置springMVC配置文件及名称
<!-- servlet标签 --><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 设置springMVC读取指定配置文件的位置和名称,而不是再读取原先 /WEB-INF/dispatcher-servlet.xml 配置文件 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:conf/springMVC.xml</param-value></init-param><!--标记容器是否在启动的时候就加载这个servlet。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><!--访问路径以 form 结尾的才会被 dispatcher 拦截<url-pattern>*.form</url-pattern>--><!--/ 和 /* 区别是 / 仅包含请求访问/* 是全局的,jsp页面和请求都会被当前servlet拦截/ 只有请求才会被处理,自动过滤页面jsp--><url-pattern>/</url-pattern></servlet-mapping>
2. 变更编码防止中文乱码
<!-- 编码配置器必须配置在首位,因为有缓存过滤器的话就不会再重复创建 --><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></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
七、RESTful CRUD
1. 设计
1.1 显示所有员工信息
- URI: emps
- method: GET | ID | LastName | Email | Gender | Department | Edit | Delete | | —- | —- | —- | —- | —- | —- | —- | | 1001 | AA | aa@163.com | Male/Female | AA | Edit | Delete |
1.2 添加员工
1.2.1 显示添加页面
- URI: emp
- method: GET
显示效果
URI: emp
- method: POST
- 完成添加,重定向到list页面
1.3 删除员工
- URL: emp/{id}
- method: DELETE
- 删除后对应记录从数据表中删除
1.4 修改员工
LastName不可修改
1.4.1 修改页面
- URL: emp/{id}
- GET
- 回显表单
1.4.2 修改员工信息
- URL: emp
- PUT
- 修改完成重定向回list页
1.5 类
- 实体类:
Employee、Department

- Handler:
EmployeeHandler - Dao:
EmployeeDao、DepartmentDao
1.6 页面
- list.jsp
- input.jsp
- edit.jsp
2. 如何放行静态资源(比如 jQuery)
在模块配置中新增:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc ="http://www.springframework.org/schema/mvc"xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 扫描组件,将 @Controller 注解的类作为SpringMVC的控制层 --><context:component-scan base-package="xyz.simorel"/><!-- 配置视图解析器作用:将 prefix + 视图名称 + suffix 确定最终跳转页面/WEB-INF/view/success.jsp--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/view/"></property><property name="suffix" value=".jsp"></property></bean><!-- 解决静态资源无法请求问题 --><mvc:default-servlet-handler/><mvc:annotation-driven /></beans>
3. 使用a标签发送DELETE请求
<head><script type="text/javascript" src="static/jquery-3.5.1.min.js"></script><script type="text/javascript">$(function () {$('.delete').click(function () {console.log('delete click');const href = $(this).attr('href');console.log('href', href);$('form').attr('action', href).submit();return false;})})</script></head><body><form action="" method="POST"><input type="hidden" name="_method" value="DELETE"></form><a class="delete" href="emp/${emp.id}">Delete</a></body>

