Yunjiao Spring Boot v0.4.0 参考手册
Yunjiao Spring Boot v0.4.0 参考手册
版本:0.4.0
日期:2025-09-04
作者:杨运交
框架概述
本框架集成第三开源工具,开发Spring Boot Starter风格的包,方便引入及使用
主要目标:
- 只集成工具,适当的扩展工具,使其更容易与Spring Boot集成
- 每个Starter功能单一,或者只专注某一方面,如:ID生成器,验证码生成器等等
- 积累知识,技术,经验
源码仓库
Gitee: https://gitee.com/yunjiao-source/yunjiao-spring-boot
Github: https://github.com/yunjiao-source/yunjiao-spring-boot
注意,Gitee是主库,发布时会同步到Github
主要依赖及版本对应
- JDK: 17.0.12
- Spring Boot 3.0.13
| 本框架版本 | Spring Boot 版本 |
|---|---|
| <= 0.4.0 | 3.0.13 |
如何使用
有两个方法引入本框架,分别是继承starter-parent项目和导入dependencies项目。第一个方法更方便;第二个方法更有灵活性。
如果是示例或小型系统(单一项目),推荐使用第一种方法。大型系统(多项目)就使用第二种方法
继承starter-parent项目
starter-parent继承了spring-boot-starter-parent项目,在此基础上扩展功能,如:导入本框架,添加插件等等
在项目pom.xml中添加:
<parent>
<groupId>io.gitee.yunjiao-source.spring-boot</groupId>
<artifactId>starter-parent</artifactId>
<version>LAST_VERSION</version>
</parent>
starter-parent的版本与Spring Boot的版本的对应关系请查看主要依赖及版本对应
导入dependencies项目
dependencies项目包含本框架的所有包,在项目中导入即可
在项目pom.xml中添加:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.gitee.yunjiao-source.spring-boot</groupId>
<artifactId>dependencies</artifactId>
<version>LAST_VERSION</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
编译源码
源码目录中包含多个独立项目,需要分别编译,打包
因为是独立的项目,IDE中只能自动导入主项目,其他项目需要手工导入
目录结构
| 项目名 | 目录及说明 |
|---|---|
| Spring Boot | autoconfigure(自动配置包), dependencies(所有的依赖包), extensions(扩展包), starters(启动器包) |
| Spring Boot :: Starter Parent | starter-parent, 此项目集成Spring Boot的spring-boot-starter-parent项目 |
| Spring Boot :: Examples | examples, 示例项目 |
| Spring Boot :: Projects | projects, 示例应用 |
编译打包
首先编译打包主项目
# cd yunjiao-spring-boot
# mvn clean install
其次打包starter-parent
# cd starter-parent
# mvn clean install
其他的项目,编译,打包方法是一样的
ID扩展
ID生成是企业信息系统需要的,重要的,必须的功能。目前使用雪花算法生成ID是最流行的,本框架集成Hutool,uid-generator等框架,
这些框架实现了雪花算法。
uid-generator框架(官网)是百度开源的,此框架没有发布到Maven中心仓库,所以
在pom中无法引入。本框架引入的是uid-core包(官网)
雪花算法需要一个中心化服务分配机器ID,在不同的应用中实现统一的ID(不重复),但这并不常见,实现也很复杂。一般情况下,比如在用户应用与订单应用,
用户表的ID与订单表的ID是可以重复的。
在微服务场景中,需要在多台服务器上部署相同的应用,如用户应用,必须保证每个用户应用新增用户的ID是不重复的。
根据以上分析,可以把每台服务当做中心化服务,分配机器ID。只需要在系统定义环境变量,雪花ID算法工具获取环境变量,就可以保证相同的应用统一的ID(不重复),
这个思路我称为有限的分布式ID。本框架实现了有限的分布式ID,支持在系统中定义环境变量SNOWFLAKE_WORKER_ID和SNOWFLAKE_DATACENTER_ID。
如果需要真正的分布式ID,推荐
uid-generator-starter(官网),它支持中心化服务,如
数据库,redis,zk等
雪花ID算法
是一个在分布式系统中广泛使用的全局唯一ID生成算法,由Twitter公司提出,旨在解决在分布式环境下高并发、高性能地生成唯一ID的问题
优点
- 全局唯一:通过时间戳+机器ID+序列号的组合,在分布式系统下几乎不可能重复。
- 趋势递增:由于时间戳在最前面,生成的ID整体上是随时间递增的。这对于数据库索引(如MySQL的B+Tree)非常友好,插入性能高。
- 高性能:本地生成,无需远程调用数据库或Redis等中间件,速度极快(每毫秒每台机器可生成4096个ID)。
- 无需中心化服务:不像UUID需要中心化的发号器,避免了单点故障和性能瓶颈。(但分配机器ID可能需要一个中心化服务)。
- 信息隐含:ID本身包含时间戳和机器ID信息,在排查问题时可以根据ID反推出生成时间和生成机器。
(信息来源:DeepSeek)
示例
Gitee: examples/example-id
如何使用
在pom.xml文件中添加
<dependency>
<groupId>io.gitee.yunjiao-source.spring-boot</groupId>
<artifactId>starter-id</artifactId>
</dependency>
配置指南
在application.yml中配置参数
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.id.uid-generator.time-bits | 28 | |
| spring.id.uid-generator.worker-bits | 22 | |
| spring.id.uid-generator.seq-bits | 13 | |
| spring.id.uid-generator.epoch-str | 2025-08-20 |
开发指南
在服务中注入
@Slf4j
@Component
public class IdCommandLineRunner implements CommandLineRunner {
@Autowired
private Snowflake snowflake;
@Autowired
private UidGeneratorCached uidGeneratorCached;
@Autowired
private UidGeneratorDefault uidGeneratorDefault;
@Override
public void run(String... args) throws Exception {
TimeUnit.SECONDS.sleep(3);
log.info("Snowflake = {}", generator(() -> snowflake.nextId()).size());
log.info("uidGeneratorCached = {}", generator(() -> uidGeneratorCached.getUID()).size() );
log.info("uidGeneratorDefault = {}", generator(() -> uidGeneratorDefault.getUID()).size() );
}
private Set<Long> generator(Supplier<Long> supplier) {
return IntStream.range(0, 4000).mapToObj(i -> supplier.get())
.peek(l -> System.out.print(l + ","))
.collect(Collectors.toSet());
}
}
在使用中,日志中会出现警告信息
WARN --- [ main] y.s.e.i.u.EnvironmentWorkerIdAssigner : Uid-Generator 框架雪花算法配置使用默认参数。如需支持分布式,请设置系统环境变量:'yunjiao.springboot.extension.id.snowflakeWorkId'
WARN --- [ main] y.s.a.id.HutoolIdConfiguration : Hutool 框架雪花算法配置使用默认参数。如需支持分布式,请设置系统环境变量:'yunjiao.springboot.extension.id.snowflakeWorkId' 与 'yunjiao.springboot.extension.id.snowflakeDatacenterId'
如果不是微服务或集群部署应用,可以忽略此警告
本框架提供的雪花ID工具,没有必要都使用,使用其中的一种就可以满足大部分场景
使用CachedUidGeneratorConfigurer自定义配置
@Slf4j
@Configuration
public class IdConfiguration {
@Bean
CachedUidGeneratorConfigurer CachedUidGeneratorConfigurer() {
return generator -> {
log.info("自定义配置");
generator.setBoostPower(3);
generator.setPaddingFactor(50);
generator.setScheduleInterval(60);
};
}
}
Captcha(验证码)扩展
Captcha(验证码)是很常见的需求,广泛应用在登录,下载等功能中。本框架集成Hutool,aj-captcha等开源验证码工具,提供多种验证码,如:线段干扰验证码,
圆圈干扰验证码,扭曲干扰验证码,GIF验证码,滑块拼图验证码,文字点选验证码,旋转拼图验证码等等
本框架验证码服务只有生成,校验功能。不涉及验证码缓存及失效
示例
Gitee: examples/example-captcha
如何使用
在pom.xml文件中添加
<dependency>
<groupId>io.gitee.yunjiao-source.spring-boot</groupId>
<artifactId>starter-captcha</artifactId>
</dependency>
配置指南
在application.yml中配置参数
线段干扰验证码(line)配置
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.captcha.hutool.line.width | 250 | 图片的宽度 |
| spring.captcha.hutool.line.height | 50 | 图片的高度 |
| spring.captcha.hutool.line.interfereCount | 60 | 验证码干扰元素个数 |
| spring.captcha.hutool.line.backgroundColor | ColorType.white | 背景色 |
| spring.captcha.hutool.line.transparency | null | 文字透明度,取值0~1,1表示不透明 |
| spring.captcha.hutool.line.fuzziness | 2 | 模糊度(0 - 30) |
| spring.captcha.hutool.line.validIgnoreCase | true | 校验时忽略大小写 |
| spring.captcha.hutool.line.font.name | null | 字体名称,为空表示使用系统默认字体 |
| spring.captcha.hutool.line.font.style | FontStyle.plain | 字体风格 |
| spring.captcha.hutool.line.font.size | 36 | 字体大小 |
| spring.captcha.hutool.line.code.generator | CodeGeneratorType.numAndChar | 码生成类型 |
| spring.captcha.hutool.line.code.length | 5 | 字符长度 |
圆圈干扰验证码(circle)配置
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.captcha.hutool.circle.width | 250 | 图片的宽度 |
| spring.captcha.hutool.circle.height | 50 | 图片的高度 |
| spring.captcha.hutool.circle.interfereCount | 30 | 验证码干扰元素个数 |
| spring.captcha.hutool.circle.backgroundColor | ColorType.white | 背景色 |
| spring.captcha.hutool.circle.transparency | null | 文字透明度,取值0~1,1表示不透明 |
| spring.captcha.hutool.circle.fuzziness | 2 | 模糊度(0 - 30) |
| spring.captcha.hutool.circle.validIgnoreCase | true | 校验时忽略大小写 |
| spring.captcha.hutool.circle.font.name | null | 字体名称,为空表示使用系统默认字体 |
| spring.captcha.hutool.circle.font.style | FontStyle.plain | 字体风格 |
| spring.captcha.hutool.circle.font.size | 36 | 字体大小 |
| spring.captcha.hutool.circle.code.generator | CodeGeneratorType.numAndChar | 码生成类型 |
| spring.captcha.hutool.circle.code.length | 5 | 字符长度 |
扭曲干扰验证码(shear)配置
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.captcha.hutool.shear.width | 250 | 图片的宽度 |
| spring.captcha.hutool.shear.height | 50 | 图片的高度 |
| spring.captcha.hutool.shear.interfereCount | 10 | 干扰线宽度 |
| spring.captcha.hutool.shear.backgroundColor | ColorType.white | 背景色 |
| spring.captcha.hutool.shear.transparency | null | 文字透明度,取值0~1,1表示不透明 |
| spring.captcha.hutool.shear.fuzziness | 2 | 模糊度(0 - 30) |
| spring.captcha.hutool.shear.validIgnoreCase | true | 校验时忽略大小写 |
| spring.captcha.hutool.shear.font.name | null | 字体名称,为空表示使用系统默认字体 |
| spring.captcha.hutool.shear.font.style | FontStyle.plain | 字体风格 |
| spring.captcha.hutool.shear.font.size | 36 | 字体大小 |
| spring.captcha.hutool.shear.code.generator | CodeGeneratorType.numAndChar | 码生成类型 |
| spring.captcha.hutool.shear.code.length | 5 | 字符长度 |
Gif验证码(gif)配置
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.captcha.hutool.gif.width | 250 | 图片的宽度 |
| spring.captcha.hutool.gif.height | 50 | 图片的高度 |
| spring.captcha.hutool.gif.interfereCount | 10 | 干扰线宽度 |
| spring.captcha.hutool.gif.backgroundColor | ColorType.white | 背景色 |
| spring.captcha.hutool.gif.transparency | null | 文字透明度,取值0~1,1表示不透明 |
| spring.captcha.hutool.gif.fuzziness | 2 | 模糊度(0 - 30) |
| spring.captcha.hutool.gif.validIgnoreCase | true | 校验时忽略大小写 |
| spring.captcha.hutool.gif.font.name | null | 字体名称,为空表示使用系统默认字体 |
| spring.captcha.hutool.gif.font.style | FontStyle.plain | 字体风格 |
| spring.captcha.hutool.gif.font.size | 36 | 字体大小 |
| spring.captcha.hutool.gif.code.generator | CodeGeneratorType.numAndChar | 码生成类型 |
| spring.captcha.hutool.gif.code.length | 5 | 字符长度 |
| spring.captcha.hutool.gif.quality | 10 | 量化器取样间隔,1~20值之间-默认是10ms |
| spring.captcha.hutool.gif.repeat | 0 | 帧循环次数,默认是0,意味着无限循环 |
| spring.captcha.hutool.gif.min-color | 0 | 设置随机颜色时,最小的取色范围 |
| spring.captcha.hutool.gif.max-color | 255 | 设置随机颜色时,最大的取色范围 |
滑块拼图验证码(blockPuzzle)及文字点选验证码(clickWord)配置
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| spring.captcha.anji.water-mark | 我的水印 | 右下角水印文字 |
| spring.captcha.anji.water-font | WenQuanZhengHei.ttf | 右下角水印字体 |
| spring.captcha.anji.block-puzzle.jigsaw | 滑动拼图底图路径 | |
| spring.captcha.anji.block-puzzle.slip-offset | 5 | 校验滑动拼图允许误差偏移量 |
| spring.captcha.anji.block-puzzle.interference-options | 0 | 滑块干扰项 |
| spring.captcha.anji.click-word.pic-click | 点选文字底图路径 | |
| spring.captcha.anji.click-word.font-type | WenQuanZhengHei.ttf | 点选文字验证码的文字字体 |
| spring.captcha.anji.click-word.font-style | FontStyle.bold | 点选字体样式 |
| spring.captcha.anji.click-word.font-size | 25 | 点选字体大小 |
| spring.captcha.anji.click-word.click-word-count | 4 | 点选文字个数 |
| spring.captcha.anji.click-word.slip-offset | 13 | 校验拼图允许误差(默认13像素) |
开发指南
使用验证码服务工厂(CaptchaServiceFactory),可以很方便获取验证码服务
@Slf4j
@Component
public class CaptchaCommandLineRunner implements CommandLineRunner {
@Autowired
private CaptchaServiceFactory factory;
@Override
public void run(String... args) throws Exception {
CaptchaService circleService = factory.findService(CaptchaCategory.circle);
CaptchaData data = circleService.draw();
log.info(GsonUtils.toJson(data));
saveImage(data);
CaptchaService lineService = factory.findService(CaptchaCategory.line);
data = lineService.draw();
saveImage(data);
CaptchaService gifService = factory.findService(CaptchaCategory.gif);
data = gifService.draw();
saveImage(data);
CaptchaService shearService = factory.findService(CaptchaCategory.shear);
data = shearService.draw();
saveImage(data);
CaptchaService blockPuzzleService = factory.findService(CaptchaCategory.blockPuzzle);
data = blockPuzzleService.draw();
saveImage(data);
CaptchaService clickWordService = factory.findService(CaptchaCategory.clickWord);
data = clickWordService.draw();
saveImage(data);
}
private void saveImage(CaptchaData data) throws IOException {
Path targetDir = Paths.get("target", "processed-images");
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
Path filePath = targetDir.resolve(data.category().name() + "-captcha." + data.category().getExt());
Files.write(filePath, data.captchaImage());
if (data.backgroundImage() != null) {
filePath = targetDir.resolve(data.category().name() + "-background." + data.category().getExt());
Files.write(filePath, data.backgroundImage());
}
}
}
所有的验证码服务生成的验证码信息是统一的,使用更加方便
验证码信息(json)格式
{"key":"5e1bf15c178b4ea3a6d0599ba8fb3743","captchaImage":[-119,80,78,71,13,10,....],"backgroundImage":null,"code":"z8yOk","category":"circle"}
验证码信息属性说明
| 属性 | 说明 |
|---|---|
| key | String类型,验证码ID,生成的每个验证码都有唯一的ID |
| captchaImage | byte[]类型,验证码图片。 |
| backgroundImage | byte[]类型,验证码背景图片。分类是blockPuzzle才有值 |
| code | String类型,校验码, |
| category | 枚举类型,分类 |
如果需要Base64类型的图片信息,可以调用
CaptchaData.captchaImageBase64Url或CaptchaData.backgroundImageBase64Url方法
使用验证码缓存工厂(CaptchaCacheFactory)存储验证码信息,支持Hutool框架的TimedCache缓存和Guava框架的LoadingCache缓存,可以自由
选择缓存,而且可以自定义配置
@Slf4j
@Configuration
public class CaptchaConfiguration {
@PostConstruct
void postConstruct() {
// 设置过期时间
CaptchaCacheFactory.initHtoolCache(Duration.ofSeconds(30));
}
}
验证码缓存工厂(CaptchaCacheFactory)功能与验证码服务工厂(CaptchaServiceFactory)功能没有关联
写一个简单的验证码生成及校验接口
@RestController
@RequiredArgsConstructor
public class CaptchaController {
private final CaptchaServiceFactory factory;
private final CaptchaCache cache = CaptchaCacheFactory.getInstance();
@GetMapping("/captcha")
public CaptchaReponse get(@RequestParam(name = "category") CaptchaCategory category) {
CaptchaService service = factory.findService(category);
CaptchaData data = service.draw();
CaptchaReponse reponse = new CaptchaReponse();
reponse.setKey(data.key());
reponse.setCategory(service.getCategory());
reponse.setCaptchaImageBase64(data.captchaImageBase64Url());
reponse.setBackgroundImageBase64(data.backgroundImageBase64Url());
cache.put(data.key(), data.code());
System.out.println("code=" + data.code());
return reponse;
}
@PostMapping("/captcha")
public String post(@RequestBody CaptchaValidate validate) {
String cacheCode = cache.get(validate.getKey()).orElse(null);
if (!StringUtils.hasText(cacheCode)) {
return "验证码校验失败";
}
CaptchaService service = factory.findService(validate.getCategory());
boolean pass = service.verify(cacheCode, validate.getCode());
if (pass) {
return "验证码校验成功";
} else {
return "验证码校验失败";
}
}
}
获取验证码请求
curl --location --request GET 'http://localhost:8080/captcha?category=line' \
--header 'Accept: */*' \
--header 'Host: localhost:8080' \
--header 'Connection: keep-alive'
校验验证码请求
curl --location --request POST 'http://localhost:8080/captcha' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'Host: localhost:8080' \
--header 'Connection: keep-alive' \
--data-raw '{
"key": "e3d15841b93543f88e2404fc93cd8edb",
"category": "line",
"code": "1kNk9"
}'
注意编写生成验证码接口时,不要将校验码(CaptchaData.code属性)返回给前端
最后更新:2025-08-31 10:42:29 +0800
浙公网安备 33010602011771号