1、SpringBoot快速入门
Spring是简化开发的
SpringBoot就是一个javaweb的开发框架,和SpringMVC类似,对比其他框架的好处,就是简化开发,约定大于配置,能迅速的开发web应用
所有的框架都遵循一个规律:从一个复杂的应用场景 衍生 一种规范,只要遵循她的规则
约定大于配置
SpringBoot的主要优点
- 为所有Spring开发者更快的入门
- 开箱即用,提供各种默认配置来简化项目配置
- 内嵌式容器简化Web项目
- 没有冗余代码生成和XML配置的要求
2、什么是微服务架构
1、微服务架构
all in one 的架构方式,我们把所有的功能单元放在一个应用里面。然后我们把整个应用部署到服务器上。如果负载能力不行,我们将整个应用进行水平复制,进行扩展,然后在负载均衡。
所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时间时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。
好处:
- 节省了调用资源
- 每个功能元素的服务都是一个可替换的、可独立升级的软件代码。
2、如何构建微服务
一个大型系统的微服务架构,就像一个复杂交织的神经网络就是一个功能元素,它们各自完成自己的功能,然后通过Http相互请求调用。
但是这种庞大的系统架构给部署和运维带来很大的难度。于是,spring为我们带来了构建大型分布式微服务的全套、全程产品:
- 构建一个个功能独立的微服务应用单元,可以使用SpringBoot,可以帮我们快速构建一个应用
- 大型分布式网络服务的调用,这部分由Spring Cloud来完成,实现分布式
- 在分布式中间,进行流式数据计算、批处理,我们有spring cloud data flow。
- spring为我们想清楚了整个从开始构建应用到大型分布式应用全流程方案。
- SpringBoot构建一切
- SpringCloud协调一切
- SpringCloudDataFlow连接一切
3、第一个SpringBoot程序
1、准备工作
- jdk 1.8
- maven 3.6.0
- springboot 最新版
- IDEA
2、创建项目
官方:提供了一个快速生成的网站!IDEA集成了这个网站!
- 可以在官网直接下载后,导入idea开发(https://start.spring.io/)
- 打开https://start.spring.io/
- 填写项目信息
- 点击“Generata Preject”按钮生成项目(下载下来)
- 解压
- idea导入即可
- 直接使用idea创建一个SpringBoot项目(一般开发直接在IDEA中创建)
3、项目结构分析
通过上面步骤完成了基础项目的创建,就会自动生成以下文件
- 程序的主程序类
- 一个application.properties配置文件
- 一个测试类
生成的DemoApplication和测试包下的DemoApplicationTests类都可以直接运行来启动当前创建的项目,由于目前该项目未配合任何数据访问或Web模块,程序会在加载完Spring之后结束运行
pom
- parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容
- dependencies:项目依赖
- build:构建配置部分
4、编写HTTP接口
-
新建一个controller包(一定要跟测试类在同级目录下)
-
建一个Controller类
@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ // 调用业务,接收前端的参数 return "hello,World"; } }
-
编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回
-
将项目打成jar包
5、彩蛋
-
更改端口号
- 在springboot核心配置(application.properties)文件里面添加
server.port = 端口号
-
更改springboot启动banner
- 在百度上搜索springboot banner在线生成
- 生成好的复制下来
- 在resource下面创建banner.txt复制进去
- 重新运行
4、SpringBoot自动装配原理
我们之前写的HelloSpringBoot,到底是怎么运行的呢,Maven项目,我们一般从pom.xml文件探究起;
pom.xml
父依赖
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
点进去,发现还有一个父依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;
启动器 spring-boot-starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
springboot-boot-starter-xxx:就是spring-boot的场景启动器
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
主启动类
分析完了 pom.xml 来看看这个启动类
默认的主启动类
//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//以为是启动了一个方法,没想到启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}
但是**一个简单的启动类并不简单!**我们来分析一下这些注解都干了什么
@SpringBootApplication
作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
进入这个注解:可以看到上面还有很多其他注解!
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ......
}
@ComponentScan
这个注解在Spring中很重要 ,它对应XML配置中的元素。
作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
@SpringBootConfiguration
作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
我们继续进去这个注解查看
// 点进去得到下面的 @Component
@Configuration
public @interface SpringBootConfiguration {}
@Component
public @interface Configuration {}
这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!
我们回到 SpringBootApplication 注解中继续看。
@EnableAutoConfiguration
@EnableAutoConfiguration :开启自动配置功能
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
点进注解接续查看:
@AutoConfigurationPackage :自动配置包
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@import :Spring底层注解@import , 给容器中导入一个组件
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;
这个分析完了,退到上一步,继续看
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;
AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
1、这个类中有一个这样的方法
// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这里的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
2、这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
//这里它又调用了 loadSpringFactories 方法
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
3、我们继续点击查看 loadSpringFactories 方法
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//去获取一个资源 "META-INF/spring.factories"
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
//将读取到的资源遍历,封装成为一个Properties
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
4、发现一个多次出现的文件:spring.factories,全局搜索它
spring.factories
我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
WebMvcAutoConfiguration
我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FPkB1URg-1607397139918)(img/spring.factories1.png)]
可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
结论:
- SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
- 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
- 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
- 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
- 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
现在大家应该大概的了解了下,SpringBoot的运行原理,后面我们还会深化一次!
SpringApplication
不简单的方法
我最初以为就是运行了一个main方法,没想到却开启了一个服务;
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
SpringApplication.run分析
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication
这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
查看构造器:
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
// ......
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances();
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
run方法流程分析
跟着源码和这幅图就可以一探究竟了!
5、自定义starter
1、说明
启动器模块是一个空jar文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或者其他类库
命名规范:
-
官方命名:
前缀:
spring-boot-starter-xxx
比如:
spring-boot-starter-web
-
自定义命名:
xxx-spring-boot-starter
比如:mybatis-spring-boot-starter
2、编写启动器
-
在IDEA中新建一个空项目spring-boot-starter-diy
-
新建一个普通的Maven模块:longyu-spring-boot-starter
-
新建一个SpringBoot模块:longyu-spring-boot-starter-autoconfigure
-
点击确定即可,基本结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vboxsNTm-1607397139921)(img/image-20201120114415721.png)]
-
在我们的starter中导入autoconfigure的依赖
<!--启动器--> <dependencies> <!--引入自动配置模块--> <dependency> <groupId>org.example</groupId> <artifactId>longyu-spring-boot-starter-autoconfigure</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
-
将autoconfigure项目下多余的文件都删掉,Pom中只留下一个starter,这是所有的启动器基本配置!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XiUlBwBX-1607397139922)(img/image-20201120114745784.png)]
-
我们编写一个自己的服务
package com.longyu; public class HelloService { HelloProperties helloProperties; public HelloProperties getHelloProperties() { return helloProperties; } public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties; } public String sqyHello(String name){ return helloProperties.getPrefix() + name + helloProperties.getSuffix(); } }
-
编写HelloProperties配置类
package com.longyu; import org.springframework.boot.context.properties.ConfigurationProperties; // 前缀 longyu.hello @ConfigurationProperties(prefix = "longyu.hello") public class HelloProperties { private String prefix; public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getSuffix() { return suffix; } public void setSuffix(String suffix) { this.suffix = suffix; } private String suffix; }
-
编写我们自动配置类并注入bean(HelloServiceAutoConfiguration)
package com.longyu; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnWebApplication// web应用生效 @EnableConfigurationProperties(HelloProperties.class) public class HelloServiceAutoConfiguration { HelloProperties helloProperties; @Bean public HelloService helloService(){ HelloService service = new HelloService(); service.setHelloProperties(helloProperties); return service; } }
-
在resources编写一个自己的META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.longyu.HelloServiceAutoConfiguration
-
编写成功后,可以安装到maven仓库中
> 这样我们的启动器就完成了,新建一个项目测试
1. 新建一个SpringBoot项目
2. 导入我们自己写的启动器
```xml
<dependency>
<groupId>org.example</groupId>
<artifactId>longyu-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
```
3. 编写一个HelloController进行测试我们自己写的接口
```java
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@RequestMapping("/hello")
public String hello(){
return helloService.sqyHello("测试");
}
}
```
4. 编写配置文件application.properties
```properties
longyu.hello.prefix="ppp"
longyu.hello.suffix="sss"
```
5. 启动项目进行测试;
http://localhost:8080/hello
6、SpringBoot配置文件
1、配置文件
SpringBoot使用一个全局的配置文件,配置文件名称是固定的
application.properties
- 语法结构:
key=value
- 语法结构:
- application.yaml
- 语法结构:
key: value
- 语法结构:
配置文件的作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们配置好了
2、yaml
语法:例:
# k: v
#普通的key=value
name: xiaoming
#对象
student: {name: xiaoming,age: 3}
# 数组pets:
pets:
- cat
- dog
- pig
#等价上面
pets: [cat,dog,pig]
给属性赋值的几种方式:
-
第一种就是普通赋值也就是上面的方式
-
第二种通过
ymal
配置文件赋值(核心)yaml支持松散绑定
松散绑定也就是说在配置文件里面first-name是这样而在类里面可以使用驼峰命名firstName
-
首先我们需要先定义一个yaml配置类用来赋值
person: name: xiaoming age: 3 happy: false birth: 2020/02/21 maps: {k1: v1,k2: v2} lists: - code - music - girl dog: name: 旺财 age: 3
-
使用
yaml
赋值的时候要通过·来扫描注入的类 -
person
:是你在yaml
配置文件里注入的类名注意:使用
ConfigurationProperties
爆红是正常的,只要使用添加一个依赖就好了<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3SZQaYTJ-1607397139923)(img/ConfigurationProperties.png)]
-
yaml还可以使用Spring 的EL表达式
例如:
${random.uuid}
随机数${random.int}
${random.hello:hello}_hello
占位符
-
-
第三种方式通过
properties
配置文件-
首先定义一个
properties
配置文件用来赋值name = xiaoming
-
利用
@PropertySource(value = "classpath:test.properties")
注解用来加载指定的配置文件 -
赋值 通过
@Value("${name}")
SPEL
表达式赋值
-
7、JSR303校验和多环境切换
JSR303校验
1、什么是jsr303校验
- 比如说我们前端写一个input框类型是
Email
我们就必须遵循这个规则否则提交不成功 - 在我们java后台也有这种方法
- 就是jsr303校验
2、使用方式
-
只需要在要赋值的类的属性名上添加你要验证的数据类型即可
比如说我们要验证
email
就可以这样写@Email private String name;
-
也可以返回自己的错误信息,可以这样写
@Email(message="邮箱格式错误") private String name;
3、常用参数为
@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) string is between min and max included.
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
多环境切换
配置文件名是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;
1、多配置文件(properties)
我们在主配置文件编写的时候,文件名可以是 application-{配置文件名}.properties/yml , 用来指定多个环境版本;
例如:
application-test.properties 代表测试环境配置
application-dev.properties 代表开发环境配置
但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置
所以我们需要通过一个配置来选择需要激活的环境:
#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev
2、yaml的多文档块
和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了 !
server:
port: 8081
#选择要激活那个环境块
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev #配置环境的名称
---
server:
port: 8084
spring:
profiles: prod #配置环境的名称
注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!
3、配置文件加载位置
外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置
官方外部配置文件说明参考文档
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:
优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件
优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot会从这四个位置全部加载主配置文件;互补配置;
我们在最低级的配置文件中设置一个项目访问路径的配置来测试互补问题;
#配置项目的访问路径
server.servlet.context-path=/kuang
8、自动配置原理
- 通过Run方法里的refreshContext(Context)来刷新容器
- 刷新容器的时候通过解析注解解析配置文件的方式把我们的Bean注入到容器里面
- 这时候他会解析SpringBootApplication
1、分析自动配置原理
我们以**HttpEncodingAutoConfiguration(Http编码自动配置)**为例解释自动配置原理;
//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration
//启动指定类的ConfigurationProperties功能;
//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
//并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class})
//Spring底层@Conditional注解
//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass({CharacterEncodingFilter.class})
//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
//如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final Encoding properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
//给容器中添加一个组件,这个组件的某些值需要从properties中获取
@Bean
@ConditionalOnMissingBean //判断容器没有这个组件?
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
//。。。。。。。
}
一句话总结 :根据当前不同的条件判断,决定这个配置类是否生效!
- 一但这个配置类生效;这个配置类就会给容器中添加各种组件;
- 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
- 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;
- 配置文件能配置什么就可以参照某个功能对应的这个属性类
//从配置文件中获取指定的值和bean的属性进行绑定
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
}
我们去配置文件里面试试前缀,看提示!
这就是自动装配的原理!
2、精髓
1、SpringBoot启动会加载大量的自动配置类
2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
**xxxxAutoConfigurartion:自动配置类;**给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
3、了解:@Conditional
了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了。
我们怎么知道哪些自动配置类生效?
我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
#开启springboot的调试类
debug=true
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
9、SpringBoot Web开发
1、静态资源问题
-
第一种方式导入静态资源 (通过Webjars引入)
使用SpringBoot需要使用Webjars,我们可以去搜索一下:
网站:https://www.webjars.org
-
导入我们需要的静态文件依赖(比如js文件)
-
要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.4.1</version> </dependency>
-
-
第二种方式导入静态资源
这四个目录源码里面支持的
优先级为resource>static(默认)>public
"classpath:/META-INF/resources/" "classpath:/resources/" "classpath:/static/" "classpath:/public/"
-
自定义静态资源路径
我们也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在application.properties中配置;
spring.resources.static-locations=classpath:/coding/,classpath:/kuang/
2、首页处理
欢迎页,静态资源文件夹下的所有 index.html 页面;被 /** 映射。
比如我访问 http://localhost:8080/ ,就会找静态资源文件夹下的 index.html
新建一个 index.html ,在我们上面的3个目录中任意一个;然后访问测试 http://localhost:8080/ 看结果!
3、图标定制
只需要把图标文件放在静态资源目录下即可生效(注意:名称为favicon)
10、Thymeleaf模板引擎
Thymeleaf命名空间
xmlns:th="http://www.thymeleaf.org"
Thymeleaf依赖
<!--Thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
模板引擎
模板引擎就相当于我们之前写的jsp页面,处理后台的数据返回到指定的页面,
1、使用Thymelaf
- 首先我们指定的pom依赖
- 在我们的templates下,写我们的Html测试网页
- 编写一个Controller类用来调用我们的测试网页即可
注意:要找SpringBoot版本对应的模板引擎
2、Thymelaf语法
我们先传一个参数到页面
-
从我们的controller层传一个参数到页面
@RequestMapping("/test") public String index(Model model){ model.addAttribute("msg","<h1>hello,SpringBoot</h1>"); model.addAttribute("users", Arrays.asList("longyu","龙雨")); return "test"; }
-
我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。
xmlns:th="http://www.thymeleaf.org"
-
前端代码
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div th:text="${msg}"></div> <div th:utext="${msg}"></div> <div th:each="user:${users}" th:text="${user}"> </div> </body> </html>
th:text 表示为普通变量(文本)
th:utext 可以转义我们后台传来的字符串
th:each 遍历集合 效果跟我们的foreach一样
我们可以使用任意的 th:attr 来替换Html中原生属性的值!
11、页面国际化
就是说页面可以语言切换
1、准备工作
先在idea中统一设置编码问题
2、配置文件编写
-
我们在resource资源文件下新建一个i18n目录,存放国际化配置文件
-
建立一个login.properties文件,还有一个login_zh_CN.properties;idea会自动识别我们要做国际化操作
-
再建一个login_en_US.properties英文的配置文件
-
在这三个里边添加数据
默认:
login.btn=登录 login.password=密码 login.remember=记住我 login.tip=请登录 login.username=用户名
中文:
login.tip = 请登录 login.password = 密码 login.remember = 记住我 login.username = 用户名 login.btn = 登录
英文:
login.btn=Sign in login.password=Password login.remember=Remember me login.tip=Please sign in login.username=Username
3、配置文件生效探究
我们去看一下SpringBoot对国际化的自动配置!这里又涉及到一个类:MessageSourceAutoConfiguration
里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource;
// 获取 properties 传递过来的值进行判断 @Bean public MessageSource messageSource(MessageSourceProperties properties) { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) { // 设置国际化文件的基础名(去掉语言国家代码的) messageSource.setBasenames( StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace(properties.getBasename()))); } if (properties.getEncoding() != null) { messageSource.setDefaultEncoding(properties.getEncoding().name()); } messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale()); Duration cacheDuration = properties.getCacheDuration(); if (cacheDuration != null) { messageSource.setCacheMillis(cacheDuration.toMillis()); } messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat()); messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage()); return messageSource; }
我们真实 的情况是放在了i18n目录下,所以我们要去配置这个messages的路径;
spring.messages.basename=i18n.login
4、配置页面国际化值
去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}。我们去页面测试下:
现在已经设置为中文了
如果我们想要更好,可以根据按钮自动切换中英文
5、配置国际化解析
在Spring中有一个国际化的Locale (区域信息对象);里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!
我们去我们webmvc自动配置文件,寻找一下!看到SpringBoot默认配置:
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
// 容器中没有就自己配,有的话就用用户配置的
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
// 接收头国际化分解
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
AcceptHeaderLocaleResolver 这个类中有一个方法
public Locale resolveLocale(HttpServletRequest request) {
Locale defaultLocale = this.getDefaultLocale();
// 默认的就是根据请求头带来的区域信息获取Locale进行国际化
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
} else {
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = this.getSupportedLocales();
if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
} else {
return defaultLocale != null ? defaultLocale : requestLocale;
}
} else {
return requestLocale;
}
}
}
那假如我们现在想点击链接让我们的国际化资源生效,就需要让我们自己的Locale生效!
我们去自己写一个自己的LocaleResolver,可以在链接上携带区域信息!
修改一下前端页面的跳转连接:
<!-- 这里传入参数不需要使用 ?使用 (key=value)-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
我们去写一个处理的组件类!
package com.kuang.component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
//可以在链接上携带区域信息
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
String language = request.getParameter("l");
Locale locale = Locale.getDefault(); // 如果没有获取到就使用系统默认的
//如果请求链接不为空
if (!StringUtils.isEmpty(language)){
//分割请求参数
String[] split = language.split("_");
//国家,地区
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
为了让我们的区域化信息能够生效,我们需要再配置一下这个组件!在我们自己的MvcConofig下添加bean;
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
12、整合JDBC
1、SpringData简介
对于数据访问层,无论是Sql(关系型数据库)还是NoSql(非关系型数据库),SpringBoot底层都是采用SpringData的方式进行统一管理
SpringBoot底层都是采用SpringData的方式进行统一处理各种数据库,SpringData也是Spring中与SpringBoot、SpringCloud等齐名的知名项目
Sping Data 官网:https://spring.io/projects/spring-data
数据库相关的启动器 :可以参考官方文档:
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
2、整合JDBC
测试数据源
- 首先创建一个项目:springboot-data;引入相应模块!
基础模块:
- SpringWeb
- JDBC API
- MysqlDriver
-
创建完项目会自动帮我们导入以下的启动器:
<!--web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--jdbc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
-
编写yaml配置文件链接数据库:
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: longyu.. #假如时区报错了,就增加一个时区配置就OK了serverTimezone=UTC url: jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 type: com.alibaba.druid.pool.DruidDataSource
-
测试类测试一下看看(是否已经连接上数据源)
@SpringBootTest class Springboot04DataApplicationTests { @Autowired DataSource dataSource; @Test void contextLoads() throws SQLException { // 查看一下默认的数据源 System.out.println(dataSource.getClass()); // 获取数据库链接 Connection connection = dataSource.getConnection(); System.out.println(connection); // 关闭数据库 connection.close(); } }
结果:
默认数据源为:class com.zaxxer.hikari.HikariDataSource
看一下DataSourceAutoConfiguration文件
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) protected static class PooledDataSourceConfiguration { }
这里导入的类都在DataSourceConfiguration配置类下,可以看出SpringBoot2.3.5默认使用HikariDataSource数据源,而以前的版本默认使用org.apache.tomcat.jdbc.pool.DataSource作为数据源
HikariDataSource号称JavaWeb当前速度最快的数据源,相比与传统的C3P0、DBCP、Tomcat jdbc等连接池更加优秀;
可以在配置文件里面使用spring.datasource.type指定自定义的数据源类型,值为 要使用的连接池 全限定类名
3、JDBCTemplate
-
有了数据源(Hikari),然后可以拿到数据库链接,有了链接(Connection),就可以使用原生的JDBC语句来操作数据库
-
Spring对原生的JDBC做了轻量级的封装,即jdbcTemplate
-
数据库操作的所有CRUD方法都在jdbcTemplate中
-
SpringBoot默认已经配置好了jdbcTemplate放在了容器中,程序员只需自己注入即可使用
-
jdbcTemplate的自动配置是依赖org.springframework.boot,autoconfiure.jdbc包下的JdbcTemplateConfiguration类
JdbcTemplate主要提供一下几类方法
- execute方法:可以用于执行任何sql语句,一般用于执行DDL语句(操作数据库)
- update方法及batchUpdate方法:update方法用于执行增、删、改等语句;batchUpdate方法用于执行批处理相关语句
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句
4、测试一下JDBC(CRUD)
编写一个Controller,注入jdbcTemplate,编写测试方法进行访问测试
@RestController
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
// 查询数据库的所有信息
@GetMapping("/userList")
public List<Map<String,Object>> userList(){
String sql = "select * from admin";
List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);
return list_maps;
}
@GetMapping("/addUser")
public String addUser(){
String sql = "insert into admin(id,username,password) values (3,'小明','1234')";
jdbcTemplate.update(sql);
return "updateOK";
}
@GetMapping("/updateUser/{id}")
public String updateUser(@PathVariable("id") int id){
String sql = "update admin set username=?,password=? where id="+id;
// 封装
Object[] objects = new Object[2];
objects[0] = "小明2";
objects[1] = "3333";
jdbcTemplate.update(sql,objects);
return "updateOK";
}
@GetMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id") int id){
String sql = "delete from admin where id=?";
jdbcTemplate.update(sql,id);
return "updateOK";
}
}
测试成功!
13、整合Druid数据源
1、Druid简介
Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,又不得不使用数据库连接池
Druid是阿里巴巴开源平台上一个数据连接池实现,结合了c3p0、DBCP等DB池的优点,同时加入了日志监控。
Druid可以很好的监控DB池链接和Sql的执行情况,天生就是针对监控而生的DB连接池
Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验
SpringBoot2.0以上默认使用Hikari数据源,可以说Hikari与Druid都是当前JavaWeb上最优秀的数据源,我们来重点介绍SpringBoot如何集成Druid数据源,如何实现数据库监控。
com.alibaba.druid.pool.DruidDataSource基本配置参数如下:
2、配置数据源
-
添加上Druid数据源依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.24</version> </dependency>
-
切换数据源,我们通过spring.datasource.type指定数据源
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: longyu.. #假如时区报错了,就增加一个时区配置就OK了serverTimezone=UTC url: jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 type: com.alibaba.druid.pool.DruidDataSource
-
切换完成后可以在通过测试类测试一下是否切换
-
切换成功!就可以设置数据源链接初始大小、最大连接数、等待时间、最小连接数等设置项;
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: longyu.. #假如时区报错了,就增加一个时区配置就OK了serverTimezone=UTC url: jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 type: com.alibaba.druid.pool.DruidDataSource #Spring Boot 默认是不注入这些属性值的,需要自己绑定 #druid 数据源专有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
-
导入Log4j的依赖
<!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
我们把自己的DruidDataSource绑定全局配置文件参数中,再添加到容器中,而不使用SpringBoot的自动生成了;我们需要自己添加DruidDataSource组件到容器中,并绑定属性;
package com.kuang.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; @Configuration public class DruidConfig { /* 将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建 绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效 @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中 前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中 */ @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druidDataSource() { return new DruidDataSource(); } }
-
测试一下
package com.longyu; import com.alibaba.druid.pool.DruidDataSource; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; @SpringBootTest class Springboot04DataApplicationTests { @Autowired DataSource dataSource; @Test void contextLoads() throws SQLException { // 查看一下默认的数据源 System.out.println(dataSource.getClass()); // 获取数据库链接 Connection connection = dataSource.getConnection(); System.out.println(connection); DruidDataSource druidDataSource = (DruidDataSource) dataSource; System.out.println("druidDataSource 数据源最大连接数:"+druidDataSource.getMaxActive()); System.out.println("druidDataSource 数据源初始化连接数:"+druidDataSource.getInitialSize()); // 关闭数据库 connection.close(); } }
输出结果:配置参数已经生效!
3、配置Druid数据源监控
Druid数据源具有监控的功能,并提供了一个web界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的web页面
所有第一步需要设置Druid后台管理页面,比如 登录账号、密码等;配置后台管理
// 后台监控 : web.xml
// 因为SpringBoot 内置了 servlet容器,所以没有web.xml,替代方法:ServletRegistrationBean
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
// 后台需要有人登陆,账号密码配置
HashMap<String,String> initParameters = new HashMap<>();
// 增加配置
// 登陆key是固定的loginUsername loginPassword
initParameters.put("loginUsername","admin");// 后台管理界面的而登陆账号
initParameters.put("loginPassword","123456");
//后台允许谁可以访问
//initParams.put("allow", "localhost"):表示只有本机可以访问
//initParams.put("allow", ""):为空或者为null时,表示允许所有访问
initParameters.put("allow", "");
//deny:Druid 后台拒绝谁访问
//initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问
bean.setInitParameters(initParameters);// 设置初始化参数
return bean;
}
配置完毕后,我们可以选择访问:http://localhost:8080/druid/login.html
进入之后
配置Druidweb监控filter过滤器
//配置 Druid 监控 之 web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
bean.setInitParameters(initParams);
//"/*" 表示过滤所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
按需求进行配置即可,主要用作监控!
14、整合mybatis
-
导入myabtis的依赖
<!--mybatis-spring-boot-stater--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency>
-
配置数据源的信息
spring.datasource.username=root spring.datasource.password=longyu.. spring.datasource.url=jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 整合mybatis mybatis.type-aliases-package=com.longyu.pojo mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
-
测试数据库是否连接成功
-
创建实体类
Admin
@Data @NoArgsConstructor @AllArgsConstructor public class Admin { private int id; private String username; private String password; }
-
创建接口以及对应的Mapper接口
AdminMapper
// 这个注解表示这是一个mybatis的mapper类 @Mapper @Repository("adminMapper") public interface AdminMapper { // 查询数据 List<Admin> queryAdminList(); }
-
对应的Mapper映射文件
AdminMapper.xml
<?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.longyu.mapper.AdminMapper"> <select id="queryAdminList" resultType="com.longyu.pojo.Admin"> select * from admin </select> </mapper>
-
maven配置资源过滤问题
<resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources>
-
编写Controller测试
AdminController
package com.longyu.controller; import com.longyu.mapper.AdminMapper; import com.longyu.pojo.Admin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class AdminController { @Autowired @Qualifier("adminMapper") private AdminMapper adminMapper; @GetMapping("/") public List<Admin> queryAdminList(){ List<Admin> admins = adminMapper.queryAdminList(); for (Admin admin : admins) { System.out.println(admin); } return admins; } }
-
启动项目测试!
15、任务
1、异步任务
-
为什么要使用异步任务
- 比如我们现在要上传一个Excel表格数据有上万条,后台要进行插入数据库操作
- 此时前台会造成影响不动,直到数据插入成功,响应才会成功
- 所以我们这里要使用异步任务处理
- 这样用户不用等待,直接跳转,任务继续在后台运行
-
使用方法
-
创建一个要执行处理的Service
模仿后台处理需要加载的操作 延时3秒
@Service public class AsyncService { public void hello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("数据正在处理。。。"); } }
-
编写一个Controller类 测试一下没有进行异步处理的操作
@RestController public class AsyncController { @Autowired AsyncService asyncService; @RequestMapping("/hello") public String hello(){ asyncService.hello();// 停止三秒 return "hello"; } }
-
执行访问localhost:8080我们会发现页面会在三秒之后打印hello
-
实现异步任务
第一步我们需要在主程序上加一个@EnableAsync,开启异步注解
@Service public class AsyncService { // 告诉Spring这是一个异步的方法 @Async public void hello(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("数据正在处理。。。"); } }
第二步我们需要在要进行处理的方法上加上@Async
@EnableAsync // 开启异步注解功能 @SpringBootApplication public class SpringbootRenwuApplication { public static void main(String[] args) { SpringApplication.run(SpringbootRenwuApplication.class, args); } }
-
测试 页面直接跳转
-
2、定时任务
定时任务,就跟我们定闹钟一样,到固定时间提醒你该干什么了,Spring为我们提供了异步执行任务调度的方式。
1、步骤
-
创建一个service
写一个我们要执行定时的方法
@Service public class ScheduledService { // 在一个特定的时间执行这个方法 // cron表达式 // 秒 分 时 日 月 周几 @Scheduled(cron = "0 51 10 * * ?") public void hello(){ System.out.println("该我执行了"); } }
-
在主程序上开启@EnableScheduling开启定时任务
@EnableAsync // 开启异步注解功能 @EnableScheduling // 开启定时功能 @SpringBootApplication public class SpringbootRenwuApplication { public static void main(String[] args) { SpringApplication.run(SpringbootRenwuApplication.class, args); } }
ps :@EnableScheduling :开启定时功能
@Scheduled(cron = “0 51 10 * * ?”): 设置定时的时间
详细了解cron表达式:http://www.bejson.com/othertools/cron/
3、邮件发送
SpringBoot为我们提供了JavaMailSender接口实现邮件发送,在Spring Boot的Starter模块中也为此提供了自动化配置。
在SpringBoot中使用JavaMailSender发送邮件
步骤:
-
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
-
application.properties中配置我们的属性
spring.mail.username= qq邮箱 spring.mail.password= qq授权码 spring.mail.host=smtp.qq.com # 开启加密验证 spring.mail.properties.mail.smtp.ssl.enable=true
ps:获取授权码:在QQ邮箱中的设置->账户->开启pop3和smtp服务
-
测试一下
@SpringBootTest class SpringbootRenwuApplicationTests { @Autowired JavaMailSenderImpl mailSender; // 发送一个简单的邮件 @Test void contextLoads() { SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setSubject("傻狗"); // 标题 mailMessage.setText("大傻狗");// 内容 mailMessage.setTo("2659734735@qq.com"); // 邮箱到哪里去 mailMessage.setFrom("2659734735@qq.com");// 要从哪里发送邮箱 // 发送 mailSender.send(mailMessage); } // 发送一个带文件的邮件 @Test void contextLoads2() throws MessagingException { MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true); // 利用helper对象发送邮件 helper.setSubject("傻狗"); // 标题 helper.setText("<p style='color:red'>大傻狗</p>",true);// 内容 true为开启编码 // 附件 helper.addAttachment("1.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg")); helper.addAttachment("2.jpg",new File("C:\\Users\\Administrator\\Desktop\\2.jpg")); //发送 helper.setTo("276055422@qq.com"); // 收件人 helper.setFrom("2659734735@qq.com"); // 发件人 mailSender.send(mimeMessage); } }
-
成功