SpringBoot 基础学习
SpringBoot
https://spring.io/projects/spring-boot
Reference:
1. 简介
1.1 SpringBoot
- Spring
- Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson 。
- Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。
如何简化?
- 基于POJO的轻量级和最小侵入性编程,所有东西都是bean;
- 通过IOC,依赖注入(DI)和面向接口实现松耦合;
- 基于切面(AOP)和惯例进行声明式编程;
- 通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;
SpringBoot
学过javaweb的同学就知道,开发一个web应用,从最初开始接触Servlet结合Tomcat, 跑出一个Hello Wolrld程序,是要经历特别多的步骤;后来就用了框架Struts,再后来是SpringMVC,到了现在的SpringBoot,过一两年又会有其他web框架出现;
SpringBoot,就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置
Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。
- 优点
- 为所有Spring开发者更快的入门
- 开箱即用,提供各种默认配置来简化项目配置
- 内嵌式容器简化Web项目
- 没有冗余代码生成和XML配置的要求
1.2 微服务
微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通
==高内聚、低耦合==
1.2.1 开发演变
1.2.2 单体应用架构
将一个应用中的所有服务都封装在一个应用中
- 优点:易于开发和测试;也十分方便部署;当需要扩展时,只需将war包复制多分,然后放到多个服务器上,再做负载均衡
- 缺点:修改维护麻烦
1.2.2 微服务架构
把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素。所有微服务是对功能元素进行复制,而没有对整个应用进行复制
2. 第一个SpringBoot程序
2.1 项目创建
2.1.1 官网方式
官网提供的快速构建项目的网址:Spring Initializr
GEBERATE
-> Maven项目- 项目结构:
2.1.2 IDEA方式
- 新建项目
- 添加依赖
- 直接运行
:warning:
1
2
3
4 java: 无法访问org.springframework.boot.SpringApplication
错误的类文件: /D:/Coding/Java/apache-maven-3.9.3/maven-repo/org/springframework/boot/spring-boot/3.0.9/spring-boot-3.0.9.jar!/org/springframework/boot/SpringApplication.class
类文件具有错误的版本 61.0, 应为 52.0
请删除该文件或确保该文件位于正确的类路径子目录中。
- 解决方法1 SpringBoot使用了3.0或者3.0以上,因为Spring官方发布从Spring6以及SprinBoot3.0开始最低支持JDK17,所以仅需将SpringBoot版本降低为3.0以下即可。
- 解决方法2 将JDK版本提高
2.1.3 直接使用
1 |
|
2.1.4 注意点
新建包要在
HelloworldideaApplication.java
同级目录下建包程序入口也是Spring的组件
pom.xml
```xml
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.2</version> <relativePath/> <!-- lookup parent from repository -->
</parent>
com.bayyy helloworld 0.0.1-SNAPSHOT helloworld Demo project for Spring Boot 8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test <!-- 打jar包插件 --> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
4. 打包
- ![image-20230728200204481](https://s2.loli.net/2023/07/28/DOjIpbTJCLPV24a.png)
- ![image-20230728200256244](https://s2.loli.net/2023/07/28/CkLRPGAQpncjbmz.png)
- 此时可以直接运行 `java -jar .\helloworld-0.0.1-SNAPSHOT.jar`
- ![image-20230728200657915](https://s2.loli.net/2023/07/28/zBJxOcejn8Dh5Wm.png)
## 2.2 基础配置
### 2.2.1 修改端口号
> application.properties
```properties
server.port=8081
2.2.2 修改Banner
resources 目录下新建一个banner.txt
- 七彩佛祖
1 | ${AnsiColor.BRIGHT_GREEN}$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ |
3. SpringBoot自动装配原理
3.1 pom.xml
- 核心依赖在父工程中
- spring-boot-dependencies
- 我们在引入一些Springboot依赖的时候,不需要版本,就是因为有这些版本仓库
3.1.1 父工程的父工程中管理了大量的 jar
包
3.1.2 父工程中配置了资源过滤
3.2 启动器
1 | <!-- 启动器 --> |
- 启动器:SpringBoot的启动场景;
- 比如:Spring-boot-starter-web,会帮助我们自动导入web环境所有的依赖!
- 使用功能 -> 导入对应启动器(Developing with Spring Boot)
3.3 主程序
1 | // 标注这个类是一个SpringBoot的应用(组合注解) |
3.3.1 注解
- 所有的配置都是在启动的时候扫描并加载:
类路径下/META-INF/spring.factories
- 判断条件生效(
ConditionalOnXXX
) - 导入对应
start
就回存在对应的启动器 -> 自动装配生效
- 判断条件生效(
- 整合Java2E ,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.5.RELEASE.jar 这个包下
- 所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
3.3.2 SpringApplication
- 作用:
- 推断应用的类型是普通项目还是Web项目
- 查找并加载所有可用初始化器,设置到
initializers
属性中 - 找出所有的应用程序监听器,设置到
initializers
属性中 - 推断并设置main方法的定义类,找到运行的主类
4. YML 配置文件
4.1 yml语法及概述
4.1.1 配置文件
SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的
application.properties
- 语法结构 :
key=value
- 语法结构 :
application.yml
==推荐==- 语法结构 :
key: value
- 语法结构 :
配置文件作用
- 修改SpringBoot自动配置的默认值
4.1.2 yaml概述
- YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
- 这种语言以数据作为中心,而不是==以标记语言为重点==
4.1.3 yml语法
- xml配置
1 | <server> |
- yaml配置 ==简单==
1 | server: |
4.2 yml实体类配置
4.2.1 yml配置实体类
- 实体类
1 | package com.bayyy.pojo; |
解决方法:
- ```xml
</dependency><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- `@configurationProperties`
- 将配置文件中的每一个属性的值,映射到这个组件中
- 告诉SpringBoot将类中的所有属性和配置文件中相关的配置进行绑定
- 参数:`prefix “person” `:将配置文件中的person 下面的所有属性一一定义
- 只有这个组件是容器中的组件,才能使用容器提供的`@ConfigurationProperties`功能
```yaml
person:
name: bayyy
age: 18
happy: true
birth: 2023/7/29
maps:
k1: v1
k2: v2
lists:
- code
- music
- girl
dog:
name: 旺财
age: 3
- ```xml
测试
1 |
|
- 测试结果:
4.2.2 @PropertySource注解
用于加载指定的配置文件
1 |
|
- dog.properties
1 | dog.name=旺财 |
4.3 松散绑定
- yml中
- person_name —> personName
- 可以有效的转换为驼峰命名法
@ConfigurationProperties
只需要写一次即可 ,@Value
则需要每个字段都添加- JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
- 复杂类型封装,yml中可以封装对象 , 使用value就不支持
4.4 yml高级应用
1 | person: |
4.5 JSR303数据校验 @Validated
Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
1
2
3
4 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>可以写个注解让我们的name只能支持Email格式;
同时可以修改错误消息
```java
@Email(message=”邮箱错误”)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
### 4.5.1 空检查
- @Null 验证对象是否为null
- @NotNull 验证对象是否不为null, 无法查检长度为0的字符串
- @NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
- NotEmpty 检查约束元素是否为NULL或者是EMPTY.
### 4.5.2 Booelan检查
- @AssertTrue 验证 Boolean 对象是否为 true
- @AssertFalse 验证 Boolean 对象是否为 false
### 4.5.3 长度检查
- @Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
- @Length(min=, max=) Validates that the annotated string is between min and max included.
### 4.5.4 日期检查
- @Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
- @Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
- @Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。
### 4.5.5 数值检查
建议使用在**Stirng Integer**类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换Stirng为”“,Integer为null
- @Min 验证 Number 和 String 对象是否大等于指定的值
- @Max 验证 Number 和 String 对象是否小等于指定的值
- @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
- @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
- @Digits 验证 Number 和 String 的构成是否合法
- @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
- @Range(min=, max=) 被指定的元素必须在合适的范围内
- @Range(min=10000,max=50000,message=”range.bean.wage”)
- @Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
- @CreditCardNumber信用卡验证
- @Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
- @ScriptAssert(lang= ,script=, alias=)
- @URL(protocol=,host=, port=,regexp=, flags=)
## 4.6 多配置文件
### 4.6.1 优先级
- 优先级1:**项目路径**下的**config**文件夹配置文件
- 优先级2:**项目路径**下配置文件
- 优先级3:**资源路径**下的**config**文件夹配置文件
- 优先级4:**资源路径**下配置文件
![image-20230729175444128](https://s2.loli.net/2023/07/29/OcxvXagYAkE86Ni.png)
![image-20230729173854922](https://s2.loli.net/2023/07/29/ayTrl26Sfw3WRHx.png)
### 4.6.2 多配置文件
在主配置文件编写的时候,文件名可以是 **application-{profile}.properties/yml** , 用来指定多个环境版本
![image-20230729174141523](https://s2.loli.net/2023/07/29/U3FGREZ4Qywvukf.png)
```yaml
# 比如在配置文件中指定使用dev环境
spring:
profiles:
active: dev
4.6.3 单文件写多个配置
---
可以区分多个文件
1 | server: |
4.6.4 互补配置
1 | server: |
4.7 配置文件内容
4.7.1 配置内容
- 以
HttpEncodingAutoConfiguration
(Http
编码自动配置) 为例
1 | // 表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件; |
- 从配置文件中获取指定值和bean的属性进行绑定
1 | //从配置文件中获取指定的值和bean的属性进行绑定 |
4.7.2 @Conditional
@Conditional派生注解(Spring注解版原生的@Conditional作用)
- 必须是指定条件成立,才给容器添加组件,配置中的内容才会生效
4.7.3 配置类输出
控制台打印自动配置报告
1 | # 开启SpringBoot的调试类 |
- 测试结果:
1 | ============================ |
- Positive matches:(自动配置类启用的:正匹配)
- Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
- Unconditional classes: (没有条件的类)
5. web开发探究
5.1 静态资源映射规则-webjars
SpringMVC的web配置都在
WebMvcAutoConfiguration
配置类中
5.1.1 addResourceHandlers 添加资源处理
1 |
|
- 所有的
/webjars/**
都会对应到classpath:/META-INF/resources/wewbjars/
找对应的资源
5.1.2 wenjars
- 可以通过 Maven 形式引入
- 静态资源会去相应路径寻找资源,可以访问:localhost:8080/webjars/jquery/3.7.0/jquery.js
5.2 静态资源映射规则-classpath
5.2.1 默认静态资源路径
1 | // 进入方法 |
- 即以上路径下的所有文件都可以被访问到
- 优先级顺序也是按照如上的书写顺序
resources>static>public
5.2.2 自定义静态资源路径
1 | spring.resources.static-locations=classpath:/coding/,classpath:/bayyy/ |
:warning: 自定义后,默认的自动配置失效
5.2.3 首页和图标
1)首页
1 |
|
其中 getWelcomePage
:
1 | private Optional<Resource> getWelcomePage() { |
- 静态资源目录下的所有
index.html
会被/**
映射 访问
http://localhost:8080/
, 就会找静态资源目录下的index.html
测试结果:
2)图标 ==已废弃==
静态资源目录下查找
favicon.ico
1 | #关闭默认图标 |
6. Thymeleaf模板引擎
6.1 模板引擎
前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。jsp支持非常强大的功能,包括能写Java代码
但是 SpringBoot 默认是不支持jsp的
- SpringBoot项目首先是以jar的方式,不是war
- 用的是嵌入式的Tomcat
SpringBoot推荐使用模板引擎:
jsp
就是一个模板引擎,还有freemarker
,包括Thymeleaf
作用
- 将页面模板和数据进行组合,进行表达式解析、数据填充等操作
6.2 引入Thymeleaf
Thymeleaf 官网:https://www.thymeleaf.org/
Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf
Spring官方文档:Developing with Spring Boot
1 | <dependency> |
6.3 Thymeleaf
- Thymeleaf 自动配置类 -
ThymeleafPropert
1 | public class ThymeleafProperties { |
:pushpin: 文件放置在
classpath:/templates/
下,后缀为.html
测试
TestController
1
2
3
4
public String test() {
return "test";
}test.html -
./templeates/test.html
1
2
3
4
5
6
7
8
9
10
11
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thymeleaf</title>
</head>
<body>
<h1>模板引擎</h1>
</body>
</html>
6.4 基本语法
6.4.1 基本使用
Controller
1
2
3
4
5
public String test(Model model) {
model.addAttribute("msg", "Hello, SpringBoot");
return "test";
}Html
1
2
3
4
5
6
7
8
9
10
11
12
13
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf</title>
</head>
<body>
<h1>模板引擎</h1>
<!-- 所有的html元素都可以被 thymeleaf 解析 -->
<!-- 通过th:text属性来指定标签体内容 -->
<div th:text="${msg}"></div>
</body>
</html>- 需要加入命名空间
xmlns:th="http://www.thymeleaf.org"
- 所有的html元素都可以被 thymeleaf 解析
- 通过
th:元素名
进行替换接管
- 需要加入命名空间
测试结果:
6.4.2 使用语法
使用任意的 th:attr 来替换Html中原生属性的值
6.4.3 表达式使用
1 | Simple expressions:(表达式语法) |
6.4.4 测试遍历
1 |
|
1 |
|
7. MVC自动配置原理
7.1 官网说明
1 | Spring MVC Auto-configuration |
7.2 ContentNegotiatingViewResolver 内容协商视图解析器
7.2.1 源码分析
- WebMvcAutoConfiguration -> ContentNegotiatingViewResolver
1 |
|
- 视图解析代码
1 | // 注解说明:@Nullable 即参数可为null |
- getCandidateViews中把所有的视图解析器进行while循环,解析
1 | Iterator var5 = this.viewResolvers.iterator(); |
7.2.2 自己实现视图解析器
./config/MyMvcConfig.java
1 | // 扩展 SpringMVC |
- 验证自己实现的视图解析器,在
DispatcherServlet
中的doDispatch
方法 加断点 ==所有的请求都会在此处进行分发==
7.3 转换器和格式化器
1 | public FormattingConversionService mvcConversionService() { |
1 | public String getDateFormat() { |
7.4 修改SpringBoot的默认配置
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
我们要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc注解;我们去自己写一个;我们新建一个包叫config,写一个类MyMvcConfig;
1 |
|
- 测试结果:
7.5 全面接管SpringMVC
If you want to take complete control of Spring MVC you can add your own @Configuration annotated with @EnableWebMvc.
全面接管:SpringBoot对SpringMVC的自动配置清空
其导入了一个类
1
public EnableWebMvc {}
继承父类
1
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { // ......}
而最基础的Webmvc自动配置类中
ConditionalOnClass
注释说明仅在无指定组件时,自动配置类才会生效1
2
3
4
5
6
7
8
9
10
11
// 这个注解的意思就是:容器中没有这个组件的时候,这个自动配置类才生效
public class WebMvcAutoConfiguration {
}
8. 员工管理系统
9. 整合JDBC
9.1 SpringData简介
对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。
Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。
Sping Data 官网:Spring Data
9.2 简单实用
9.2.1 项目创建
9.2.2 yaml配置文件(连接数据库)
1 | spring: |
9.2.3 测试
```java
@Autowired
DataSource dataSource;@Test
void contextLoads() throws SQLException {// 查看一下默认的数据源: class com.zaxxer.hikari.HikariDataSource System.out.println(dataSource.getClass()); // 获得数据库连接 Connection connection = dataSource.getConnection(); System.out.println(connection); connection.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- ![image-20230801225815471](https://s2.loli.net/2023/08/01/LugJ5n6rqfEY4A7.png)
> HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀
### 9.2.4 源码
- `DataSourceAutoConfiguration`
- ```java
@Import(
{Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class}
)
protected static class PooledDataSourceConfiguration {
protected PooledDataSourceConfiguration() {
}
}
9.3 JDBCTemplate
- 即使不使用第三方第数据库操作框架,如 MyBatis等,Spring 本身也对原生的JDBC 做了轻量级的封装,即JdbcTemplate。数据库操作的所有 CRUD 方法都在 JdbcTemplate 中
- Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中, 注入即可使用
- JdbcTemplate 的自动配置是依赖
org.springframework.boot.autoconfigure.jdbc
包下的JdbcTemplateConfiguration
类
9.3.1 主要方法
execute
方法:可以用于执行任何SQL语句,一般用于执行DDL语句;update
方法及batchUpdate
方法:update方法用于执行新增、修改、删除等语句;batchUpdate
方法用于执行批处理相关语句;query
方法及queryForXXX
方法:用于执行查询相关语句;call
方法:用于执行存储过程、函数相关语句。
9.3.2 测试
1 |
|
9.3.3 指定数据源
spring.datasource.type
SpringBoot默认支持以下数据源:
com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 以上,默认使用此数据源)
org.apache.tomcat.jdbc.pool.DataSource
org.apache.commons.dbcp2.BasicDataSource
10. 整合Druid
10.1 简介
- Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控;
- Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
- Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源
- Github: https://github.com/alibaba/druid/
10.2 starter配置
apache中已经出了一套完美支持SpringBoot的方案
- 引入依赖
1 | <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter --> |
- 配置
1 | spring: |
- 配置StatViewServlet -> 监控信息展示html页面
1 | spring: |
- 配置监控
1 | spring: |
10.3 基本配置
com.alibaba.druid.pool.DruidDataSource
基本配置参数
配置 | 缺省值 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-“ + System.identityHashCode(this). 另外配置此属性至少在1.0.5版本中是不起作用的,强行设置name会出错 详情-点此处。 | |
url | 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilter | |
driverClassName | 根据url自动识别 | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 | |
validationQueryTimeout | 单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 1分钟(1.0.14) | 有两个含义: 1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | 30分钟(1.0.14) | 连接保持空闲而不被驱逐的最长时间 |
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall | |
proxyFilters | 类型是List |
10.4 配置连接池
- 添加pom依赖
1 | <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> |
- 切换数据源
1 | spring: |
测试:
```java
@Autowired
DataSource dataSource;@Test
void contextLoads() throws SQLException {// 查看一下默认的数据源: class com.zaxxer.hikari.HikariDataSource System.out.println(dataSource.getClass());
}
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
- ![image-20230802220355487](https://s2.loli.net/2023/08/02/BJFyPhiZYab8svM.png)
3. Druid配置
```yaml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
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依赖
1 | <dependency> |
- 绑定自定义全局配置参数,添加DruidDataSource组件
1 | // DruidConfig.java |
10.5 配置Druid数据源监控
Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。
- 设置 Druid 的后台管理页面,比如 登录账号、密码 等;配置后台管理;
1 | // DruidConfig.java |
- 使用sql后查看
- 配置
Druid
监控filter
过滤器
1 | //配置 Druid 监控 之 web 监控的 filter |
11. 整合MyBatis
11.1 导入依赖
1 | <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> |
11.2 测试数据库连接信息
1 |
|
11.3 创建实体类
1 |
|
11.4 配置Mapper接口类
1 | //@Mapper : 表示本类是一个 MyBatis 的 Mapper,等价于以前 Spring 整合 MyBatis 时的 Mapper 接口 |
或者在启动文件中添加
MapperScan
注释
11.5 Mapp映射文件
1 |
|
11.6 maven配置资源过滤
1 | <resources> |
11.7 配置整合
1 | mybatis: |
11.8 Controller
1 |
|
- 测试结果:
12. SpringSecurity
18.1 简介
在 Web 开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,因而需要更多的开发时间,影响应用的发布进程。因此,从应用开发的第一天就应该把安全相关的因素考虑进来,并在整个应用的开发过程中。
- 比较主流的安全框架:Shiro,Spring Security
- Spring Security
- Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它实际上是保护基于spring的应用程序的标准
- 侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求
Web安全性
- 用户认证(Authentication)
- 验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统
- 要求用户提供用户名和密码
- 用户授权(Authorization)
- 验证某个用户是否有权限执行某个操作
- 系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限
- 用户认证(Authentication)
SpringSecurity
- 用户认证:Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等
- 用户授权:提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制
18.2 基本使用
18.2.1 认识SpringSecurity
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
三个基本类
WebSecurityConfigurerAdapter
:自定义Security策略AuthenticationManagerBuilder
:自定义认证策略@EnableWebSecurity
:开启WebSecurity模式
“认证”(Authentication)
- 身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
- 身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
- “授权” (Authorization)
- 授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
18.2.2 基本使用
- 编写SpringSecurity配置类
参考官网:Spring Security
1 | // SerurityConfig.java |
- 认证规则
1 | //定义认证规则 |
18.2.3 权限控制和注销
- 开启自动配置的注销的功能
1 | //定制请求的授权规则 |
- 修改注销后的跳转页面
1 | // .logoutSuccessUrl("/"); 注销成功来到首页 |
18.2.4 权限控制与前端显示结合
- hymeleaf-security整合包
1 | <dependency> |
- 导入命名空间
1 | xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" |
- 导航栏增加认证判断
1 | <!--登录注销--> |
根据是否登录显示:1)登录按钮;2)用户名和角色
- 测试结果:
- 请求改为post表单提交
1 | http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求 |
- 根据角色显示模块
1 | <div class="ui three column stackable grid"> |
- 测试结果:
18.2.5 记住用户名/密码
1 | //定制请求的授权规则 |
- remember 创建了对应的cookie
- 测试结果:
18.2.6 定制登录页
- 登录页面配置指定
loginpage
1 | // SecutityConfig.java |
- 前端页面指向自定义 login 请求
1 | <a class="item" th:href="@{/toLogin}"> |
- 自定义页面登录信息的发送
1 | <!--如果要使用toLogin,则http.formLogin().loginPage("/toLogin");配置一致。 |
- 接收用户名、密码并指定登录表单提交请求
1 | // SecurityConfig.java |
Remember Me
多选框
1 | <input type="checkbox" name="remember"> 记住我 |
- 后端验证处理
1 | http.rememberMe().rememberMeParameter("remember"); |
18.3 Controller配置
1 |
|
13. Shiro
13.1 Shiro简介
13.1.1 概述
- Apache Shiro 是 Java 的一个安全(权限)框架。
- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。
- Shiro 可以完成:认证、授权、加密、会话管理、与Web 集成、缓存等。
- 官网:Apache Shiro
- Github:https://github.com/apache/shiro
13.1.2 功能描述
- Authentication: 身份认证/登录,验证用户是不是拥有相应的身份
- Authorization: 授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限
- Session Management: 会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web 环境的
- Cryptography: 加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
- Web Support: Web 支持,可以非常容易的集成到Web 环境
- Caching: 缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率
- Concurrency: Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去
- Testing: 提供测试支持
- “Run As”: 允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
- Remember Me: 记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
13.1.3 Shiro框架-外部
从外部看Shiro,即从应用程序角度来观察如何使用Shiro完成工作
- Subject:应用代码直接交互的对象是Subject,也就是说Shiro的对外API 核心就是Subject。Subject 代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;与Subject 的所有交互都会委托给SecurityManager;Subject 其实是一个门面,SecurityManager才是实际的执行者
- SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且其管理着所有Subject;可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherServlet的角色
- Realm:Shiro从Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm 看成DataSource
13.1.4 Shiro-内部
- Subject:任何可以与应用交互的“用户”;
- SecurityManager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证、授权、会话及缓存的管理。
- Authenticator:负责Subject 认证,是一个扩展点,可以自定义实现;可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
- Authorizer:授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
- Realm:可以有1 个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要实现自己的Realm;
- SessionManager:管理Session 生命周期的组件;而Shiro并不仅仅可以用在Web 环境,也可以用在如普通的JavaSE环境
- CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能
- Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密。
13.2 简单使用
- 参照官网进行配置:shiro/samples/quickstart
1 | // Quickstart.java |
主要操作:
1
2
3
4
5
6
7
8// 获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
currentUser.isAuthenticated()
currentUser.getPrincipal()
currentUser.hasRole("schwartz")
currentUser.isPermitted("lightsaber:wield")
currentUser.logout();
13.3 SpringBoot继承Shiro
13.3.1 编写导入配置类
- 导入依赖
1 | <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-starter --> |
- 自定义
UserRealm
1 | // 自定义的 UserRealm |
- 编写配置
ShiroConfig
- 创建
realm
对象,需要自定义类 DefaultWebSecurityManager
ShiroFilterFactoryBean
-> 需要命名为shiroFilterFactoryBean
- 创建
1 |
|
13.3.2 登录拦截
getShiroFilterFactoryBean
方法中添加指定配置- anon: 无需认证就可以访问
- authc: 必须认证了才能访问
- user: 必须拥有记住我功能才能用
- perms: 拥有对某个资源的权限才能访问
- role: 拥有某个角色权限
1 | /** |
此时
add
或update
页面无授权已无法访问
添加拦截成功界面
登录页面
login.html
getShiroFilterFactoryBean
设置登录请求1
2
3// 设置登录的请求
bean.setLoginUrl("/toLogin");
return bean;
测试结果:
13.3.3 用户认证
- 处理表单 - controller
1 |
|
UserRealm
认证 -doGetAuthenticationInfo
- 用户名验证错误抛出
null
,对应UnknownAccountException
- 密码验证是自动进行,返回给上一级即可
- 用户名验证错误抛出
1 | // 认证 |
13.4 Shiro整合Mybatis
13.4.1 基本流程
- 导入对应依赖
1 | <!-- 此阶段用的依赖 --> |
application.yml
1 | spring: |
pojo.User + mapper.UserMapper + service.UserService
:warning: 创建
mapper.xml
时模板位置需要修改namespace
1
<mapper namespace="com.bayyy.mapper.UserMapper">
UserRealm
->doGetAuthenticationInfo()
连接数据库进行认证
1 | // 认证 |
13.4.2 加密认证
默认是
SimpleCredentialsMatcher
加密认证MD5 加密
- MD5 盐值加密 -> 在普通MD 5加密基础上加入一些其他值,避免被简单的暴力尝试破解
13.5 用户授权
ShiroConfig
中getShiroFilterFactoryBean()
1 | //授权,正常情况下,没有授权会跳转到为授权页面 |
- 仅对
add
进行授权的添加,测试结果:
添加授权页面
controller
1
2
3
4
5
public String unauthorized() {
return "未经授权! 无法访问此页面!";
}ShiroConfig
中getShiroFilterFactoryBean()
1
2// 设置未授权的请求
bean.setUnauthorizedUrl("/unauthorized");测试结果:
给用户授权
实际中用户权限位于数据库中
doGetAuthenticationInfo
-> 认证(也就是登录时)doGetAuthorizationInfo
-> 授权(访问权限资源,我们可以在认证时放入用户、密码和realmName),授权时就可以获取
1 | // 授权 |
- 测试结果:
13.6 logout
- controller
1 |
|
- 测试结果:
13.7 Shiro整合Thymeleaf
- 整合包依赖
1 | <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro --> |
ShiroConfig
中添加整合ShiroDialect
类
1 | // 整合 ShiroDialect:用来整合 Shiro 和 thymeleaf |
- 前端修改
1 |
|
- 测试结果:
14. Swagger
- 官网:Swagger
14.1 Swagger简介
- 前后端分离
- 前端 -> 前端控制层、视图层
- 后端 -> 后端控制层、服务层、数据访问层
- 前后端通过API进行交互
- 前后端相对独立且松耦合
前后端分离,无法及时沟通 —> 定义schema[计划的提纲],并实时跟踪最新的API,降低集成风险
Swagger
- 号称世界上最流行的API框架
- Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新
- 直接运行,在线测试API
- 支持多种语言 (如:Java,PHP等)
14.2 SpringBoot集成Swagger
14.2.1 项目创建
- 引入依赖
1 | <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> |
:key: 3.0.0 之后需要额外的依赖
1
2
3
4
5 <dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
- 另外需要额外的配置
1
2
3
4 spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
- 基本测试
SwaggerConfig
配置
1 | // SwaggerConfig.java |
- 访问测试
:key: Swagger3.0 后访问地址变为:Swagger UI
14.2.2 配置Swagger
- Swagger实例Bean是
Docket
,所以通过配置Docket
实例来配置Swaggger
1 | // SwaggerConfig.java |
- 通过
apiInfo()
属性配置文档信息
1 | // 配置Swagger的apiInfo |
Docket
实例关联apiInfo()
1 | // 配置Swagger2的Docket的bean实例 |
- 结果结果:
14.3 配置扫描接口
14.3.1 select() 配置扫描
- 构建Docket时通过select()方法配置怎么扫描接口
14.3.2 apis() 扫描类型
apis()
指定扫描的类型any()
扫描全部none()
不扫描withClassAnnotation()
扫描类上的注解,参数是一个注解的反射对象withMethodAnnotation()
扫描方法上的注解basePackage()
扫描指定包
链式编程
1 | // 配置Swagger2的Docket的bean实例 |
- 测试结果:
14.3.3 paths() 扫描过滤
- 配置接口扫描过滤
ant()
过滤指定路径any()
过滤全部none()
不过滤regex()
正则表达式
1 | // 配置Swagger2的Docket的bean实例 |
- 测试结果:
14.4 配置Swagger开关
14.4.1 基本开关配置
enable()
1 | // 配置Swagger2的Docket的bean实例 |
- 测试结果:
14.4.2 配置特定开发环境开关
1 | // 配置Swagger2的Docket的bean实例 |
- 测试结果:
14.5 配置API分组
14.5.1 基本分组
没有配置分组,默认是default
groupName()
配置分组
1 | // 配置Swagger2的Docket的bean实例 |
- 测试结果:
14.5.2 多组存在
- 配置多个
Docket()
即可
1 | ... |
- 测试结果:
14.6 实体配置
:key: 只要出现在接口方法的返回值上的实体都会显示
- 创建实体类
1 |
|
- 将实体类作为请求接口的返回值 (泛型),都能映射到实体项中
1 |
|
- 测试结果:
:warning: 并不是因为@ApiModel这个注解让实体显示在这里了,而是只要出现在接口方法的返回值上的实体都会显示在这里,而@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的
14.7 常用注释
:pushpin: Swagger的所有注解定义在
io.swagger.annotations
包下
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “xxx模块说明”) | 作用在模块类上 |
@ApiOperation(“xxx接口说明”) | 作用在接口方法上 |
@ApiModel(“xxxPOJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “xxx属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“xxx参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty |
- 示例:
1 |
|
:white_check_mark: 正式环境部署前需要关闭Swagger
14.8 Swagger在线测试
14.9 扩展:其他皮肤
默认
1
2
3
4<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>bootstrap-ui
1
2
3
4
5<!-- 引入swagger-bootstrap-ui包 /doc.html-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>Layui-ui
1
2
3
4
5<!-- 引入swagger-ui-layer包 /docs.html-->
<dependency>
<groupId>com.github.caspar-chen</groupId>
<artifactId>swagger-ui-layer</artifactId>
</dependency>mg-ui
1
2
3
4
5<!-- 引入swagger-ui-layer包 /document.html-->
<dependency>
<groupId>com.zyplayer</groupId>
<artifactId>swagger-mg-ui</artifactId>
</dependency>
15. 异步、定时、邮件任务
15.1 异步任务
15.1.1 耗时任务等待问题
- 创建耗时的测试方法
1 | // AsyncService.java |
- AsyncController
1 |
|
- 测试结果:
15.1.2 异步任务
@Async
1 | // 告诉Spring这是一个异步方法 |
EnableAsync
- 需要在主程序上添加一个注解
@EnableAsync
,开启异步注解功能
- 需要在主程序上添加一个注解
1 |
|
- 测试结果:
15.2 定时任务
15.2.1 相关类和注释
异步执行任务调度
- | 接口 | 注释 |
| ———————- | ———————————————— |
|TaskExecutor
|@EnableScheduling
(主程序添加) |
|TaskScheduler
|@Scheduled
|
- | 接口 | 注释 |
15.2.2 cron表达式
| 字段 | 允许值 | 允许的特殊字符 |
| ——————————— | ——————————————————— | ————————————— |
| 秒(Seconds) | 0~59的整数 | , - / 四个字符 |
| 分(Minutes) | 0~59的整数 | , - / 四个字符 |
| 小时(Hours) | 0~23的整数 | , - / 四个字符 |
| 日期(DayofMonth) | 1~31的整数(但是你需要考虑你月的天数) | ,- ? / L W C 八个字符 |
| 月份(Month) | 1~12的整数或者 JAN-DEC | , - / 四个字符 |
| 星期(DayofWeek) | 1~7的整数或者 SUN-SAT (1=SUN) | , - ? / L C # 八个字符 |
| 年(可选,留空)(Year) | 1970~2099 | , - * / 四个字符 || 特殊字符 | 代表含义 |
| ———— | —————————————————————————————— |
| | 任意 可用在所有字段中,表示对应时间域的每一个时刻,例如,在分钟字段时,表示“每分钟” |
| ? | 日/星期冲突匹配 该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符 |
| - | 区间 表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12 |
| , | 枚举 表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五 |
| / | 步长 x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用/y,它等同于0/y |
| L | 最后 该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值 X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五 |
| W | 工作日 该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值 X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五 |
| LW | 在日期字段可以组合使用LW,它的意思是当月的最后一个工作日 |
| C | 和calendr联系后计算过的值 该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天 |
| # | *星期(4#2 - 第2个星期三) 该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发 |
15.2.3 使用
- ScheduledService 添加
@Scheduled
注释
1 |
|
- 主程序添加
@EnableScheduling
注释
1 |
|
- 测试结果:
15.2.4 一些cron表达式
1 | (1)0/2 * * * * ? 表示每2秒 执行任务 |
15.3 邮件任务
15.3.1 基本步骤
- 邮件发送需要引入
spring-boot-start-mail
- SpringBoot 自动配置
MailSenderAutoConfiguration
- 定义
MailProperties
内容,配置在application.yml
中 - 自动装配
JavaMailSender
- 测试邮件发送
15.3.2 发送邮件
1)引入依赖
1 | <dependency> |
其内部为:
1
2
3
4
5
6 <dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>1.6.7</version>
<scope>compile</scope>
</dependency>
自动配置类
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
public class MailProperties {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private String host;
private Integer port;
private String username;
private String password;
private String protocol = "smtp";
private Charset defaultEncoding = DEFAULT_CHARSET;
private Map<String, String> properties = new HashMap<>();
private String jndiName;
}MailSenderJndiConfiguration
2)配置文件
1 | spring: |
3)发送测试
简单邮件
```java
@Autowired
JavaMailSenderImpl mailSender;@Test
void SimpleMail() {// 简单邮件 SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("简单邮件测试"); message.setText("这是一封简单邮件"); message.setTo("111@qq.com"); message.setFrom("111@qq.com"); mailSender.send(message);
}
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
-
- ![image-20230806001621865](https://s2.loli.net/2023/08/06/RgDvohyz8amMCYX.png)
- 复杂邮件
- ```java
@Test
void ComplexMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("复杂邮件测试");
// 第二个参数为true表示开启HTML
helper.setText("<p style='color:red'>这是一封复杂邮件</p>", true);
// attachmentFilename 表示附件名
// File("文件路径") 表示附件路径
// static目录下的文件可以直接访问
helper.addAttachment("warning.jpg", new File("file_path"));
helper.setTo("111@qq.com");
helper.setFrom("111@qq.com");
mailSender.send(mimeMessage);
}
16. 分布式Dubbo和Zookeeper
Dubbo:Apache Dubbo
Zookeeper:Apache ZooKeeper
16.1 分布式系统
分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统
- 分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统
- 分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务
- 其目的是利用更多的机器,处理更多的数据。
分布式系统(distributed system)
- 建立在网络之上的软件系统
:key: 只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,才需要考虑分布式系统
16.2 Dubbo文档
16.2.1 单一应用架构 ORM
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键
- 适用于小型网站,小型管理系统,将所有功能都部署到一个功能里,简单易用。
- 缺点:
- 性能扩展比较难
- 协同开发问题
- 不利于升级维护
16.2.2 垂直应用架构 MVC
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键
- 通过切分业务来实现各个模块独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性。
- 缺点:公用模块无法重复利用,开发性的浪费
16.2.3 分布式服务架构 RPC
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键
- RPC(Remote Procedure Call)- 远程过程调用
- 一种进程间通信方式,是一种技术的思想,而不是规范
- 允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同
- RPC就是要像调用本地的函数一样去调远程函数
- 核心:通讯,序列化
- RPC基本原理
- 步骤解析
16.2.4 流动计算架构 SOA
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)[ Service Oriented Architecture]是关键。
16.3 Dubbo简介
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现
16.3.1 Dubbo基本概念
- 服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
- 监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
16.3.2 调用关系说明
- 服务容器负责启动,加载,运行服务提供者
- 服务提供者在启动时,向注册中心注册自己提供的服
- 服务消费者在启动时,向注册中心订阅自己所需的服务
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
16.3.3 环境搭建 -> Zookeeper
ZooKeeper是一个集中式服务,用于维护配置信息、命名、提供分布式同步、提供组服务。所有这些类型的服务都以某种形式由分布式应用程序使用。每次实施它们时,都需要进行大量工作来修复不可避免的错误和竞争条件。由于实现此类服务很困难,应用程序最初通常会忽略它们,这使得它们在发生变化时变得脆弱并且难以管理。即使正确完成,这些服务的不同实现也会导致部署应用程序时的管理复杂
运行:/bin/zkServer.cmd
没有
zoo.cfg
配置文件会闪退
修改
zoo.cfg
配置文件- 最新版本需要添加
audit.enable=true
- 最新版本需要添加
重要位置
dataDir=./
临时数据存储的目录(可写相对路径)clientPort=2181
zookeeper的端口号
再次启动,使用
/bin/zkCli.cmd
进行测试
16.3.4 基本使用
- 打开 Server端和Client端
ls /
列出zookeeper根下保存的所有节点create –e /bayyy 123
创建一个bayyy节点,值为123get /bayyy
获取bayyy节点的值
16.3.5 安装dubbo-admin
dubbo本身并不是一个服务软件。它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务
但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用
- Github:apache/dubbo-admin at master-0.2.0 (github.com)
修改配置
- 修改
dubbo-admin\src\main\resources \application.properties
指定zookeeper地址- 如果 Zookeeper 未做修改则无需修改
- 修改
项目目录下打包dubbo-admin
mvn clean package -Dmaven.test.skip=true
执行
dubbo-admin\target
下的dubbo-admin-0.0.1-SNAPSHOT.jar
- 此时 Zookeeper服务需要打开
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
- 运行会报错
- 添加
--add-opens java.base/java.lang=ALL-UNNAMED
- 由于 JDK 8 中有关反射相关的功能自从 JDK 9 开始就已经被限制了,为了兼容原先的版本,需要在运行项目时添加
--add-opens java.base/java.lang=ALL-UNNAMED
选项来开启这种默认不被允许的行为
- 由于 JDK 8 中有关反射相关的功能自从 JDK 9 开始就已经被限制了,为了兼容原先的版本,需要在运行项目时添加
java -jar --add-opens java.base/java.lang=ALL-UNNAMED dubbo-admin-0.0.1-SNAPSHOT.jar
-
- 默认用户名/密码 均为 root
16.4 SpringBoot+Dubbo+Zookeeper
16.4.1 项目搭建
创建两个模块分别为
- provider-server
- consumer-server
provider
- ```java
public class TicketServiceImpl implements TicketService{
}@Override public String getTicket() { return "《厉害了,我的国》"; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- consumer
### 16.4.2 服务提供者
1. 导入依赖
```xml
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
- ```java
新版本需要解决日志冲突,以及提出日志依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!-- 引入zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<!--排除这个slf4j-log4j12-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>springboot配置dubbo相关属性
1
2
3
4
5
6#当前应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描指定包下服务
dubbo.scan.base-packages=com.bayyy.provider.serviceservice的实现类中配置服务注解,发布服务
导包要是
org.apache.dubbo.config.annotation.Service
1
2
3
4
5
6
7
8
9
10
11import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
// 放在容器中,不要用原来的Service,因为会和dubbo的Service重名,容易误操
// 将服务发布
public class TicketServiceImpl implements TicketService{
public String getTicket() {
return "《厉害了,我的国》";
}
}
16.4.3 服务消费者
导入依赖(同上)
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<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- 引入zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<!--排除这个slf4j-log4j12-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>配置参数 - 表明从何处哪服务,以及自己的身份
1
2
3
4# 当前应用名字
dubbo.application.name=consumer-server
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181运行发现需要在启动类上增加
@EnableDubbo
注解启动
Dubbo
+Zookeeper
+SpringBoot-provider
将服务接口复制,需要保证路径正确,即与服务提供者相同
服务者消费类
@Reference
此处可以使用正常SpringBoot的
@Service
注解进行容器注册1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
//注入到容器中
public class UserService {
//远程引用指定的服务,他会按照全类名进行匹配,看谁给注册中心注册了这个全类名
TicketService ticketService;
public void buyTicket() {
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到了" + ticket);
}
}测试
1
2
3
4
5
6
7
UserService userService;
void contextLoads() {
userService.buyTicket();
}
- 测试结果:
- dubbo-admin