[Study]SpringMVC

Posted Spring-_-Bear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Study]SpringMVC相关的知识,希望对你有一定的参考价值。

文章目录

一、概述及示例

1.1 MVC 思想介绍

  1. MVC 是一种软件架构的思想,将软件按照模型(model)、视图(view)、控制器(controller)来划分

  2. M(Model):模型层,指工程中的 JavaBean,作用是处理数据。JavaBean分为以下两类

    1. 一类称为实体 Bean:用于存储业务数据,如 Student、User 等
    2. 一类称为业务 Bean:指 ServiceDao 对象,专门用于处理业务逻辑和数据访问
  3. V(View):视图层,指工程中的 htmlJSP 等页面,作用是与用户进行交互,展示数据

  4. C(Controller):控制层,指工程中的 Servlet,作用是接收请求和响应浏览器

  5. MVC 的工作流程

    1. 用户通过视图层(view)发送请求到服务器,在服务器中请求被 Controller 接收
    2. Controller 调用相应的 Model 层处理请求
    3. 模型层处理完毕后将结果返回到Controller
    4. Controller 根据请求处理的结果找到相应的 View
    5. 由视图层渲染数据后最终响应给浏览器

1.2 SpringMVC 概述

SpringMVCSpring 的一个后续产品,是 Spring 的一个子项目。SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案,在表述层框架历经 StrustWebWorkStrust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 JavaEE 项目表述层开发的首选方案。相比其它框架,SpringMVC 具有以下显著特点

  1. Spring 家族原生产品,与 IOC 容器等基础组件无缝对接
  2. 基于原生的 Servlet,通过功能强大的前端控制器 DispatcherServlet 对请求和响应进行统一处理
  3. 可插拔式组件即插即用,内部组件化程度高,想要什么功能配置相应组件即可
  4. 性能卓著,尤其适合现代大型、超大型互联网项目要求

1.3 HelloWorld

  1. 新建 maven 工程,给普通的 maven 工程添加 web 模块(添加 web.xml、指定工程上下文路径到 webapp

  2. 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>
    
  3. 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>
    
  4. 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>
    
  5. 创建请求控制器 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";
        
    
    
  6. 创建前端页面 hello.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello World</title>
    </head>
    <body>
    <h1>Hello World</h1>
    </body>
    </html>
    
  7. 部署 Tomcat 访问

  8. 项目结构如下

  9. 访问成功

1.4 请求响应流程

  1. 浏览器发送请求,若请求地址符合前端控制器的 url-pattern,该请求就会被前端控制器 DispatcherServlet 捕获
  2. 前端控制器会读取 SpringMVC 的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中 @RequestMapping 注解的 value 属性值进行匹配
  3. 若匹配成功,该注解所标识的控制器方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析
  4. 视图解析器加上前缀和后缀组成视图的路径,通过 Thymeleaf 对视图进行渲染,最终转发到视图所对应页面

二、请求映射

2.1 注解的使用位置

  1. @RequestMapping 标识一个类:设置映射请求路径初始信息
  2. @RequestMapping 标识一个方法:设置映射请求路径的具体信息
@Controller
@RequestMapping("/test")
public class RequestMappingController 
	// 此时浏览器具体请求路径为:/test/testRequestMapping
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping()
        return "success";
    

2.2 value、method 属性

  1. @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>
    
  2. @RequestMapping 注解的 method 属性是通过请求的请求方式来匹配请求映射。method 属性是一个 RequestMethod 类型的数组,表示该请求映射能够匹配多种请求方式的请求(不配置 method 属性的时表示当前控制器方法可以匹配所有请求方式的请求)

    @RequestMapping(value = "/testRequestMapping", "/test", method = RequestMethod.GET, RequestMethod.POST)
    public String testRequestMapping()
        return "success";
    
    
  3. 若当前请求的请求地址满足请求映射的 value 属性,但是请求方式不满足 method 属性,则浏览器报错 405:Request method 'POST' not supported

  4. method 的派生注解:目前浏览器只支持 get 和 post,若在 form 表单提交时,为 method 设置了其他请求方式的字符串(put 或 delete),则按照默认的请求方式 get 进行处理

    1. @PostMapping:处理 post 请求的映射(增)
    2. @DeleteMapping:处理 delete 请求的映射(删)
    3. @PutMapping:处理 put 请求的映射(改)
    4. @GetMapping:处理 get 请求的映射(查)

2.3 params、headers 属性

  1. @RequestMapping 注解的 params 属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系

    1. param:请求必须携带 param 参数
    2. !param:请求不能携带 param 参数
    3. param=value:请求必须携带 param 参数且 param=value
    4. param!=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>
    
  2. 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

  1. @RequestHeader 是将请求头信息和控制器方法的形参创建映射关系
  2. @RequestHeader 注解一共有三个属性:value、required、defaultValue,用法同 @RequestParam

3.5 @CookieValue

  1. @CookieValue 是将 cookie 数据和控制器方法的形参创建映射关系
  2. @CookieValue 注解一共有三个属性:value、required、defaultValue,用法同 @RequestParam
  3. 第一次创建 session 会话时,服务器创建 Cookie 并响应给浏览器(浏览器 Cookie 信息存在于响应报文中),此后的请求 Cookie 存在于请求报文中

3.6 POJO 对象

// 若请求参数中不存在的 POJO 对象中的字段时则对应字段值为 null
@RequestMapping("/testPojo")
public String testPojo(User user) 
    System.out.println(user);
    return "success";

3.7 中文乱码

  1. 在 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的主要内容,如果未能解决你的问题,请参考以下文章

    第七天冲刺

    leo--study

    如何在 Spring MVC 中的不同类中创建动态 bean

    poj 3539 Elevator——同余类bfs

    如何将一个控制器中的会话变量访问到 SpringMVC 中的另一个控制器?

    webpack server 怎么静态资源路径