[TOC]
# base-spring-boot-starter
base-spring-boot-starter 提供了平台通用的模型和工具类,作为公司二方包提供基础组件。
## 功能
* 加密解密算法
* 公用model类
* 通用工具类
* 通用事件驱动模型
* 通用异常类
* 通用异常通知
* 通用线程池配置
* 通用下载水印
* 统一异常处理
## maven 配置
![](https://img.kancloud.cn/b1/ea/b1ea062dcb04a42bc192475723ef2ca5_2534x1153.png)
## 公用model类
用户 角色 菜单 公共模型,提供权限模型的基础工具类。映射数据库中的三张表sys_user,sys_role,
sys_menu
![](https://img.kancloud.cn/f5/50/f5502c27f878ce17996383d715ff5a55_1102x984.png)
## 通用工具类
通过各种通用配置,通用工具类简化开发
### 菜单树
![](https://img.kancloud.cn/1a/a0/1aa0d217a93ed115881168de94f3aa69_2490x1054.png)
### 获取用户信息
* 获取用户信息工具类1
![](https://img.kancloud.cn/df/6d/df6df7f5c3442b5a66c46db38e644bb3_2548x1176.png)
* 获取用户信息工具类2
```
com.open.capacity.uaa.common.util.AuthUtils.getLoginAppUser()
```
### 通用分页对象
![](https://img.kancloud.cn/65/cf/65cf7d828d61144c973c2830e666f362_2527x1212.png)
### BeanValidator参数校验
![](https://img.kancloud.cn/f3/3c/f33c4da9d88ada0885426206e654b1b6_1355x1132.png)
### 父子线程异步传递问题
![](https://img.kancloud.cn/b7/66/b7668cdb5891a8fea1edbe678e1a5910_2429x1000.png)
### Optional工具类
```
Optional.of(1).ifPresent(o ->{
System.out.println(o);
});
System.out.println(Optional.ofNullable(2).orElseGet( ()-> 1));
```
### EntityUtils
```
List<Long> userIds = EntityUtils.toList(list, SysUser::getId) ;
EntityUtils.toSet(roles, SysRole::getCode);
Map<Long, SysMenu> roleMenusMap = EntityUtils.toMap(roleMenus, SysMenu::getId);
```
### json通用配置
![](https://img.kancloud.cn/b1/3e/b13ea340361cfd142723a871c883a139_2512x1101.png)
### spring 安全防火墙配置
![](https://img.kancloud.cn/a9/42/a942a2a29de9e17b062e6a5ca1f6e034_2509x1132.png)
### 白名单配置
![](https://img.kancloud.cn/4f/21/4f2129dfc88717d199b02faa9c85e586_2085x1212.png)
### spring自定义密码处理器
![](https://img.kancloud.cn/5c/db/5cdbaee8bae7d01fa6f047cab59eeae7_2531x506.png)
### google 二维码
![](https://img.kancloud.cn/50/c2/50c22644b513226fe8364d5922f9e213_2560x984.png)
~~~
@Override
@SneakyThrows
public BufferedImage createQrCode(String deviceId, String secret) {
String codeUrl = GoogleOTPAuthUtil.generateTotpURI(deviceId, secret);
//生成二维码配置
Map<EncodeHintType,Object> hints = new HashMap<>();
//设置纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.L);
//编码类型
hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl,BarcodeFormat.QR_CODE,200,200,hints);
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig();
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
return bufferedImage;
}
~~~
### 白名单配置类
![](https://img.kancloud.cn/d4/84/d484be4aaf4d44e9aa67be8053a0f485_2222x1004.png)
### 接口级自动加密工具
![](https://img.kancloud.cn/a2/a3/a2a370782cd7efd92a81c428028792f8_2498x1191.png)
### javers审计比较对象不同
```
import org.javers.core.Changes;
import org.javers.core.Javers;
import org.javers.core.JaversBuilder;
import org.javers.core.diff.Change;
import org.javers.core.diff.Diff;
import org.javers.core.diff.changetype.NewObject;
import org.javers.core.diff.changetype.ObjectRemoved;
import org.javers.core.diff.changetype.ValueChange;
import lombok.Data;
public class ObjectComparator {
public static void main(String[] args) {
// 创建Javers实例
Javers javers = JaversBuilder.javers().build();
// 创建要比较的对象
Person person1 = new Person("John", 30);
Person person2 = new Person("John", 35,"1");
// 使用Javers比较两个对象
Diff diff = javers.compare(person1, person2);
// 输出ValueChange类型的变化
Changes changes = diff.getChanges();
for (Change change : changes) {
if ((change instanceof NewObject)) {
System.out.println("新增改动: " + change);
// change.getAffectedObject().ifPresent(System.out::println);
System.out.println("新增");
}
if ((change instanceof ObjectRemoved)) {
System.out.println("删除改动: " + change);
// change.getAffectedObject().ifPresent(System.out::println);
}
if ((change instanceof ValueChange)) {
System.out.println("修改改动: " + change);
// change.getAffectedObject().ifPresent(System.out::println);
}
}
}
}
@Data
class Person {
private String name;
private int age;
private String id ;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age,String id ) {
this.name = name;
this.age = age;
this.id=id ;
}
}
```
### hutool 工具类
文档:[https://www.hutool.cn/docs/#/](https://www.hutool.cn/docs/#/)
#### 类型转化
~~~
int a = 1 ;
String aString = Convert.toStr(a) ;//整型转String
System.out.println(aString);
long[] b = {1L,2L,3L,4L,5L} ;
String bString = Convert.toStr(b) ;//long数组 转String数组
System.out.println(bString);
String[] c = {"1","2","3","4","5"};
Integer[] cArray = Convert.toIntArray(c) ;// String数组转int数组
System.out.println(cArray);
String dateString ="2018-05-22 14:09:33" ;
Date date = Convert.toDate(dateString) ;//时间转化
System.out.println(date);
String quanjiao ="1234567" ;
String banjiao =Convert.toSBC(quanjiao) ;//半角转化
System.out.println(banjiao);
System.out.println(Convert.toDBC(banjiao)) ;//全角转化
String str = "明文字符串" ;
String encodeString = Convert.toHex(str,CharsetUtil.CHARSET_UTF_8) ;//加密
System.out.println(encodeString);
String decodeString = Convert.hexToStr(encodeString, CharsetUtil.CHARSET_UTF_8) ;
//解密
System.out.println(decodeString);
String unicode = Convert.strToUnicode(str) ;
System.out.println(unicode);
String raw = Convert.unicodeToStr(unicode);
System.out.println(raw);
String result = Convert.convertCharset(str, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1) ;//字符集转化
System.out.println(result);
String iso = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, CharsetUtil.UTF_8) ; //字符集转化
System.out.println(iso);
long date = 72 ;
long day = Convert.convertTime(date, TimeUnit.HOURS, TimeUnit.DAYS);//时间转化72小时3天
System.out.println(day);
double price = 6449.89;
System.out.println(Convert.digitToChinese(price)) ;//金钱转化
~~~
#### 时间
~~~
Date date = DateUtil.date();
String format = DateUtil.format(date, "yyyy-MM-dd") ;
System.out.println(format);
Date beginOfDate = DateUtil.beginOfDay(date) ;
Date endOfDate = DateUtil.endOfDay(date) ;
System.out.println(beginOfDate);
System.out.println(endOfDate);
date = DateUtil.date(System.currentTimeMillis());
String now = DateUtil.now(); //yyyy-MM-dd HH:mm:ss
String tody = DateUtil.today();//yyyy-MM-dd
DateUtil.yesterday();
DateUtil.tomorrow();
DateUtil.lastWeek();
DateUtil.lastMonth();
int age = DateUtil.ageOfNow("1998-04-04" ) ;
System.out.println(age);
~~~
#### excel
~~~
List<?> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd", DateUtil.date(), 3.22676575765);
List<?> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1", DateUtil.date(), 250.7676);
List<?> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2", DateUtil.date(), 0.111);
List<?> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3", DateUtil.date(), 35);
List<?> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4", DateUtil.date(), 28.00);
List<List<?>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);
BigExcelWriter writer= ExcelUtil.getBigWriter("e:"+File.separator+"xxx.xlsx");
// 一次性写出内容,使用默认样式
writer.write(rows);
// 关闭writer,释放内存
writer.close();
ExcelReader reader = ExcelUtil.getReader("e:"+File.separator+"xxx.xlsx");
List<Map<String,Object>> readAll = reader.readAll();
readAll.forEach( item -> {
System.out.println(item);
});
~~~
## 通用事件驱动模型
Disruptor是一个高性能的并发框架,专门用于改善事件驱动的系统。它可以在不使用锁的情况下实现高并发,并能够提供一些非常高效的内存读写操作,这使得它在处理高并发的情况下能够获得很高的性能。基于此创建的双event事件模型可以简化开发disruptor的难度,更快速的使用事件驱动解耦项目。
![](https://img.kancloud.cn/b4/e1/b4e1e376cb1f0d939ff28e8c03fc67bd_1707x691.png)
通过请求异步化带来其他明显优点:
* 可以处理更高并发连接数,提高系统整体吞吐量
* 请求解析与业务处理完全分离,职责单一
* 自定义业务线程池,我们可以更容易对其监控,降级等处理
* 可以根据不同业务,自定义不同线程池,相互隔离,不用互相影响
### 类图关系
![](https://img.kancloud.cn/be/28/be28bf933555792dc08171951efb7505_1665x849.png)
### 自动装配
![](https://img.kancloud.cn/62/dd/62dd56a14eef17d2e538816a2ff1f8c0_2502x1055.png)
## 通用异常
平台提供通用异常定义,后续可扩展
![](https://img.kancloud.cn/21/e2/21e2f3c61b9df7384dd66b8a88bd079d_2267x1042.png)
## 通用异常通知
平台异常主动通知依赖alertmanager组件,根据eventbus方式异常通知配置化。
![](https://img.kancloud.cn/11/28/1128c78d6428b311d132bd6cfd22f172_1323x574.png)
异常通知alertmanager与企业微信对接
![](https://img.kancloud.cn/bc/0a/bc0a32b4aa309b917c2670200e113beb_950x416.png)
## 通用线程池配置
![](https://img.kancloud.cn/7d/c9/7dc959b4371a918a5e99ab5ec1dca3b6_2528x933.png)
## 通用水印
利用poi等组件对word,excel,ppt加水印
![](https://img.kancloud.cn/b8/55/b855501bc0862f3830474bdbf88a5db1_2502x983.png)
代码详解
![](https://img.kancloud.cn/65/ff/65ffee199fc0640e654ac7a001c9586e_1403x629.png)
示例代码
```
public static void main(String[] args) throws FileNotFoundException {
{
String file = "D:\\file\\自主升级部分功能.docx" ;
FileInputStream is = new FileInputStream(file);
String waterMark = "管理员,2020-10-10";
WatermarkParam param = WatermarkParam.builder().file(file).inputStream(is).useImage(true).text(waterMark)
.fontSize(20).degree(345F).alpha(0.4f).bespread(Boolean.TRUE).color(Color.GRAY).build();
WatermarkUtils.addWatermark(param, new File("D:\\file\\自主升级部分功能1.docx"));
IoUtil.close(is);
}
}
```
下载水印效果
![](https://img.kancloud.cn/cf/4c/cf4cb71f338bdf2beca0329107356797_2075x1088.png)
## 统一异常
### springboot异常
![](https://img.kancloud.cn/5c/71/5c717a1928e3084338694385a4029845_1320x585.png)
![](https://img.kancloud.cn/e0/61/e061d0591cc123b438f3d2d274783834_2484x1226.png)
### feign异常
![](https://img.kancloud.cn/d5/65/d565f521349c133db80bdd5c3ceafb8d_2484x1189.png)
## 混沌工程
混沌工程是一种可试验的、基于系统的方法来处理大规模分布式系统中的混乱问题。通过不断试验,了解系统的实际能承受的韧性边界并建立信心,通过不同的试验方法和目的,观察分布式系统的行为和反应。一句话——**以试验的方法尽早揭露系统弱点**。
混沌工程类似于“故障演练”,不局限于测试,而更像是工程实践。混沌试验类似于”探索性测试“,试验本身没有明确是输入和预期结果,通过对系统和服务的干预,来观察系统的”反应“。我们将混沌工程原则融入在试验过程中:在生产环境小规模模拟系统故障并定期自动化执行试验,通过试验结果与正常结果进行比对,观察系统”边界“。
### 如何引入混沌工程?
在众多服务化改造案例中,Netflix无疑是最成功的公司之一,该公司的很多试验工具也都集成在Spring Cloud中,成为微服务框架的标准。而Chaos Monkey就是Netflix进行混沌试验一个重要工具。
Spring Cloud是时下最流行的分布式微服务架构下的一站式解决方案之一,它方便快速的将Spring Boot的微服务有效的管理起来,并提供了包括负载均衡、全链路监控、服务网关以及众多基于Netflix的开源工具。除此之外,鉴于Netflix在服务化演进中的成功案例,我们来了解下Netflix开源的混沌工程试验框架Chaos Monkey究竟是什么?
### [Chaos Monkey for Spring Boot文档](https://codecentric.github.io/chaos-monkey-spring-boot/)
chaos-monkey-spring-boot是专门为Spring Boot打造的Chaos Monkey,
![](https://img.kancloud.cn/e1/d8/e1d8427ee67d707afab3bea7998053d5_1114x487.png)
maven位置
![](https://img.kancloud.cn/49/07/49073ef49d5be684215c73db840de8c8_2332x844.png)
### 加配置
![](https://img.kancloud.cn/ab/46/ab4695eadaf994954928dca9b068966e_2470x1071.png)
从配置文件中我们可以很容易看到,Chaos Monkey的三种袭击方式——延时、异常和进程终止,同时我们也可以设置一个数值范围,在对服务进行延时攻击时生成随机延时。默认攻击方式为延时攻击,当同时开启异常攻击时,进程攻击则不会发生。Level:N表示第N个请求将被攻击,N=1时,表示每个请求都会被攻击,当同时开启异常攻击时,与N值无关,表示每个请求都将被攻击。
### 总结
chaos-monkey-spring-boot非常适合用来进行故障演练,暴露服务间调用的问题,好提升系统的健壮性、故障自动恢复能力等。
- 01.前言
- 02.快速开始
- 01.maven构建项目
- 02.安装mysql数据库
- 03.安装redis缓存中间件
- 04.快速启动框架
- 03.总体流程
- 01.架构设计图
- 02.oauth接口
- 03.功能介绍
- 04.部署细节
- 04.模块详解
- 01.基础介绍
- 02.自定义db-spring-boot-starter
- 03.自定义log-spring-boot-starter
- 04.自定义redis-spring-boot-starter
- 05.自定义base-spring-boot-starter
- 06.自定义common-spring-boot-starter
- 07.自定义loadbalancer-spring-boot-starter
- 08.自定义swagger-spring-boot-starter
- 09.自定义uaa-client-spring-boot-starter
- 10.自定义uaa-server-spring-boot-starter
- 11.自定义oss-spring-boot-starter
- 12.自定义sentinel-spring-boot-starter
- 05.服务详解
- 01.nacos-server
- 02.auth-server
- 03.user-center
- 04.new-api-gateway
- 05.file-center
- 06.log-center
- 07.back-center
- 08.auth-sso模块
- 09.admin-server
- 10.job-center
- 06.系统安全
- 01.非法字符漏洞攻击
- 02.防重放攻击
- 03.代码审计
- 04.Xray扫洞
- 05.混沌工程质量保证
- 07.生产部署K8S
- 01.基本环境安装
- 02.基本组件安装
- 03.集群验证
- 04.安装Metrics Server
- 05.安装容器平台
- 06.Ingress网关
- 07.metalb负载均衡器
- 08.容器平台集群
- 08.K8S资源练习
- 01.Deployment
- 02.StatefulSet
- 03.DaemonSet
- 04.redis集群服务
- 05.elasticsearch集群
- 06.rocketmq部署
- 09.生产容器化部署
- 01.nacos集群部署
- 02.user-center服务
- 03.auth-server服务
- 04.new-api-gateway服务
- 技术交流