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

news2024/11/15 22:24:48

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

    • 8.RESTful案例
      • 8.1准备工作
      • 8.2功能清单
      • 8.3.具体功能:访问首页
        • (1).配置view-controller
        • (2).创建页面
      • 8.4具体功能:查询所有员工数据
        • (1).控制器方法
        • (2).创建employee_list.html
      • 8.5具体功能:删除
        • (1).创建处理delete请求方式的表单
        • (2).删除超链接绑定点击事件
        • (3).控制器方法
      • 8.6具体功能:跳转到添加数据页面
        • (1).配置view-controller
        • (2).创建employee_add.html
      • 8.7具体功能:执行保存(添加)
        • (1).控制器方法
      • 8.8具体功能:跳转到更新数据页面
        • (1).修改超链接
        • (2).控制器方法
        • (3).创建employee_update.html
      • 8.9具体功能:执行更新
        • (1).控制器方法
    • 9.SpringMVC处理ajax请求
      • 9.1@RequestBody
        • 9.2@RequestBody获取json格式的请求参数
        • 9.3@ResponseBody
        • 9.4@ResponseBody响应浏览器json数据
        • 9.5@RestController注解
    • 10.文件上传和下载
      • 10.1文件下载
      • 10.2文件上传
        • (1).添加依赖
        • (2).在SpringMVC的配置文件中添加配置
        • (3).控制器方法
    • 11.拦截器
      • 11.1拦截器的配置
      • 11.2拦截器的三个抽象方法
        • (1).若拦截器的preHandle()返回true
        • (2).若拦截器的preHandle()返回了false
        • (3).拦截器的配置
          • 方式一:在 < mvc:interceptors >外配置bean,然后用ref引用bean id即可。
          • 方式二:通过注解+扫描的方式
          • 方式三:mvc配置
      • 11.3多个拦截器的执行顺序
        • (1).若每个拦截器的preHandle()都返回true
        • (2).若某个拦截器的preHandle()返回了false
        • (3).若所有拦截器的preHandle()都返回了false
    • 12.异常处理器
      • 12.1基于配置的异常处理
      • 12.2基于注解的异常处理
    • 13.注解配置SpringMVC
      • 13.1创建初始化类,代替web.xml
      • 13.2创建SpringConfig配置类,代替spring的配置文件
      • 13.3创建WebConfig配置类,代替SpringMVC的配置文件
      • 13.4测试功能

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
在这里插入图片描述
单击测试拦截器,成功跳转错误页面
在这里插入图片描述
后台控制台输出
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业电子招投标采购系统源码之功能模块功能描述

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

激光焊接/点焊的特性及优势分析?

目前应用于生产的点焊方式大多为电阻点焊、电弧点焊、激光点焊和胶接点焊等多种点焊方法。其中激光焊接是激光材料加工技术应用的重要方面之一。 激光点焊机主要由激光器、电源及控制、冷却机、导光及调焦、双目体视显微观察几部分构成&#xff0c;结构紧凑&#xff0c;体积小…

Android中对图片的操作,移动、缩放、涂鸦和保存到图库

一、实现方法 监听用户手势&#xff0c;提取用户操作 &#xff08;1&#xff09;移动&#xff1a; 分别计算X,Y轴的结束与初始之间移动偏移的量 &#xff08;2&#xff09;缩放&#xff1a;&#xff08;结束两指间距离伸缩比例&#xff09;/ 初始两指间距离&#xff0c;scaleX…

云计算|OpenStack|社区版OpenStack安装部署文档(五 --- 计算服务nova安装部署---Rocky版)

前言&#xff1a; nova服务是openstack最重要的一个组件&#xff0c;没有之一&#xff0c;该组件是云计算的计算核心&#xff0c;大体组件如下&#xff1a; OpenStack Docs: Compute service overview 挑些重点&#xff0c;nova-api&#xff0c;libvirt&#xff0c;nova-pla…

最小生成树与最短路径

目录 一.最小生成树 1.1概念 1.2Kruskal算法 1.3Prim算法 二.最短路径 2.11单源最短路径--Dijkstra算法 2.1.2单源最短路径--Bellman-Ford算法 一.最小生成树 1.1概念 连通图中的每一棵生成树&#xff0c;都是原图的一个极大无环子图&#xff0c;即&#xff1a;从其中删去…

虹科分享|论企业网络安全的重要性

拥有有效的企业网络安全不仅仅是让你的员工创建一个不是他们宠物名字的密码--除非他们的猫的名字至少有12个字符长&#xff0c;由大小写字母和符号组成。无论是经过充分研究的鱼叉式钓鱼尝试&#xff0c;还是绕过MFA&#xff0c;威胁者都变得更加大胆。随着全球各行业数据泄露事…

判断是否为平衡树

对二叉树有困惑的小伙伴可以看一下我之前的文章&#xff1a;二叉树&#xff08;一&#xff09;_染柒_GRQ的博客-CSDN博客二叉树&#xff08;二&#xff09;_染柒_GRQ的博客-CSDN博客二叉树&#xff08;三&#xff09;_染柒_GRQ的博客-CSDN博客点击上方链接即可查看。题目110. 平…

Ext2explore查看ext2/ext3/ext4 file

比如想查看Android system.img&#xff0c;file看起来是ext2文件&#xff0c;file system.img system.img: Linux rev 1.0 ext2 filesystem data, UUID49e89c77-3dc4-553f-a392-7d11ff348228 (extents) (large files) (huge files)2、windows下怎么看呢&#xff0c;Ext2explore…

Springboot——常用注解及实例

一、常用注解解释&#xff1a;ConfigurationBeanResourceSpringBootApplicationRestControllerRestController 注解包含了原来的 Controller 和 ResponseBody 注解&#xff0c;使用过 Spring 的朋友对 Controller 注解已经非常了解了&#xff0c;这里不再赘述&#xff0c; Resp…

【BSV应用范例】区块链上的自我主权身份

发表时间&#xff1a;2022年6月27日 信息来源&#xff1a;bsvblockchain.org 自我主权身份&#xff08;SSI&#xff09;只是一个空想吗&#xff1f; &#xff08;全球区块链组织联合创始人&#xff09;Jorge Sebastio对此表示&#xff1a;“并非如此&#xff01;” 更重要的是…

OS 学习笔记(7) 虚拟机

OS 学习笔记(7) 虚拟机 这篇笔记对应的王道OS 1.6 虚拟机&#xff0c;同时参考了 《Operating System Concepts, Ninth Edition》和 俗称ostep的《 Operating Systems: Three Easy Pieces》还有 《Operating Systems: Principles and Practice》 文章目录OS 学习笔记(7) 虚拟机…

软件测试之Android单元测试

根据维基百科的解释&#xff0c;单元测试又称为模块测试。是针对程序单元来进行正确性校验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中&#xff0c;一个单元就是单个程序&#xff0c;函数&#xff0c;过程等&#xff0c;对于面向对象编程&#xff0c;最小单元…

STL——string类

一、标准库中的string类 1.string类文档介绍 &#xff08;1&#xff09;字符串是表示字符序列的类。 &#xff08;2&#xff09;标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的接口&#xff0c;但添加了专门用于操作单字节字符字符串的设计特…

IOS逆向--恢复Dyld的内存加载方式

之前我们一直在使用由dyld及其NSCreateObjectFileImageFromMemory/NSLinkModule API方法所提供的Mach-O捆绑包的内存加载方式。虽然这些方法我们今天仍然还在使用&#xff0c;但是这个工具较以往有一个很大的区别…现在很多模块都被持久化到了硬盘上。 roguesys 在 2022 年 2 …

还在用 OpenFeign?来试试 SpringBoot3 中的这个新玩意!

好久没发技术文章了&#xff0c;最近回到工作地&#xff0c;晚上有空又可以码码技术了&#xff0c;今天我们就来聊一个 Spring Boot3 中的新鲜玩意&#xff0c;声明式 HTTP 调用。 1. 由来 Spring Boot3 去年底就已经正式发布&#xff0c;我也尝了一把鲜&#xff0c;最近有空…

(02)Cartographer源码无死角解析-(53) 2D后端优化→位姿图优化理论(SPA)讲解、核型函数调用流程

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

Docker镜像部署至Rancher全局配置 以xxl-job-admin为例

流程以xxl-job-admin为例 1.基础环境 win/mac/linuxRancherDocker 2.下载源码 从Github上下载xxl-job xxl-jobGithub xxl-job官方地址 3.修改源码 打开 xxl-job 下的 xxl-job-admin 修改 application-properties 文件 修改数据库 修改为这种格式&#xff1a; 大括号包…

MPLS实验

目录实验要求mpls简介mpls工作过程实验的配置环回的配置R1和R5之间公网的ospf配置配置mpls-ldp配置R1和R5间的mplsvpn私网的rip及ospf的宣告配置公网mp-bgp的建立R2和R4上面的双向重发布R7和R8之间创建R7和R8间的mplsvpn配置静态路由及环回重发布实验要求 如图 要求&#xff1…

【C++修炼之路】15.C++继承

每一个不曾起舞的日子都是对生命的辜负 继承C继承一. 继承的概念及定义1.1 继承的引出1.2 继承的概念1.3 继承的定义二.基类和派生类对象赋值转换三.继承中的作用域3.1 作用域的概念3.2 举例说明同名冲突四.派生类的默认成员函数4.1 派生类的构造函数4.2 派生类的拷贝构造函数4…

【python学习笔记】:数据科学库操作(二)

接上一篇&#xff1a; 4、PIL Python Imaging Library(PIL) 已经成为 Python 事实上的图像处理标准库了&#xff0c;这是由于&#xff0c;PIL 功能非常强大&#xff0c;但API却非常简单易用。但是由于PIL仅支持到 Python 2.7&#xff0c;再加上年久失修&#xff0c;于是一群志…