当前位置: 首页 > news >正文

【框架学习 | 第六篇】SpringBoot基础篇(快速入门、自动配置原理分析、配置文件、整合第三方技术、拦截器、文件上传/下载、访问静态资源)

在这里插入图片描述

文章目录

  • 1.SpringBoot简介
    • 1.1原有Spring优缺点分析
      • 1.1.1Spring优点
      • 1.1.2Spring缺点
    • 1.2SpringBoot概述
      • 1.2.1SpringBoot解决上述Spring的缺点
      • 1.2.2SpringBoot特点
      • 1.2.3SpringBoot核心功能
  • 2.SpringBoot快速入门
    • 2.1代码实现
      • 2.1.1创建Maven工程
      • 2.1.2添加SpringBoot的起步依赖
      • 2.1.3编写SpringBoot引导类
      • 2.1.4编写controller
      • 2.1.5测试
    • 2.2快速入门解析
      • 2.2.1引导类解析
      • 2.2.2工程热部署解析
    • 2.3使用Idea快速创建SpringBoot项目(自动导入依赖)
  • 3.SpringBoot原理分析
    • 3.1起步依赖原理分析
      • 3.1.1分析spring-boot-starter-parent
      • 3.1.2分析spring-boot-starter-web
    • 3.2自动配置原理解析
  • 4.SpringBoot的配置文件
    • 4.1SpringBoot配置文件的类型及作用
      • 4.1.1配置文件类型及作用
      • 4.1.2 application.properties
      • 4.1.3 application.yml或application.yaml
      • 4.1.4读取配置文件数据
    • 4.2配置文件的加载顺序
      • 4.2.1项目内配置文件加载顺序
        • (1)不同目录的配置文件的加载顺序
        • (2)同一目录、不同后缀的配置文件加载顺序
      • 4.2.2外部配置文件
        • (1)命令行参数
        • (2)spirng.config.location
    • 4.3多环境配置
      • 4.3.1多文件配置多个环境
      • 4.3.2单个文件配置多个环境
      • 4.3.3补充:命令行指定
  • 5.SpringBoot整合其他技术
    • 5.1SpringBoot整合Junit
      • 5.1.1添加依赖
      • 5.1.2编写测试类
      • 5.1.3控制台
    • 5.2SpringBoot整合Mybatis
      • 5.2.1添加依赖
      • 5.2.2添加数据库驱动
      • 5.2.3添加数据库连接
      • 5.2.4创建user表
      • 5.2.5创建实体Bean
      • 5.2.6编写Mapper接口
      • 5.2.7配置Mapper映射文件
      • 5.2.8在application.properties添加映射文件信息
      • 5.2.9controller层
      • 5.2.10测试
    • 5.3SpringBoot整合Redis
    • 5.4SpringBoot整合Mybatis Plus
      • 5.4.1导入依赖
      • 5.4.2yml配置
      • 5.4.3用户信息实体
      • 5.4.4配置类
      • 5.4.5启动类
      • 5.4.6Dao层
      • 5.4.7Service层
      • 5.4.8扩展:Mybatis Plus的核心
    • 5.5SpringBoot整合RabbitMQ
  • 6.SpringBoot实现拦截器
    • 6.1拦截器介绍
    • 6.2拦截器作用
    • 6.3自定义拦截器
      • 6.3.1LogInterceptor类
      • 6.3.2OldLoginInterceptor类
      • 6.3.3配置拦截器
    • 6.4应用
      • 6.4.1性能监控
      • 6.4.2登录检测
  • 7.文件上传/下载
    • 7.1文件上传/下载流程概述
      • 7.1.1文件上传
      • 7.1.2文件下载
    • 7.2实现过程
      • 7.2.1添加依赖
      • 7.2.2配置文件上传大小限制
      • 7.2.3上传控制器
      • 7.2.4下载控制器
  • 8.SpringBoot访问静态资源
    • 8.1何为静态资源?
    • 8.2设置访问静态资源的两种方法
      • 8.2.1application设置方法
        • (1)配置详讲
        • (2)实践
        • (3)优缺点
      • 8.2.2设置配置类方法
        • (1)方法介绍
        • (2)实践
        • (3)优缺点

1.SpringBoot简介

1.1原有Spring优缺点分析

1.1.1Spring优点

Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的Java对象(Plain Old Java Object,POJO)实现了EJB的功能。

1.1.2Spring缺点

虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。

所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。

除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

1.2SpringBoot概述

1.2.1SpringBoot解决上述Spring的缺点

SpringBoot对上述Spring的缺点进行的改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。

1.2.2SpringBoot特点

  1. 基于Spring的开发提供更快的入门体验
  2. 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
  3. 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等
  4. SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式

1.2.3SpringBoot核心功能

  1. 起步依赖
    • 起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
    • 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
  2. 自动配置
    • Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

2.SpringBoot快速入门

2.1代码实现

2.1.1创建Maven工程

  • 使用idea工具创建一个maven工程,该工程为普通的java工程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.1.2添加SpringBoot的起步依赖

  • SpringBoot要求:项目要继承SpringBoot的起步依赖spring-boot-starter-parent
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version>
</parent>

SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

2.1.3编写SpringBoot引导类

@SpringBootApplication
public class MySpringBootApplication {public static void main(String[] args) {SpringApplication.run(MySpringBootApplication.class);}}

2.1.4编写controller

@Controller
public class QuickStartController {@RequestMapping("/quick")@ResponseBodypublic String quick(){return "springboot 访问成功!";}}

2.1.5测试

执行SpringBoot起步类的主方法,控制台打印日志如下:

image-20240312151455162

通过日志发现,Tomcat started on port(s): 8080 (http) with context path ‘’

tomcat已经起步,端口监听8080,web应用的虚拟工程名称为空

打开浏览器访问url地址为:http://localhost:8080/quick

image-20240312151536906

2.2快速入门解析

2.2.1引导类解析

  • @SpringBootApplication:标注SpringBoot的启动类,该注解具备多种功能(后面详细剖析)
  • SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类,参数为SpringBoot启动类的字节码对象

2.2.2工程热部署解析

可以在修改代码后不重启就能生效,在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署:

<!--热部署配置-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId>
</dependency>

注意:IDEA进行SpringBoot热部署失败原因

出现这种情况,并不是热部署配置问题,其根本原因是因为Intellij IEDA默认情况下不会自动编译,需要对IDEA进行自动编译的设置,如下:

在这里插入图片描述

  • 然后 Shift+Ctrl+Alt+/,选择Registry

在这里插入图片描述

2.3使用Idea快速创建SpringBoot项目(自动导入依赖)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 通过idea快速创建的SpringBoot项目的pom.xml中已经导入了我们选择的web的起步依赖的坐标
<?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"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>springboot_quick2</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>springboot_quick2</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>9</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

可以使用快速入门的方式创建Controller进行访问,此处不再赘述

3.SpringBoot原理分析

3.1起步依赖原理分析

3.1.1分析spring-boot-starter-parent

按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配置如下(只摘抄了部分重点配置):

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.0.1.RELEASE</version><relativePath>../../spring-boot-dependencies</relativePath>
</parent>

按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了spring-boot-starter-dependencies的pom.xml,xml配置如下(只摘抄了部分重点配置):

<properties><activemq.version>5.15.3</activemq.version><antlr2.version>2.7.7</antlr2.version><appengine-sdk.version>1.9.63</appengine-sdk.version><artemis.version>2.4.0</artemis.version><aspectj.version>1.8.13</aspectj.version><assertj.version>3.9.1</assertj.version><atomikos.version>4.0.6</atomikos.version><bitronix.version>2.1.4</bitronix.version><build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version><byte-buddy.version>1.7.11</byte-buddy.version>... ... ...
</properties>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId><version>2.0.1.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.0.1.RELEASE</version></dependency>... ... ...</dependencies>
</dependencyManagement>
<build><pluginManagement><plugins><plugin><groupId>org.jetbrains.kotlin</groupId><artifactId>kotlin-maven-plugin</artifactId><version>${kotlin.version}</version></plugin><plugin><groupId>org.jooq</groupId><artifactId>jooq-codegen-maven</artifactId><version>${jooq.version}</version></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.0.1.RELEASE</version></plugin>... ... ...</plugins></pluginManagement>
</build>

从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递。

3.1.2分析spring-boot-starter-web

按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如下(只摘抄了部分重点配置):

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starters</artifactId><version>2.0.1.RELEASE</version></parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.0.1.RELEASE</version><name>Spring Boot Web Starter</name><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.0.1.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId><version>2.0.1.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.0.1.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.0.9.Final</version><scope>compile</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.0.5.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.5.RELEASE</version><scope>compile</scope></dependency></dependencies>
</project>

从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”,这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用

3.2自动配置原理解析

  • 按住Ctrl点击查看启动类MySpringBootApplication上的注解@SpringBootApplication
@SpringBootApplication
public class MySpringBootApplication {public static void main(String[] args) {SpringApplication.run(MySpringBootApplication.class);}
}
  • 注解@SpringBootApplication的源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {/*** Exclude specific auto-configuration classes such that they will never be applied.* @return the classes to exclude*/@AliasFor(annotation = EnableAutoConfiguration.class)Class<?>[] exclude() default {};... ... ...}

其中有三个核心注解:

  • @SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
  • @EnableAutoConfiguration:SpringBoot自动配置功能开启
  • @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包

按住Ctrl点击查看注解@EnableAutoConfiguration:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {... ... ...
}

其中,@Import(AutoConfigurationImportSelector.class) 导入了AutoConfigurationImportSelector类

按住Ctrl点击查看AutoConfigurationImportSelector源码

public String[] selectImports(AnnotationMetadata annotationMetadata) {... ... ...List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);configurations = removeDuplicates(configurations);Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);return StringUtils.toStringArray(configurations);
}protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());return configurations;
}

其中,SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表:

image-20240312153441044

该spring.factories文件格式为键值对,键为自动配置类全类名值(多个),为该自动配置类所对应的配置类的全类名

  • 这些配置类定义的Bean会根据条件注解所指定的条件判断是否将其注入到spring容器中
  • 条件判断注解(举例)
    • @ConditionalOnClass:类加载器中是否存在对应的类(引入jar包一般就会有对应的类,就会将该配置类 里面的bean注入到spring容器中)
    • @ConditionalOnBean:容器中是否存在对应的bean

4.SpringBoot的配置文件

4.1SpringBoot配置文件的类型及作用

4.1.1配置文件类型及作用

如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。

SpringBoot默认会从Resources目录下加载==application.properties或application.yml(application.yaml)==文件

其中,application.properties文件是键值对类型的文件,之前一直在使用,所以此处不在对properties文件的格式进行阐述。除了properties文件外,SpringBoot还可以使用yml文件进行配置,下面对yml文件进行讲解。

4.1.2 application.properties

# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

4.1.3 application.yml或application.yaml

# 数据库连接配置
spring:datasource:url: jdbc:mysql://localhost:3306/mydatabaseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver

4.1.4读取配置文件数据

  • application.yml
person:name: zhangsanage: 18
  • 读取
@Value("${person.name}")
private String name;
@Value("${person.age}")
private Integer age;

4.2配置文件的加载顺序

4.2.1项目内配置文件加载顺序

(1)不同目录的配置文件的加载顺序
  • Springboot程序启动时,会从以下位置加载配置文件:优先级由高到底,高优先级的配置会覆盖低优先级的配置,没有的配置进行互补配置
优先级1:项目路径下的config文件夹配置文件
优先级2:项目的根目录下面配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件

在这里插入图片描述

(2)同一目录、不同后缀的配置文件加载顺序

当properties、yaml和yml三种文件路径相同时,三个文件中的配置信息都会生效,但是当三个文件中有配置信息冲突时,加载顺序是

优先级低的配置会被先加载,所以优先级高的配置会覆盖优先级低的配置

properties(最高)> yml > yaml(最低)

在这里插入图片描述

  • 验证:

在这里插入图片描述

4.2.2外部配置文件

当我们把项目打包后,如何在配置SpringBoot项目呢?

(1)命令行参数

项目打包好以后,我们可以使用命令行参数的形式,来改变想改变的几个参数,直接在启动命令后添加启动参数,如果有多个配置项,可以用空格分开。

java -jar springboot-configuration.jar --server.port=8088 --server.servlet.context-path=/spring

在这里插入图片描述

(2)spirng.config.location

在第一种情况下,如果参数数量过多,我们就要考虑配置文件了,我们在启动项目的时候可以用spring.config.location来指定配置文件的新位置。指定的配置文件和jar包中默认加载的配置文件共同起作用形成互补配置。

指定配置文件从F盘下读取
java -jar springboot-configuration.jar --spring.config.location=F:/application.properties

4.3多环境配置

4.3.1多文件配置多个环境

  • 环境区分:

dev:开发环境
test:测试环境
prod:生产环境(线上)

  • 三个环境配置文件

application-dev.yml

application-test.yml

application-prod.yml

  • 指定文件生效:在application.yml指定
spring:profiles:active:dev

4.3.2单个文件配置多个环境

不需要创建多个文件来区分了,直接以 三个横杠 来当做一个配置文件环境

以下案例就是分为了两个环境,然后最上方active来指定对应的profiles环境

spring:profiles:active: prod---
server:port: 8083
spring:profiles: dev---server:port: 8084
spring:profiles: prod

4.3.3补充:命令行指定

java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;

5.SpringBoot整合其他技术

5.1SpringBoot整合Junit

5.1.1添加依赖

<!--测试的起步依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

5.1.2编写测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MySpringBootApplication.class)
public class MapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void test() {List<User> users = userMapper.queryUserList();System.out.println(users);}
}

其中,SpringRunner继承自SpringJUnit4ClassRunner,使用哪一个Spring提供的测试测试引擎都可以

public final class SpringRunner extends SpringJUnit4ClassRunner 

@SpringBootTest的属性指定的是引导类的字节码对象

5.1.3控制台

image-20240312163241617

5.2SpringBoot整合Mybatis

5.2.1添加依赖

<!--mybatis起步依赖-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version>
</dependency>

5.2.2添加数据库驱动

<!-- MySQL连接驱动 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

5.2.3添加数据库连接

spring:datasource:url: jdbc:mysql://localhost:3306/mydatabaseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver

5.2.4创建user表

在test数据库中创建user表

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`name` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '张三');
INSERT INTO `user` VALUES ('2', 'lisi', '123', '李四');

5.2.5创建实体Bean

public class User {// 主键private Long id;// 用户名private String username;// 密码private String password;// 姓名private String name;//此处省略getter和setter方法 .. ..}

5.2.6编写Mapper接口

@Mapper
public interface UserMapper {public List<User> queryUserList();
}

5.2.7配置Mapper映射文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.mapper.UserMapper"><select id="queryUserList" resultType="user">select * from user</select>
</mapper>

5.2.8在application.properties添加映射文件信息

#spring集成Mybatis环境
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.domain
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

5.2.9controller层

@Controller
public class MapperController {@Autowiredprivate UserMapper userMapper;@RequestMapping("/queryUser")@ResponseBodypublic List<User> queryUser(){List<User> users = userMapper.queryUserList();return users;}}

5.2.10测试

在这里插入图片描述

5.3SpringBoot整合Redis

  • 笔记链接:【Redis | 第三篇】Springboot整合Redis

5.4SpringBoot整合Mybatis Plus

5.4.1导入依赖

	<!-- mybatisPlus 核心库 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>

5.4.2yml配置

server:port: 10100   #  配置启动端口号mybatis:config-location: classpath:mybatis.cfg.xml    #  mybatis主配置文件所在路径type-aliases-package: com.demo.drools.entity  #  定义所有操作类的别名所在包mapper-locations:                                     #  所有的mapper映射文件- classpath:mapper/*.xmlspring: #springboot的配置datasource: #定义数据源#127.0.0.1为本机测试的ip,3306是mysql的端口号。serverTimezone是定义时区,照抄就好,mysql高版本需要定义这些东西#useSSL也是某些高版本mysql需要问有没有用SSL连接url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&useSSL=FALSEusername: root  #数据库用户名,root为管理员password: 123456 #该数据库用户的密码# 使用druid数据源type: com.alibaba.druid.pool.DruidDataSource# mybatis-plus相关配置
mybatis-plus:# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)mapper-locations: classpath:mapper/*.xml# 以下配置均有默认值,可以不设置global-config:db-config:#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";id-type: auto#字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"field-strategy: NOT_EMPTY#数据库类型db-type: MYSQLconfiguration:# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射map-underscore-to-camel-case: true# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段call-setters-on-nulls: true# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5.4.3用户信息实体

@Data
@TableName("user_info")//@TableName中的值对应着表名
public class UserInfoEntity {/*** 主键* @TableId中可以决定主键的类型,不写会采取默认值,默认值可以在yml中配置* AUTO: 数据库ID自增* INPUT: 用户输入ID* ID_WORKER: 全局唯一ID,Long类型的主键* ID_WORKER_STR: 字符串全局唯一ID* UUID: 全局唯一ID,UUID类型的主键* NONE: 该类型为未设置主键类型*/@TableId(type = IdType.AUTO)private Long id;/*** 姓名*/private String name;/*** 年龄*/private Integer age;/*** 技能*/private String skill;/*** 评价*/private String evaluate;/*** 分数*/private Long fraction;
}

5.4.4配置类

public class MybatisPlusConfig {/*** mybatis-plus SQL执行效率插件【生产环境可以关闭】*/@Beanpublic PerformanceInterceptor performanceInterceptor() {return new PerformanceInterceptor();}/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}
}

5.4.5启动类

@SpringBootApplication
//@MapperScan和dao层添加@Mapper注解意思一样
@MapperScan(basePackages = "com.demo.drools.dao")
public class DroolsApplication {public static void main(String[] args) {SpringApplication.run(DroolsApplication.class, args);}
}

5.4.6Dao层

@Mapper
public interface UserInfoDao extends BaseMapper<UserInfoEntity> {
}

5.4.7Service层

public interface UserInfoService extends IService<UserInfoEntity> {}
@Service
public class UserInfoSerivceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService {}

5.4.8扩展:Mybatis Plus的核心

Mybatis Plus的核心为QueryWrapper、UpdateWrapper

  1. QueryWrapperEntity 对象封装操作
  2. UpdateWrapper : Update 条件封装,用于Entity对象更新操作
  3. 条件构造器使用中的各个方法格式和说明

img

5.5SpringBoot整合RabbitMQ

  • 笔记链接:【RabbitMQ篇】Springboot整合RabbiMQ

6.SpringBoot实现拦截器

6.1拦截器介绍

拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置…

Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。

6.2拦截器作用

  1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
  2. 权限检查:如登录检测,进入处理器检测是否登录;
  3. 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
  4. 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。

6.3自定义拦截器

如果你需要自定义 Interceptor 的话必须实现 org.springframework.web.servlet.HandlerInterceptor接口或继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter类,并且需要重写下面下面 3 个方法:

  1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是 Boolean 类型,当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。
  2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的 Interceptor 类的 postHandler 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。

6.3.1LogInterceptor类

public class LogInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {long startTime = System.currentTimeMillis();System.out.println("\n-------- LogInterception.preHandle --- ");System.out.println("Request URL: " + request.getRequestURL());System.out.println("Start Time: " + System.currentTimeMillis());request.setAttribute("startTime", startTime);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("\n-------- LogInterception.postHandle --- ");System.out.println("Request URL: " + request.getRequestURL());}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("\n-------- LogInterception.afterCompletion --- ");long startTime = (Long) request.getAttribute("startTime");long endTime = System.currentTimeMillis();System.out.println("Request URL: " + request.getRequestURL());System.out.println("End Time: " + endTime);System.out.println("Time Taken: " + (endTime - startTime));}
}

6.3.2OldLoginInterceptor类

public class OldLoginInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("\n-------- OldLoginInterceptor.preHandle --- ");System.out.println("Request URL: " + request.getRequestURL());System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login");response.sendRedirect(request.getContextPath()+ "/admin/login");return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("\n-------- OldLoginInterceptor.afterCompletion --- ");}
}

6.3.3配置拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LogInterceptor());registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin");registry.addInterceptor(new AdminInterceptor()).addPathPatterns("/admin/*").excludePathPatterns("/admin/oldLogin");}
}
  • LogInterceptor 拦截器用于拦截所有请求; OldLoginInterceptor 用来拦截链接 “ / admin / oldLogin”,它将重定向到新的 “ / admin / login”。;AdminInterceptor用来拦截链接 “/admin/*”,除了链接 “ / admin / oldLogin”。

6.4应用

6.4.1性能监控

如记录一下请求的处理时间,得到一些慢请求(如处理时间超过500毫秒),从而进行性能改进,一般的反向代理服务器如 apache 都具有这个功能,但此处我们演示一下使用拦截器怎么实现。

  • 实现分析

    • 进入处理器之前记录开始时间,即在拦截器的 preHandle 记录开始时间;
    • 结束请求处理之后记录结束时间,即在拦截器的 afterCompletion 记录结束实现,并用结束时间-开始时间得到这次请求的处理时间
  • 问题:

    • 我们的拦截器是单例,因此不管用户请求多少次都只有一个拦截器实现,即 线程不安全,那我们应该怎么记录时间呢?

    • 解决方案是使用 ThreadLocal,它是线程绑定的变量,提供线程局部变量(一个线程一个 ThreadLocal,A线程的ThreadLocal 只能看到A线程的 ThreadLocal,不能看到B线程的 ThreadLocal)。

    • 代码实现:

      public class StopWatchHandlerInterceptor extends HandlerInterceptorAdapter {private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("StopWatch-StartTime");private Logger logger = LoggerFactory.getLogger(StopWatchHandlerInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {long beginTime = System.currentTimeMillis();//1、开始时间startTimeThreadLocal.set(beginTime);//线程绑定变量(该数据只有当前请求的线程可见)return true;//继续流程}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {long endTime = System.currentTimeMillis();//2、结束时间long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间)long consumeTime = endTime - beginTime;//3、消耗的时间if(consumeTime > 500) {//此处认为处理时间超过500毫秒的请求为慢请求//TODO 记录到日志文件logger.info(String.format("%s consume %d millis", request.getRequestURI(), consumeTime));}//测试的时候由于请求时间未超过500,所以启用该代码
      //        logger.info(String.format("%s consume %d millis", request.getRequestURI(), consumeTime));}
      }
      

      NamedThreadLocal:Spring提供的一个命名的ThreadLocal实现。

      在测试时需要把 stopWatchHandlerInterceptor 放在拦截器链的第一个,这样得到的时间才是比较准确的。

    • 拦截器配置类

      @Configuration
      public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new StopWatchHandlerInterceptor());registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin");}
      }
      

6.4.2登录检测

在访问某些资源时(如订单页面),需要用户登录后才能查看,因此需要进行登录检测。

  • 流程

    1. 访问需要登录的资源时,由拦截器重定向到登录页面;
    2. 如果访问的是登录页面,拦截器不应该拦截;
    3. 用户登录成功后,往 cookie/session 添加登录成功的标识(如用户编号);
    4. 下次请求时,拦截器通过判断 cookie/session 中是否有该标识来决定继续流程还是到登录页面;
    5. 在此拦截器还应该允许游客访问的资源。
  • 代码实现

    public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {boolean flag = true;String ip = request.getRemoteAddr();long startTime = System.currentTimeMillis();request.setAttribute("requestStartTime", startTime);if (handler instanceof ResourceHttpRequestHandler) {System.out.println("preHandle这是一个静态资源方法!");} else if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();System.out.println("用户:" + ip + ",访问目标:" + method.getDeclaringClass().getName() + "." + method.getName());}//如果用户未登录User user = (User) request.getSession().getAttribute("user");if (null == user) {//重定向到登录页面response.sendRedirect("toLogin");flag = false;}return flag;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {if (handler instanceof ResourceHttpRequestHandler) {System.out.println("postHandle这是一个静态资源方法!");} else if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();long startTime = (long) request.getAttribute("requestStartTime");long endTime = System.currentTimeMillis();long executeTime = endTime - startTime;int time = 1000;//打印方法执行时间if (executeTime > time) {System.out.println("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : "+ executeTime + "ms");} else {System.out.println("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : "+ executeTime + "ms");}}}}
    

7.文件上传/下载

7.1文件上传/下载流程概述

7.1.1文件上传

  1. 当客户端发送文件上传请求时,Spring Boot会接收到一个包含文件的MultipartHttpServletRequest对象
  2. 在控制器方法中,可以通过参数接收这个MultipartHttpServletRequest对象,并从中获取上传的文件。
  3. Spring Boot会将上传的文件存储到临时目录中,可以通过MultipartFile对象的getOriginalFilename()方法获取文件名,通过getBytes()方法获取文件内容
  4. 文件上传后,可以将其保存到服务器的持久化存储中,例如本地磁盘、云存储等。

7.1.2文件下载

  1. 当客户端发送文件下载请求时,Spring Boot会根据请求的URL找到对应的文件
  2. 找到文件后,需要将文件的内容写入到Response的输出流中,为了防止浏览器解析,需要在响应头中设置正确的MIME类型(Content-Type)。
  3. 如果要实现断点续传功能,需要根据文件的元数据信息判断是否已经下载过该文件,如果已经下载过,则直接返回已存在的文件内容即可。

7.2实现过程

7.2.1添加依赖

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency>

7.2.2配置文件上传大小限制

server:port: 18080spring:servlet:multipart:max-file-size: 10MBmax-request-size: 10MB

7.2.3上传控制器

  • 创建一个控制器类,用于处理文件上传请求。在这个类中,使用@PostMapping注解指定处理POST请求的方法,并使用@RequestParam("file") MultipartFile file参数接收上传的文件。
// 创建文件上传控制器  
@RestController  
@RequestMapping("/api/upload")  
public class FileUploadController {  // 处理文件上传请求的POST方法  @PostMapping("/")  public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {  try {  // 获取上传文件的文件名  String fileName = file.getOriginalFilename();  // 将文件保存到磁盘或执行其他操作,这里只是简单地将文件保存到静态资源目录下  file.transferTo(new File("D:/" + fileName));  return new ResponseEntity<>("文件上传成功!", HttpStatus.OK);  } catch (Exception e) {  return new ResponseEntity<>("文件上传失败:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);  }  }  
}

7.2.4下载控制器

  1. 创建一个控制器类,用于处理文件下载请求。在这个类中,我们将使用@GetMapping注解指定处理GET请求的方法,并使用@RequestParam(“filename”) String fileName参数接收要下载的文件名。然后,我们可以使用文件名来获取要下载的文件,并将其作为响应返回给客户端。
  2. 为了让Spring Boot能够找到静态资源(如文件),你需要在src/main/resources目录下创建一个名为static的文件夹,并在其中创建一个名为files的文件夹,用于存放要下载的文件。
@RestController
@RequestMapping("/api/download")
public class FileDownloadController {private static final Logger log = LoggerFactory.getLogger(FileDownloadController.class);@Autowiredprivate ResourceLoader resourceLoader;// 处理文件下载请求的GET方法,通过文件名获取文件并返回给客户端下载@GetMapping("/{filename:.+}")public ResponseEntity<Resource> handleFileDownload(@PathVariable String filename) throws IOException {// 获取要下载的文件的Resource对象,这里假设文件保存在静态资源目录下的files文件夹中Resource resource = resourceLoader.getResource("classpath:static/files/" + filename);if (resource == null) {return new ResponseEntity<>(HttpStatus.NOT_FOUND);}// 将文件内容包装为响应体,并设置响应头信息,提示浏览器下载文件而不是打开文件InputStreamResource inputStreamResource = new InputStreamResource(resource.getInputStream());HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);return ResponseEntity.ok().headers(headers).contentType(MediaTypeFactory.getMediaType(resource).get()).body(inputStreamResource);}
}

8.SpringBoot访问静态资源

8.1何为静态资源?

静态资源,一般是网页端的:HTML文件、JavaScript文件和图片。尤其是设置图片的静态资源,尤其重要:

8.2设置访问静态资源的两种方法

  • Springboot内设置静态资源,或者说静态资源文件夹,主要有两种方法(均为SpringMVC实现):
    • application.yml/application.properties内配置。
    • 设置Configuration配置类

以上两种方法,均可实现用户访问网址,不走Controller层的拦截,直接进行静态文件访问。

8.2.1application设置方法

(1)配置详讲
  • spring.mvc.static-path-pattern:根据官网的描述和实际效果,可以理解为**静态文件URL匹配头**,也就是静态文件的URL地址开头。Springboot默认为:/**

  • spring.web.resources.static-locations:根据官网的描述和实际效果,可以理解为==实际静态文件地址==,也就是静态文件URL后,匹配的实际静态文件

    Springboot默认为:
    classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
    
  • 注意:

    • spring.web.resources.static-locations是后续配置,旧版Springboot的配置项为:spring-resources-static-locations;在2.2.5版本之后,旧版本配置已经失效。
    • spring.web.resources.static-locations有多个配置项,在Springboot编译后,会合并为一个文件。多个配置文件,使用,进行分割。
    • spring.web.resources.static-location仅仅允许一个配置,无法使用,进行分割,如果需要多个静态资源文件,可以使用下文的配置类方法。
    • spring.web.resources.static-locations可以使用classpath、file进行匹配。如果使用file,这个时候的相对路径为项目地址(打包为.jar后,相对路径就是.jar运行地址)
(2)实践
  • 最终效果:

    • 浏览器输入:http://localhost:8088/SystemData/UserData/Avatar/Mintimate.jpeg

    • 可以直接访问项目文件下的:/SystemData/UserData/Avatar/Mintimate.jpeg

      就是这个文件了嗷

  • 配置文件:

spring:mvc:# URL响应地址(Springboot默认为/**)static-path-pattern: /SystemData/**web:resources:# 静态文件地址,保留官方内容后,进行追加static-locations: classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources,file:SystemData

其中,file:SystemData就是映射本地文件了。

(3)优缺点
  • 优点:简单粗暴
  • 缺点:
    • URL响应地址只能为一项,也就是spring.mvc.static-path-pattern配置只能写一项
    • 上文设置了/SystemData/**为URL匹配,就不能设置第二个/resources/**这样的配置为第二静态目录
    • 如果需要设置多个地址为静态资源目录,可以参考下文的设置配置类方法方法。

8.2.2设置配置类方法

(1)方法介绍

写一个配置类,实现静态资源的文件夹方法很多。比如:

  • 继承于WebMvcConfigurationSupport父类,并实现addResourceHandlers方法。

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
    

    这里的registry使用链式编程,方法为:

    • addResourceHandler:添加URL响应地址目录。
    • addResourceLocations:添加实际资源目录。
  • 引用WebMvcConfigurer接口,并实现addInterceptors方法(常用)

一些文章可能会让你继承于WebMvcConfigurerAdapter方法,但是实际上WebMvcConfigurerAdapter方法在Spring5.0和Springboot2.0之后,已经弃用。

(2)实践
  • 最终效果1:

    • 浏览器输入:http://localhost:8088/SystemData/UserData/Avatar/Mintimate.jpeg
    • 可以直接访问项目文件下的:/SystemData/UserData/Avatar/Mintimate.jpeg
  • 最终效果2:

    • 浏览器输入:http://localhost:8088/SystemDataTest/UserData/Avatar/Mintimate.jpeg
    • 可以直接访问项目文件下的:/Test/UserData/Avatar/Demo.jpeg
  • 添加一个配置类,并继承WebMvcConfigurationSupport,实现addResourceHandlers方法,并打上@Configuration注解,使其成为配置类:

@Configuration
public class WebConfig extends WebMvcConfigurationSupport{@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//定位到项目文件夹下的SystemData文件夹static final String IMG_PATH=System.getProperty("user.dir")+"/SystemData/";static final String IMG_PATH_TWO=System.getProperty("user.dir")+"/Test/";registry.addResourceHandler("/SystemData/**)").addResourceLocations("file:"IMG_PATH);registry.addResourceHandler("/SystemDataTest/**)").addResourceLocations("file:"IMG_PATH_TWO);super.addResourceHandlers(registry);}
}
(3)优缺点
  • 相比前文,这样的配置更麻烦。
  • 相比前文,这样的可塑性更高:可以添加更多的映射、不会对默认配置造成覆盖等。
    在这里插入图片描述

相关文章:

【框架学习 | 第六篇】SpringBoot基础篇(快速入门、自动配置原理分析、配置文件、整合第三方技术、拦截器、文件上传/下载、访问静态资源)

文章目录 1.SpringBoot简介1.1原有Spring优缺点分析1.1.1Spring优点1.1.2Spring缺点 1.2SpringBoot概述1.2.1SpringBoot解决上述Spring的缺点1.2.2SpringBoot特点1.2.3SpringBoot核心功能 2.SpringBoot快速入门2.1代码实现2.1.1创建Maven工程2.1.2添加SpringBoot的起步依赖2.1.…...

使用 ReclaiMe Pro 恢复任意文件系统(Win/Linux/MacOS)

天津鸿萌科贸发展有限公司是 ReclaiMe Pro 数据恢复软件授权代理商。 ReclaiMe Pro 是一个通用工具包&#xff0c;几乎可以用于从所有文件系统&#xff08;从 Windows 系列文件系统、Linux 和 MacOS&#xff09;中恢复数据。此外&#xff0c;考虑到数据恢复工作的具体情况&…...

全视智慧机构养老解决方案,以科技守护长者安全

2024年2月28日凌晨1时许&#xff0c;在上海浦东大道的一家养护院四楼杂物间内发生了一起火灾事故。尽管火势不大&#xff0c;过火面积仅为2平方米&#xff0c;但这场小火却造成了1人死亡和3人受伤的悲剧。这一事件再次提醒我们&#xff0c;养老院作为老年人聚集的场所&#xff…...

NavicatPremium16破解激活

背景&#xff1a; 如题&#xff0c;本篇主要参考一个个人博客&#xff0c;里面提供百度网盘形式的下载链接&#xff0c;博主在个人尝试的过程中加了几点补充&#xff0c;便于更快安装&#xff01; Navicat Premium 16 永久破解激活 - 酷酷的洛克 - 博客园 (cnblogs.com) 背景…...

thinkphp6.1~8.0 快速创建CRUD

GIT 源码 TINKPHP 快速创建模型CRUD源码 import os import tkinter as tk from tkinter import messagebox#转小写 def toLowerCase(str):""":type str: str:rtype: str"""return "".join(chr(ord(c) 32) if 65 < ord(c) < 90…...

MySQL的常用函数

MySQL函数 聚合函数时间函数字符集函数数学函数其他函数 聚合函数 函数名说明COUNT()统计个数SUM()总和&#xff0c;不是数字没有意义AVG()求平均值&#xff0c;不是数字没有意义MAX()求最大值&#xff0c;不是数字没有意义MIN()求最小值&#xff0c;不是数字没有意义 group …...

Android Gradle 开发与应用 (五) : 基于Gradle 8.2,创建Gradle插件

1. 前言 本文介绍在Android中&#xff0c;如何基于Gradle 8.2&#xff0c;创建Gradle插件。 1.1 本文环境 Android Studio 版本 : Android Studio Hedgehog | 2023.1.1Gralde版本 : gradle 8.2 使用 Android Gradle 插件升级助理 Android Gradle 插件版本说明 1.2 为什么要写…...

中文在职博士|中国社科院-新加坡社科大学(公立大学)工商管理博士

中文在职博士|中国社科院-新加坡社科大学&#xff08;公立大学&#xff09;工商管理博士 中国社科大-新加坡社科大学合作举办全球战略领导力博士项目 【条件】&#xff1a;硕士学位&#xff0b;三年管理经验 【证书】&#xff1a;颁发新加坡社科大学博士学位证书 【招生】&…...

前端性能优化终极指南

前端性能优化一直是很多同学非常关注的问题&#xff0c;在日常的面试中也是经常会被用到的点。今天就来了解一下前端性能优化方案。 一&#xff1a;页面渲染相关 01&#xff1a;减少页面重绘和回流 回流&#xff08;reflow&#xff09;&#xff1a;是指由于DOM结构或样式发生…...

基于Logstash由SQLServer向Elasticsearch同步数据: logstash配置文件

文章目录 I Logstash1.1 Logstash 安装1.2 logstash配置文件参数含义1.3 启动LogstashII 增量数据同步方案2.1 思路2.2 使用LastModifyTime来追踪DB的变更数据2.3 将最大ID 设置为查询条件,获取增量数据2.4 把时间戳设置为记录产生的时间III 单表同步IV 多表同步V 使用 Logsta…...

sqllab第八关通关笔记

知识点&#xff1a; 这里感觉是一个单纯的单引号绕过bp爆破配置的条件和第七关一样 首先判断注入类型 构造id1/0 回显成功 构造id1 错误回显&#xff0c;感觉又是一个单引号绕过 构造id1 正常回显了&#xff0c;说明不错&#xff0c;就是一个单引号绕过 构造payload:id1 a…...

unity text 文本符号显示问题与打字机效果的结合

问题1&#xff1a;unity text显示文本时&#xff0c;符号可能显示在某行的开头的位置 问题2&#xff1a;打字机效果没有适配问题1的脚本 解决方法&#xff1a; 问题1&#xff1a;通过遍历text组件每一行数据(第二行开始)&#xff0c;如果是符号&#xff0c;就在它之前的字符前…...

Netty架构详解

文章目录 概述整体结构Netty的核心组件逻辑架构BootStrap & ServerBootStrapChannelPipelineFuture、回调和 ChannelHandler选择器、事件和 EventLoopChannelHandler的各种ChannelInitializer类图 Protocol Support 协议支持层Transport Service 传输服务层Core 核心层模块…...

Unity自带的WebSocket使用说明

Unity中的WebSocket是一种用于实时性强、低延迟的双向通信的技术。它可以在客户端和服务器之间建立一个持久的连接&#xff0c;允许双方随时互相发送数据。这种实时性使得WebSocket在游戏中非常有用&#xff0c;特别是对于多人在线游戏和实时竞技游戏。 在Unity中&#xff0c;…...

【Web】浅聊XStream反序列化之SortedSetTreeMap利用链

前文&#xff1a;【Web】浅聊XStream反序列化本源之恶意动态代理注入-CSDN博客 前言 在上一篇文章我们聊到可以用XStream反序列化来进行恶意动态代理的注入&#xff0c;但其有一个很大的限制就是必须要知道目标靶机会调用哪个接口的方法&#xff0c;才能去相应地精心构造对应…...

HTML CSS学习

# html css 日常学习记录---学习途径--渡一教育-袁老师# 元素包含关系 以前&#xff1a;块级元素可以包含行级元素&#xff0c;行级元素不可以包含块级元素&#xff0c;a元素除外 元素的包含关系由元素的内容类别决定。 例如&#xff0c;查看h1元素中是否可以包含p元素 总…...

MySQL的事务隔离是如何实现的?

目录 从一个例子说起 快照读和当前读 事务的启动时机和读视图生成的时刻 MVCC 隐藏字段 Undo Log回滚日志 Read View - 读视图 可重复读(RC)隔离级别下的MVCC 读提交(RR)隔离级别下的MCC 关于MVCC的一些疑问 1.为什么需要 MVCC &#xff1f;如果没有 MVCC 会怎样&am…...

STM32电源及时钟介绍

一、STM32最小系统 二、电源电路 2.1供电电压VDD&#xff0c;VSS F103VET6 的引角图 在 F103VET6 的引角图中可找到 49\50 角&#xff0c; 74\75 角&#xff0c; 99\100 角&#xff0c; 27\28角&#xff0c;10 \11角一共 5 对的VDD&#xff0c;VSS&#xff0c;也就是给我们芯片…...

使用公式在Excel中指定列值的变化实现自动间隔着色(不是按照固定的行数)

如果你的文件很小&#xff0c;可以手工着色&#xff1b;但如果很大&#xff0c;就要借助公式来着色&#xff1b; 目的是什么&#xff0c;其中之一是&#xff1a;提升可读性。 一起往下看吧&#xff01;&#xff01; 如果你想要根据Excel某列中值的变化来间隔着色&#xff0c;…...

蚓链给传统供应链的数字化解决方案会带来什么价值呢?

传统供应链在蚓链数字化的加持下&#xff0c;通过互相融合、结合将为数字经济带来多方面的影响和变革&#xff0c;包括但不限于以下几点&#xff1a; 1. 提高效率和降低成本&#xff1a;数字化可以优化供应链中的各个环节&#xff0c;例如采购、生产、物流和销售等&#xff0…...

有来团队后台项目-解析8

UnoCss 介绍 UnoCss 官网UnoCss 官网 安装 pnpm add -D unocss引入 vite.config.ts import UnoCSS from unocss/vite // plugins 中引入 UnoCSS({/* options */ }),创建uno.config.ts // uno.config.ts import {defineConfig,presetAttributify,presetIcons,presetTyp…...

vs2022的下载及安装教程(Visual Studio 2022)

vs简介 Visual Studio在团队项目开发中使用非常多且功能强大&#xff0c;支持开发人员编写跨平台的应用程序;Microsoft Visual C 2022正式版(VC2022运行库)&#xff0c;具有程序框架自动生成&#xff0c;灵活方便的类管理&#xff0c;强大的代码编写等功能&#xff0c;可提供编…...

BFS(宽度优先搜索)C++(Acwing)

代码&#xff1a; #include <cstring> #include <iostream> #include <algorithm>using namespace std;typedef pair<int, int> PII;const int N 110;int n, m; int g[N][N]; int d[N][N]; PII q[N * N];int bfs() {int hh 0, tt 0;q[0] {0, 0};m…...

信息收集:端口扫描原理,端口扫描分类,端口扫描工具,手动判断操作系统,操作系统识别工具

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「专栏简介」&#xff1a;此文章已录入专栏《网络安全自学教程》 端口&系统版本 一、端口扫描1、telnet2、Nmap3、Masscan4、端口扫描原…...

【Tauri】(5):本地运行candle和 qwen 大模型,并测试速度

1&#xff0c;本地运行candle 关于candle项目 https://github.com/huggingface/candle Hugging Face 使用rust开发的高性能推理框架。 语法简单&#xff0c; 风格与 PyTorch 相似。 CPU 和 Cuda Backend&#xff1a;m1、f16、bf16。 支持 Serverless&#xff08;CPU&#xff…...

基于udp协议的cs网络通信代码(echo版+命令行输入版+执行指令版),netstat指令

目录 引入 基础版 服务端 思路 头文件log类 套接字的初始化 思路 代码 服务器开始运行 思路 代码 注意点 -- ip地址和端口号的来源 ip地址的选择 本地环回地址 端口号 ​编辑 运行情况 netstat -nlup 客户端 思路 初始化 思路 代码 客户端的运行 思…...

centos7网络命令:ping、dig、nsloopup、tcpdump

目录 一、ping1、命令参数&#xff1a;2、示例-将当前的信息打印到一个文件中3、示例-结束进程 二、dig1、安装2、语法格式选项说明 3、示例4、示例-将当前的信息打印到一个文件中 三、nslookup1、安装2、语法格式选项说明 3、示例 四、tcpdump抓包1、安装2、语法格式&#xff…...

Excel判断CD两列在EF两列的列表中是否存在

需求 需要将CD两列的ID和NAME组合起来&#xff0c;查询EF两列的ID和NAME组合起来的列表中是否存在&#xff1f; 比如&#xff0c;判断第二行的“123456ABC”在EF的第二行到第四行中是否存在&#xff0c;若存在则显示Y&#xff0c;不存在则显示N 实现的计算公式 IF(ISNUMBER…...

基于斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO)的无人机三维路径规划(MATLAB)

一、无人机路径规划模型介绍 二、算法介绍 斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO),是由Abdelazim Hussien于2024年提出的一种基于群体的新型元启发式算法,它从自然界中观察到的斑翠鸟独特的狩猎行为和共生关系中汲取灵感。PKO 算法围绕三个不同的阶段构建:栖息…...

同程旅行前端面试汇总

一、同程旅行一面 自我介绍技术提问 打开新的tab页、window.open是否共享sessionStorage存储的数据vue、react 源码有没有看过&#xff0c;说一下react17 与 react18区别webpack中loader与plugin&#xff0c;有没有自己写过vuex、reactx 刷新数据丢失 怎么做的持久化 反问 总…...