学习资源

  1. 视频课程
  2. 时长统计小工具

学习笔记

一、SpringMVC概述

  • 轻量级基于MVC的web层应用框架
  • 与Spring框架集成(IOC、AOP)
  • 支持Restful风格
  • 支持灵活的URL到页面控制器的映射

1. IDEA2020.2dds创建SpringMVC项目

1.1 新建项目

20201124104713.png
20201124104730.png

1.2 添加框架支持

20201124104806.png
20201124104842.png
20201124104903.png

  • 实际引用的jar包

image.png

1.3 配置xml

1.3.1 配置 web.xml
  1. <!-- servlet标签 -->
  2. <servlet>
  3. <servlet-name>dispatcher</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <!--标记容器是否在启动的时候就加载这个servlet。
  6. 当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
  7. 当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
  8. 正数的值越小,启动该servlet的优先级越高。-->
  9. <load-on-startup>1</load-on-startup>
  10. </servlet>
  11. <servlet-mapping>
  12. <servlet-name>dispatcher</servlet-name>
  13. <!--访问路径以 form 结尾的才会被 dispatcher 拦截
  14. <url-pattern>*.form</url-pattern>-->
  15. <!--/ 和 /* 区别是 / 仅包含请求访问,而 /* 是全局页面和请求都会被当前servlet拦截-->
  16. <url-pattern>/</url-pattern>
  17. </servlet-mapping>

1.3.2 配置 DispatcherServlet.xml
  • 配置完成 DispatcherServlet 会自动加载配置文件,

    • 配置文件有默认路径(web/WEB-INF/
    • 默认名称(-servlet.xml),例如上图配置方式那么配置文件名为 dispatcher-servlet.xml
      1. <!-- dispatcher-servlet.xml -->
      2. <?xml version="1.0" encoding="UTF-8"?>
      3. <beans xmlns="http://www.springframework.org/schema/beans"
      4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      5. xmlns:context="http://www.springframework.org/schema/context"
      6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
      8. <!-- 扫描组件,将 @Controller 注解的类作为SpringMVC的控制层 -->
      9. <context:component-scan base-package="xyz.simorel" />
      10. <!-- 配置视图解析器
      11. 作用:将 prefix + 视图名称 + suffix 确定最终跳转页面
      12. /WEB-INF/view/success.jsp
      13. -->
      14. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      15. <property name="prefix" value="/WEB-INF/"></property>
      16. <property name="suffix" value=".jsp"></property>
      17. </bean>
      18. </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”; // 实际返回的是 视图名称 } }

  1. - 最终跳转到 web/WEB-INF/view/success.jsp
  2. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/339035/1606191429968-7d9ff3fe-2ed1-4f61-a862-9472c4abbb12.png#align=left&display=inline&height=107&margin=%5Bobject%20Object%5D&name=image.png&originHeight=107&originWidth=248&size=5803&status=done&style=none&width=248)
  3. <a name="0sCDj"></a>
  4. ## 二、@RequestMapping注解
  5. - 当注解只有一个属性时可以省略 `(value = "xxx")` 直接写 `("xxx")`
  6. - `@RequestMapping` 设置请求映射,把请求和控制层方法设置映射关系,当请求路径和 `@RequestMapping` 中的value属性一致时,则该注解所标注的方法即为处理请求的方法
  7. <a name="kEnRl"></a>
  8. ### 1. 注解属性
  9. <a name="lemNi"></a>
  10. #### 1.1 method
  11. 设置请求方式,只有请求方式和method一致,才能处理请求
  12. - 可用值
  13. - RequestMethod.GET
  14. - RequestMethod.POST
  15. - RequestMethod..PUT
  16. - RequestMethod.DELETE
  17. <a name="2zmw4"></a>
  18. #### 1.2 params
  19. 设置客户端传递到客户端参数,支持表达式
  20. - `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"age!=12"``})`
  21. 请求参数中age不能为12,或者不写age参数也是可以的
  22. - `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"!age"``})`
  23. `!age` 请求参数中不能包含 age
  24. - `@RequestMapping``(value = ``"/ceshiparams"``, ``params = {``"username"``, ``"age=12"``})` <br /> 请求参数中必须包含age参数,且其值必须为12,否则请求失败
  25. <a name="MZ5CV"></a>
  26. #### 1.3 headers
  27. 设置请求头信息,所发送请求请求头信息必须和设置的请求头一致<br />`headers = {"Accept-Language=zh-CN,zh;"}`
  28. <a name="woBFO"></a>
  29. ### 2. RequestMapping 注解位置
  30. - RequestMapping 注解位于类顶部时,代表类内所有方法都可以作为请求处理方法,但是这个时候路径就要由之前直接 `/[``方法注解value]` 变为 `/[类注解value]/[方法注解value]`
  31. - 作用是切分不同模块,看一眼就知道这个请求属于哪个模块
  32. <a name="Ge4lH"></a>
  33. ### 3. Ant路径风格
  34. - Ant 风格资源地址支持 3 种通配符:
  35. - ? : 匹配文件名中的一个字符
  36. - * : 匹配文件名中的任意字符
  37. - ** : 匹配多层路径
  38. ```java
  39. package xyz.simorel;
  40. import org.springframework.stereotype.Controller;
  41. import org.springframework.web.bind.annotation.RequestMapping;
  42. @Controller
  43. public class SpingMVCControllerAnt {
  44. /** http://localhost:8080/springmvc/mvc/testant */
  45. @RequestMapping("/*/testant")
  46. public String test() {
  47. System.out.println("/*/testant");
  48. return "success";
  49. }
  50. /** http://localhost:8080/springmvc/mvc/ant12/testant */
  51. @RequestMapping("/*/ant??/testant")
  52. public String test1() {
  53. System.out.println("/*/ant??/testant");
  54. return "success";
  55. }
  56. /** http://localhost:8080/springmvc/mvc/ant12/a/b/c/testant */
  57. @RequestMapping("/*/ant??/**/testant")
  58. public String test2() {
  59. System.out.println("/*/ant??/**/testant");
  60. return "success";
  61. }
  62. }

4. 解析占位符

为了解析原先 user?id=1001 改变为 user/1001 , 这个时候就要用到占位符了

  1. 路径使用 /{xxx}/{yyy} 方式匹配

  2. @PathVariable(“xxx”) 此注解用于获取请求路径上的参数并装欢类型为指定形参类型

  1. package xyz.simorel;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.PathVariable;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. @Controller
  6. public class SpringMVCControllerPlaceholder {
  7. @RequestMapping("/placeholder/{id}/{username}")
  8. // 通过 @PathVariable 注解获取请求链接上的属性值,赋给对应的形参
  9. public String test(@PathVariable("id")Integer id, @PathVariable("username")String username) {
  10. System.out.println("placeholder");
  11. System.out.println(id + " --> " + username);
  12. return "success";
  13. }
  14. }

三、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 筛选器

    1. <!--筛选器-->
    2. <filter>
    3. <filter-name>HiddenHttpMethodFilter</filter-name>
    4. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    5. </filter>
    6. <filter-mapping>
    7. <filter-name>HiddenHttpMethodFilter</filter-name>
    8. <url-pattern>/*</url-pattern>
    9. </filter-mapping>
  • 此时请求需满足几个条件

    • POST 请求
    • 携带参数 _method
  • 结果
    • 若不符合条件 —> 仍是 post 请求
    • 符合条件,经过转换后,变为真正的 _method 设定的请求方式

四、处理请求数据

  • 复习
    • JavaWEB: HttpServletRequest
      • Request.getParamter(参数名)
      • Request.getParamterMap()
      • Request.getCookies()
      • Request.getHeader()

1. 获取POST请求参数

1.1 通过形参获取POST请求参数

保持 形参参数名 请求参数的参数名 一致,来自动赋值

1.2 通过 @RequestParam 注解获取POST请求参数

  • @RequestParam 注解参数
    • value 配置请求参数名,映射关系
    • required 是否必填,默认true(必填)
    • defaultValue 默认参数,当未传此参数时,使用默认参数
      1. @RequestMapping(method = RequestMethod.POST)
      2. public String param(@RequestParam(value = "name", required = false, defaultValue = "admin") String username, String password, String age) {
      3. }

2. 获取请求头数据

  • @RequestHeader 注解参数,获取请求头数据
    • value 配置请求参数名,映射关系
    • required 是否必填,默认true(必填)
    • defaultValue 默认参数,当未传此参数时,使用默认参数

3. 获取Cookie数据

  • @CookieValue 获取请求中的Cookie数据
    • value 配置请求参数名,映射关系
    • required 是否必填,默认true(必填)
    • defaultValue 默认参数,当未传此参数时,使用默认参数

4. 使用POJO作为参数

  • 当使用嵌套类时,可以使用级联选项
  • 要求实体类对象中的属性名一定要和页面表单元素的name属性值一致,且支持级联关系
    1. <form action="pojo" method="post">
    2. username:<input name="username">
    3. password:<input name="password">
    4. age:<input name="age">
    5. province:<input name="address.province">
    6. city:<input name="address.city">
    7. country:<input name="address.country">
    8. <input type="submit" value="提交pojo参数">
    9. </form>

    5. 使用Servlet原生API作为参数

    image.png

五、处理响应数据

1. ModelAndView重要属性和方法

  1. /** 描述视图信息 */
  2. private Object view;
  3. /** 描述模型数据(响应数据) */
  4. private ModelMap model;
  5. /** 设置视图名字 */
  6. public void setViewName(String viewName){}
  7. /** 设置模型数据 */
  8. public ModelAndView addObject(String attributeName, Object attributeValue){return null;}
  9. /** 返回模型数据 */
  10. protected Map<String, Object> getModelInternal(){return null;}
  11. /** 返回模型数据 */
  12. public ModelMap getModelMap(){return null;}
  13. /** 返回模型数据 */
  14. public Map<String, Object> getModel(){return null;}

20201125141208.png

2. 处理模型数据源码调试

2.1 调用请求处理器中的请求处理方法

[DispatcherServlet.java] 1040L
image.png

  1. // Actually invoke the handler.
  2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

2.2 返回一个ModelAndView对象

执行请求处理器中的请求处理方法,方法执行完成后,返回一个ModelAndView对象,最终将ModelAndView对象返回到 DispatcherServlet 的1040行。

2.3 准备ModelAndView

[DispatcherServlet.java] 1057L
image.png

2.4 准备ModelAndView的视图信息还有模型

步入processDispatchResult方法中
[DispatcherServlet.java] 1118L
image.png

2.5 根据ModelAndView中视图信息通过视图解析器得到view视图对象

步入render方法中
[DispatcherServlet.java] 1350L
image.png

2.6 视图对象开始处理模型数据

继续往下执行
[DispatcherServlet.java] 1373L
image.png
render() 方法是 View 接口中定义的,在 AbstractView 类中进行了实现。所有具体的视图类都使用 AbstractView 中实现的 render 方法。

2.7 AbstractView整合输出模型数据

步入view.render方法中
[AbstractView.java] 316L
image.png
renderMergedOutputModel方法是 AbstractView 中定义的抽象方法,在每个具体的视图实现类中进行实现

2.8 InternalResourceView中将模型数据设置到Request域对象中

步入renderMergedOutputModel方法中
[InternalResourceView.java] 142L
image.png
image.png
设置模型数据

2.9 获取转发器

继续向下执行
[InternalResourceView.java] 151L
image.png

2.10 转发

继续向下执行
[InternalResourceView.java] 171L
image.png

3. 使用 ModelAndView

  1. // 方式一:
  2. @RequestMapping(method = RequestMethod.POST)
  3. public ModelAndView test() {
  4. ModelAndView modelAndView = new ModelAndView();
  5. modelAndView.addObject("username", "admin"); // 向request作用域中设置值
  6. modelAndView.setViewName("success"); // 设置视图名称,实现页面跳转
  7. return modelAndView;
  8. }
  9. // 方式二:
  10. @RequestMapping(value = "/map", method = RequestMethod.POST)
  11. public String test1(Map<String, Object> map) {
  12. map.put("username", "admin test"); // 向作用域中存放值
  13. return "success"; // 返回视图名称
  14. }
  15. // 方式三:
  16. @RequestMapping(value = "/model", method = RequestMethod.POST)
  17. public String test2(Model model) {
  18. model.addAttribute("username", "model admin");
  19. return "success"; // 返回视图名称
  20. }

@SessionAttributes 将模型中的某个属性暂存到HttpSession中,以便多个请求共享这个属性

@ModelAttribute 方法入参标注该注解后,入参的对象就会放到数据模型中

六、 视图解析

  • 无论控制器返回一个 String、ModelAndView、View 都会转换为 ModelAndView 对象,由视图解析器解析视图,然后进行页面跳转

image.png

1. View

  • 处理模型数据,实现页面跳转(转发,重定向)
  • view类型
    • InternalResourceView 转发视图
    • JstlView 转发视图(extends InternalResourceView,主要补充了对于 Jstl 的支持)
    • RedirectView 重定向视图
      1. @RequestMapping("/redirect")
      2. public String test3() {
      3. return "redirect:/index.jsp";
      4. }

2. 设置springMVC配置文件及名称

  1. <!-- servlet标签 -->
  2. <servlet>
  3. <servlet-name>dispatcher</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <!-- 设置springMVC读取指定配置文件的位置和名称,而不是再读取原先 /WEB-INF/dispatcher-servlet.xml 配置文件 -->
  6. <init-param>
  7. <param-name>contextConfigLocation</param-name>
  8. <param-value>classpath:conf/springMVC.xml</param-value>
  9. </init-param>
  10. <!--标记容器是否在启动的时候就加载这个servlet。
  11. 当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
  12. 当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
  13. 正数的值越小,启动该servlet的优先级越高。-->
  14. <load-on-startup>1</load-on-startup>
  15. </servlet>
  16. <servlet-mapping>
  17. <servlet-name>dispatcher</servlet-name>
  18. <!--访问路径以 form 结尾的才会被 dispatcher 拦截
  19. <url-pattern>*.form</url-pattern>-->
  20. <!--
  21. / 和 /* 区别是 / 仅包含请求访问
  22. /* 是全局的,jsp页面和请求都会被当前servlet拦截
  23. / 只有请求才会被处理,自动过滤页面jsp
  24. -->
  25. <url-pattern>/</url-pattern>
  26. </servlet-mapping>

2. 变更编码防止中文乱码

  1. <!-- 编码配置器必须配置在首位,因为有缓存过滤器的话就不会再重复创建 -->
  2. <filter>
  3. <filter-name>CharacterEncodingFilter</filter-name>
  4. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  5. <!-- 配置编码 -->
  6. <init-param>
  7. <param-name>encoding</param-name>
  8. <param-value>UTF-8</param-value>
  9. </init-param>
  10. </filter>
  11. <filter-mapping>
  12. <filter-name>CharacterEncodingFilter</filter-name>
  13. <url-pattern>/*</url-pattern>
  14. </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
  • 显示效果

    • LastName input
    • Email input
    • Gender select
    • Department select
    • Submit button
      1.2.2 添加员工信息
  • 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 类

  • 实体类: EmployeeDepartment

image.png

  • Handler:EmployeeHandler
  • Dao: EmployeeDaoDepartmentDao

1.6 页面

  • list.jsp
  • input.jsp
  • edit.jsp

2. 如何放行静态资源(比如 jQuery)

在模块配置中新增:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:mvc ="http://www.springframework.org/schema/mvc"
  5. xmlns="http://www.springframework.org/schema/beans"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/mvc
  11. http://www.springframework.org/schema/mvc/spring-mvc.xsd"
  12. >
  13. <!-- 扫描组件,将 @Controller 注解的类作为SpringMVC的控制层 -->
  14. <context:component-scan base-package="xyz.simorel"/>
  15. <!-- 配置视图解析器
  16. 作用:将 prefix + 视图名称 + suffix 确定最终跳转页面
  17. /WEB-INF/view/success.jsp
  18. -->
  19. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  20. <property name="prefix" value="/WEB-INF/view/"></property>
  21. <property name="suffix" value=".jsp"></property>
  22. </bean>
  23. <!-- 解决静态资源无法请求问题 -->
  24. <mvc:default-servlet-handler/>
  25. <mvc:annotation-driven />
  26. </beans>

3. 使用a标签发送DELETE请求

  1. <head>
  2. <script type="text/javascript" src="static/jquery-3.5.1.min.js"></script>
  3. <script type="text/javascript">
  4. $(function () {
  5. $('.delete').click(function () {
  6. console.log('delete click');
  7. const href = $(this).attr('href');
  8. console.log('href', href);
  9. $('form').attr('action', href).submit();
  10. return false;
  11. })
  12. })
  13. </script>
  14. </head>
  15. <body>
  16. <form action="" method="POST">
  17. <input type="hidden" name="_method" value="DELETE">
  18. </form>
  19. <a class="delete" href="emp/${emp.id}">Delete</a>
  20. </body>

4. 数据转换

5. 数据格式化

6. 数据校验