• 尚硅谷springboot笔记


    1、hellospringboot

    一个最简单的springboot项目开发步骤

    第一步是先创建一个普通的maven工程

    第二步是导入依赖

    
    <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">
        <modelVersion>4.0.0modelVersion>
    
        <groupId>com.htygroupId>
        <artifactId>springboot-01-helloworldartifactId>
        <version>1.0-SNAPSHOTversion>
    
        
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.6.4version>
        parent>
    
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
        dependencies>
    
        <build>
            <plugins>
                
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                plugin>
            plugins>
        build>
    project>
    
    • 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

    第三步就是编写主启动类

    //这个注解说明这是一个springboot应用  这个类叫做主程序类
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            SpringApplication.run(MainApplication.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    第四步编写controller 注:所有的包都必须放在主启动类同级包下

    @RestController
    public class HelloController {
    
        @RequestMapping(value = "/hello")
        public String handle01(){
            return "hello springboot";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    最后运行主启动类就行

    springboot部署的方法很简单,只需要使用maven的package命令打成jar包,然后直接在控制台使用java -jar 命令执行这个jar包就行

    注:一定要导入打包依赖才行

    2、依赖管理的自动配置

    2.1、依赖管理

    每一个springboot都有一个父项目,父项目做依赖管理

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.6.4version>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个父项目还有一个父项目

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-dependenciesartifactId>
        <version>2.6.4version>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    spring-boot-dependencies这个父项目中包含了所有我们可能会用到的jar包

    开发导入starter场景启动器

    在springboot开发中会见到spring-boot-starter-*之类的jar包,*就代表的是某种场景,只要引入starter这个场景的所有常规需要的依赖就会自动引入

    若官方的starter不满足需求,我们也可以自己自定义starter,但是不能以sprint-boot开头

    所有场景启动器最底层的依赖

    <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starterartifactId>
          <version>2.6.4version>
          <scope>compilescope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    无需关注版本号,自动版本仲裁

    引入依赖默认都可以不写版本号

    可以修改版本号

    在开发中,我们可以不想使用自带的jar包版本,修改版本的办法是,先去父项目中的properties标签中,找到要修改的jar包的标签,然后去自己的项目的pom文件,仿照父项目的写法,将自己的版本号填入即可

    2.2、自动配置

    自动配置好了tomcat,在前面引入webstarter的时候就已经引入了tomcat依赖

    自动配置好了springMVC,自动配置好了springmvc的常用功能,如字符编码问题

    默认的包结构,主程序所在的包及其下面的所有子包里面的组件都会被默认扫描进来,如果想要改变扫描路径有两种方式

    //方式一
    @SpringBootApplication(scanBasePackages="com.hty")
    
    //方式二
    @ComponentScan("com.hty")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    各种配置都有默认值,默认配置最终都是映射到某一个类上,配置文件的值最终会绑定到某个类上,这个类会在容器中有创建对象,springboot所有的自动配置功能都在spring-boot-autoconfigure包里面

    3、注解

    3.1、@Contiguration

    标记一个类为springboot中的配置类,我们使用一个案例来进行解析

    目前我们有一个User实体类,其中的构造和get,set方法在这里就省略,自行添加即可

    public class User {
        private String name;
        private Integer age;
    }
    
    • 1
    • 2
    • 3
    • 4

    在spring中,将一个实体类添加为bean的方法就是创建一个配置文件,然后在配置文件中进行配置,在springboot中我们可以创建一个配置类就相当于创建了一个配置文件,在config包下创建MyConfig配置类

    /*
    * 配置类中使用@Bean标注在方法上,给容器注册组件,默认是单实例的
    * 配置类也是容器的一个组件
    * proxyBeanMethods:代理bean的方法  默认为true  若为true则返回的是代理对象  每次调用组件的时候springboot都会检查容器中是否有这个组件
    *                                若为false   则就是多实例
    * */
    @Configuration(proxyBeanMethods = true)//告诉springboot这是一个配置类 == 配置文件
    public class MyConfig {
    
        /*
        * 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是同一个对象
        * */
        @Bean("user")  //以方法名作为组件的id  返回类型就是组件类型  创建的对象就是组件
        public User user01(){
            return new User("zhangsan",18);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    之后在主启动类中进行测试

    //这个注解说明这是一个springboot应用  这个类叫做主程序类
    @SpringBootApplication
    public class MainApplication {
    
        public static void main(String[] args) {
            //返回一个ioc容器
            ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
    
            //查看容器里面的所有组件
            String[] beanDefinitionNames = run.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
    		
            User user1 = run.getBean("user", User.class);
            User user2 = run.getBean("user", User.class);
            System.out.println(user1 == user2);//true 说明此时是单例模式
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.2、@Import

    给容器中导入一个组件 需要写在组件类的上面 参数是一个数组,可以将需要导入的组件写在里面,springboot就会在容器中创建这些组件,导入的组件的默认名称为全类名

    @Import({User.class})
    @Configuration(proxyBeanMethods = false)
    public class MyConfig {}
    
    • 1
    • 2
    • 3

    3.3、@Conditional

    条件装配,满足Conditional指定的条件则进行组件注入,Conditional是一个根注解,下面有很多的衍生注解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuEpZw45-1658323664146)(%E7%AC%94%E8%AE%B0.assets/image-20220321121545575.png)]

    /*表示只有在容器中有tom这个组件的时候才装配user这个组件,此时的tom组件不在容器中,这个注解还可以标注在类上表示只有在有tom这个组件的时候这个类中所有的组件才被创建*/
    @ConditionalOnBean(name = "tom")
    @Bean("user")  //以方法名作为组件的id  返回类型就是组件类型  创建的对象就是组件
    public User user(){
        return new User();
    }
    
    //@Bean("tom")
    public Pet pet(){
        return new Pet();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.3、@ImportResource

    引入原生配置文件,可以将xml配置文件中的bean迁移为配置类中的使用@Bean注解配置的组件

    @ImportResource("classpath:beans.xml")//导入resources目录下的beans.xml的spring配置文件
    public class MyConfig {}
    
    • 1
    • 2

    3.4、@ConfigurationProperties

    配置绑定,利用这个注解可以读取到配置文件中的属性,但是要注意,需要让配置绑定的类称为一个组件才能访问配置文件中的内容

    方式一 :@ConfigurationProperties+@Component

    首先我们创建一个实体类

    @Component//需要将其加入为一个组件才能使用springboot中的内容
    @ConfigurationProperties(prefix = "mycar")//prefix表示以这个为前缀的所有属性
    public class Car {
        private String brand;
        private Integer price;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编写配置文件中的内容

    # 汽车的信息
    mycar.brand=BYD
    mycar.price=100000
    
    • 1
    • 2
    • 3

    此时配置文件中的属性就已经注入进实体类了

    方式二 :@ConfigurationProperties+@EnableConfigurationProperties

    @EnableConfigurationProperties注解需要写在配置类上并指定需要开启属性配置功能的类

    @EnableConfigurationProperties(Car.class)//开启car的属性配置功能 并将car这个组件导入容器中
    public class MyConfig {}
    
    • 1
    • 2

    之后在实体类上加入@ConfigurationProperties注解,和前面的例子一样

    4、自动配置原理

    4.1、主启动类注解

    在主启动类中的@SpringBootApplication相当于一下三个注解

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    
    • 1
    • 2
    • 3
    • 4

    4.1.1、@SpringBootConfiguration

    查看源码可以发现,其实底层就是一个@Configuration,代表当前是一个配置类,也就是说,主启动类也是springboot中的一个配置类

    4.1.2、@ComponentScan

    指定扫描哪些包中的组件

    4.2.3、@EnableAutoConfiguration

    查看源码,发现主要是这两个注解

    /*
    自动配置包,进入这个注解的源码发现其实就是一个import注解
    @Import(AutoConfigurationPackages.Registrar.class)
    给容器中导入一个组件,利用register给容器中导入MainApplication包下的所有组件
    */
    @AutoConfigurationPackage
    /*
    利用AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)方法给容器中批量导入一些组件,这个方法又调用List configurations = getCandidateConfigurations(annotationMetadata,attributes)获取到所有需要导入到容器中的配置类
    */
    @Import(AutoConfigurationImportSelector.class)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5、简化开发的工具jar

    5.1、lombok

    简化javabean的开发,我们不需要手写bean中的一些方法,首先引入lombok的依赖

    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们还需要安装一个插件来使用lombok

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WSqz6PvW-1658323664147)(%E7%AC%94%E8%AE%B0.assets/image-20220322133359161.png)]

    lombok的使用

    @NoArgsConstructor//无参构造
    @AllArgsConstructor//有参构造
    @ToString//生成toString
    @Data//生成get和set方法
    @EqualsAndHashCode//重写equals和hashcode方法
    public class Car {
        private String brand;
        private Integer price;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    要注意:lombok并不是添加注解之后直接生成这些方法,而是在编译的时候生成这些方法

    若需要创建只包含个别属性的构造函数,那就需要自己手写

    @Slf4j日志注解的使用

    我们在平时的调试中会使用输出语句进行调试,使用lombok的@Slf4j注解就可以不使用输出语句来输出,直接使用自带的log属性就可以输出日志信息,这个日志也分为很多种类

    5.2、dev-tools

    [官方文档][https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools]

    引入依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-devtoolsartifactId>
        <optional>trueoptional>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    dev-tools可以实现springboot项目的热部署,以后项目只要出现改变,我们就可以直接按快捷键ctrl+F9就可以进行热部署,但是实际上仍然是重启,与手动点击重启是一样的效果

    真正的热部署是需要进行付费服务

    5.3、Spring Initailizr

    这个就是直接可以在idea的项目创建页面直接创建一个springboot的工程

    6、springboot的配置文件

    springboot兼容yaml格式配置文件,这种格式的配置文件非常适合用来做以数据为中心的配置文件

    6.1、基本的语法

    key: value; kv之间有空格

    大小写敏感

    使用缩进表示层级

    缩进不允许使用tab,只允许空格

    缩进的空格数不重要,只要相同层级的元素左对齐即可

    '#'表示注释

    单引号与双引号表示字符串内容,单引号中的换行符会被当做普通字符串输出,但是双引号中的换行符就会产生换行效果

    6.2、数据类型

    字面量:单个的,不可再分的值,date boolean string number null

    k: v
    
    • 1

    对象:键值对的集合,map,hash,set,object

    行内写法  k: {k1:v1,k2:v2,k3:v3}
    或者
    k:
    	k1: v1
    	k2: v2
    	k3: v3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数组:一组按次序排列的值 array、list、queue

    行内写法  k: [v1,v2,v3]
    或者
    k:
    	- v1
    	- v2
    	- v3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    案例

    我们定义两个实体类–人类和宠物类

    @Component
    @ConfigurationProperties(prefix = "person")
    @Data
    public class Person {
    
        private String userName;
        private Boolean boss;
        private Date birth;
        private Integer age;
        private Pet pet;
        private String[] interests;
        private List<String> animal;
        private Map<String, Object> score;
        private Set<Double> salarys;
        private Map<String, List<Pet>> allPets;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    @Data
    public class Pet {
        private String name;
        private Double weight;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    之后我们在配置文件中进行赋值

    person:
      userName: zhangsan
      boss: true
      birth: 2019/12/9
      age: 18
      interests: [篮球,足球]
      animal:
        - cat
        - dog
      score:
        english: 80
        math: 90
      salarys: [123123.12312,123123.123123]
      pet:
        name: xiaogou
        weight: 99.99
      allPets:
        sick:
          - {name: xiaogou,weight: 99.99}
          - name: xiaomao
            weight: 88
          - name: xiaoniao
            weight: 11
        health:
          - {name: xiaogou,weight: 99.99}
          - name: xiaomao
            weight: 88
          - name: xiaoniao
            weight: 11
    
    • 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

    6.3、自定义配置提示功能

    我们在使用spring原生的yaml配置的时候就会有补全提示,但是我们写自己的配置时没有提示,解决方法就是给类上加配置处理器

    导入依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-configuration-processorartifactId>
        <optional>trueoptional>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    刷新pom文件然后重启项目,以后自定义配置就会有自动补全功能了

    注:yaml会将属性名比较长的,按照驼峰命名规则命名的属性进行变形,例如userName会变形成user-name

    在插件中需要加入

    
    <plugin>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-maven-pluginartifactId>
        <configuration>
            <excludes>
                <exclude>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-configuration-processorartifactId>
                exclude>
            excludes>
        configuration>
    plugin>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样以后项目部署的时候就不会启动过于缓慢

    7、web开发

    7.1、静态资源部分

    7.1.1、静态资源的访问

    静态资源的目录可以是/static/public/resources/META-INF/resources,然后访问当前项目的根路径/+静态资源名称就能访问到了

    当我们的静态资源名与动态的controller的访问路径一致的时候,会访问动态的资源而不是静态资源,原理就是:静态映射/**,请求进来先去找Controller,然后再去找静态资源

    如何改变默认静态资源路径呢?

    spring:
      web:
        resources:
          static-locations: classpath:/haha
    
    • 1
    • 2
    • 3
    • 4

    静态资源访问路径可以配置多个,写法就是数组的写法

    7.1.2、静态资源访问前缀

    我们需要在配置文件中配置一个属性就可以了

    spring:
      mvc:
        static-path-pattern: /res/**
    
    • 1
    • 2
    • 3

    相当于是给静态资源配置一个访问路径的前缀,那么以后的访问路径就是当前项目/+static-path-pattern+静态资源名

    7.1.3、Webjars

    这个其实就是将一些静态的资源变成了依赖以供我们使用,比如jQuery

    具体使用可以访问webjars的官网https://www.webjars.org/

    在官网中就可以找到对应的依赖

    这类静态资源的访问地址是 http://ip:port/webjars/… 后面点点点这部分要按照依赖里面的包路径

    7.1.4、欢迎页

    欢迎页的设置有两种方式

    第一种方式

    在静态资源路径下创建一个index.html这个就会被默认当做欢迎页,但是要注意:可以配置静态资源路径但是不能配置静态资源的访问前缀,否则就会导致index.html就不能被默认访问

    第二种方式

    controller中有一个请求地址为/index,这个controller默认被当做欢迎页处理

    7.1.5、网页图标favicon

    只需要将要设置的图标改为favicon.ico名称,然后放在静态资源文件夹下就好了

    7.1.6、静态资源配置原理

    • spingboot启动默认加载 xxxAutoConfiguration类(自动配置类)
    • spingMVC功能的自动配置类WebMvcAutoConfiguration
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    		ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    7.2、常用参数注解

    7.2.1、@PathVariable

    在我们使用restful风格传递参数的时候,我们可以使用PathVariable注解来指定参数名

    //我们访问的地址为    /car/1/2
    @ReqestMapping("/car/{id}/{age}")
    public String hello(@PathVariable("id") Integer id,@PathVariable("age") Integer age){}
    
    • 1
    • 2
    • 3

    使用这个注解的好处就是当方法参数名与前端参数不一致的时候,程序依然能够获取到正确的值

    我们还可以使用一个Map集合直接获取所有的参数,key为前端的name

    注:map的泛型必须是两个String类型

    public String hello(@PathVariable Map<String,String> map{}
    
    • 1

    7.2.2、@RequestParam

    这个注解和@PathVariable用法几乎一样,这个注解翻译过来就是请求参数,那么也就是可以指定请求参数中的某一个,一般用于使用&符号拼接的请求参数

    7.2.3、@RequestHeader

    这个使用这个注解我们可以获取到此次请求的请求头信息

    我们可以使用一个Map集合获取所有的请求头信息,和@PathVariable中的Map的使用方法相同

    @RequestMapping()
    public String hello(@RequestHeader Map<String,String> map){}
    
    • 1
    • 2

    7.2.4、@CookieValue

    使用这个注解可以获取cookie的值

    public String hello(@CookieValue("key") String value){}
    
    • 1

    7.2.5、@RequestBody

    这个注解可以获取请求体中的内容,只有post请求才有请求体,所以相当于只有post请求能使用这个注解,例如:在前端有一个表单提价过来,我们将就可以使用这个注解来获取所有的key和value

    注:这个注解获取到的就是一个字符串,这个字符串的形式就是 k1=v1&k2=v2&k3=v3这种形式

    public String hello(@RequestBody String content){}
    
    • 1

    7.2.6、@RequestAttribute

    这个注解可以获取request域中保存的数据

    注:这个不能使用前面的注解的map形式

    7.2.7、@MatrixVariable

    矩阵变量

    正常的请求
    /cars/{path}?xxx=xxx&xxx=xxx
        
    矩阵变量  使用分号间隔
    /cars/{path;low=34;brand=byd,audi,yd}
    //Controller层获取参数的方式
    public String hello(@MatrixVariable("low") Integer low,
                        @MatrixVariable("brand") List<String> brand){}
    
    
    区别就在于,矩阵变量以分号为间隔而正常请求以&为间隔
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实际的案例

    当我们的cookie被禁用那么session如何使用?

    session被浏览器保存为一个名叫jsessionid的cookie,如果cookie被禁用那么就无法使用session,解决的方法就是使用矩阵变量形式/abc;jessionid=xxx,也叫作url重写

    矩阵变量的写法:

    两个key之间使用分号隔开,如果一个key有多个value,可以key=v1,v2,v2或者key=v1;key=v2两种方式都可以

    springboot默认禁用了矩阵变量的功能,我们需要手动开启

    手动开启矩阵变量

    原理:对于路径的处理,都是用UrlPathHelper进行解析,在UrlPathHelper中有一个属性是removeSemicolonContent支持矩阵变量的属性,这个属性默认为true,会自动移除分号后面的内容

    自定义的方法是编写一个配置类实现WebMvcConfigurer接口

    写法一:

    实现WebMvcConfigurer接口中的configurePathMatch方法来重写路径映射规则

    @Configuration(proxyBeanMethods = false)
    public class WebConfig implements WebMvcConfigurer {
        //重写路径映射规则
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper urlPathHelper = new UrlPathHelper();
            //设置为不移除分号后面的内容,矩阵变量功能就可以生效
            urlPathHelper.setRemoveSemicolonContent(false);
            configurer.setUrlPathHelper(urlPathHelper);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    写法二:

    不实现接口,直接写一个bean

    @Configuration(proxyBeanMethods = false)
    public class WebConfig implements WebMvcConfigurer {
        @Bean
        public WebMvcConfigurer webMvcConfigurer(){
            return new WebMvcConfigurer() {
                @Override
                public void configurePathMatch(PathMatchConfigurer configurer) {
                    UrlPathHelper urlPathHelper = new UrlPathHelper();
                    //设置为不移除分号后面的内容,矩阵变量功能就可以生效
                    urlPathHelper.setRemoveSemicolonContent(false);
                    configurer.setUrlPathHelper(urlPathHelper);
                }
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注:我们在使用矩阵变量的时候,需要将@RequestMapping中的请求地址写为restful风格

    //真实访问地址  /cars/{path;low=34;brand=byd,audi,yd}
    @RequestMapping(value="/cars/{path}")
    
    • 1
    • 2

    这样才能正常的访问,不然就会报404错误

    问题:当矩阵变量遇到相同名称的值如何解决?

    //访问地址为    /boss/1;age=20/2;age=10
    //有两个age
    @GetMapping(value="/boss/{bossId}/{empId}")
    public String hello(@MatrixVariable(value="age",pathVar="bossId") Integer bossAge,
                        @MatrixVariable(value="age",pathVar="empId") Integer empAge){}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样就可以解决这种问题了

    8、Thymeleaf

    视图解析:springboot默认不支持JSP,需要引入第三方模板引擎技术实现页面渲染

    整合thymeleaf需要引入starter依赖

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-thymeleafartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    thymeleaf已经自动配置好了

    所有的thymeleaf页面都是html后缀,并且应该放在templates目录下,而且在html标签中加入名称空间

    xmlns:th="http://www.thymeleaf.org"
    
    • 1

    8.1、Thymeleaf初体验

    @Controller
    public class ViewTestController {
        @GetMapping(value = "/hty")
        public String hty(Model model){
            model.addAttribute("msg","hello");
            model.addAttribute("link","www.baidu.com");
            //在这里只需要写html的名字不需要写前后缀
            return "success";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    DOCTYPE html>
    
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
        <h1 th:text="${msg}">h1>
        <h2>
            
            <a href="www.baidu.com" th:href="${link}">去百度a>
            
            <a href="www.baidu.com" th:href="@{link}">去百度a>
        h2>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    当我们在application.yaml配置文件中使用server.servlet.context-path属性给项目设置地址之后,使用@符号取地址,thymeleaf就会自动给地址前加上项目的地址,但是必须是绝对路径的写法(以/开头的地址写法),相对路径就是不以斜杠开头

    8.2、静态导入

    我们可以将页面的公共部分进行抽取,在common页面中存放公共的部分,语法为

    
    <div th:fragment="name">
    	公共部分
    div>
    
    • 1
    • 2
    • 3
    • 4

    在使用的时候有语法供我们选择 th:insert th:replace th:include

    语法

    <div th:insert="~{footer :: copy}">div>
    或者
    <div th:insert="footer :: copy">div>
    
    • 1
    • 2
    • 3

    三者的区别

    <body>
    
      ...
      <div th:insert="footer :: copy">div>  将公共部分连同标签一同导入
      <div th:include="footer :: copy">div> 将公共部分的标签内部的内容导入
      <div th:replace="footer :: copy">div> 将原来的标签直接替换为公共部分的标签
      
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果为

    <body>
    
      ...
      <div>
          <footer>
        	© 2011 The Good Thymes Virtual Grocery
      	  footer>
      div>
      <div>
        © 2011 The Good Thymes Virtual Grocery
      div>
      <footer>
        © 2011 The Good Thymes Virtual Grocery
      footer>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    8.3、循环

    语法

    <tr class="gradeX" th:each="user,stats : ${users}">
        <td th:text="${stats.count}">td>
        <td th:text="${user.username}">td>
        <td th:text="${user.password}">td>
    tr>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在循环变量的后面加上一个status就可以使用thymeleaf中自带的一些变量,例如count表示计数,从1开始

    9、拦截器

    实现拦截器需要实现HandlerInterceptor接口

    首先写一个拦截器的类LoginInterceptor

    /**
     * 登陆检查
     * 1.配置好拦截器要拦截哪些请求
     * 2.把这些配置放在容器中
     * 3.指定拦截规则
     * */
    public class LoginInterceptor implements HandlerInterceptor {
        //目标方法执行之前
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //登陆检查逻辑
            HttpSession session = request.getSession();
    
            Object loginUser = session.getAttribute("loginUser");
            if(loginUser != null){
                //放行
                return true;
            }
            //拦截
            request.setAttribute("msg","请先登陆");
            request.getRequestDispatcher("/login").forward(request,response);
            return false;
        }
    
        //目标方法执行完成以后
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        //页面渲染以后
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    
    • 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

    之后在web配置类中对拦截器进行配置

    @Configuration
    public class MyWebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LoginInterceptor())
                    .addPathPatterns("/**") //默认拦截的请求 一般都是些/**
                    .excludePathPatterns(
                            "/",
                            "/login",
                            "/css/**",
                            "/fonts/**",
                            "/images/**",
                            "/js/**"
                    );//放行的内容
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    10、文件上传

    前端的写法

    <form th:action="@{/upload}" method="post" enctype="multipart/form-data">
        
        <label for="exampleInputFile">头像label>
        <input type="file" name="headerImg" id="exampleInputFile">
        
        <label for="exampleInputFile">照片label>
        <input type="file" name="photos" multiple>
        <button type="submit" class="btn btn-primary">提交button>
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Controller层的写法

    //MultipartFile自动封装上传过来的文件
    @PostMapping(value = "/upload")
    public String upload(@RequestParam("email") String email,
                         @RequestParam("username") String username,
                         @RequestParam("headerImg") MultipartFile headerImg,
                         @RequestParam("photos") MultipartFile[] photos) throws IOException {
        if(!headerImg.isEmpty()){
            //保存到文件服务器
            String originalFilename = headerImg.getOriginalFilename();//获取文件名
            headerImg.transferTo(new File("D:\\"+originalFilename));
        }
        if(photos.length > 0){
            for (MultipartFile photo : photos) {
                if(!photo.isEmpty()){
                    String originalFilename = photo.getOriginalFilename();//获取文件名
                    photo.transferTo(new File("D:\\"+originalFilename));
                }
            }
        }
        return "main";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    springboot中封装好了一个文件对象是MultipartFile,直接使用即可

    如果文件上传大小太大就会报错,解决方法是在配置文件中进行配置

    spring.servlet.multipart.max-file-size=10MB
    spring.servlet.multipart.max-request-size=100MB
    
    • 1
    • 2

    11、注入原生组件

    注入servlet,filter和listener

    11.1、使用servlet

    编写一个servlet继承HttpServlet类,在这个类上面添加一个注解@WebServlet(urlPatterns=“/访问地址”)这样就可以注入servlet了

    @WebServlet(urlPatterns = "/helloservlet")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("helloservlet");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们还需要在主启动类中写一个注解,可以将servlet扫描到

    @ServletComponentScan(basePackages = "com.hty")
    
    • 1

    11.2、filter

    使用@WebFilter注解来注入,

    11.3、listener

    使用@WebListener注解来注入

  • 相关阅读:
    Redis 缓存数据库
    iOS持续集成打包从Intel芯片迁移到Apple M2芯片解决方案
    redis 常用方法
    教育教学论坛杂志教育教学论坛杂志社教育教学论坛编辑部2022年第39期目录
    LeetCode_多源 BFS_中等_2258.逃离火灾
    【编程DIY】一.几个有趣的小程序
    非零基础自学Golang 2 开发环境 2.5 第一个Go 程序
    景联文科技:语音工程系列(一)——语音标注的应用场景
    边缘检测算法
    总结七大排序算法
  • 原文地址:https://blog.csdn.net/m0_51654746/article/details/125901109