• springmvc-day01


    springmvc-day01

    第一节 SpringMVC概述

    1. SpringMVC 优势

    SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。之所以能做到这一点,是因为 SpringMVC 具备如下显著优势:

    • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
    • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
    • 代码清新简洁,大幅度提升开发效率
    • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
    • 性能卓著,尤其适合现代大型、超大型互联网项目要求

    2. 表述层框架要解决的基本问题

    • 请求映射:让一个方法处理一个请求,核心关键点是:请求路径与处理请求的方法对应
    • 数据输入:获取请求参数,核心关键点: 与请求参数名对应
    • 类型转换:内置或者自定义类型转换器,对请求参数的类型进行转换
    • 数据校验:参数的非空校验
    • 视图界面:Thymeleaf,核心关键点: 逻辑视图以及前后缀的配置
    • 请求分发:请求转发、重定向,核心关键点:路径的编写
    • 与域对象交互, 核心关键点: 往域对象存数据(发生在表现层)的时候是存键值对,从域对象取出数据(发生在Thymeleaf页面)的时候是根据key取出值
    • 会话控制:Session
    • 过滤拦截:SpringMVC中有与Filter功能类似的拦截器
    • 异步交互:获取JSON类型的请求参数封装到实体类对象、以及将对象转成JSON响应给客户端
    • 文件上传
    • 文件下载

    第二节 SpringMVC入门案例

    1. 功能需求

    1.1 访问首页

    在这里插入图片描述

    1.2 在首页点超链接

    在这里插入图片描述

    2. 搭建环境

    2.1 导入依赖
    <dependencies>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.3.1version>
        dependency>
        
        
        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-classicartifactId>
            <version>1.2.3version>
        dependency>
        
        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>
        
        
        <dependency>
            <groupId>org.thymeleafgroupId>
            <artifactId>thymeleaf-spring5artifactId>
            <version>3.0.12.RELEASEversion>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    由于Maven的传递性,我们不必将所有的包全部配置依赖,而是配置最顶端的依赖,其他考传递性导入

    在这里插入图片描述

    2.2日志配置文件

    文件名:logback.xml

    
    <configuration debug="true">
        
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                
                
                <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%line] [%msg]%npattern>
            encoder>
        appender>
    
        
        
        <root level="DEBUG">
            
            <appender-ref ref="STDOUT" />
        root>
    
        
        <logger name="org.springframework.web.servlet.DispatcherServlet" level="DEBUG" />
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    2.3 web.xml配置
    
    <servlet>
        <servlet-name>DispatcherServletservlet-name>
        
        
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        
        
        <init-param>
        
            
            <param-name>contextConfigLocationparam-name>
        
            
            <param-value>classpath:spring-mvc.xmlparam-value>
        init-param>
        
        
        
        <load-on-startup>1load-on-startup>
        
    servlet>
        
    <servlet-mapping>
        <servlet-name>DispatcherServletservlet-name>
        
        
        
        
        <url-pattern>/url-pattern>
    servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    2.4 Spring配置文件
    
    <context:component-scan base-package="com.atguigu.mvc.handler"/>
        
    
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
        
                        
                        <property name="prefix" value="/WEB-INF/templates/"/>
        
                        
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8" />
                    bean>
                property>
            bean>
        property>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.代码实现

    3.1 创建请求处理器类
    3.1.1 命名规范

    SpringMVC 对处理请求的类并没有特殊要求,只要是 JavaBean 即可。我们自己习惯上有两种命名方式:

    • XxxHandler:意思是 Xxx 处理器的意思
    • XxxController:意思是 Xxx 控制器的意思

    这只是一个命名的习惯,不是语法要求。所以往往把处理请求的类叫做『Handler类』,处理请求的方法叫做『Handler方法』。

    3.1.2 创建处理器类
    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HelloController {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.2 实现访问页面

    3.2.1 创建方法
    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HelloController {
    
        @RequestMapping("/sayHello")
        public String sayHello(){
            System.out.println("Hello world!!");
            // 方法的返回值就是对应的Thymeleaf模板的逻辑视图
            return "target";
        }
    
        @RequestMapping("/sayHaha")
        private String sayHaha(){
            System.out.println("haha world!!!");
            return "haha";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    3.2.2 创建页面

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hahatitle>
    head>
    <body>
        <h1>hahaha!!!h1>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    启动tomcat 输入地址查看
    在这里插入图片描述

    3.2.3 整体流程解析

    在这里插入图片描述

    第三节 常见注解

    1.RequestMapping注解

    1.1 作用

    从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求的 URL 地址和处理请求的方式关联起来,建立映射关系。

    SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。

    1.2 使用位置
    • 类上
    • 方法上
    1.2.1 准备客户端访问路径
    <h3>测试@RequestMapping注解标记在类上h3>
    <a th:href="@{/user/login}">用户登录a><br/>
    <a th:href="@{/user/register}">用户注册a><br/>
    <a th:href="@{/user/logout}">用户退出a><br/>
    
    • 1
    • 2
    • 3
    • 4
    1.2.2 仅标记在方法上的RequestMapping注解
    @RequestMapping("/user/login")
    @RequestMapping("/user/register")
    @RequestMapping("/user/logout")
    
    • 1
    • 2
    • 3
    1.2.3 分别标记在类和方法上的@RequestMapping注解

    在类级别:抽取各个方法上@RequestMapping注解地址中前面重复的部分

    @RequestMapping("/hello")
    
    • 1

    在方法级别:省略被类级别抽取的部分

    @RequestMapping("/sayHello")
    @RequestMapping("/sayHaha")
    
    • 1
    • 2
    1.3 指定请求方式
    1.3.1 通过RequestMapping的method属性指定

    HTTP 协议定义了八种请求方式,在 SpringMVC 中封装到了下面这个枚举类

    public enum RequestMethod {
        GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
    }
    
    • 1
    • 2
    • 3

    设置RequestMapping注解的method属性

    @RequestMapping(value = "/sayHaha", method = RequestMethod.POST)
    private String sayHaha(){
        System.out.println("haha world!!!");
        return "haha";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    必须使用post方式向此方法发起请求 否则会抛出异常405

    1.3.2 通过RequestMapping的进阶注解指定
    原版进阶版
    @RequestMapping(value = “/emp”, method = RequestMethod.GET)@GetMapping(“/emp”)
    @RequestMapping(value = “/emp”, method = RequestMethod.POST)@PostMapping(“/emp”)
    @RequestMapping(value = “/emp”, method = RequestMethod.PUT)@PutMapping(“/emp”)
    @RequestMapping(value = “/emp”, method = RequestMethod.DELETE)@DeleteMapping(“/emp”)

    针对Http的八种请求方式都有专门的注解

    另外需要注意:进阶版的这几个注解是从 4.3 版本才开始有,低于 4.3 版本无法使用。

    1.4 Ambiguous mapping异常

    出现原因:多个 handler 方法映射了同一个地址,导致 SpringMVC 在接收到这个地址的请求时该找哪个 handler 方法处理。

    Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map ‘demo03MappingMethodHandler’ method com.atguigu.mvc.handler.Demo03MappingMethodHandler#empPost() to { [/emp]}: There is already ‘demo03MappingMethodHandler’ bean method com.atguigu.mvc.handler.Demo03MappingMethodHandler#empGet() mapped.

    2.RequestHeader注解

    2.1 作用

    通过这个注解获取请求消息头中的具体数据。

        // 相当于| 原版@RequestMapping(value = "/getHeader",method = RequestMethod.GET) |        |
        @GetMapping("/getHeader")
        public String getHeader(@RequestHeader("user-agent") String userAgent){
            // 目标:获取一个名为"user-agent"的请求头的值
            System.out.println("user-agent:" + userAgent);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    3.CookieValue注解

    3.1 作用

    获取当前请求中的Cookie数据

    3.2 用法

    先创建IndexController类

    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpSession;
    
    @Controller
    public class IndexController {
    
        @RequestMapping("/")
        // 设置session
        public String index(HttpSession session){
            return "index";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    创建index.html页面

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>首页title>
    head>
    <body>
    <a th:href="@{/hello/sayHello}">访问sayHelloa> <br>
    <a th:href="@{/hello/sayHaha}">访问sayHahaa> <br>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    获取session

        @GetMapping("/getCookieValue")
        public String getCookieValue(@CookieValue(value = "JSESSIONID", defaultValue = "none") String sessionId){
            // 目标获取一个名为"JSESSIONID"的cookie的值,如果没有值则赋默认值为none
            System.out.println("JSESSIONID:" + sessionId);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    第四节 获取请求参数

    1.根据一个参数名获取一个参数值

    1.1 前端页面携带请求参数
    <a th:href="@{/parameter/oneNameOneValue(username='aobama',nickname='sqyx',age=18)}">一个请求参数名对应一个值a>
    <br>
    
    • 1
    • 2
    1.2 处理器中获取请求参数
    1.2.1 最简写法
    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    @Controller
    @RequestMapping("/parameter")
    public class ParameterController {
        @RequestMapping("oneNameOneValue")
        public String oneNameOneValue(String username,
                                      String nickname,
                                      Integer age){
            // 最简单的方式获取单个请求参数:就是在handler方法中添加一个和请求参数名同名的参数,来接收请求参数
            // 其实这个地方此处省略了一个注解 @RequestParam
            System.out.println("获取到的请求参数username=" + username);
            System.out.println("获取到的请求参数nickname=" + nickname);
            System.out.println("获取到的请求参数age=" + age);
    
            return "target";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1.2.2 使用RequestParam注解
    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    @Controller
    @RequestMapping("/parameter")
    public class ParameterController {
        @RequestMapping("oneNameOneValue")
        public String oneNameOneValue(@RequestParam("username") String username,
                                      @RequestParam("nickname") String nickname,
                                      @RequestParam("age") Integer age){
            System.out.println("获取到的请求参数username=" + username);
            System.out.println("获取到的请求参数nickname=" + nickname);
            System.out.println("获取到的请求参数age=" + age);
    
            return "target";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    1.2.3 如果此时请求中没有携带或少携带了参数

    在这里插入图片描述

    页面信息说明:

    • 响应状态码:400(在 SpringMVC 环境下,400通常和数据注入相关)
    • 说明信息:必需的 String 请求参数 ‘username’ 不存在

    原因可以参考 @RequestParam 注解的 required 属性:默认值为true,表示请求参数默认必须提供

    /**
         * Whether the parameter is required.
         * 

    Defaults to {@code true}, leading to an exception being thrown * if the parameter is missing in the request. Switch this to * {@code false} if you prefer a {@code null} value if the parameter is * not present in the request. *

    Alternatively, provide a {@link #defaultValue}, which implicitly * sets this flag to {@code false}. */ boolean required() default true;

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们可以通过将required 属性设置为 false 表示这个请求参数可有可无:

    @RequestParam(value = "userName", required = false)
    
    • 1

    当然,我们也可以通过设置请求参数的默认值来解决上述400错误

    @RequestParam(value = "userName", defaultValue = "missing")
    
    • 1

    2. 根据一个参数名获取多个参数值

    2.1 前端页面携带请求参数
    <a th:href="@{/parameter/oneNameMultiValue(hobby='basketball',hobby='sing',hobby='dance')}">一个请求参数名对应多个值a>
    <br>
    
    • 1
    • 2
    2.2 处理器中获取请求参数
        @RequestMapping("/oneNameMultiValue")
        public String oneNameMultiValue(@RequestParam("hobby") List<String> hobby){
            System.out.println("获取到的请求hobby的值为:" + hobby);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    3.使用实体类封装请求参数

    3.1 前端页面携带请求参数
    <a th:href="@{/parameter/parametersToBean(username='aobama',address='ayd',age=18,phone=1233123123)}">多个请求参数封装到beana>
    <br>
    
    • 1
    • 2
    3.2 封装实体类

    注意:实体类的属性名要和请求参数名一致

    package com.atguigu.pojo;
    
    import lombok.Data;
    
    @Data
    public class User {
        private String username;
        private String address;
        private Integer age;
        private String phone;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    .3.3 处理器中获取请求参数
    	@RequestMapping("/parametersToBean")
        public String parametersToBean(User user){
            System.out.println("获取请求参数封装到user中:" + user);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    3.4 解决POST请求得中文字符乱码问题
    <form th:action="@{/parameter/parametersToBean}" method="post">
        用户名: <input type="text" name="username"> <br>
        地址: <input type="text" name="address"> <br>
        年龄: <input type="text" name="age"> <br>
        手机号: <input type="text" name="phone"> <br>
        <button>提交button>
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    到 web.xml 中配置 CharacterEncodingFilter 即可:

    
    <filter>
        <filter-name>CharacterEncodingFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        
        
        <init-param>
            <param-name>encodingparam-name>
            <param-value>UTF-8param-value>
        init-param>
        
        
        <init-param>
            <param-name>forceRequestEncodingparam-name>
            <param-value>trueparam-value>
        init-param>
        
        <init-param>
            <param-name>forceResponseEncodingparam-name>
            <param-value>trueparam-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    注1:在较低版本的 SpringMVC 中,forceRequestEncoding 属性、forceResponseEncoding 属性没有分开,它们是一个 forceEncoding 属性。这里需要注意一下。

    注2:由于 CharacterEncodingFilter 是通过 request.setCharacterEncoding(encoding); 来设置请求字符集,所以在此操作前不能有任何的 request.getParameter() 操作。在设置字符集之前获取过请求参数,那么设置字符集的操作将无效。

    4.使用Map封装请求参数

    4.1 前端页面
    <a th:href="@{/parameter/parametersToMap(username='aobama',address='ayd',age=18,phone=1233123123)}">多个请求参数封装到Mapa>
    <br>
    
    • 1
    • 2
    4.2 处理器接收参数
        @RequestMapping("/parametersToMap")
        public String parametersToMap(@RequestParam Map parameterMap){
            System.out.println("获取请求参数封装到parameterMap中:" + parameterMap);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    5.实体类封装得数据包含级联属性

    5.1 实体类

    Student

    package com.atguigu.pojo;
    
    import lombok.Data;
    
    import java.util.List;
    import java.util.Map;
    
    @Data
    public class Student {
        private String stuName;
        private School school;
        private List<Subject> subjectList;
        private Map<String,Double> scores;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    School

    package com.atguigu.pojo;
    
    import lombok.Data;
    
    @Data
    public class School {
        private String schoolName;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Subject

    package com.atguigu.pojo;
    
    import lombok.Data;
    
    @Data
    public class Subject {
        private String subjectName;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    5.2 前端页面
    
    <form th:action="@{/parameter/toNestEntity}" method="post">
        stuName:<input type="text" name="stuName" value="tom"/><br/>
        school.schoolName:<input type="text" name="school.schoolName" value="atguigu"/><br/>
        subjectList[0].subjectName:<input type="text" name="subjectList[0].subjectName" value="java"/><br/>
        subjectList[1].subjectName:<input type="text" name="subjectList[1].subjectName" value="php"/><br/>
        subjectList[2].subjectName:<input type="text" name="subjectList[2].subjectName" value="javascript"/><br/>
        subjectList[3].subjectName:<input type="text" name="subjectList[3].subjectName" value="css"/><br/>
        subjectList[4].subjectName:<input type="text" name="subjectList[4].subjectName" value="vue"/><br/>
        scores['Chinese']:<input type="text" name="scores['Chinese']" value="100"/><br/>
        scores['English']:<input type="text" name="scores['English']" value="95" /><br/>
        scores['Mathematics']:<input type="text" name="scores['Mathematics']" value="88"/><br/>
        scores['Chemistry']:<input type="text" name="scores['Chemistry']" value="63"/><br/>
        scores['Biology']:<input type="text" name="scores['Biology']" value="44"/><br/>
        <input type="submit" value="保存"/>
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    5.3 处理器中获取请求参数
        @RequestMapping("/toNestEntity")
        public String toNestEntity(Student student){
            System.out.println("接收到得请求参数封装到Student对象:" + student);
            return "target";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    第五节 访问静态资源

    1.SpringMVC环境下的静态资源访问问题

    1.1 问题描述

    在Web应用中加入图片资源

    在这里插入图片描述

    访问静态资源

    在这里插入图片描述

    1.2 分析原因
    • DispatcherServlet 的 url-pattern 配置的是“/”
    • url-pattern 配置“/”表示整个 Web 应用范围内所有请求都由 SpringMVC 来处理
    • 对 SpringMVC 来说,必须有对应的 @RequestMapping 才能找到处理请求的方法
    • 现在static/images/mm.jpg 请求没有对应的 @RequestMapping 所以返回 404
    1.3 解决办法

    在SpringMVC配置文件中增加配置

    
    
    <mvc:default-servlet-handler/>
    
    • 1
    • 2
    • 3

    再次测试访问图片
    在这里插入图片描述

    新的问题:其他原本正常的请求访问不了了,进一步解决问题:再增加一个配置

    在这里插入图片描述

    
    
    <mvc:annotation-driven/>
    
    • 1
    • 2
    • 3

    加了此注解之后解决问题了

    在这里插入图片描述

    1.4 default-servlet-handler底层

    所在类:org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler

    关键方法:handleRequest()方法

    大体机制:SpringMVC 首先查找是否存在和当前请求对应的 @RequestMapping;如果没有,则调用handleRequest()方法转发到目标资源。

    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
        
        Assert.state(this.servletContext != null, "No ServletContext set");
        RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
        if (rd == null) {
            throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
            this.defaultServletName + "'");
        }
        
        // 这里执行请求转发操作
        rd.forward(request, response);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第六节 页面跳转控制

    1.访问Thymeleaf前后缀控制范围内的页面

    访问Thymeleaf前后缀控制范围之内的页面,直接return逻辑视图即可,但是访问前后缀控制范围之外的页面,则需要使用重定向或者请求转发

    2.访问Thymeleaf前后缀控制范围外的页面

    2.1 创建范围之外的页面

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h1>范围之外页面h1>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2.2 在 SpringMVC 配置文件加入配置

    下面配置是访问静态资源所需配置(如果没有它的话,访问静态资源会被DispatcherServlet所拦截):

    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>
    
    • 1
    • 2
    2.3 使用指令进行跳转
    2.3.1 请求转发的指令
    @RequestMapping("/forwardCommand")
    public String forwardCommand(){
        //使用转发指令:在handler方法中,访问Thymeleaf前后缀控制范围外的页面
        //"forward:要转发到的资源路径",相当于使用的是请求转发跳转
        //请求转发的绝对路径是:在uri的基础上省略"/项目名"
        return "forward:/outter.html";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.mvc:view-controller访问页面

    3.1 场景描述

    在一个 handler 方法中,仅仅只是完成 @RequestMapping 映射,将请求转发到目标视图,除此之外没有任何其他代码。此时可以使用 SpringMVC 配置文件中的配置代替这样的 handler 方法。

    3.2 具体操作
    3.2.1 访问Thymeleaf前后缀控制范围内的页面

    在 SpringMVC 配置文件中使用 mvc:view-controller 配置:

    
        <mvc:view-controller path="/xixi" view-name="xixi">mvc:view-controller>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时浏览器路径"xixi"可以访问到Thymeleaf前后缀控制范围内的xixi.html页面

    3.2.2 访问Thymeleaf前后缀控制范围外的页面

    在 SpringMVC 配置文件中使用 mvc:view-controller 配置:

        <mvc:view-controller path="/outer" view-name="redirect:/outer.html">mvc:view-controller>
    
    
    • 1
    • 2

    此时就相当于代替了之前的重定向访问的哪个handler方法

    3.3.3 遇到的问题

    加入 mvc:view-controller 配置后,其他正常 @RequestMapping 将失效。此时还是需要加入 mvc:annotation-driven 来解决。

    4.三个配置影响访问效果探索

    通过前面的学习,我们发现无论是添加了default-servlet-handler还是view-controller,我们都必须添加annotation-driven标签。所以annotation-driven标签是SpringMVC必须添加的

    接下来我们从源码角度分析这三个配置:

    4.1 相关组件:HandlerMapping

    见名知意,HandlerMapping 封装的数据包含了请求地址和 handler 方法之间的映射关系。所以请求访问是否能生效关键要看 HandlerMapping 在 IOC 容器中加载的情况。为了看到这一点,我们可以在 DispatcherServlet 中找到 doDispatch() 方法设置断点。之所以选择这个方法,是因为每一个由 SpringMVC 处理的请求都会经过这里,便于操作。

    在这里插入图片描述

    4.2 按三种标签的配置情况进行分析
    4.2.1 三个标签都没有配置的情况

    在这里插入图片描述

    我们看到 SpringMVC 加载了三个 HandlerMapping:

    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    org.springframework.web.servlet.function.support.RouterFunctionMapping

    其中 RequestMappingHandlerMapping 封装了 @RequestMapping 相关请求,有它在 @RequestMapping 相关请求就能访问到。

    这里顺带一提,在较低版本的 SpringMVC 此处要加载的是:

    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

    其中 DefaultAnnotationHandlerMapping 封装了 @RequestMapping 相关请求,有它在 @RequestMapping 相关请求就能访问到。

    4.2.2 配置了 mvc:view-controller 或 mvc:default-servlet-handler 的情况

    在这里插入图片描述

    我们看到 SpringMVC 加载了两个 HandlerMapping:

    org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

    此时没有了RequestMappingHandlerMapping,所以无法根据@RequestMapping的映射来调用handler方法了

    较低版本的 SpringMVC 在这里的情况一样。

    4.2.3 三个标签全部配置了的情况

    配置全部 mvc:view-controller、mvc:default-servlet-handler、mvc:annotation-driven 三个标签。

    在这里插入图片描述

    我们看到 SpringMVC 加载了略有不同的三个 HandlerMapping:

    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

    此时RequestMappingHandlerMapping 封装了 @RequestMapping 相关请求,有它在 @RequestMapping 相关请求就能访问到。

    较低版本的 SpringMVC 在这里的情况还是一样。

    第七节 SpringMVC使用域对象

    1.请求域对象

    1.1 将数据传入请求域对象
    1.1.1 使用原生的Servlet的API操作
    package com.atguigu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Controller
    @RequestMapping("/scope")
    public class ScopeController {
    
        @RequestMapping("/useRequestScope")
        public String useRequestScope(HttpServletRequest httpServletRequest){
            // 目标:将数据存储到请求域对象,然后跳转到target页面
            // 方式一:使用原始的request来完成
            httpServletRequest.setAttribute("requestScopeKey", "requestScopeValue");
            return "scopeValue";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    scope.html代码

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        获取请求域中的数据 <span th:text="${requestScopeKey}">span> <br>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1.1.2 使用 Model 类型的形参操作
        // 方式二:使用Model对象往请求域中存储值
        @RequestMapping("/useRequestScope")
        public String useRequestScope(Model model) {
            // 目标:将数据存储到请求域对象,然后跳转到target页面
            model.addAttribute("requestScopeKey", "requestScopeValue");
            return "scopeValue";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.1.3 使用 ModelMap 类型的形参
    @RequestMapping("/attr/request/model/map")
    public String useRequestScope(
        
            // 在形参位置声明ModelMap类型变量,用于存储模型数据
            ModelMap modelMap) {
        
        // 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
        // 存入请求域这个动作也被称为暴露到请求域
        modelMap.addAttribute("requestScopeMessageModelMap","i am very happy[model map]");
        
        return "target";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1.1.4 使用 Map 类型的形参
    @RequestMapping("/attr/request/map")
    public String useRequestScope(
        
            // 在形参位置声明Map类型变量,用于存储模型数据
            Map<String, Object> map) {
        
        // 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
        // 存入请求域这个动作也被称为暴露到请求域
        map.put("requestScopeMessageMap", "i am very happy[map]");
        
        return "target";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1.1.5 使用 ModelAndView 对象
    @RequestMapping("/attr/request/mav")
    public ModelAndView useRequestScope() {
        
        // 1.创建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        
        // 2.存入模型数据
        modelAndView.addObject("requestScopeMessageMAV", "i am very happy[mav]");
        
        // 3.设置视图名称
        modelAndView.setViewName("target");
        
        return modelAndView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1.2 模型的本质
    1.2.1 BindingAwareModelMap

    SpringMVC 传入的 Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的。

    1.2.2 体系结构

    在这里插入图片描述

    2.会话域对象

    使用会话域最简单直接的办法就是使用原生的 HttpSession 对象

        // 会话域
        @RequestMapping("/useSessionScope")
        public String useSessionScope(HttpSession httpSession){
            httpSession.setAttribute("sessionScopeKey", "sessionScopeValue");
            return "scopeValue";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    前端代码

        获取会话域中的数据 <span th:text="${session.sessionScopeKey}">span> <br>
    
    • 1

    在这里插入图片描述

    3.应用域

    应用域同样是使用IOC注入的方式来操作:

    package com.atguigu.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    @Controller
    @RequestMapping("/scope")
    public class ScopeController {
    
        @Autowired
        private ServletContext servletContext;
    
        // 应用域 需要使用IOC注入的方式来操作
        @RequestMapping("/useApplicationScope")
        public String useApplicationScope(){
            servletContext.setAttribute("applicationScopeKey", "applicationValue");
            return "scopeValue";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    前端代码

        获取应用域中的数据 <span th:text="${application.applicationScopeKey}">span> <br>
    
    
    • 1
    • 2

    浏览器发起请求 输出结果

    在这里插入图片描述

    第八节 综合案例

    1.案例准备工作

    1.1 引入依赖
      <dependencies> 
          
        <dependency> 
          <groupId>org.springframeworkgroupId>  
          <artifactId>spring-webmvcartifactId>  
          <version>5.3.1version> 
        dependency>  
          
        <dependency> 
          <groupId>ch.qos.logbackgroupId>  
          <artifactId>logback-classicartifactId>  
          <version>1.2.3version> 
        dependency>  
          
        <dependency> 
          <groupId>javax.servletgroupId>  
          <artifactId>javax.servlet-apiartifactId>  
          <version>3.1.0version>  
          <scope>providedscope> 
        dependency>  
          
        <dependency> 
          <groupId>org.thymeleafgroupId>  
          <artifactId>thymeleaf-spring5artifactId>  
          <version>3.0.12.RELEASEversion> 
        dependency>  
        <dependency> 
          <groupId>org.junit.jupitergroupId>  
          <artifactId>junit-jupiter-apiartifactId>  
          <version>5.7.0version>  
          <scope>testscope> 
        dependency>  
        <dependency> 
          <groupId>org.springframeworkgroupId>  
          <artifactId>spring-testartifactId>  
          <version>5.3.1version> 
        dependency>  
          
        <dependency> 
          <groupId>org.projectlombokgroupId>  
          <artifactId>lombokartifactId>  
          <version>1.18.8version>  
          <scope>providedscope> 
        dependency>  
          
        <dependency> 
          <groupId>org.springframeworkgroupId>  
          <artifactId>spring-ormartifactId>  
          <version>5.3.1version> 
        dependency>  
          
        <dependency> 
          <groupId>mysqlgroupId>  
          <artifactId>mysql-connector-javaartifactId>  
          <version>8.0.27version> 
        dependency>  
          
        <dependency> 
          <groupId>com.alibabagroupId>  
          <artifactId>druidartifactId>  
          <version>1.0.31version> 
        dependency>  
        <dependency> 
          <groupId>org.springframeworkgroupId>  
          <artifactId>spring-aspectsartifactId>  
          <version>5.3.1version> 
        dependency> 
      dependencies> 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    1.2 数据建模
    1.2.1 物理建模

    使用之前的t_soldier表

    1.2.2 逻辑建模
    package com.atguigu.pojo;
    
    import lombok.Data;
    
    @Data
    public class Soldier {
        private Integer soldierId;
        private String soldierName;
        private String soldierWeapon;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1.3 创建Dao
    1.3.1 创建SoldierDao接口
    package com.atguigu.dao;
    
    import com.atguigu.pojo.Soldier;
    
    import java.util.List;
    
    public interface SoldierDao {
    
        /**
         * 根据id删除
         * @param soldierId
         */
        void deleteById(Integer soldierId);
    
        /**
         * 更新
         * @param soldier
         */
        void update(Soldier soldier);
    
    
        /**
         * 新增士兵
         * @param soldier
         */
        void add(Soldier soldier);
    
        /**
         * 根据id查询士兵
         * @param soldierId
         * @return
         */
        Soldier getSoldierById(Integer soldierId);
    
        /**
         * 获取所有士兵
         * @return
         */
        List<Soldier> findAll();
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    1.3.2 创建SoldierDaoImpl实现类
    package com.atguigu.impl;
    
    import com.atguigu.dao.SoldierDao;
    import com.atguigu.pojo.Soldier;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    @Repository
    public class SoldierDaoImpl implements SoldierDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void deleteById(Integer soldierId) {
            String sql = "delete from t_soldier where soldier_id=?";
            jdbcTemplate.update(sql, soldierId);
        }
    
        @Override
        public void update(Soldier soldier) {
            String sql = "update t_soldier set soldier_name=?,soldier_weapon=? where soldier_id=?";
            jdbcTemplate.update(sql, soldier.getSoldierName(),soldier.getSoldierWeapon(),soldier.getSoldierId());
    
        }
    
        @Override
        public void add(Soldier soldier) {
            String sql = "insert into t_soldier(soldier_name,soldier_weapon) values(?,?)";
            jdbcTemplate.update(sql, soldier.getSoldierName(),soldier.getSoldierWeapon());
    
        }
    
        @Override
        public Soldier getSoldierById(Integer soldierId) {
            String sql = "select soldier_id soldierId,soldier_name soldierName,soldier_weapon soldierWeapon from t_soldier where soldier_id=?";
            return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Soldier.class), soldierId);
        }
    
        @Override
        public List<Soldier> findAll() {
            String sql = "select soldier_id soldierId,soldier_name soldierName,soldier_weapon soldierWeapon from t_soldier";
            return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Soldier.class));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    1.4 创建Service
    1.4.1 创建SoldierService接口
    package com.atguigu.service;
    
    import com.atguigu.pojo.Soldier;
    
    import java.util.List;
    
    public interface SoldierService {
    
        /**
         * 根据id删除
         * @param soldierId
         */
        void deleteById(Integer soldierId);
    
        /**
         * 更新
         * @param soldier
         */
        void update(Soldier soldier);
    
    
        /**
         * 新增士兵
         * @param soldier
         */
        void add(Soldier soldier);
    
        /**
         * 根据id查询士兵
         * @param soldierId
         * @return
         */
        Soldier getSoldierById(Integer soldierId);
    
        /**
         * 获取所有士兵
         * @return
         */
        List<Soldier> findAll();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1.4.2 创建SoldierServiceImpl实现类
    package com.atguigu.service.impl;
    
    import com.atguigu.dao.SoldierDao;
    import com.atguigu.pojo.Soldier;
    import com.atguigu.service.SoldierService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    
    @Service
    public class SoldierServiceImpl implements SoldierService {
    
        @Autowired
        private SoldierDao soldierDao;
    
        @Transactional(propagation = Propagation.REQUIRED)
        @Override
        public void deleteById(Integer soldierId) {
            soldierDao.deleteById(soldierId);
        }
    
        @Transactional(propagation = Propagation.REQUIRED)
        @Override
        public void update(Soldier soldier) {
            soldierDao.update(soldier);
        }
    
        @Transactional(propagation = Propagation.REQUIRED)
        @Override
        public void add(Soldier soldier) {
            soldierDao.add(soldier);
        }
    
        @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
        @Override
        public Soldier getSoldierById(Integer soldierId) {
            return soldierDao.getSoldierById(soldierId);
        }
    
        @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
        @Override
        public List<Soldier> findAll() {
            return soldierDao.findAll();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    2.环境搭建

    2.1 配置文件
    2.1.1 web.xml
    
    <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">
    	
    	<servlet>
    			<servlet-name>dispatcherServletservlet-name>
    			<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    			<init-param>
    				<param-name>contextConfigLocationparam-name>
    				<param-value>classpath:spring-web.xmlparam-value>
    			init-param>
    			<load-on-startup>1load-on-startup>
    		servlet>
    		
    		<servlet-mapping>
    			<servlet-name>dispatcherServletservlet-name>
    			<url-pattern>/url-pattern>
    		servlet-mapping>
    	
    	    
    	        
    	        <filter>
    	            <filter-name>CharacterEncodingFilterfilter-name>
    	            <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    	            
    	            <init-param>
    	                <param-name>encodingparam-name>
    	                <param-value>UTF-8param-value>
    	            init-param>
    	            
    	            <init-param>
    	                <param-name>forceRequestEncodingparam-name>
    	                <param-value>trueparam-value>
    	            init-param>
    	            
    	            <init-param>
    	                <param-name>forceResponseEncodingparam-name>
    	                <param-value>trueparam-value>
    	            init-param>
    	        filter>
    	        <filter-mapping>
    	            <filter-name>CharacterEncodingFilterfilter-name>
    	            <url-pattern>/*url-pattern>
    	        filter-mapping>
    	
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    2.1.2. logback.xml
    
    <configuration debug="true">
        
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                
                
                <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%line] [%msg]%npattern>
            encoder>
        appender>
    
        
        
        <root level="DEBUG">
            
            <appender-ref ref="STDOUT"/>
        root>
    
        
        <logger name="org.springframework.web.servlet.DispatcherServlet" level="DEBUG"/>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    2.1.3 SpringMVC配置文件spring-web.xml
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    
    
        
        <mvc:annotation-driven>mvc:annotation-driven>
    
        
        <mvc:default-servlet-handler>mvc:default-servlet-handler>
    
        
        <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
            <property name="order" value="1"/>
            <property name="characterEncoding" value="UTF-8"/>
            <property name="templateEngine">
                <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                    <property name="templateResolver">
                        <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    
                            
                            <property name="prefix" value="/WEB-INF/templates/"/>
    
                            
                            <property name="suffix" value=".html"/>
    
                            
                            <property name="templateMode" value="HTML5"/>
                            
                            <property name="characterEncoding" value="UTF-8"/>
                        bean>
                    property>
                bean>
            property>
        bean>
        
    
        <import resource="spring.xml">import>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    2.1.4 spring配置文件spring.xml
    
    <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:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <context:component-scan base-package="com.atguigu">context:component-scan>
    
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource">property>
        bean>
        
    
        <context:property-placeholder location="classpath:jdbc.properties">context:property-placeholder>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="username" value="${datasource.username}">property>
            <property name="password" value="${datasource.password}">property>
            <property name="url" value="${datasource.url}">property>
            <property name="driverClassName" value="${datasource.driver}">property>
        bean>
        
    
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource">property>
        bean>
        
        <tx:annotation-driven>tx:annotation-driven>
        
    
        <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    2.1.5 数据库配置文件 jdbc.properties
    datasource.url=jdbc:mysql://localhost:3306/mybatis2?characterEncoding=utf8&serverTimezone=UTC
    datasource.driver=com.mysql.cj.jdbc.Driver
    datasource.username=root
    datasource.password=123456
    
    • 1
    • 2
    • 3
    • 4

    3.测试功能是否正常

    package com.atguigu;
    
    import com.atguigu.pojo.Soldier;
    import com.atguigu.service.SoldierService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
    
    @SpringJUnitConfig(locations = "classpath:spring.xml")
    public class SoldierTest {
    
        @Autowired
        private SoldierService soldierService;
    
    
        @Test
        public void testFindAll(){
            System.out.println(soldierService.findAll());
        }
    
        @Test
        public void testGetSoldierById(){
            Soldier soldier = soldierService.getSoldierById(2);
            System.out.println(soldier);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    4.实现前后端功能

    4.1 显示展示士兵列表页面

    index.html

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>首页title>
    head>
    <body>
    <h1>欢迎来到首页h1>
    <a th:href="@{/soldier/findAll}">展示士兵列表a>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    spring-web.xml中添加

        <mvc:view-controller path="/" view-name="index.html">mvc:view-controller>
    
    
    • 1
    • 2

    效果:
    在这里插入图片描述

    4.2 在首页点击超链接显示全部数据
    4.2.1处理器类和处理器方法
    package com.atguigu.controller;
    
    import com.atguigu.pojo.Soldier;
    import com.atguigu.service.SoldierService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.util.List;
    
    @Controller
    @RequestMapping("/soldier")
    public class SoldierController {
        public static final String LIST_ACTION = "redirect:/soldier/findAll";
        public static final String PAGE_EDIT = "edit";
        public static final String PAGE_LIST = "list";
    
        @Autowired
        private SoldierService soldierService;
    
        @RequestMapping("/findAll")
        public String findAll(Model model){
            List<Soldier> soldierList = soldierService.findAll();
            model.addAttribute("soldierList", soldierList);
            return PAGE_LIST;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    4.2.2 前端页面 list.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>士兵列表页面title>
    head>
    <body>
    <table>
        <tr>
            <td>序号td>
            <td>士兵名称td>
            <td>士兵武器td>
            <td>修改td>
            <td>删除td>
        tr>
        <tr th:each="soldier,status:${soldierList}">
            <td th:text="${status.count}">td>
            <td th:text="${soldier.soldierName}">td>
            <td th:text="${soldier.soldierWeapon}">td>
            <td>
                <a>修改a>
            td>
            <td>
                <a>删除a>
            td>
        tr>
        <tr>
            <td >
                <a>添加士兵a>
            td>
        tr>
    table>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    展示效果:

    在这里插入图片描述

    4.3 删除一条数据
    4.3.1 修改数据展示时候的删除数据的超链接
            <td>
                <a th:href="@{/soldier/deleteById(id=${soldier.soldierId})}">删除a>
            td>
    
    • 1
    • 2
    • 3
    4.3.2 处理器方法 deleteById
        @RequestMapping("/deleteById")
        public String deleteById(@RequestParam("id") Integer soldierId){
            soldierService.deleteById(soldierId);
            // 重新查询所有,重定向查询所有方法
            return LIST_ACTION;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.4 跳转到添加页面
    4.4.1 修改页面上添加数据的超链接
        <tr>
            <td colspan="5">
                <a th:href="@{/add.html}">添加士兵a>
            td>
        tr>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    4.4.2 spring-web.xml中配置访问添加页面
        <mvc:view-controller path="/add.html" view-name="add">mvc:view-controller>
    
    
    • 1
    • 2
    4.4.3 创建add.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>添加士兵页面title>
    head>
    <body>
    <form th:action="@{/soldier/add}" method="post">
        士兵名称: <input type="text" name="soldierName"> <br>
        士兵武器:<input type="text" name="soldierWeapon"> <br>
        <button>提交button>
    form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    4.5 执行添加数据
    4.5.1 处理器方法
        @RequestMapping("/add")
        public String add(Soldier soldier){
            // 调用业务层的方法添加Soldier
            soldierService.add(soldier);
            // 重新查询所有
            return LIST_ACTION;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.6 跳转到更新表单回显数据
    4.6.1 修改页面更新数据的超链接
            <td>
                <a th:href="@{/soldier/getSoldierById(id=${soldier.soldierId})}">修改a>
            td>
    
    • 1
    • 2
    • 3
    4.6.2 处理器方法
        @RequestMapping("/getSoldierById")
        public String getSoldierById(@RequestParam("id") Integer soldierId, Model model){
            Soldier soldier = soldierService.getSoldierById(soldierId);
            model.addAttribute("soldier", soldier);
            return PAGE_EDIT;
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.6.3 创建edit.html
    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>编辑士兵页面title>
    head>
    <body>
    <form th:action="@{/soldier/update}">
        <input type="hidden" name="soldierId" th:value="${soldier.soldierId}">
        士兵姓名:<input type="text" name="soldierName" th:value="${soldier.soldierName}"> <br>
        士兵武器:<input type="text" name="soldierWeapon" th:value="${soldier.soldierWeapon}"> <br>
        <button>提交button>
    form>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    4.7 执行更新
    4.7.1 处理器方法
        @RequestMapping("/update")
        public String update(Soldier soldier){
            soldierService.update(soldier);
            return LIST_ACTION;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第九节 案例总结

    1. Spring和SpringMVC的环境

    1. 依赖
    2. web.xml中的配置:DispatcherServlet、CharacterEncodingFilter
    3. springmvc配置文件:
      1. 包扫描:为了解析组件注解(IOC和依赖注入的主键)
      2. 配置Thymeleaf的模板解析器:为了解析Thymeleaf模板
      3. 加载MVC注解驱动:为了能够找到Handler方法处理请求
      4. 处理静态资源
      5. view-controller:访问页面
    4. 注解:
      1. IOC和依赖注入的注解: Controller、Service、Repository、AutoWired
      2. SpringMVC的注解: RequestMapping(请求映射)、RequestParam(获取请求参数)
    5. 日志配置文件

    2. 持久层环境

    1. 依赖
    2. springmvc配置文件中配置持久层:
      1. 数据源:DruidDataSource
      2. JdbcTemplate
    3. 持久层实现类的方法中执行各个SQL语句

    3. 测试环境

    1. 依赖: junit5
    2. Spring整合Junit
    3. 测试:需要测试业务层和持久层的代码

    第十节 功能总结

    1. 单纯跳转页面的功能

    例如:访问首页、访问add.html添加页面,使用view-controller标签实现

    2. 查询功能

    例如:查询士兵列表、更新前的数据回显。它们的具体步骤:

    1. 需不需要带参数:就要看有没有查询条件
    2. 获取参数:
    3. 调用业务层的方法进行查询,获取到查询的数据
    4. 将查询到的数据存储到请求域
    5. 返回逻辑视图
    6. 在Thymeleaf页面获取请求域的数据,并展示

    3. 增删改功能

    例如:添加士兵、删除士兵、更新士兵。它们的具体步骤:

    1. 肯定需要带参数:Thymeleaf的路径携带参数、以及表单携带参数
    2. 参数乱码:配置过滤器解决
    3. 获取参数:单个参数、POJO封装参数
    4. 调用业务层的方法进行增删改
    5. 重新查询所有: 使用redirect指令重定向访问查询所有士兵的功能
  • 相关阅读:
    [AUTOSAR][诊断管理][ECU][$34] 下载请求
    详解MeerEVM:MeerDAG共识下的智能合约执行引擎
    LeetCode每日一题:1462. 课程表 IV(2023.9.12 C++)
    VS2015过期怎么办
    【Leetcode】1054. Distant Barcodes
    【Python】Python 格式化文本转换
    RFID产线自动化升级改造管理方案
    2023NOIP A层联测10-子序列
    升级 Kubernetes 上的 TiDB 集群
    IDataReader转成List<T>
  • 原文地址:https://blog.csdn.net/Libra_97/article/details/127954876