2022尚硅谷SSM框架跟学(八)Spring MVC基础三

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

2022尚硅谷SSM框架跟学 八 Spring MVC基础三

8.RESTful案例

8.1准备工作

和传统 CRUD 一样实现对员工信息的增删改查。

  • 搭建环境
  • 准备实体类
    创建实体类Employee.java
    在这里插入图片描述
    代码如下
package com.atguigu.pojo;

/**
 * @ClassName: Employee
 * @Description:
 * @Author: wty
 * @Date: 2023/1/31
 */

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    //1 male, 0 female
    private Integer gender;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Employee(Integer id, String lastName, String email, Integer
            gender) {
        super();
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
    }

    public Employee() {
    }
}

  • 准备dao模拟数据
    在这里插入图片描述
    代码如下
package com.atguigu.dao;

import com.atguigu.pojo.Employee;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: EmployeeDao
 * @Description:
 * @Author: wty
 * @Date: 2023/1/31
 */
@Repository
public class EmployeeDao {
    private static Map<Integer, Employee> employees = null;

    static {
        employees = new HashMap<Integer, Employee>();
        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
    }

    private static Integer initId = 1006;

    public void save(Employee employee) {
        if (employee.getId() == null) {
            employee.setId(initId++);
        }
        employees.put(employee.getId(), employee);

    }

    public Collection<Employee> getAll() {
        return employees.values();
    }

    public Employee get(Integer id) {
        return employees.get(id);
    }

    public void delete(Integer id) {
        employees.remove(id);
    }

}

创建控制层EmployeeController.java
在这里插入图片描述

8.2功能清单

功能URL 地址请求方式
访问首页√/GET
查询全部数据√/employeeGET
删除√/employee/2DELETE
跳转到添加数据页面√/toAddGET
执行保存√/employeePOST
跳转到更新数据页面√/employee/2GET
执行更新√/employeePUT

8.3.具体功能访问首页

(1).配置view-controller

在springmvc.xml增加如下配置

    <!-- 配置视图控制器 -->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>

(2).创建页面

给控制层EmployeeController.java添加代码要使用Dao层调用业务逻辑。

@Autowired
    private EmployeeDao employeeDao;

只是这么加的话发现自动装配的注解报错了
在这里插入图片描述
于是我们更改springmvc.xml扩大扫描控制层的包的范围

    <!-- 扫描控制层组件(自己配置package) -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>

在index.html中添加代码

<hr>
<a th:href="@{/employee}">查询所有的员工信息</a><br>

8.4具体功能查询所有员工数据

(1).控制器方法

在EmployeeController.java中添加方法

    /**
     * 查询所有的员工信息-->/employee-->GET
     */
    @RequestMapping(value = "/employee", method = RequestMethod.GET)
    public String getAllEmployee(ModelMap map) {
        // 获取所有员工信息
        Collection<Employee> all = employeeDao.getAll();
        // 将所有的员工信息在请求域中共享
        map.addAttribute("all", all);
        return "employee_list";
    }

(2).创建employee_list.html

在这里插入图片描述
代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>employee_list</title>
</head>
<body>
<table>
    <tr>
        <th colspan="5">employee_list</th>
    </tr>
    <tr>
        <th>id</th>
        <th>lastName</th>
        <th>email</th>
        <th>gender</th>
        <th>操作</th>
    </tr>
    <tr th:each="employee:${all}">
        <td th:text="${employee.id}"></td>
        <td th:text="${employee.lastName}"></td>
        <td th:text="${employee.email}"></td>
        <td th:text="${employee.gender}"></td>
        <td>
            <a href="">删除</a>
            <a href="">修改</a>
        </td>
    </tr>
</table>

</body>
</html>

发现有红色波浪线
在这里插入图片描述
在settings中搜索thymeleaf,关掉检查
在这里插入图片描述
之后红色波浪线消失了
在这里插入图片描述
一般情况建议还是把勾打上有红线就有红线将就看如果关掉检查真的有错误了自己也不太好排查。

部署Tomcat看一下页面展示效果
在这里插入图片描述
点击超链接后跳转到列表展示
在这里插入图片描述
看到展示的列表很难看现在我们加上样式。
把课件中的webapp拷贝到webapp目录之下
在这里插入图片描述
因为刚导入的渲染并不会立即生效所以我们把Maven清空一下
在这里插入图片描述
清理完成后点击重新打包
在这里插入图片描述
看到target目录下有static即为成功部署
在这里插入图片描述
修改employee_list.html

<link rel="stylesheet" th:href="@{/static/css/index_work.css}">

在这里插入图片描述

重新部署Tomcat,发现页面还是没有加载样式这里按F12
在这里插入图片描述
原因就在于静态资源的处理不是经过DispatcherServlet这种情况我们参考一下Tomcat的配置文件
在这里插入图片描述
打开Tomcat的web.xml后查看L103左右有静态资源的加载设置。
在这里插入图片描述
下面L388行DefaultServlet配置的url-pattern是/
在这里插入图片描述

工程中的web.xml是逻辑上继承自Tomcat的web.xml比如Tomcat中的欢迎列表
在这里插入图片描述
假如我们在工程的web.xml中更换了欢迎页的地址那么优先以工程中更换后的欢迎页为跳转。
在这里插入图片描述
这里明白后静态界面加载不出来的原因就如下
在这里插入图片描述
所以要修改springmvc.xml增加代码

 <!--
        配置默认的servlet处理静态资源
        当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/
        Tomcat的web.xml配置的DefaultServlet的url-pattern也是/
        此时浏览器发送的请求优先按照工程的DispatcherServlet处理所以静态资源处理不了
        若配置了<mvc:default-servlet-handler/>浏览器发送的请求都会被DefaultServlet处理
        如果配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven/>浏览器发送的请求会先被DispatcherServlet处理无法处理后再交给DefaultServlet处理
    -->
    <mvc:default-servlet-handler/>

这里要注意如果要配置默认的servlet则必不可少开启mvc的注解驱动这里是因为配置了视图控制器提前加上了开启mvc的注解驱动这里要注意如果没配置视图控制器的情况下也不能少mvc的注解驱动。
在这里插入图片描述
此时再重新部署Tomcat看一下样式加载成功
在这里插入图片描述

结论
配置默认的servlet处理静态资源
当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/Tomcat的web.xml配置的DefaultServlet的url-pattern也是/此时浏览器发送的请求优先按照工程的DispatcherServlet处理所以静态资源处理不了。
< a >若配置了< mvc:default-servlet-handler/ >浏览器发送的请求都会被DefaultServlet处理。
< b >如果配置了< mvc:default-servlet-handler/>和<mvc:annotation-driven/ >浏览器发送的请求会先被DispatcherServlet处理无法处理后再交给DefaultServlet处理。

8.5具体功能删除

(1).创建处理delete请求方式的表单

修改employee_list.html

	<!-- 作用通过超链接控制表单的提交将post请求转换为delete请求 -->
    <form method="post" id="delete_form">
    	<!-- HiddenHttpMethodFilter要求必须传输_method请求参数并且值为最终的请求方式 -->
        <input type="hidden" name="_method" value="delete">
    </form>

添加div标签
在这里插入图片描述

(2).删除超链接绑定点击事件

引入vue.js
在这里插入图片描述

代码如下

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>

删除超链接
修改employee_list.html增加单击事件
在这里插入图片描述
代码如下

<a @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">删除</a>

通过vue处理点击事件
在这里插入图片描述
代码如下

<script type="text/javascript">
    var vue = new Vue({
        el: "#app",
        methods: {
            deleteEmployee() {
                // 获取form表单
                var form = document.getElementsByTagName("form")[0];
                //var form = document.getElementById("delete_form");
                // 将超链接的href属性值赋值给form表单的action属性
                // event.target表示当前触发事件的标签
                form.action = event.target.href;
                // 表单提交
                form.submit();
                // 阻止超链接的默认行为
                event.preventDefault();

            }
        }

    });
</script>

(3).控制器方法

修改EmployeeController.java

    /**
     * 删除员工信息-->/employee/1-->DELETE
     */
    @RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
    public String deleteEmployee(@PathVariable("id") Integer id) {
        // 删除员工的信息
        employeeDao.delete(id);
        return "redirect:/employee";
    }

重新部署一下Tomcat点击删除最后一条数据
在这里插入图片描述
发现删除成功
在这里插入图片描述

8.6具体功能跳转到添加数据页面

(1).配置view-controller

修改employee_list.html
在这里插入图片描述
代码如下

<th>操作(<a th:href="@{/to/add}">+</a> )</th>

这里的跳转地址也可以配置成视图加载
修改springmvc.xml增加代码
在这里插入图片描述
代码如下

<mvc:view-controller path="/to/add" view-name="employee_list_add"></mvc:view-controller>

重新部署后查看效果
在这里插入图片描述

(2).创建employee_add.html

那么跳转添加界面需要新建一个employee_list_add.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>add employee</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
<form th:action="@{/employee}" method="post">
    <table>
        <tr>
            <th colspan="2">add employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName">
            </td>
        </tr>
        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email">
            </td>
        </tr>
        <tr>
            <td>gender</td>
            <td>
                <input type="radio" name="gender" value="1">male
                <input type="radio" name="gender" value="0">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="提交">
            </td>
        </tr>
    </table>
</form>

</body>
</html>

8.7具体功能执行保存(添加)

(1).控制器方法

修改EmployeeController.java

    /**
     * 跳转到添加页面-->/to/add-->GET
     * 添加-->/employee-->POST
     * 注意这里是从employee_list_add.html跳转过来的
     */
    @RequestMapping(value = "/employee", method = RequestMethod.POST)
    public String insertEmployee(Employee employee) {
        // 保存员工信息
        employeeDao.save(employee);
        // 重新跳转到getAllEmployee的请求
        return "redirect:/employee";
    }

重新部署Tomcat
单击+号后跳转界面
在这里插入图片描述
重新部署即可
在这里插入图片描述
提交后发现添加成功
在这里插入图片描述

8.8具体功能跳转到更新数据页面

(1).修改超链接

修改employee_list.html
这里要注意有跳转的逻辑地址和参数时用‘’将地址括起来
在这里插入图片描述

代码如下

<a th:href="@{'/employee/'+${employee.id}}">修改</a>

重新部署鼠标悬停添加上看跳转地址正确
在这里插入图片描述

(2).控制器方法

修改EmployeeController.java增加方法
注意不要忘记加注释@PathVariable

    /**
     * 跳转到修改页面-->/employee/1-->GET
     */
    @RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
    public String toUpdateEmployee(@PathVariable("id")Integer id, Map<String, Object> map) {
        // 跳转到员工修改信息,根据id查询员工信息
        Employee employee = employeeDao.get(id);
        // 把employee共享到共享域中
        map.put("employee", employee);
        return "employee_update";
    }

(3).创建employee_update.html

增加页面
在这里插入图片描述
代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>employee_update</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
<form th:action="@{/employee}" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="hidden" name="id" th:value="${employee.id}">
    <table>
        <tr>
            <th colspan="2">update employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName" th:value="${employee.lastName}">
            </td>
        </tr>

        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email" th:value="${employee.email}">
            </td>
        </tr>

        <tr>
            <td>gender</td>
            <td>
                <input type="radio" name="gender" value="1" th:field="${employee.gender}">male
                <input type="radio" name="gender" value="0" th:field="${employee.gender}">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="更新">
            </td>
        </tr>

    </table>

</form>

</body>
</html>

重新部署Tomcat跳转成功
在这里插入图片描述
当前界面单击鼠标右键选择查看源代码
在这里插入图片描述
查看源代码如下
在这里插入图片描述

8.9具体功能执行更新

(1).控制器方法

修改EmployeeController.java

    /**
     * 修改员工信息-->/employee-->PUT
     */
    @RequestMapping(value = "/employee", method = RequestMethod.PUT)
    public String updateEmployee(Employee employee) {
        // 保存员工修改的信息
        employeeDao.save(employee);
        return "redirect:/employee";
    }

重新部署Tomcat
在这里插入图片描述
修改之后点击更新更新内容如下在这里插入图片描述

9.SpringMVC处理ajax请求

新创建一个项目

Name:spring-mvc-ajax
GroupId:com.atguigu

拷贝上一个项目的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SSM</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>

    <groupId>com.atguigu</groupId>
    <artifactId>spring-mvc-ajax</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>

</project>

添加web.xml
在这里插入图片描述

地址如下

F:\javawebwork\SSM\spring-mvc-ajax\src\main\webapp\WEB-INF\web.xml

web.xml中加入相关配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 编码过滤器 -->
    <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>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 设置处理请求方法的过滤器 -->
    <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>

    <!-- 前端控制器 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 将前端控制器的启动时间提前到服务启动时 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

创建首页index.html
在这里插入图片描述
首页代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>

拷贝之前项目的springmvc.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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫描控制层组件(自己配置package) -->
    <context:component-scan base-package="com.atguigu.controller"></context:component-scan>

    <!-- 配置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">
                        <!--
                            比如当前index的实际位置在/WEB-INF/templates/index.html(物理视图)
                            去掉视图前缀变为 index.html
                            去掉视图后缀变为 index(逻辑视图)
                        -->
                        <!-- 视图前缀 -->
                        <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>

    <!-- 配置视图控制器 -->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>

    <!-- 开启mvc注解驱动 -->
    <mvc:annotation-driven/>

    <!--
        配置默认的servlet处理静态资源
        当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/
        Tomcat的web.xml配置的DefaultServlet的url-pattern也是/
        此时浏览器发送的请求优先按照工程的DispatcherServlet处理所以静态资源处理不了
        若配置了<mvc:default-servlet-handler/>浏览器发送的请求都会被DefaultServlet处理
        如果配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven/>浏览器发送的请求会先被DispatcherServlet处理无法处理后再交给DefaultServlet处理
    -->
    <mvc:default-servlet-handler/>
</beans>

创建控制层TestAjaxController
在这里插入图片描述
部署Tomcat,配置启动方式
在这里插入图片描述
配置地址
在这里插入图片描述
启动部署Tomcat,正常部署
在这里插入图片描述
在官网中查看axious的用法
axious文档官网
在这里插入图片描述
继续修改index.html
在这里插入图片描述

代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<div id="app">
    <h1>index.html</h1>
    <input type="button" value="测试SpringMVC处理ajax请求" @click="testAjax">
</div>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/js/axios.min.js}"></script>
<script type="text/javascript">
    /**
     *              axios({
     *                     url: "",//请求路径
     *                     method: "",//请求方式
     *                     params: {},// 以name = value&name = value的方式发送请求参数,不管请求方式是get还是post
     *                     请求参数都会被拼接到请求地址后;此种方式的请求参数可以通过request.getParameter获取参数。
     *                     data: {}// 以json格式发送请求参数,请求参数会被保存到请求报文的请求体保存到服务器用GSON获取参数
     *                 }).then(response => {
     *                     console.log(response.data);
     *                 });
     */
    var vue = new Vue({
        el: "#app",
        methods: {
            testAjax() {
                axios.post(
                    "/SpringMVC/test/ajax?id=1001",
                    {username: "admin", password: "123456"}
                ).then(response => {
                    console.log(response.data);
                });
            }
        }
    });
</script>
</body>
</html>

修改控制层TestAjaxController.java

@Controller
public class TestAjaxController {
    @RequestMapping("test/ajax")
    public void testAjax(Integer id, HttpServletResponse response) throws IOException {
        System.out.println("id:" + id);
        response.getWriter().write("hello,axios");
    }
}

创建success.html
在这里插入图片描述
代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
<h1>success.html</h1>

</body>
</html>

重新部署Tomcat,打开F12切换到控制台点击按钮浏览器控制台输出语句。
在这里插入图片描述
后台控制台获取到id
在这里插入图片描述
F12切换到网络
在这里插入图片描述

9.1@RequestBody

@RequestBody可以获取请求体信息使用@RequestBody注解标识控制器方法的形参当前请求的请求体就会为当前注解所标识的形参赋值。

修改TestAjaxController.java

@Controller
public class TestAjaxController {
    @RequestMapping("test/ajax")
    public void testAjax(Integer id, @RequestBody String requestBody, HttpServletResponse response) throws IOException {
        System.out.println("requestBody:" + requestBody);
        System.out.println("id:" + id);
        response.getWriter().write("hello,axios");
    }
}

重新部署一下Tomcat,看一下输出结果requestBody
在这里插入图片描述

输出结果
requestBody:username=admin&password=123456

总结
@RequestBody将请求体中的内容和控制器方法的形参进行绑定

9.2@RequestBody获取json格式的请求参数

在使用了axios发送ajax请求之后浏览器发送到服务器的请求参数有两种格式
1、name=value&name=value…此时的请求参数可以通过request.getParameter()获取对应SpringMVC中可以直接通过控制器方法的形参获取此类请求参数。
2、{key:value,key:value,…}此时无法通过request.getParameter()获取之前我们使用操作json的相关jar包gson或jackson处理此类请求参数可以将其转换为指定的实体类对象或map集合。在SpringMVC中直接使用@RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象。

使用@RequestBody获取json格式的请求参数的条件
1.导入jackson的依赖
在这里插入图片描述
代码如下

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.12.1</version>
</dependency>

2.SpringMVC的配置文件中设置开启mvc的注解驱动
在这里插入图片描述
代码如下

<!--开启mvc的注解驱动-->
<mvc:annotation-driven />

3.在控制器方法的形参位置设置json格式的请求参数要转换成的java类型实体类或map的参数并使用@RequestBody注解标识
修改index.html增加超链接标签。
创建实体类User
在这里插入图片描述
代码如下

package com.atguigu.pojo;

/**
 * @ClassName: User
 * @Description:
 * @Author: wty
 * @Date: 2023/1/31
 */

public class User {
    private Integer id;
    private String username;
    private String password;
    private String gender;
    private Integer age;

    public User() {
    }

    public User(Integer id, String username, String password, String gender, Integer age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }
}

    <input type="button" value="使用@RequestBody注解处理json格式的请求参数" @click="testRequestBody">

增加axios

testRequestBody() {
                axios.post(
                    "/SpringMVC/test/RequestBody/json",
                    {username: "admin", password: "123456", gender: "男", age: 23}
                ).then(response => {
                    console.log(response.data);
                })
            }

修改TestAjaxController.java增加方法

    @RequestMapping("/test/RequestBody/json")
    public void testRequestBody(@RequestBody User user, HttpServletResponse response) throws IOException {
        response.getWriter().write("hello,RequestBody");
        System.out.println(user);
    }

重新部署Tomcat,单击新加的超链接
在这里插入图片描述
看一下后台的控制台
在这里插入图片描述
我们继续更改TestAjaxController.java用另一种方式来接收

    @RequestMapping("/test/RequestBody/json")
    public void testRequestBody(@RequestBody Map<String, Object> map, HttpServletResponse response) throws IOException {
        response.getWriter().write("hello,RequestBody");
        System.out.println(map);
    }

用map来接收
在这里插入图片描述
再重新部署一下Tomcat,看一下后台的输出
在这里插入图片描述

9.3@ResponseBody

@ResponseBody用于标识一个控制器方法可以将该方法的返回值直接作为响应报文的响应体响应到浏览器。
在index.html添加超链接

    <a th:href="@{/test/ResponseBody}">测试@ResponseBody注解响应浏览器数据</a>

修改TestAjaxController.java

    @RequestMapping("/test/ResponseBody")
    public String testResponseBody() {
        return "success";
    }

重新部署Tomcat
在这里插入图片描述
点击 超链接后成功跳转
在这里插入图片描述
紧接着我们给TestAjaxController.java的方法加上@ResponseBody注解

@RequestMapping("/test/ResponseBody")
    @ResponseBody
    public String testResponseBody() {
        return "success";
    }

重新部署后再点击超链接
在这里插入图片描述
我们发现@ResponseBody注解把方法testResponseBody的返回值作为了响应体返回到了页面。
在这里插入图片描述
总结
@ResponseBody注解将所标识的控制器方法的返回值作为响应报文的响应体响应到浏览器。

9.4@ResponseBody响应浏览器json数据

服务器处理ajax请求之后大多数情况都需要向浏览器响应一个java对象此时必须将java对象转换为json字符串才可以响应到浏览器之前我们使用操作json数据的jar包gson或jackson将java对象转换为json字符串。在SpringMVC中我们可以直接使用@ResponseBody注解实现此功能@ResponseBody响应浏览器json数据的条件
1.导入jackson的依赖

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.12.1</version>
</dependency>

2.SpringMVC的配置文件中设置开启mvc的注解驱动

<!--开启mvc的注解驱动-->
<mvc:annotation-driven />

3.使用@ResponseBody注解标识控制器方法在方法中将需要转换为json字符串并响应到浏览器的java对象作为控制器方法的返回值此时SpringMVC就可以将此对象直接转换为json字符串并响应到浏览器
修改index.html添加标签

    <input type="button" value="使用@ResponseBody注解响应浏览器json格式的数据" @click="testResponseBody">

增加axios

testResponseBody() {
                axios.post(
                    "/SpringMVC/test/ResponseBody/json"
                ).then(response => {
                    console.log(response.data);
                })
            }

修改TestAjaxController.java

    @RequestMapping("test/ResponseBody/json")
    @ResponseBody
    public User testResponseBodyJson() {
        User user = new User(1001, "admin", "123456", "男", 21);
        return user;
    }

重新部署Tomcat
在这里插入图片描述
按F12控制台输出json对象
在这里插入图片描述
那换一种返回值呢我们来看下Map集合
修改TestAjaxController.java

 @RequestMapping("test/ResponseBody/json")
    @ResponseBody
    public Map<String, Object> testResponseBodyJson() {
        User user1 = new User(1001, "admin1", "123456", "男", 21);
        User user2 = new User(1002, "admin2", "123", "女", 22);
        User user3 = new User(1003, "admin3", "456", "男", 23);
        Map<String, Object> map = new HashMap<>();
        map.put("1001", user1);
        map.put("1002", user2);
        map.put("1003", user3);
        return map;
    }

重新部署Tomcat
在这里插入图片描述
那再换一种返回值我们来看下List集合
修改TestAjaxController.java

@RequestMapping("test/ResponseBody/json")
    @ResponseBody
    public List<Object> testResponseBodyJson() {
        User user1 = new User(1001, "admin1", "123456", "男", 21);
        User user2 = new User(1002, "admin2", "123", "女", 22);
        User user3 = new User(1003, "admin3", "456", "男", 23);
        List<Object> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        return list;
    }

在这里插入图片描述

总结
常用的Java对象(后台)转换为json(前台)的结果

实体类→json对象
map集合→json对象
list集合→json数组

9.5@RestController注解

@RestController注解是springMVC提供的一个复合注解标识在控制器的类上就相当于为类添加了@Controller注解并且为其中的每个方法添加了@ResponseBody注解。

10.文件上传和下载

10.1文件下载

ResponseEntity用于控制器方法的返回值类型该控制器方法的返回值就是响应到浏览器的响应报文使用ResponseEntity实现下载文件的功能。

首先准备一张图片放到webapp下新建目录img
在这里插入图片描述
图片拷贝完要整体清空Maven
在这里插入图片描述
确保target中有图片
在这里插入图片描述

修改index.html增加一个超链接

<a th:href="@{/test/down}">下载图片</a>

创建一个控制层FileUpAndDownController.java

@Controller
public class FileUpAndDownController {
    /**
     * @param
     * @return org.springframework.http.ResponseEntity<byte [ ]>
     * @description //TODO
     * @param: session
     * @date 2023/2/1 0:30
     * @author wty
     **/
    @RequestMapping("/test/down")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        //String realPath = servletContext.getRealPath("/img/1.PNG");
        String realPath = servletContext.getRealPath("img");
        // 可以用文件分隔符来表示\或者/
        realPath = realPath + File.separator + "1.PNG";
        //创建输入流
        InputStream is = new FileInputStream(realPath);
        //创建字节数组 is.available()获取输入流所对应文件的字节数
        byte[] bytes = new byte[is.available()];
        //将流读到字节数组中
        is.read(bytes);
        //创建HttpHeaders对象设置响应头信息
        MultiValueMap<String, String> headers = new HttpHeaders();
        //设置要下载方式以及下载文件的名字以附件形式下载文件
        headers.add("Content-Disposition", "attachment;filename=1.PNG");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        //bytes, 响应体
        // headers,  响应头
        // statusCode 响应状态码
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
        //关闭输入流
        is.close();
        return responseEntity;
    }
}

重新部署Tomcat
在这里插入图片描述
下载成功
在这里插入图片描述

10.2文件上传

文件上传要求form表单的请求方式必须为post并且添加属性enctype=“multipart/form-data”
SpringMVC中将上传的文件封装到MultipartFile对象中通过此对象可以获取文件相关信息。

修改index.html

    <!--multipart/form-data:当前表单数据以二进制形式提交到服务中 -->
    <form th:action="@{/test/up}" method="post" enctype="multipart/form-data">
        头像:<input type="file" name="photo"><br>
        <input type="submit" value="上传">
    </form>

上传步骤

(1).添加依赖

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --
>
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>

(2).在SpringMVC的配置文件中添加配置

在springmvc.xml中添加配置

<!-- 配置文件上传解析器 -->
    <!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置编码 -->
        <!--<property name="defaultEncoding" value="UTF-8"></property>-->
        <!-- 设置最大上传值 -->
        <!--<property name="maxUploadSize" value="102400"></property>-->
    </bean>

(3).控制器方法

FileUpAndDownController.java中新增上传方法

    /**
     * @param
     * @return java.lang.String
     * @description //文件上传
     * @param: photo
     * @param: session
     * @date 2023/2/1 12:07
     * @author wty
     **/
    @RequestMapping("/test/up")
    public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //获取上传的文件的文件名
        String fileName = photo.getOriginalFilename();
        //处理文件重名问题
        String hzName = fileName.substring(fileName.lastIndexOf("."));
        fileName = UUID.randomUUID().toString() + hzName;
        //获取服务器中photo目录的路径
        ServletContext servletContext = session.getServletContext();
        // 获取工程下Tomcat中photo目录下的真实路径
        String photoPath = servletContext.getRealPath("photo");
        File file = new File(photoPath);
        // 判断photo目录是否存在
        if (!file.exists()) {
            // 不存在就创建photo目录
            file.mkdir();
        }
        // 最终上传的路径
        String finalPath = photoPath + File.separator + fileName;
        //实现上传功能
        photo.transferTo(new File(finalPath));
        return "success";
    }

重新部署Tomcat
在这里插入图片描述
选择1张图片
在这里插入图片描述

点击上传成功跳转
在这里插入图片描述
看一下Tomcat的目录成功生成图片因为名称会重复这里代码设置的图片名称为UUID。
在这里插入图片描述
UUID如下段代码设置
在这里插入图片描述

11.拦截器

过滤器是浏览器和目标资源之间拦截。
拦截器和过滤器图示如下
在这里插入图片描述
新创建工程

Name:spring-mvc-extension
GroupId:com.atguigu

拷贝上一个工程的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SSM</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>

    <groupId>com.atguigu</groupId>
    <artifactId>spring-mvc-extension</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>

</project>

创建web.xml
修改地址为

F:\javawebwork\SSM\spring-mvc-extension\src\main\webapp\WEB-INF\web.xml

在这里插入图片描述
在新创建的web.xml中进行配置

    <!-- 编码过滤器 -->
    <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>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 设置处理请求方法的过滤器 -->
    <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>

    <!-- 前端控制器 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 将前端控制器的启动时间提前到服务启动时 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

新建springmvc.xml拷贝之前的项目
在springmvc.xml中配置

 <!-- 扫描控制层组件(自己配置package) -->
    <context:component-scan base-package="com.atguigu.controller"></context:component-scan>

    <!-- 配置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">
                        <!--
                            比如当前index的实际位置在/WEB-INF/templates/index.html(物理视图)
                            去掉视图前缀变为 index.html
                            去掉视图后缀变为 index(逻辑视图)
                        -->
                        <!-- 视图前缀 -->
                        <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>

    <!-- 配置视图控制器 -->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>

    <!-- 开启mvc注解驱动 -->
    <mvc:annotation-driven/>

    <!--
        配置默认的servlet处理静态资源
        当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/
        Tomcat的web.xml配置的DefaultServlet的url-pattern也是/
        此时浏览器发送的请求优先按照工程的DispatcherServlet处理所以静态资源处理不了
        若配置了<mvc:default-servlet-handler/>浏览器发送的请求都会被DefaultServlet处理
        如果配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven/>浏览器发送的请求会先被DispatcherServlet处理无法处理后再交给DefaultServlet处理
    -->
    <mvc:default-servlet-handler/>

    <!-- 配置文件上传解析器 -->
    <!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置编码 -->
        <!--<property name="defaultEncoding" value="UTF-8"></property>-->
        <!-- 设置最大上传值 -->
        <!--<property name="maxUploadSize" value="102400"></property>-->
    </bean>

创建首页index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>

在这里插入图片描述
创建控制层TestController.java

@Controller
public class TestController {
    @RequestMapping("/test/hello")
    public String testHello() {
        return "success";
    }
}

创建跳转成功的界面success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
<h1>success.html</h1>
</body>
</html>

在这里插入图片描述
配置Tomcat,启动
在这里插入图片描述

配置地址
在这里插入图片描述
启动Tomcat,页面加载成功
在这里插入图片描述

11.1拦截器的配置

SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置

在index.html中添加语句

<a th:href="@{/test/hello}">测试拦截器</a>

修改TestController.java
修改FirstInterceptor.java

public class FirstInterceptor implements HandlerInterceptor {
}

在这里插入图片描述

都是default修饰的所以不会报错现在用ctrl+o重写一下这些方法
在这里插入图片描述
重写FirstInterceptor.java后如下

/**
 * @ClassName: FirstInterceptor
 * @Description:
 * @Author: wty
 * @Date: 2023/2/1
 */

public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor.preHandle");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor.postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor.afterCompletion");
    }
}

创建完拦截器后我们重新部署Tomcat,这时候发现后台控制台什么也没打印说明拦截器此时并没有调用。
在这里插入图片描述
点击测试拦截器
在这里插入图片描述
需要在springmvc.xml中配置拦截器

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
    </mvc:interceptors>

重新部署Tomcat
在这里插入图片描述
看一下控制台的输出情况只输出了preHandle
在这里插入图片描述

11.2拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法

  • preHandle控制器方法执行之前执行preHandle()其boolean类型的返回值表示是否拦截或放行返回true为放行即调用控制器方法返回false表示拦截即不调用控制器方法
  • postHandle控制器方法执行之后执行postHandle()
  • afterCompletion控制器方法执行之后且处理完视图和模型数据渲染视图完毕之后执行afterCompletion()

(1).若拦截器的preHandle()返回true

将FirstInterceptor.java中preHandle方法设置为true

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor.preHandle");
        return true;
    }

在这里插入图片描述
重新部署Tomcat,点击拦截器
在这里插入图片描述
跳转成功
在这里插入图片描述
最后看一下后台输出三个拦截器都输出了
在这里插入图片描述

(2).若拦截器的preHandle()返回了false

这里看一下源码DispatcherServlet.class
这里如果返回了false后就直接跳出之后的拦截器就不会执行了

 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     return;
 }

(3).拦截器的配置

方式一在 < mvc:interceptors >外配置bean然后用ref引用bean id即可。

修改springmvc.xml

<bean id="firstInterceptor" class="com.atguigu.interceptor.FirstInterceptor"></bean>

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <ref bean="firstInterceptor"></ref>
    </mvc:interceptors>

在这里插入图片描述

方式二通过注解+扫描的方式

这种方式配置的拦截器默认对DispatcherServlet处理的所有请求进行拦截
1.修改FirstInterceptor.java
加上注解

@Component

在这里插入图片描述
2.修改springmvc.xml
扫描控制层设置为

    <context:component-scan base-package="com.atguigu"></context:component-scan>

在这里插入图片描述
3.修改springmvc.xml

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!--<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>-->
        <ref bean="firstInterceptor"></ref>
    </mvc:interceptors>

重新部署Tomcat
在这里插入图片描述
跳转成功
在这里插入图片描述

后台输出拦截器的信息
在这里插入图片描述
我们在地址后随便加个后缀
在这里插入图片描述
发现页面是404但是后台拦截器依然执行了
在这里插入图片描述
可见这种拦截器的配置方式是应用于所有页面的。

方式三mvc配置

这种方式配置的拦截器比较精确
修改springmvc.xml

<!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
        	<!-- 配置需要拦截额请求的请求路径 -->
            <mvc:mapping path="/*"/>
            <!-- 排除拦截 -->
            <mvc:exclude-mapping path="/abc"/>
            <ref bean="firstInterceptor"></ref>
        </mvc:interceptor>
    </mvc:interceptors>

重新部署Tomcat
在这里插入图片描述
控制台生成
在这里插入图片描述
那么我们再试一下排除拦截的地址
在这里插入图片描述
同代码中地址一致
在这里插入图片描述
发现控制台没有拦截信息了
在这里插入图片描述
这里注意一下/*只能表示下一级目录的跳转受到拦截器的拦截
在这里插入图片描述
我们输入个下一级地址看一下效果

http://localhost:8080/SpringMVC/ab

展示结果如下
在这里插入图片描述
后台输出了三个拦截器的语句
在这里插入图片描述
那如果我们设置多级目录呢看一下
在这里插入图片描述
控制台没有输出
在这里插入图片描述
那该怎么办呢原来我们需要配置成/**
修改springmvc.xml

<mvc:mapping path="/**"/>

在这里插入图片描述
再重新部署一下Tomcat
前台展示不变
在这里插入图片描述
后台输出了三个拦截器
在这里插入图片描述

11.3多个拦截器的执行顺序

配置springmvc.xml

 <!-- 配置拦截器 -->
    <mvc:interceptors>
        <ref bean="firstInterceptor"></ref>
    </mvc:interceptors>

在这里插入图片描述
重新Tomcat加上断点看DispatcherServlet.class源码
preHandle拦截器
在这里插入图片描述
postHandle拦截器
在这里插入图片描述
afterCompletion拦截器位置
在这里插入图片描述
创建多个拦截器
创建控制层SecondInterceptor.java

package com.atguigu.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @ClassName: FirstInterceptor
 * @Description:
 * @Author: wty
 * @Date: 2023/2/1
 */
@Component
public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor.preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondInterceptor.postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondInterceptor.afterCompletion");
    }
}

在这里插入图片描述
配置springmvc.xml

<ref bean="secondInterceptor"></ref>

拦截器配置如下
在这里插入图片描述
这里2个控制层的拦截器preHandle()都返回true

(1).若每个拦截器的preHandle()都返回true

重新部署Tomcat,点击测试拦截器
在这里插入图片描述
跳转成功
在这里插入图片描述
看后台的控制台
在这里插入图片描述
交换一下配置拦截器的顺序
在这里插入图片描述
重新部署Tomcat,点击拦截器
在这里插入图片描述
跳转成功
在这里插入图片描述
看一下控制台
在这里插入图片描述
得出以下结论

总结
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关
preHandle()会按照配置的顺序执行
而postHandle()和afterCompletion()会按照配置的反序执行。

为什么会这样呢我们看一下源码
在这里插入图片描述
进入断点
在这里插入图片描述
preHandle正序执行的源码
在这里插入图片描述
postHandle逆序执行源码
在这里插入图片描述
afterCompletion逆序执行原因
在这里插入图片描述

(2).若某个拦截器的preHandle()返回了false

修改SecondInterceptor.java的preHandle方法

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondInterceptor.preHandle");
        return false;
    }
    }

在这里插入图片描述
修改springmvc.xml的顺序

<ref bean="firstInterceptor"></ref>
        <ref bean="secondInterceptor"></ref>

重新部署Tomcat输出结果
在这里插入图片描述
原因
在这里插入图片描述
此时SecondInterceptor没有加入interceptorList中紧接着看triggerAfterCompletion方法
在这里插入图片描述
总结
若某个拦截器的preHandle()返回了false。
preHandle()返回false和它之前的拦截器的preHandle()都会执行拦截器中所有的postHandle()都不执行拦截器的preHandle()返回false之前的拦截器的afterCompletion()会执行。

(3).若所有拦截器的preHandle()都返回了false

修改FirstInterceptor.java

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("FirstInterceptor.preHandle");
        return false;
    }

在这里插入图片描述
重新部署Tomcat,发现后台输出FirstInterceptor的preHandle也很好理解源码只执行了FirstInterceptor的preHandle后就返回了
在这里插入图片描述

12.异常处理器

12.1基于配置的异常处理

SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口HandlerExceptionResolver。

看一下接口的源码:

public interface HandlerExceptionResolver {
    @Nullable
    ModelAndView resolveException(HttpServletRequest var1, HttpServletResponse var2, @Nullable Object var3, Exception var4);
}

HandlerExceptionResolver接口的实现类有DefaultHandlerExceptionResolver和
SimpleMappingExceptionResolver

看一下类图的关系
在这里插入图片描述

SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver使用方式如下
首先注释掉springmvc.xml中的拦截器配置
在这里插入图片描述
紧接着配置异常处理解析器
修改springmvc.xml

<!-- 异常处理解析器 -->
    <bean id="SimpleMappingExceptionResolver"
          class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <!-- error是逻辑视图, key设置要处理的异常value设置出现该异常时要跳转的页面所对应的逻辑视图 -->
                <prop key="java.lang.ArithmeticException">error</prop>
            </props>
        </property>
    </bean>

新建error.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>错误</title>
</head>
<body>
<h1>error.html</h1>
</body>
</html>

在这里插入图片描述
修改TestController.java

    @RequestMapping("/test/hello")
    public String testHello() {
        System.out.println(1 / 0);
        return "success";
    }

重新部署Tomcat
直接填写地址

http://localhost:8080/SpringMVC/test/hello

发现直接跳转到我们配置的错误页面
在这里插入图片描述
我们看一下源码SimpleMappingExceptionResolver.class
这个返回类型是ModelAndView
在这里插入图片描述
我们跳转error相当于只是设置了视图那么共享域呢我们继续修改
springmvc.xml

<!-- 设置共享在请求域中的异常信息的属性名 -->
<property name="exceptionAttribute" value="ex"></property>

在这里插入图片描述
修改error.html

<p th:text="${ex}"></p>

在这里插入图片描述
重新部署Tomcat,发现错误信息也展示在页面上了
在这里插入图片描述

12.2基于注解的异常处理

先注释springmvc.xml中的xml配置
在这里插入图片描述
新增控制层ExceptionController.java
在这里插入图片描述
代码如下
增加@ControllerAdvice注解
在这里插入图片描述
ExceptionController.java如下

// 将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
    // 设置要处理的异常信息
    @ExceptionHandler(ArithmeticException.class)
    // ex表示控制器方法出现的异常
    public ModelAndView handleException(Throwable ex) {
        ModelAndView mav = new ModelAndView();
        //向请求域共享数据
        mav.addObject("ex", ex);
        //设置视图实现页面跳转
        mav.setViewName("error");
        return mav;
    }
}

重新部署Tomcat,发现跳转成功异常信息成功展示
在这里插入图片描述

13.注解配置SpringMVC

使用配置类和注解代替web.xml和SpringMVC配置文件的功能

新建一个Module

Name:spring-mvc-annotation
GroupId:com.atguigu

拷贝上一个工程的pom.xml过来即可

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SSM</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>

    <groupId>com.atguigu</groupId>
    <artifactId>spring-mvc-annotation</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>
        <!-- 导入jackson的依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>

</project>

13.1创建初始化类代替web.xml

在Servlet3.0环境中容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类如果找到的话就用它来配置Servlet容器。 Spring提供了这个接口的实现名为
SpringServletContainerInitializer这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现名为AbstractAnnotationConfigDispatcherServletInitializer当我们的类扩展了
AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候容器会自动发现它并用它来配置Servlet上下文。
新建类com.atguigu.WebInit

package com.atguigu;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

/**
 * @ClassName: WebInit
 * @Description:
 * @Author: wty
 * @Date: 2023/2/1
 */

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    /**
     * @param
     * @return java.lang.Class<?>[]
     * @description //设置一个配置类来代替spring的配置文件
     * @date 2023/2/1 18:21
     * @author wty
     **/
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * @param
     * @return java.lang.Class<?>[]
     * @description //设置一个类代替springmvc的配置文件
     * @date 2023/2/1 18:21
     * @author wty
     **/
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    /**
     * @param
     * @return java.lang.String[]
     * @description //设置springmvc前端口之前DispatcherServlet的url-pattern
     * @date 2023/2/1 18:22
     * @author wty
     **/
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    /**
     * @param
     * @return javax.servlet.Filter[]
     * @description //设置过滤器
     * @date 2023/2/1 18:29
     * @author wty
     **/
    @Override
    protected Filter[] getServletFilters() {
        // 创建编码过滤器
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);

        // 创建处理请求方式的过滤器
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();

        return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
    }
}

创建几个配置类
在这里插入图片描述

13.2创建SpringConfig配置类代替spring的配置文件

创建类SpringConfig.java

package com.atguigu;

import org.springframework.context.annotation.Configuration;

/**
 * @ClassName: SpringConfig
 * @Description:代替spring的配置文件
 * @Author: wty
 * @Date: 2023/2/1
 */
// 将当前类标识为配置类
@Configuration
public class SpringConfig {
    //ssm整合之后spring的配置信息写在此类中
}

13.3创建WebConfig配置类代替SpringMVC的配置文件

创建控制层TestController.java里面内容暂时不用写。
在这里插入图片描述

创建拦截器com.atguigu.interceptor.FirstInterceptor
在这里插入图片描述
代码如下

@Component
public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor.postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("FirstInterceptor.afterCompletion");
    }
}

创建前台界面
在这里插入图片描述

创建WebConfig.java

package com.atguigu.config;

import com.atguigu.interceptor.FirstInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import java.util.List;
import java.util.Properties;

/**
 * @ClassName: WebConfig
 * @Description:代替springmvc的配置文件 扫描组件
 * 视图解析器--手动配置xml比较方便
 * 默认的servlet
 * mvc注解驱动
 * 视图控制器
 * 文件上传解析器
 * 拦截器
 * 异常解析器
 * @Author: wty
 * @Date: 2023/2/1
 */
// 将当前类标识为配置类
@Configuration
// 扫描组件
@ComponentScan("com.atguigu.controller")
// mvc注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    /**
     * @param
     * @return void
     * @description //默认的servlet,处理静态资源
     * @param: configurer
     * @date 2023/2/1 21:28
     * @author wty
     **/
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    /**
     * @param
     * @return void
     * @description //配置视图控制器(首页)
     * @param: registry
     * @date 2023/2/1 21:54
     * @author wty
     **/
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    /**
     * @param
     * @return org.springframework.web.multipart.commons.CommonsMultipartResolver
     * @description //文件上传解析器
     * @date 2023/2/1 21:56
     * @author wty
     **/

    // 可以将标识的方法的返回值作为Bean来管理,bean的id为方法的方法名
    @Bean
    public CommonsMultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }

    /**
     * @param
     * @return void
     * @description //拦截器
     * @param: registry
     * @date 2023/2/1 22:02
     * @author wty
     **/
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        FirstInterceptor firstInterceptor = new FirstInterceptor();
        registry.addInterceptor(firstInterceptor).addPathPatterns("/**").excludePathPatterns("/abc");
    }

    /**
     * @param
     * @return void
     * @description //异常处理解析器
     * @param: resolvers
     * @date 2023/2/1 22:08
     * @author wty
     **/
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("java.lang.ArithmeticException", "error");
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        simpleMappingExceptionResolver.setExceptionAttribute("ex");
        resolvers.add(simpleMappingExceptionResolver);
    }

    /**
     * @param
     * @return org.thymeleaf.templateresolver.ITemplateResolver
     * @description //配置生成模板解析器
     * @date 2023/2/1 22:22
     * @author wty
     **/
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    /**
     * @param
     * @return org.thymeleaf.spring5.SpringTemplateEngine
     * @description //生成模板引擎并为模板引擎注入模板解析器
     * @param: templateResolver
     * @date 2023/2/1 22:22
     * @author wty
     **/
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    /**
     * @param
     * @return org.springframework.web.servlet.ViewResolver
     * @description //生成视图解析器并未解析器注入模板引擎
     * @param: templateEngine
     * @date 2023/2/1 22:21
     * @author wty
     **/
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }
}

13.4测试功能

配置Tomcat
在这里插入图片描述
设置启动项
在这里插入图片描述
修改TestController.java

@Controller
public class TestController {
    @RequestMapping("/test/hello")
    public String testHello() {
        System.out.println(1 / 0);
        return "success";
    }
}

重启Tomcat
在这里插入图片描述
单击测试拦截器成功跳转错误页面
在这里插入图片描述
后台控制台输出
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring