mirror of
https://github.com/RemainderTime/spring-boot-base-demo.git
synced 2026-06-09 19:47:50 +08:00
Merge remote-tracking branch 'origin/master' into feature/admin-auth-satoken
# Conflicts: # pom.xml # src/main/java/cn/xf/basedemo/controller/business/UserController.java # src/main/java/cn/xf/basedemo/service/impl/UserServiceImpl.java
This commit is contained in:
171
README.md
171
README.md
@@ -1,65 +1,136 @@
|
|||||||
## 拿来即用springboot基础脚手架
|
# XF-Boot-Base (Spring Boot Base Demo)
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="https://img.shields.io/badge/Spring_Boot-3.3.3-6DB33F?style=for-the-badge&logo=spring-boot&logoColor=white" alt="Spring Boot"/>
|
||||||
|
<img src="https://img.shields.io/badge/Java-17%2B-ED8B00?style=for-the-badge&logo=openjdk&logoColor=white" alt="Java"/>
|
||||||
|
<img src="https://img.shields.io/badge/Nacos-2.x-00C7D5?style=for-the-badge&logo=AlibabaCloud&logoColor=white" alt="Nacos"/>
|
||||||
|
<img src="https://img.shields.io/badge/MyBatis_Plus-3.5.8-00599C?style=for-the-badge&logo=Spring&logoColor=white" alt="MyBatis Plus"/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
[](https://github.com/RemainderTime/spring-boot-base-demo)
|
||||||
|
[](./LICENSE)
|
||||||
|
|
||||||
---
|
---
|
||||||
### 项目介绍
|
|
||||||
|
|
||||||
[](https://blog.csdn.net/qq_39818325?type=blog)
|
### 「 为企业级开发而生的高效脚手架 」
|
||||||
[](https://github.com/RemainderTime/spring-boot-base-demo)
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
---
|
|
||||||
> 这是一个基于 **Spring Boot 3.3.3** 的快速构建单体架构脚手架,旨在帮助开发者快速搭建高效、稳定的项目基础框架。项目集成了多种常用的技术组件与功能,涵盖从用户认证到数据加密、从全局异常处理到搜索引擎操作,适合个人学习与企业级单体应用开发。
|
|
||||||
|
|
||||||
#### 分支
|
<p align="center">
|
||||||
- master 快速上手开发spring boot 用户端单体应用
|
<a href="#-关于项目">💎 关于项目</a> |
|
||||||
- feature/admin-auth-spring-security 基于master分支集成spring官方鉴权框架spring security框架,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制
|
<a href="#-核心亮点">⚡ 核心亮点</a> |
|
||||||
- feature/admin-auth-sa-token 基于master分支集成国产权限框架sa-token,可用于后台管理系统后端项目,实现RBAC模型(角色 → 用户 → 菜单 → 权限)基于角色的访问控制
|
<a href="#-生态全景">🌿 生态全景</a> |
|
||||||
|
<a href="#-快速运行">🚀 快速运行</a> |
|
||||||
|
<a href="#-项目日志">📅 项目日志</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
### 集成技术与功能亮点
|
<br/>
|
||||||
|
|
||||||
- 身份认证与授权(JWT):基于 JWT 实现用户认证与授权,确保系统安全性。
|
## <20> 关于项目
|
||||||
- 数据加密(RSA):提供 RSA 非对称加密支持,保障敏感数据安全。
|
|
||||||
- 持久层框架(MyBatis Plus):简化数据库操作,提供高效的 CRUD 支持。
|
|
||||||
- 数据库(MySQL):采用 MySQL 作为默认数据库,易于扩展和维护。
|
|
||||||
- 数据连接池(Hikari):高性能数据源管理,优化数据库连接效率。
|
|
||||||
- 缓存(Redis):支持分布式缓存,提升系统响应速度与并发能力。
|
|
||||||
- 接口文档(springdoc-openapi):自动生成标准化 API 文档,便于调试与集成。
|
|
||||||
- 模板引擎(Thymeleaf):支持动态页面渲染,提升前后端协同效率。
|
|
||||||
- 容器化支持(Docker):内置 Dockerfile,轻松实现环境部署与迁移。
|
|
||||||
- 搜索引擎(Elasticsearch 8.x):集成最新版本 Elasticsearch Java 客户端,提供高效的全文检索与复杂查询功能。
|
|
||||||
- 全局异常处理:统一管理异常,提升代码可维护性与调试效率。
|
|
||||||
- 拦截器支持:轻松实现请求拦截与权限控制。
|
|
||||||
|
|
||||||
### 项目优势
|
**XF-Boot-Base** 并非仅仅是一个简单的 "Hello World" 示例,而是一个经过精心打磨、具备生产级标准的 **Spring Boot 3.3** 全栈开发底座。
|
||||||
**全面适配 Spring Boot 3.x**
|
|
||||||
- 所有组件已全面升级为支持 Spring Boot 3.x 的最新版本。解决了开发者在版本升级中遇到的各种不兼容和适配问题,大大减少了升级带来的额外工作量,让项目开发更加顺畅。
|
|
||||||
|
|
||||||
**初学者友好**
|
我们深入分析了企业单体应用到微服务架构演进过程中的痛点,构建了一套**模块化、可插拔、高扩展**的基础框架。从底层的 **JDK 17** 优化,到顶层的 API 接口规范;从**JWT 安全认证**的丝滑接入,到 **Docker 容器化**的一键部署。XF-Boot-Base 旨在消除重复造轮子的时间成本,让开发者能够专注于核心业务逻辑的实现。
|
||||||
- 提供清晰的代码结构与详细的配置说明,帮助初学者快速上手微服务与单体架构的开发实践。
|
|
||||||
|
|
||||||
**高扩展性**
|
无论你是想要快速验证想法的独立开发者,还是寻找稳健基石的架构师,这里都有你需要的最佳实践。
|
||||||
- 丰富的功能集成,涵盖了开发中常见的场景,减少重复开发工作量,同时为定制化需求预留了扩展空间。
|
|
||||||
|
|
||||||
**稀缺的最新技术操作示例**
|
|
||||||
- 最新版本的 Elasticsearch 8.x 集成、Java 客户端操作示例和现代化 API 设计,让开发者能够轻松掌握分布式搜索引擎的使用。
|
|
||||||
|
|
||||||
### 版本更新 2024-10-12
|
|
||||||
|
|
||||||
---
|
---
|
||||||
1. springboot版本升级3.x
|
|
||||||
2. mybatis plus版本升级3.x
|
## ⚡ 核心亮点
|
||||||
3. dynamic mybatis plus版本升级3.x
|
|
||||||
4. redis版本升级3.x以及配置优化
|
<div align="center">
|
||||||
5. 替换swagger依赖支持spring boot3.x (knife4j->springdoc-openapi)
|
|
||||||
6. 新增请求头工具类
|
| 🚀 **前沿技术** | 🔐 **安全无忧** | 🐳 **云原生友好** |
|
||||||
7. 参数校验异常捕获优化
|
| :--- | :--- | :--- |
|
||||||
8. 登录拦截器注册为spring容器管理
|
| 紧跟 **Spring Boot 3.x** 生态,<br>基于 **Java 17 LTS** 构建,<br>享受最新技术红利。 | 深度整合 **JWT** 令牌认证<br>& **RSA** 非对称加密,<br>为数据安全保驾护航。 | 内置 **Dockerfile** 脚本,<br>支持 **Docker Compose** 编排,<br>部署快人一步。 |
|
||||||
9. 新增本地日志配置文件
|
|
||||||
|
| 💾 **数据增强** | 🔌 **微服务预装** | 🛠 **极致体验** |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **MyBatis Plus** 强力驱动,<br>**Dynamic Datasource**<br>轻松驾驭多数据源场景。 | 原生集成 **Nacos**,<br>配置中心与注册中心开箱即用,<br>平滑过渡微服务。 | **SpringDoc (OpenAPI 3)**<br>自动生成精美文档,<br>调试开发得心应手。 |
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
如果这个项目对你有帮助,请随手点个 Star ⭐ 支持一下吧!🎉✨ 你的支持是我持续优化的动力!❤️
|
|
||||||
|
## 🌿 生态全景
|
||||||
|
|
||||||
|
我们采用 **"核心 + 插件化"** 的分支管理策略,以 `master` 为稳定基石,通过不同分支满足多样化的业务需求。
|
||||||
|
|
||||||
|
| 🌳 分支标识 | 🎯 定位 | 📝 功能描述 | 🏭 最佳应用场景 |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **`master`** | **核心底座** | 标准化脚手架,含 JWT/Nacos/Redis | 🚀 快速启动标准单体项目 |
|
||||||
|
| `feature/admin-auth-spring-security` | **安全堡垒** | Spring Security 官方方案 (RBAC) | 🏦 金融级、政府级后台系统 |
|
||||||
|
| `feature/admin-auth-sa-token` | **敏捷权限** | Sa-Token 轻量级权限控制 | ⚡ 中小型项目、国内快速开发 |
|
||||||
|
| `component/rocketmq-and-es` | **高并发** | RocketMQ 5.x + Elasticsearch 8.x | 📈 海量日志、搜索、高吞吐业务 |
|
||||||
|
| `feature/master-payment` | **商业变现** | 支付宝沙盒支付 (H5/App) | 💳 电商、会员订阅、SaaS 平台 |
|
||||||
|
|
||||||
|
> **💡 提示**: 所有分支均基于 `master` 演进,可根据项目规模灵活 `git merge` 所需功能模块。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 快速运行
|
||||||
|
|
||||||
|
### 🛠️ 环境依赖
|
||||||
|
* **JDK**: 17 +
|
||||||
|
* **Maven**: 3.8 +
|
||||||
|
* **MySQL**: 8.0 +
|
||||||
|
* **Redis**: 5.0 +
|
||||||
|
* **Nacos**: 2.x (可选)
|
||||||
|
|
||||||
|
### 🏃♂️ 启动步骤
|
||||||
|
|
||||||
|
> **Step 1: 获取源码**
|
||||||
|
> ```bash
|
||||||
|
> git clone https://github.com/RemainderTime/spring-boot-base-demo.git
|
||||||
|
> cd spring-boot-base-demo
|
||||||
|
> ```
|
||||||
|
|
||||||
|
> **Step 2: 数据准备**
|
||||||
|
> * 创建数据库 `xf_boot_base`
|
||||||
|
> * 修改 `src/main/resources/application.yml` 配好你的数据库账号密码
|
||||||
|
> * *(注:实体类完善,表结构建议通过 JPA 或手动创建)*
|
||||||
|
|
||||||
|
> **Step 3: 启动服务**
|
||||||
|
>
|
||||||
|
> **方式 A: 本地 Maven 运行**
|
||||||
|
> ```bash
|
||||||
|
> mvn spring-boot:run
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> **方式 B: Docker Compose 一键编排**
|
||||||
|
> ```bash
|
||||||
|
> cd src/main/resources/docker
|
||||||
|
> docker-compose -f boot-docker-compose.yml up -d
|
||||||
|
> ```
|
||||||
|
|
||||||
|
> **Step 4: 探索接口**
|
||||||
|
> 打开浏览器访问: `http://localhost:8080/doc.html`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 项目日志
|
||||||
|
|
||||||
|
### v1.0.1 (2024-10-12)
|
||||||
|
* ⬆️ **内核升级**: Spring Boot 3.3.3 & MyBatis Plus 3.5.8
|
||||||
|
* 📝 **文档重构**: 全面拥抱 SpringDoc OpenAPI,弃用旧版 Swagger
|
||||||
|
* 🛡️ **安全加固**: 优化全局异常拦截与参数校验机制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 关注趋势
|
||||||
|
|
||||||
|
[](https://star-history.com/#RemainderTime/spring-boot-base-demo&Date)
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
**喜欢这个项目?请点个 Star ⭐ 支持作者持续更新!**
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
30
pom.xml
30
pom.xml
@@ -14,7 +14,7 @@
|
|||||||
<name>xf-boot-base</name>
|
<name>xf-boot-base</name>
|
||||||
<description>拿来即用springboot单体脚手架项目</description>
|
<description>拿来即用springboot单体脚手架项目</description>
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<java.version>17</java.version>
|
||||||
<mysql.version>8.1.0</mysql.version>
|
<mysql.version>8.1.0</mysql.version>
|
||||||
<mybatis-plus.version>3.5.8</mybatis-plus.version>
|
<mybatis-plus.version>3.5.8</mybatis-plus.version>
|
||||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
<logstash.version>5.3</logstash.version>
|
<logstash.version>5.3</logstash.version>
|
||||||
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
|
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
|
||||||
<spring-cloud.version>2023.0.1</spring-cloud.version>
|
<spring-cloud.version>2023.0.1</spring-cloud.version>
|
||||||
<elasticsearch.version>8.16.0</elasticsearch.version>
|
|
||||||
<sverlet.version>4.0.1</sverlet.version>
|
<sverlet.version>4.0.1</sverlet.version>
|
||||||
<sa-token.version>1.44.0</sa-token.version>
|
<sa-token.version>1.44.0</sa-token.version>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -48,6 +47,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
@@ -123,18 +126,6 @@
|
|||||||
<version>${sverlet.version}</version> <!-- 根据需要选择合适的版本 -->
|
<version>${sverlet.version}</version> <!-- 根据需要选择合适的版本 -->
|
||||||
<scope>provided</scope> <!-- 在Web服务器环境中由服务器提供 -->
|
<scope>provided</scope> <!-- 在Web服务器环境中由服务器提供 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- elasticsearch8.x 搜索引擎 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>co.elastic.clients</groupId>
|
|
||||||
<artifactId>elasticsearch-java</artifactId>
|
|
||||||
<version>${elasticsearch.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.dev33</groupId>
|
|
||||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
|
||||||
<version>${sa-token.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -154,10 +145,17 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>14</source>
|
<release>17</release>
|
||||||
<target>14</target>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-compiler-javac</artifactId>
|
||||||
|
<version>2.15.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package cn.xf.basedemo.common.exception;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 全局异常处理类 (使用 @RestControllerAdvice 替代旧版
|
||||||
|
* HandlerExceptionResolver)
|
||||||
|
* @Author: xiongfeng
|
||||||
|
* @Date: 2025/1/9
|
||||||
|
* @Version: 2.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理登录/认证异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(LoginException.class)
|
||||||
|
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||||
|
public GenericResponse<Void> handleLoginException(LoginException e, HttpServletRequest request) {
|
||||||
|
log.warn("认证失败 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage());
|
||||||
|
return new GenericResponse<>(e.getCode(), null, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理业务逻辑异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BusinessException.class)
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST) // 或者使用 HttpStatus.OK,根据前端约定
|
||||||
|
public GenericResponse<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
|
||||||
|
log.warn("业务异常 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage());
|
||||||
|
return new GenericResponse<>(e.getCode(), null, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理参数校验异常 (处理 @Valid / @Validated 触发的异常)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
public GenericResponse<Void> handleValidationException(Exception e, HttpServletRequest request) {
|
||||||
|
BindingResult bindingResult = null;
|
||||||
|
if (e instanceof MethodArgumentNotValidException) {
|
||||||
|
bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
|
||||||
|
} else if (e instanceof BindException) {
|
||||||
|
bindingResult = ((BindException) e).getBindingResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
String errorMsg = "参数校验失败";
|
||||||
|
if (bindingResult != null && bindingResult.hasErrors()) {
|
||||||
|
FieldError fieldError = bindingResult.getFieldError();
|
||||||
|
if (fieldError != null) {
|
||||||
|
errorMsg = fieldError.getDefaultMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warn("参数校验失败 [URL:{}]: {}", request.getRequestURI(), errorMsg);
|
||||||
|
return new GenericResponse<>(ResponseCode.USER_INPUT_ERROR.getCode(), null, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有未知的系统异常 (兜底)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public GenericResponse<Void> handleSystemException(Exception e, HttpServletRequest request) {
|
||||||
|
// 生产级关键点:必须记录异常堆栈,否则无法排查 BUG
|
||||||
|
log.error("系统发生未知异常 [URL:{}]", request.getRequestURI(), e);
|
||||||
|
return new GenericResponse<>(500, null, "系统内部繁忙,请稍后再试");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package cn.xf.basedemo.common.exception;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Description: 全局异常捕获类(所有异常(包括拦截器、Controller、视图))HandlerExceptionResolver更底层
|
|
||||||
* @ClassName: GlobalExceptionResolver
|
|
||||||
* @Author: xiongfeng
|
|
||||||
* @Date: 2025/8/23 23:30
|
|
||||||
* @Version: 1.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class GlobalExceptionResolver implements HandlerExceptionResolver {
|
|
||||||
@Override
|
|
||||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
|
||||||
|
|
||||||
try (PrintWriter writer = response.getWriter()) {
|
|
||||||
if (ex instanceof LoginException) {
|
|
||||||
response.setStatus(HttpStatus.FORBIDDEN.value());
|
|
||||||
LoginException le = (LoginException) ex;
|
|
||||||
writer.write(new ObjectMapper().writeValueAsString(
|
|
||||||
new GenericResponse<>(le.getCode(), null, le.getMessage())
|
|
||||||
));
|
|
||||||
} else if (ex instanceof BusinessException) {
|
|
||||||
BusinessException be = (BusinessException) ex;
|
|
||||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
|
||||||
writer.write(new ObjectMapper().writeValueAsString(
|
|
||||||
new GenericResponse<>(be.getCode(), null, be.getMessage())
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
|
||||||
writer.write(new ObjectMapper().writeValueAsString(
|
|
||||||
new GenericResponse<>(500, null, "系统异常")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (IOException ioEx) {
|
|
||||||
log.error("写响应失败", ioEx);
|
|
||||||
}
|
|
||||||
return new ModelAndView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package cn.xf.basedemo.common.model;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* packageName cn.xf.basedemo.common.model
|
|
||||||
* @author remaindertime
|
|
||||||
* @className EsModel
|
|
||||||
* @date 2024/12/10
|
|
||||||
* @description es基础模型
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class EsBaseModel<T> {
|
|
||||||
|
|
||||||
public EsBaseModel(String indexName, String documentId, T documentModel, Class<T> clazz) {
|
|
||||||
this.indexName = indexName;
|
|
||||||
this.documentId = documentId;
|
|
||||||
this.documentModel = documentModel;
|
|
||||||
this.clazz = clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 索引名称
|
|
||||||
*/
|
|
||||||
private String indexName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文档id
|
|
||||||
*/
|
|
||||||
private String documentId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 映射对象
|
|
||||||
*/
|
|
||||||
private T documentModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 映射对象类对象
|
|
||||||
*/
|
|
||||||
private Class<T> clazz;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package cn.xf.basedemo.common.model;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* packageName cn.xf.basedemo.common.model
|
|
||||||
* @author remaindertime
|
|
||||||
* @className EsSearchModel
|
|
||||||
* @date 2024/12/11
|
|
||||||
* @description es 搜索模型
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class EsSearchModel<T> {
|
|
||||||
|
|
||||||
public EsSearchModel() {
|
|
||||||
// 使用 LinkedHashMap 保持插入顺序
|
|
||||||
this.sort = new LinkedHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 索引名称
|
|
||||||
*/
|
|
||||||
private String indexName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文档类型
|
|
||||||
*/
|
|
||||||
private Class<T> clazz;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 页数
|
|
||||||
*/
|
|
||||||
private Integer pageNum;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每页数量
|
|
||||||
*/
|
|
||||||
private Integer pageSize;
|
|
||||||
/**
|
|
||||||
* 精准查询字段
|
|
||||||
*/
|
|
||||||
private Map<String, Object> termQuery;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模糊查询字段(一般是text类型)
|
|
||||||
*/
|
|
||||||
private Map<String, Object> matchQuery;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序字段规则 ({"age":"desc"})
|
|
||||||
*/
|
|
||||||
private Map<String, String> sort;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分组去重字段(支持的字段类型:keyword、numeric、date 和 boolean )
|
|
||||||
*/
|
|
||||||
private String repeatField;;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分组嵌套查询别名
|
|
||||||
*/
|
|
||||||
private String innerAlias;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分组嵌套查询数量
|
|
||||||
*/
|
|
||||||
private Integer innerSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定需要返回的字段
|
|
||||||
*/
|
|
||||||
private List<String> includes;
|
|
||||||
/**
|
|
||||||
* 指定需要排除的字段
|
|
||||||
*/
|
|
||||||
private List<String> excludes;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,499 +0,0 @@
|
|||||||
package cn.xf.basedemo.common.utils;
|
|
||||||
|
|
||||||
import cn.xf.basedemo.common.model.EsBaseModel;
|
|
||||||
import cn.xf.basedemo.common.model.EsSearchModel;
|
|
||||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
|
||||||
import co.elastic.clients.elasticsearch._types.*;
|
|
||||||
import co.elastic.clients.elasticsearch._types.query_dsl.*;
|
|
||||||
import co.elastic.clients.elasticsearch.core.*;
|
|
||||||
import co.elastic.clients.elasticsearch.core.search.*;
|
|
||||||
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
|
|
||||||
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
|
|
||||||
import co.elastic.clients.json.JsonData;
|
|
||||||
import co.elastic.clients.transport.endpoints.BooleanResponse;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* packageName cn.xf.basedemo.common.utils
|
|
||||||
* @author remaindertime
|
|
||||||
* @className EsUtil
|
|
||||||
* @date 2024/12/10
|
|
||||||
* @description elasticsearch工具类
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class EsUtil {
|
|
||||||
|
|
||||||
public static ElasticsearchClient esClient;
|
|
||||||
|
|
||||||
{
|
|
||||||
esClient = (ElasticsearchClient) ApplicationContextUtils.getBean("elasticsearchClient");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断索引是否存在
|
|
||||||
* @param indexName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean existIndex(String indexName) {
|
|
||||||
try {
|
|
||||||
// 创建 ExistsRequest 请求
|
|
||||||
ExistsRequest request = new ExistsRequest.Builder()
|
|
||||||
.index(indexName)
|
|
||||||
.build();
|
|
||||||
// 发送请求并获取响应
|
|
||||||
BooleanResponse response = esClient.indices().exists(request);
|
|
||||||
// 返回索引是否存在
|
|
||||||
return response.value();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 处理异常
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除索引
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
*/
|
|
||||||
@SneakyThrows
|
|
||||||
public static void delIndex(String indexName) {
|
|
||||||
if (existIndex(indexName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
esClient.indices().delete(d -> d.index(indexName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建索引
|
|
||||||
*
|
|
||||||
* @param indexName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static void createIndex(String indexName) {
|
|
||||||
if (existIndex(indexName)) {
|
|
||||||
throw new RuntimeException("索引已经存在");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
CreateIndexResponse createIndexResponse = esClient.indices().create(c -> c.index(indexName));
|
|
||||||
// 处理响应
|
|
||||||
if (createIndexResponse.acknowledged()) {
|
|
||||||
log.info(" indexed create successfully.");
|
|
||||||
} else {
|
|
||||||
log.info("Failed to create index.");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 捕获异常并打印详细错误信息
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException("创建索引失败,索引名:" + indexName + ",错误信息:" + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增文档
|
|
||||||
* @param esBaseModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean addDocument(EsBaseModel esBaseModel) {
|
|
||||||
try {
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
String jsonString = objectMapper.writeValueAsString(esBaseModel.getDocumentModel());
|
|
||||||
log.info("es新增文档,文档内容:{}", jsonString);
|
|
||||||
// 创建 IndexRequest 实例
|
|
||||||
IndexRequest request = new IndexRequest.Builder()
|
|
||||||
.index(esBaseModel.getIndexName())
|
|
||||||
.id(esBaseModel.getDocumentId()) //指定文档id,不指定会自动生成
|
|
||||||
.document(esBaseModel.getDocumentModel())
|
|
||||||
.opType(OpType.Create) // 只会在文档 ID 不存在时创建文档
|
|
||||||
.build();
|
|
||||||
|
|
||||||
IndexResponse response = esClient.index(request);
|
|
||||||
if ("created".equals(response.result())) {
|
|
||||||
log.info("Document created: " + response.id());
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
log.info("Document already exists or failed to create.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es新增文档失败", e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新文档
|
|
||||||
* @param esBaseModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean updateDocument(EsBaseModel esBaseModel) {
|
|
||||||
try {
|
|
||||||
UpdateRequest updateRequest = new UpdateRequest.Builder<>()
|
|
||||||
.index(esBaseModel.getIndexName())
|
|
||||||
.id(esBaseModel.getDocumentId())
|
|
||||||
.doc(esBaseModel.getDocumentModel()).build();
|
|
||||||
UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz());
|
|
||||||
log.info("Document updated: " + updateResponse.id());
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新文档指定字段(script 脚本)
|
|
||||||
* @param esBaseModel
|
|
||||||
* @param script 脚本内容
|
|
||||||
* @param params 传递参数内容
|
|
||||||
*/
|
|
||||||
public void updateDocumentWithScript(EsBaseModel esBaseModel, String script, Map<String, JsonData> params) {
|
|
||||||
try {
|
|
||||||
UpdateRequest updateRequest = new UpdateRequest.Builder<>()
|
|
||||||
.index(esBaseModel.getIndexName())
|
|
||||||
.id(esBaseModel.getDocumentId())
|
|
||||||
.script(s ->
|
|
||||||
s.source(script)// 脚本内容:.source("ctx._source.age += params.increment")
|
|
||||||
.params(params)) // 传递参数内容:.params("increment",sonData.of(5))
|
|
||||||
.build();
|
|
||||||
UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz());
|
|
||||||
log.info("Document updated: " + updateResponse.id());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据id查询文档
|
|
||||||
* @param esBaseModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static <T> T getDocumentById(EsBaseModel esBaseModel) {
|
|
||||||
try {
|
|
||||||
GetRequest getRequest = new GetRequest.Builder()
|
|
||||||
.index(esBaseModel.getIndexName())
|
|
||||||
.id(esBaseModel.getDocumentId())
|
|
||||||
.build();
|
|
||||||
GetResponse<T> getResponse = esClient.get(getRequest, esBaseModel.getClazz());
|
|
||||||
if (getResponse.found()) {
|
|
||||||
return getResponse.source();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es列表查询失败", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询文档列表
|
|
||||||
* @param searchModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static <T> List<T> getDocumentList(EsSearchModel searchModel) {
|
|
||||||
List<T> eslist = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
SearchResponse<T> search = esClient.search(buildSearchRequest(searchModel), searchModel.getClazz());
|
|
||||||
if (Objects.isNull(search)) {
|
|
||||||
return eslist;
|
|
||||||
}
|
|
||||||
HitsMetadata<T> hits = search.hits();
|
|
||||||
if (Objects.isNull(hits)) {
|
|
||||||
return eslist;
|
|
||||||
}
|
|
||||||
List<Hit<T>> sourceHitList = hits.hits();
|
|
||||||
if (CollectionUtils.isEmpty(sourceHitList)) {
|
|
||||||
return eslist;
|
|
||||||
}
|
|
||||||
sourceHitList.forEach(item -> {
|
|
||||||
// 处理每个命中
|
|
||||||
eslist.add(item.source());
|
|
||||||
});
|
|
||||||
return eslist;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es列表查询失败", e);
|
|
||||||
}
|
|
||||||
return eslist;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询文档数量
|
|
||||||
* @param searchModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static long getDocumentCount(EsSearchModel searchModel) {
|
|
||||||
try {
|
|
||||||
CountRequest.Builder countRequest = new CountRequest.Builder();
|
|
||||||
countRequest.index(searchModel.getIndexName());
|
|
||||||
countRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery()));
|
|
||||||
CountResponse count = esClient.count(countRequest.build());
|
|
||||||
if (Objects.isNull(count)) {
|
|
||||||
log.info("es列表数量查询异常{}", searchModel);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return count.count();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es列表数量查询失败", e);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据id删除文档
|
|
||||||
* @param esBaseModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static Boolean deleteDocumentById(EsBaseModel esBaseModel) {
|
|
||||||
try {
|
|
||||||
DeleteRequest deleteRequest = new DeleteRequest.Builder()
|
|
||||||
.index(esBaseModel.getDocumentId())
|
|
||||||
.id(esBaseModel.getDocumentId())
|
|
||||||
.build();
|
|
||||||
DeleteResponse deleteResponse = esClient.delete(deleteRequest);
|
|
||||||
if ("deleted".equals(deleteResponse.result())) {
|
|
||||||
log.info("Document deleted: " + deleteResponse.id());
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
log.info("Document delete failed: " + deleteResponse.id());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es列表删除失败", e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据条件删除文档
|
|
||||||
* @param searchModel
|
|
||||||
* @return 删除数量
|
|
||||||
*/
|
|
||||||
public static long deleteDocumentByQuery(EsSearchModel searchModel) {
|
|
||||||
try {
|
|
||||||
DeleteByQueryRequest.Builder deleteRequest = new DeleteByQueryRequest.Builder();
|
|
||||||
deleteRequest.index(searchModel.getIndexName());
|
|
||||||
deleteRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery()));
|
|
||||||
deleteRequest.refresh(true); //设置删除操作后是否立即刷新索引,使删除结果立即可见
|
|
||||||
deleteRequest.timeout(new Time.Builder().time("2s").build()); //设置删除操作的超时时间
|
|
||||||
deleteRequest.conflicts(Conflicts.Proceed); //Conflicts.Proceed:在版本冲突时继续删除操作;Conflicts.Abort:在版本冲突时中止删除操作
|
|
||||||
DeleteByQueryResponse dResponse = esClient.deleteByQuery(deleteRequest.build());
|
|
||||||
if (Objects.nonNull(dResponse)) {
|
|
||||||
log.info("es条件删除成功,删除数量:{}", dResponse.deleted());
|
|
||||||
return dResponse.deleted();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("es条件删除数据失败", e);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建搜索请求对象
|
|
||||||
* @param searchModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static SearchRequest buildSearchRequest(EsSearchModel searchModel) {
|
|
||||||
//定义查询对象
|
|
||||||
SearchRequest.Builder searchRequest = new SearchRequest.Builder();
|
|
||||||
//设置索引名称
|
|
||||||
searchRequest.index(searchModel.getIndexName());
|
|
||||||
//分组去重
|
|
||||||
if (StringUtils.isNotBlank(searchModel.getRepeatField())) {
|
|
||||||
searchRequest.collapse(buildCollapse(searchModel));
|
|
||||||
}
|
|
||||||
//设置查询条件
|
|
||||||
searchRequest.query(createBoolQuery(searchModel.getTermQuery(), searchModel.getMatchQuery()));
|
|
||||||
//设置排序规则
|
|
||||||
if (searchModel.getSort() != null) {
|
|
||||||
searchRequest.sort(buildSort(searchModel.getSort()));
|
|
||||||
}
|
|
||||||
//设置分页参数
|
|
||||||
if (searchModel.getPageSize() != null && searchModel.getPageSize() != null) {
|
|
||||||
searchRequest.from(searchModel.getPageSize() * (searchModel.getPageNum() - 1));
|
|
||||||
searchRequest.size(searchModel.getPageSize());
|
|
||||||
}
|
|
||||||
//设置查询字段/排查字段
|
|
||||||
SourceConfig sourceConfig = buildSourceConfig(searchModel.getIncludes(), searchModel.getExcludes());
|
|
||||||
if (Objects.nonNull(sourceConfig)) {
|
|
||||||
searchRequest.source(sourceConfig);
|
|
||||||
}
|
|
||||||
return searchRequest.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建查询条件
|
|
||||||
* @param termQuery
|
|
||||||
* @param matchQuery
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static Query createBoolQuery(Map<String, Object> termQuery, Map<String, Object> matchQuery) {
|
|
||||||
BoolQuery.Builder cQuery = new BoolQuery.Builder();
|
|
||||||
// TermQuery 精准匹配
|
|
||||||
if (termQuery != null) {
|
|
||||||
for (Map.Entry<String, Object> entry : termQuery.entrySet()) {
|
|
||||||
if (Objects.isNull(entry.getValue())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String key = entry.getKey();
|
|
||||||
Object value = entry.getValue();
|
|
||||||
if (value.getClass().isArray()) { //数组查询,使用 TermsQuery
|
|
||||||
Object[] values = (Object[]) entry.getValue();
|
|
||||||
List<FieldValue> objs = Arrays.stream(values)
|
|
||||||
.map(v -> FieldValue.of(v)) // 将每个对象转换为 FieldValue
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
cQuery.must(new TermsQuery.Builder()
|
|
||||||
.field(key)
|
|
||||||
.terms(t -> t.value(objs))
|
|
||||||
.build()
|
|
||||||
._toQuery());
|
|
||||||
} else if (value.toString().contains(" ")) { // 短语查询,使用 MatchPhraseQuery (要严格按照单词顺序字符串中有空格,短信需匹配)
|
|
||||||
cQuery.must(new MatchPhraseQuery.Builder()
|
|
||||||
.field(key)
|
|
||||||
.query(value.toString())
|
|
||||||
.build()
|
|
||||||
._toQuery());
|
|
||||||
} else { // 其他情况,使用 TermQuery 精准匹配
|
|
||||||
cQuery.must(new TermQuery.Builder()
|
|
||||||
.field(key)
|
|
||||||
.value(value.toString())
|
|
||||||
.build()
|
|
||||||
._toQuery());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// MatchQuery 模糊匹配全文检索分词查询
|
|
||||||
if (matchQuery != null) {
|
|
||||||
for (Map.Entry<String, Object> entry : matchQuery.entrySet()) {
|
|
||||||
if (Objects.isNull(entry.getValue())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cQuery.must(new MatchQuery.Builder()
|
|
||||||
.field(entry.getKey())
|
|
||||||
.query(entry.getValue().toString())
|
|
||||||
.build()
|
|
||||||
._toQuery());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cQuery.build()._toQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建时间区间查询
|
|
||||||
* @param startTime 开始时间
|
|
||||||
* @param endTime 结束时间
|
|
||||||
* @param fieldName 时间字段
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static Query createTimeQuery(String startTime, String endTime, String fieldName) {
|
|
||||||
DateRangeQuery dataQuery = new DateRangeQuery.Builder()
|
|
||||||
.field(fieldName)
|
|
||||||
.build();
|
|
||||||
// 时间区间查询
|
|
||||||
dataQuery.of(o -> o.gte(startTime));
|
|
||||||
dataQuery.of(o -> o.lte(endTime));
|
|
||||||
return dataQuery._toRangeQuery()._toQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置查询字段/排查字段
|
|
||||||
* @param includes 需要字段
|
|
||||||
* @param excludes 排除字段
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static SourceConfig buildSourceConfig(List<String> includes, List<String> excludes) {
|
|
||||||
boolean isIncludes = CollectionUtils.isEmpty(includes);
|
|
||||||
boolean isExcludes = CollectionUtils.isEmpty(excludes);
|
|
||||||
//设置查询字段/排查字段
|
|
||||||
if (isIncludes || isExcludes) {
|
|
||||||
SourceFilter.Builder sourceFilter = new SourceFilter.Builder();
|
|
||||||
if (isIncludes)
|
|
||||||
sourceFilter.includes(includes);
|
|
||||||
if (isExcludes)
|
|
||||||
sourceFilter.excludes(excludes);
|
|
||||||
return new SourceConfig.Builder().filter(sourceFilter.build()).build();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建分组去重
|
|
||||||
* @param searchModel
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static FieldCollapse buildCollapse(EsSearchModel searchModel) {
|
|
||||||
FieldCollapse.Builder fieldCollapse = new FieldCollapse.Builder();
|
|
||||||
//设置分组字段
|
|
||||||
fieldCollapse.field(searchModel.getRepeatField());
|
|
||||||
//设置嵌套配置
|
|
||||||
if (StringUtils.isNotBlank(searchModel.getInnerAlias())) {
|
|
||||||
InnerHits.Builder innerHits = new InnerHits.Builder();
|
|
||||||
//设置别名
|
|
||||||
innerHits.name(searchModel.getInnerAlias());
|
|
||||||
//设置查询数量
|
|
||||||
if (searchModel.getInnerSize() != null) {
|
|
||||||
innerHits.size(searchModel.getInnerSize());
|
|
||||||
}
|
|
||||||
fieldCollapse.innerHits(InnerHits.of(i -> i.name(searchModel.getInnerAlias()).size(10)));
|
|
||||||
}
|
|
||||||
return fieldCollapse.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建排序规则
|
|
||||||
* @param sortMap
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static List<SortOptions> buildSort(Map<String, String> sortMap) {
|
|
||||||
if (sortMap == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<SortOptions> sortList = new ArrayList<>();
|
|
||||||
for (Map.Entry<String, String> sort : sortMap.entrySet()) {
|
|
||||||
sortList.add(new SortOptions.Builder().field(f -> f.field(sort.getKey()).order(SortOrder.valueOf(sort.getValue()))).build());
|
|
||||||
}
|
|
||||||
return sortList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 案例:组合多条件查询(关于 must、mustNot、should 条件的使用)
|
|
||||||
*/
|
|
||||||
public Query combinationQueryTest() {
|
|
||||||
//query.must():and 文档必须满足该条件,如果不满足,文档将不匹配。 and
|
|
||||||
//query.should():or 文档可以不满足该条件,但满足该条件时会得分更高;即使不满足,文档也会出现在查询结果中,只是查询结果靠后。
|
|
||||||
|
|
||||||
//场景1:文档必须符合所有 must 条件和 mustNot 条件,同时至少满足一个 should 条件。如果 should 条件都不满足,文档将被排除不查询出来。
|
|
||||||
BoolQuery.Builder query = new BoolQuery.Builder();
|
|
||||||
//数字范围查询
|
|
||||||
NumberRangeQuery.Builder numberQuery = new NumberRangeQuery.Builder();
|
|
||||||
numberQuery.field("age").lte(30.0).build();
|
|
||||||
// 构建查询条件
|
|
||||||
query.must(o -> o.term(t -> t.field("status").value("active"))) // 必须满足的条件
|
|
||||||
.mustNot(o -> o.term(t -> t.field("country").value("China"))) // 不能满足的条件
|
|
||||||
.filter(f -> f.bool(bo -> bo
|
|
||||||
.should(so -> so.range(r -> r.number(numberQuery.build()))) // 至少满足一个 should 条件
|
|
||||||
.should(so -> so.term(t -> t.field("gender").value("male"))) // 至少满足一个 should 条件
|
|
||||||
.minimumShouldMatch("1") // 至少满足一个 should 条件 也可设置百分比 “50%”
|
|
||||||
));
|
|
||||||
//场景2:文档必须符合所有 must 条件和 mustNot 条件,同时至少满足一个 should 条件。如果 should 条件都不满足,不用做额外的过滤(按照should原生特性处理)。
|
|
||||||
query.must(o -> o.bool(bo -> bo
|
|
||||||
.should(so -> so.range(r -> r.number(numberQuery.build()))) // 至少满足一个 should 条件
|
|
||||||
.should(so -> so.term(t -> t.field("gender").value("male"))) // 至少满足一个 should 条件
|
|
||||||
.minimumShouldMatch("1") // 至少满足一个 should 条件
|
|
||||||
))
|
|
||||||
.must(o -> o.term(t -> t.field("status").value("active"))) // 必须满足的条件
|
|
||||||
.mustNot(o -> o.term(t -> t.field("country").value("China"))); // 不能满足的条件
|
|
||||||
|
|
||||||
return query.build()._toQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package cn.xf.basedemo.config;
|
|
||||||
|
|
||||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
|
||||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
|
||||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
|
||||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
|
||||||
import org.apache.http.HttpHost;
|
|
||||||
import org.apache.http.auth.AuthScope;
|
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
|
||||||
import org.apache.http.client.CredentialsProvider;
|
|
||||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
|
||||||
import org.elasticsearch.client.RestClient;
|
|
||||||
import org.elasticsearch.client.RestClientBuilder;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* packageName cn.xf.basedemo.config
|
|
||||||
* @author remaindertime
|
|
||||||
* @className ElasticsearchConfig
|
|
||||||
* @date 2024/12/9
|
|
||||||
* @description es工具类
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class EsConfig {
|
|
||||||
|
|
||||||
@Value("${elasticsearch.host}")
|
|
||||||
private String elasticsearchHost;
|
|
||||||
@Value("${elasticsearch.port}")
|
|
||||||
private int elasticsearchPort;
|
|
||||||
@Value("${elasticsearch.username}")
|
|
||||||
private String username;
|
|
||||||
@Value("${elasticsearch.password}")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
/**
|
|
||||||
-最大连接数 (maxConnTotal):设置总的最大连接数,取决于业务的并发量。500-2000 之间较为合理。
|
|
||||||
-每个节点的最大连接数 (maxConnPerRoute):控制每个节点的最大连接数,建议 50-100 之间。
|
|
||||||
-IO 线程数 (setIoThreadCount):根据 CPU 核心数设置,通常为 2-4 倍 CPU 核心数。
|
|
||||||
-连接超时、套接字超时、获取连接超时:一般设置为 10-30 秒,复杂查询或大数据量操作可适当增加到 20-60 秒。
|
|
||||||
-失败监听器 (setFailureListener):自定义重试和故障处理逻辑,确保高可用性。
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public ElasticsearchClient elasticsearchClient() {
|
|
||||||
|
|
||||||
// 创建凭证提供者
|
|
||||||
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
|
||||||
credentialsProvider.setCredentials(
|
|
||||||
AuthScope.ANY,
|
|
||||||
new UsernamePasswordCredentials(username, password)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 自定义 RestClientBuilder 配置
|
|
||||||
RestClientBuilder restClientBuilder = RestClient.builder(
|
|
||||||
new HttpHost(elasticsearchHost, elasticsearchPort, "http")
|
|
||||||
).setHttpClientConfigCallback(httpClientBuilder ->
|
|
||||||
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) // 配置认证信息
|
|
||||||
);
|
|
||||||
// 配置连接超时、套接字超时、获取连接超时
|
|
||||||
restClientBuilder.setRequestConfigCallback(builder ->
|
|
||||||
builder.setConnectTimeout(20000)
|
|
||||||
.setSocketTimeout(20000)
|
|
||||||
.setConnectionRequestTimeout(20000)
|
|
||||||
);
|
|
||||||
// 创建 RestClientTransport 和 ElasticsearchClient
|
|
||||||
RestClient restClient = restClientBuilder.build();
|
|
||||||
ElasticsearchTransport transport = new RestClientTransport(
|
|
||||||
restClient,
|
|
||||||
new JacksonJsonpMapper() // 使用 Jackson 进行 JSON 处理
|
|
||||||
);
|
|
||||||
|
|
||||||
return new ElasticsearchClient(transport);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package cn.xf.basedemo.config;
|
package cn.xf.basedemo.config;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.models.Components;
|
||||||
import io.swagger.v3.oas.models.ExternalDocumentation;
|
import io.swagger.v3.oas.models.ExternalDocumentation;
|
||||||
import io.swagger.v3.oas.models.OpenAPI;
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
import io.swagger.v3.oas.models.info.Contact;
|
import io.swagger.v3.oas.models.info.Contact;
|
||||||
import io.swagger.v3.oas.models.info.Info;
|
import io.swagger.v3.oas.models.info.Info;
|
||||||
import io.swagger.v3.oas.models.info.License;
|
import io.swagger.v3.oas.models.info.License;
|
||||||
|
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||||
|
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||||
import org.springdoc.core.models.GroupedOpenApi;
|
import org.springdoc.core.models.GroupedOpenApi;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -21,6 +24,8 @@ public class SwaggerGroupApi {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OpenAPI springShopOpenAPI() {
|
public OpenAPI springShopOpenAPI() {
|
||||||
|
// 定义全局安全方案名称
|
||||||
|
String securitySchemeName = "Authorization";
|
||||||
return new OpenAPI()
|
return new OpenAPI()
|
||||||
.info(new Info().title("Spring boot脚手架 API")
|
.info(new Info().title("Spring boot脚手架 API")
|
||||||
.description("开箱即用的Spring boot脚手架 API")
|
.description("开箱即用的Spring boot脚手架 API")
|
||||||
@@ -29,7 +34,16 @@ public class SwaggerGroupApi {
|
|||||||
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
|
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
|
||||||
.externalDocs(new ExternalDocumentation()
|
.externalDocs(new ExternalDocumentation()
|
||||||
.description("Spring boot脚手架 Wiki Documentation")
|
.description("Spring boot脚手架 Wiki Documentation")
|
||||||
.url("https://springshop.wiki.github.org/docs"));
|
.url("https://springshop.wiki.github.org/docs")) // 添加安全组件
|
||||||
|
.components(new Components()
|
||||||
|
.addSecuritySchemes(securitySchemeName,
|
||||||
|
new SecurityScheme()
|
||||||
|
.type(SecurityScheme.Type.HTTP)
|
||||||
|
.scheme("bearer")
|
||||||
|
.bearerFormat("JWT")
|
||||||
|
))
|
||||||
|
// 将安全方案应用到全局
|
||||||
|
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import cn.xf.basedemo.service.UserService;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +31,7 @@ public class UserController {
|
|||||||
|
|
||||||
@Operation(summary = "用户登录", description = "用户登录")
|
@Operation(summary = "用户登录", description = "用户登录")
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public RetObj login(@RequestBody LoginInfoRes res){
|
public RetObj login(@RequestBody @Validated LoginInfoRes res) {
|
||||||
|
|
||||||
return userService.login(res);
|
return userService.login(res);
|
||||||
}
|
}
|
||||||
@@ -43,23 +44,4 @@ public class UserController {
|
|||||||
return RetObj.success(loginUser);
|
return RetObj.success(loginUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "es同步用户信息", description = "用户信息")
|
|
||||||
@SaCheckRole("admin") //角色校验
|
|
||||||
@GetMapping("/syncEs")
|
|
||||||
public RetObj syncEs(Long userId){
|
|
||||||
return userService.syncEs(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "es查询用户信息", description = "用户信息")
|
|
||||||
@GetMapping("/getEsId")
|
|
||||||
public RetObj getEsId(Long userId){
|
|
||||||
return userService.getEsId(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "获取用户权限数据", description = "用户信息")
|
|
||||||
@GetMapping("/getPermission")
|
|
||||||
public RetObj getPermission(){
|
|
||||||
return RetObj.success(StpUtil.getPermissionList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ public class TokenInterceptor implements HandlerInterceptor {
|
|||||||
token = request.getParameter("token");
|
token = request.getParameter("token");
|
||||||
if (StringUtils.isEmpty(token)) {
|
if (StringUtils.isEmpty(token)) {
|
||||||
throw new LoginException("请先登录");
|
throw new LoginException("请先登录");
|
||||||
|
}else {
|
||||||
|
//验证token
|
||||||
|
if (!token.startsWith("Bearer ")) {
|
||||||
|
throw new LoginException(ResponseCode.USER_INPUT_ERROR);
|
||||||
|
}
|
||||||
|
token = token.substring(7);
|
||||||
}
|
}
|
||||||
String value = (String) redisTemplate.opsForValue().get("token:" + token);
|
String value = (String) redisTemplate.opsForValue().get("token:" + token);
|
||||||
if (StringUtils.isEmpty(value)) {
|
if (StringUtils.isEmpty(value)) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.xf.basedemo.model.res;
|
package cn.xf.basedemo.model.res;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,6 +17,7 @@ public class LoginInfoRes {
|
|||||||
/**
|
/**
|
||||||
* 登录密文
|
* 登录密文
|
||||||
*/
|
*/
|
||||||
|
@NotBlank(message = "登录密文不能为空")
|
||||||
@Schema(name = "登录密文")
|
@Schema(name = "登录密文")
|
||||||
private String encryptedData;
|
private String encryptedData;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,4 @@ public interface UserService {
|
|||||||
|
|
||||||
RetObj login(LoginInfoRes res);
|
RetObj login(LoginInfoRes res);
|
||||||
|
|
||||||
RetObj syncEs(Long userId);
|
|
||||||
|
|
||||||
RetObj getEsId(Long userId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ import cn.xf.basedemo.common.model.EsBaseModel;
|
|||||||
import cn.xf.basedemo.common.model.LoginInfo;
|
import cn.xf.basedemo.common.model.LoginInfo;
|
||||||
import cn.xf.basedemo.common.model.LoginUser;
|
import cn.xf.basedemo.common.model.LoginUser;
|
||||||
import cn.xf.basedemo.common.model.RetObj;
|
import cn.xf.basedemo.common.model.RetObj;
|
||||||
import cn.xf.basedemo.common.utils.EsUtil;
|
|
||||||
import cn.xf.basedemo.common.utils.JwtTokenUtils;
|
import cn.xf.basedemo.common.utils.JwtTokenUtils;
|
||||||
import cn.xf.basedemo.common.utils.RSAUtils;
|
import cn.xf.basedemo.common.utils.RSAUtils;
|
||||||
import cn.xf.basedemo.common.utils.StringUtil;
|
|
||||||
import cn.xf.basedemo.config.GlobalConfig;
|
import cn.xf.basedemo.config.GlobalConfig;
|
||||||
import cn.xf.basedemo.mappers.UserMapper;
|
import cn.xf.basedemo.mappers.UserMapper;
|
||||||
import cn.xf.basedemo.model.domain.User;
|
import cn.xf.basedemo.model.domain.User;
|
||||||
@@ -96,26 +94,4 @@ public class UserServiceImpl implements UserService {
|
|||||||
return RetObj.success(loginUser);
|
return RetObj.success(loginUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public RetObj syncEs(Long userId) {
|
|
||||||
User user = userMapper.selectById(userId);
|
|
||||||
if (Objects.isNull(user)) {
|
|
||||||
return RetObj.error("用户不存在");
|
|
||||||
}
|
|
||||||
String index = StringUtil.camelToKebabCase(user.getClass().getSimpleName());
|
|
||||||
if (!EsUtil.existIndex(index)) {
|
|
||||||
EsUtil.createIndex(index);
|
|
||||||
}
|
|
||||||
EsUtil.addDocument(new EsBaseModel(index, String.valueOf(user.getId()), user, user.getClass()));
|
|
||||||
return RetObj.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RetObj getEsId(Long userId) {
|
|
||||||
Object user = EsUtil.getDocumentById(new EsBaseModel("user", String.valueOf(userId), null, User.class));
|
|
||||||
if (Objects.nonNull(user)) {
|
|
||||||
return RetObj.success(user);
|
|
||||||
}
|
|
||||||
return RetObj.error("es中不存在该用户");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,93 @@
|
|||||||
spring:
|
spring:
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 20MB
|
||||||
|
max-request-size: 20MB
|
||||||
|
jackson:
|
||||||
|
date-format: yyyy-MM-dd HH:mm:ss
|
||||||
|
time-zone: GMT+8
|
||||||
|
serialization:
|
||||||
|
WRITE_DATES_AS_TIMESTAMPS: false
|
||||||
|
FAIL_ON_EMPTY_BEANS: false
|
||||||
datasource:
|
datasource:
|
||||||
dynamic:
|
dynamic:
|
||||||
primary: master
|
primary: master
|
||||||
strict: true #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
|
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
|
||||||
hikari:
|
hikari:
|
||||||
minimum-idle: 4
|
|
||||||
maximum-pool-size: 4
|
maximum-pool-size: 4
|
||||||
|
minimum-idle: 4
|
||||||
|
leak-detection-threshold: 0
|
||||||
connection-init-sql: SELECT 1
|
connection-init-sql: SELECT 1
|
||||||
connection-test-query: SELECT 1
|
connection-test-query: SELECT 1
|
||||||
datasource:
|
datasource:
|
||||||
master: #${SERVER_ADDRESS}
|
master: #${SERVER_ADDRESS}
|
||||||
url: jdbc:mysql://9.9.9.9:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://localhost:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
|
||||||
username:
|
username:
|
||||||
password:
|
password:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
slave:
|
slave:
|
||||||
url: jdbc:mysql://9.9.9.9:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://localhost:3307/xf-boot-base?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
|
||||||
username:
|
username:
|
||||||
password:
|
password:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
port: 6379 #Redis服务器连接的端口
|
port: 6379
|
||||||
host: 9.9.9.9 # Redis服务器的地址
|
host: localhost
|
||||||
password: # Redis服务器连接密码(默认为空)
|
password:
|
||||||
timeout: 5000 # 连接超时时间(毫秒)
|
timeout: 5000
|
||||||
lettuce: #参考博客 https://blog.csdn.net/weixin_43944305/article/details/124322595
|
lettuce: #参考博客 https://blog.csdn.net/weixin_43944305/article/details/124322595
|
||||||
pool:
|
pool:
|
||||||
maxActive: 5000 #最大连接数
|
maxActive: 5000
|
||||||
maxIdle: 30 #连接池最大空闲连接数.
|
maxIdle: 30
|
||||||
minIdle: 5 #连接池最小空闲连接数.
|
minIdle: 5
|
||||||
max-wait: 2000 #从连接池中获取连接时的最大等待时间
|
max-wait: 2000
|
||||||
time-between-eviction-runs: 60s #空闲对象逐出器线程的运行间隔时间.空闲连接线程释放周期时间.
|
time-between-eviction-runs: 60s
|
||||||
cluster:
|
cluster:
|
||||||
refresh:
|
refresh:
|
||||||
adaptive: true #拓扑动态感应即客户端能够根据 redis cluster 集群的变化,动态改变客户端的节点情况,完成故障转移。
|
adaptive: true
|
||||||
period: 60s #刷新redis集群状态周期时间
|
period: 60s
|
||||||
|
|
||||||
global:
|
global:
|
||||||
rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB
|
rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB
|
||||||
rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ
|
rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ
|
||||||
|
|
||||||
redis:
|
springdoc:
|
||||||
datasource:
|
api-docs:
|
||||||
token:
|
path: /v3/api-docs # 自定义 API 文档路径
|
||||||
database: 1
|
swagger-ui:
|
||||||
host: 122.112.153.128
|
path: /swagger-ui.html # 自定义 Swagger UI 路径
|
||||||
port: 6379
|
enabled: true
|
||||||
password: 'redis'
|
info:
|
||||||
lettuce:
|
title: 文撩 API 文档
|
||||||
pool:
|
description: 这是文撩平台的 API 文档
|
||||||
max-active: 8
|
version: v1.0
|
||||||
max-wait: -1ms
|
|
||||||
max-idle: 8
|
|
||||||
min-idle: 0
|
|
||||||
timeout: 3000ms
|
|
||||||
|
|
||||||
oss:
|
mybatis-plus:
|
||||||
name: alioss
|
configuration:
|
||||||
endpoint: ll-oss-pre.lianlianlvyou.com
|
map-underscore-to-camel-case: false
|
||||||
accessKey:
|
auto-mapping-behavior: full
|
||||||
secretKey:
|
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印
|
||||||
bucketName:
|
mapper-locations: classpath*:mapper/**/*Mapper.xml
|
||||||
args:
|
global-config:
|
||||||
expireTime: 3600 #过期时间
|
# 逻辑删除配置
|
||||||
contentLengthRange: 2000 #大小限制
|
db-config:
|
||||||
# redis分布式锁
|
update-strategy: IGNORED
|
||||||
redisson:
|
# 删除前
|
||||||
enabled: true
|
logic-not-delete-value: 1
|
||||||
address: 'redis://192.168.10.113:6379'
|
# 删除后
|
||||||
password: '123456'
|
logic-delete-value: 0
|
||||||
database: 5
|
|
||||||
connectionPoolSize: 4
|
|
||||||
connectionMinimumIdleSize: 4
|
|
||||||
|
|
||||||
# 阿里云rocketmq
|
|
||||||
aliyun:
|
|
||||||
rocketmq:
|
|
||||||
config:
|
|
||||||
AccessKey: 1
|
|
||||||
SecretKey: 1
|
|
||||||
NAMESRV_ADDR: 1
|
|
||||||
GROUP_ID: 1
|
|
||||||
producer:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
rabbitmq:
|
|
||||||
configs:
|
|
||||||
order: #实例名称
|
|
||||||
host: 192.168.10.111
|
|
||||||
port: 5672
|
|
||||||
virtualHost: ll-dev
|
|
||||||
username: zhangziheng
|
|
||||||
password: zhangziheng
|
|
||||||
producer:
|
|
||||||
enabled: true
|
|
||||||
exchange: order_status
|
|
||||||
routingKey: ORDER_COMPLETE
|
|
||||||
confirmCallback: orderMqConfirmCallback
|
|
||||||
commonChange:
|
|
||||||
host: 192.168.10.111
|
|
||||||
port: 5672
|
|
||||||
virtualHost: ll-dev
|
|
||||||
username: zhangziheng
|
|
||||||
password: zhangziheng
|
|
||||||
producer:
|
|
||||||
enabled: false
|
|
||||||
consumer:
|
|
||||||
enabled: true
|
|
||||||
subscribeList:
|
|
||||||
- queue: 'app-business'
|
|
||||||
messageListener: commonChangeMessageListener
|
|
||||||
|
|
||||||
#应用可以默认使用的配置文件
|
|
||||||
#global:
|
|
||||||
# testCofnig: "aaa"
|
|
||||||
# tokenSecret: '12435twefdsfsdt4tsdcqw43tregdsgd'
|
|
||||||
# tokenExpire: 14400 #10天
|
|
||||||
# smsMqTopic: 'topic_msg'
|
|
||||||
# smsMqTag: 'tag-sms'
|
|
||||||
# rsaPrivateKey: 'MIIEpQIBAAKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQABAoIBAG6dg/UTEhq5OhXKyDwBAqfOgbk2IVacoONMg+wG+rorLdeWKRXmlEcLLfB45i409Agu2l+ekY2SzPhiwXfixxYnLSZchkJmtS9SCEWc11oSvJ24Q8mCXmeYQIikFPdW2nurlA7uo4IL5K20jIo8xVd9QOHreAHQP6eX4gkjaZHUIOSJ2P6iffEQCHbXehoyCoTMLdK+1HTuZdO4C9r/S9f/Y1kLWfV5ogEi0DHJpUy37npinfqPp0LHbgpK2WBPOkQIhKvi/4OQ71EcYR5gyrA7nR+rQyPHdhFzTTyfTNTgmuNFuAYJODN5yd62RQd8i6chMx63tYDoYhCjI/ixv8UCgYEA9S1JTacLrFQP+2ryHnn6A3JOhbzj1Y552Nc1XixI9aJMxxCJGI0PvmzDb46BSLfoOz4yaqL1lBS2vyX4tc1rKL82JiokZhDlnFNS0yQgR03484BGPJ3D1+tTWQV0cXyq0nYOI+m9vPBciI1Lw07tJ5ZqJbTabtcu2aq8WrKMuFsCgYEAwCk0WB5TTQJQgjuuFXT/GU4cIl8/Pa3IgF7Ccd1WVkFr9uI6vBpToN+0i1zAb83Ss9maD3eH1Na/7GiKwzZOJj8Yas6b1UsbcHZA1Yt+cI2WUZf8L8QVYJrUtIkbKbG+jdg/KjjZt8mAO8IcXivUhfmj8XUIBClYCezEZmSIVpcCgYEAupHWmUfHo0Bo1QqB6l0pupuuUyj1OxprcG38B4itkHYL9OOJX+xgEalUYzzO9tYz23kuBmWxeRj2I6kyhK4noF85RnuFLUIoZ/gkK9Xu1jPogOuZByGK2XETAMgc3wteNj9t7Tg+kVtbHvJet+YEo75bUgw4uGX5GdxJ7r62RMcCgYEAgJfSaJm6oxFGcTCg+cj2oaeM2k+lEZCHWaiQNQSqr0ROjMOuDI0No92wg4aJXQh+1U5sc6dI5dzkSL9ZBPQFbkDRBUDINf9yGFt6Xa1g6s9FZcrwv8JXj/NtHneWDtvcqi2pb4bl48DbqKHou/hW22VJGd94gthsCxBACkmCl3cCgYEAp2/KJrDnLwAr4h6SVCufRRuNkZSRI+XITkE4xyQ/UDeL+iwCbX38Jcqa2lxCAXCLk++1xilSF/sJbBVkiDorBU9CC0tI5tPJFfHQodbePx1C0SQE8e0F+wtaeR9Z5m5KzHNs2Gciqw+2nJPU9uFQjUfGdXuIZF2bBvtXBWH+Prk='
|
|
||||||
# rsaPublickey: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQAB'
|
|
||||||
# appDowloadUrl: 'http://llzby.cn/s/E9TTlQrJ'
|
|
||||||
# pcAccessUrl: 'http://llzby.cn/s/E9TTlQrJ'
|
|
||||||
# customServiceUrl: 'https://chaten.soboten.com/chat/h5/v2/index.html?sysnum=caf21f78c499463fbb54077f5c4a8efd&channelid=13&source=1&groupid=d16ef9bdcf3b46dc9726bbb00a7ee45b&partnerid=' #智齿客服 + biz_userId
|
|
||||||
#
|
|
||||||
|
|
||||||
|
# 参考文章 https://zhuanlan.zhihu.com/p/145359625
|
||||||
|
management:
|
||||||
|
health:
|
||||||
|
elasticsearch: #禁用健康检查
|
||||||
|
enabled: false
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: "health"
|
||||||
|
endpoint:
|
||||||
|
health:
|
||||||
|
show-details: always
|
||||||
@@ -41,98 +41,56 @@ global:
|
|||||||
rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB
|
rsaPublicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC_F5UQC1QWsu3QsESQBz9M-GDA9Atm0qVSvwIsy568lyRLi-nq3VvvnmgrlL4yTbngFzyfb2Dn35cNCHsBvIaGuCY3_PpzPqMzVpxr2QlEkhEX9atnJQ1rWexS8QeZtPjpiIwoQrChTzXjD_sYUkDrqSykFplyivf0NSO2WqCBdwIDAQAB
|
||||||
rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ
|
rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL8XlRALVBay7dCwRJAHP0z4YMD0C2bSpVK_AizLnryXJEuL6erdW--eaCuUvjJNueAXPJ9vYOfflw0IewG8hoa4Jjf8-nM-ozNWnGvZCUSSERf1q2clDWtZ7FLxB5m0-OmIjChCsKFPNeMP-xhSQOupLKQWmXKK9_Q1I7ZaoIF3AgMBAAECgYBxTUA61Ry0oL7U_86HP2TO9G4ZuhmQi9EucMaPXOPvmgYRLRIzCbDbMKc_P-BN3zwYnG57cgSZNz9OoPqeGvP_oVTnkoEpVkCSV-JP2p_DK09LdbDqszJXMrxAkPmWGUw8IRMcTJT1xJJcgzFE6T0CmTo-Vk47AnmqfJD4U6o74QJBAPRjVUJKZnrMSnSqKPDL2ThgTo8h7-KFxl_Z-g724lTOFiCmBpi6nCWAcuacFRrrYqxF-r9c4zdIyR7AvLROql8CQQDIK_kRF52dVtwShciZhyeUBLoi0nWV9F8mMGt60NTEER9zPEgPsv2aVn8h97KMWOwmd2Da4EPm25QxOuaKQC_pAkBczcfXp5co9KElkmR_pHl1jiTm97U3qSM-zPDHc_tYxvXiKgoBP4QCPbfkWMsu8MoEr4Jb3vMt0EcHlZtTQTgzAkAfmNla-lhV4sUgY1_T5EK6GbjsED6hag6u74u3ukkrnexR-10ApWdkumydBwV3I_464DM4uZfeVCDjWIHVpuYpAkEA6QLPztGD4V8Q1PqTEeSF3i68CKPM8vO1_mCH2JD7qsqDQcIKkczj5rTg7hlOKwB9V6gSw4CbnOF6moTooRD-cQ
|
||||||
|
|
||||||
##redis
|
elasticsearch:
|
||||||
#redis:
|
host: localhost
|
||||||
# datasource:
|
port: 9200
|
||||||
# token:
|
username: elastic
|
||||||
# database: 1
|
password: bz5oF*MGy8pKL_I=7KxY #window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic
|
||||||
# host: 122.112.153.128
|
|
||||||
# port: 6379
|
|
||||||
# password: 'redis'
|
|
||||||
# lettuce:
|
|
||||||
# pool:
|
|
||||||
# max-active: 8
|
|
||||||
# max-wait: -1ms
|
|
||||||
# max-idle: 8
|
|
||||||
# min-idle: 0
|
|
||||||
# timeout: 3000ms
|
|
||||||
|
|
||||||
#oss:
|
rocketmq:
|
||||||
# name: alioss
|
name-server: ${SERVER_ADDRESS}:9876
|
||||||
# endpoint: ll-oss-pre.lianlianlvyou.com
|
producer:
|
||||||
# accessKey:
|
group: producer-group
|
||||||
# secretKey:
|
consumer:
|
||||||
# bucketName:
|
group: consumer-group
|
||||||
# args:
|
enable-orderly: false
|
||||||
# expireTime: 3600 #过期时间
|
|
||||||
# contentLengthRange: 2000 #大小限制
|
springdoc:
|
||||||
##oss:
|
api-docs:
|
||||||
## name: alioss
|
path: /v3/api-docs # 自定义 API 文档路径
|
||||||
## endpoint: ll-oss-pre.lianlianlvyou.com
|
swagger-ui:
|
||||||
## accessKey:
|
path: /swagger-ui.html # 自定义 Swagger UI 路径
|
||||||
## secretKey:
|
enabled: true
|
||||||
## bucketName:
|
info:
|
||||||
## args:
|
title: 文撩 API 文档
|
||||||
## expireTime: 3600 #过期时间
|
description: 这是文撩平台的 API 文档
|
||||||
## contentLengthRange: 2000 #大小限制
|
version: v1.0
|
||||||
## redis分布式锁
|
|
||||||
#redisson:
|
mybatis-plus:
|
||||||
# enabled: true
|
configuration:
|
||||||
# address: 'redis://192.168.10.113:6379'
|
map-underscore-to-camel-case: false
|
||||||
# password: '123456'
|
auto-mapping-behavior: full
|
||||||
# database: 5
|
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印
|
||||||
# connectionPoolSize: 4
|
mapper-locations: classpath*:mapper/**/*Mapper.xml
|
||||||
# connectionMinimumIdleSize: 4
|
global-config:
|
||||||
#
|
# 逻辑删除配置
|
||||||
## 阿里云rocketmq
|
db-config:
|
||||||
#aliyun:
|
update-strategy: IGNORED
|
||||||
# rocketmq:
|
# 删除前
|
||||||
# config:
|
logic-not-delete-value: 1
|
||||||
# AccessKey: 1
|
# 删除后
|
||||||
# SecretKey: 1
|
logic-delete-value: 0
|
||||||
# NAMESRV_ADDR: 1
|
|
||||||
# GROUP_ID: 1
|
# 参考文章 https://zhuanlan.zhihu.com/p/145359625
|
||||||
# producer:
|
management:
|
||||||
# enabled: true
|
health:
|
||||||
#
|
elasticsearch: #禁用健康检查
|
||||||
#rabbitmq:
|
enabled: false
|
||||||
# configs:
|
endpoints:
|
||||||
# order: #实例名称
|
web:
|
||||||
# host: 192.168.10.111
|
exposure:
|
||||||
# port: 5672
|
include: "health"
|
||||||
# virtualHost: ll-dev
|
endpoint:
|
||||||
# username: zhangziheng
|
health:
|
||||||
# password: zhangziheng
|
show-details: always
|
||||||
# producer:
|
|
||||||
# enabled: true
|
|
||||||
# exchange: order_status
|
|
||||||
# routingKey: ORDER_COMPLETE
|
|
||||||
# confirmCallback: orderMqConfirmCallback
|
|
||||||
# commonChange:
|
|
||||||
# host: 192.168.10.111
|
|
||||||
# port: 5672
|
|
||||||
# virtualHost: ll-dev
|
|
||||||
# username: zhangziheng
|
|
||||||
# password: zhangziheng
|
|
||||||
# producer:
|
|
||||||
# enabled: false
|
|
||||||
# consumer:
|
|
||||||
# enabled: true
|
|
||||||
# subscribeList:
|
|
||||||
# - queue: 'app-business'
|
|
||||||
# messageListener: commonChangeMessageListener
|
|
||||||
#
|
|
||||||
##应用可以默认使用的配置文件
|
|
||||||
#global:
|
|
||||||
# testCofnig: "aaa"
|
|
||||||
# tokenSecret: '12435twefdsfsdt4tsdcqw43tregdsgd'
|
|
||||||
# tokenExpire: 14400 #10天
|
|
||||||
# smsMqTopic: 'topic_msg'
|
|
||||||
# smsMqTag: 'tag-sms'
|
|
||||||
# rsaPrivateKey: 'MIIEpQIBAAKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQABAoIBAG6dg/UTEhq5OhXKyDwBAqfOgbk2IVacoONMg+wG+rorLdeWKRXmlEcLLfB45i409Agu2l+ekY2SzPhiwXfixxYnLSZchkJmtS9SCEWc11oSvJ24Q8mCXmeYQIikFPdW2nurlA7uo4IL5K20jIo8xVd9QOHreAHQP6eX4gkjaZHUIOSJ2P6iffEQCHbXehoyCoTMLdK+1HTuZdO4C9r/S9f/Y1kLWfV5ogEi0DHJpUy37npinfqPp0LHbgpK2WBPOkQIhKvi/4OQ71EcYR5gyrA7nR+rQyPHdhFzTTyfTNTgmuNFuAYJODN5yd62RQd8i6chMx63tYDoYhCjI/ixv8UCgYEA9S1JTacLrFQP+2ryHnn6A3JOhbzj1Y552Nc1XixI9aJMxxCJGI0PvmzDb46BSLfoOz4yaqL1lBS2vyX4tc1rKL82JiokZhDlnFNS0yQgR03484BGPJ3D1+tTWQV0cXyq0nYOI+m9vPBciI1Lw07tJ5ZqJbTabtcu2aq8WrKMuFsCgYEAwCk0WB5TTQJQgjuuFXT/GU4cIl8/Pa3IgF7Ccd1WVkFr9uI6vBpToN+0i1zAb83Ss9maD3eH1Na/7GiKwzZOJj8Yas6b1UsbcHZA1Yt+cI2WUZf8L8QVYJrUtIkbKbG+jdg/KjjZt8mAO8IcXivUhfmj8XUIBClYCezEZmSIVpcCgYEAupHWmUfHo0Bo1QqB6l0pupuuUyj1OxprcG38B4itkHYL9OOJX+xgEalUYzzO9tYz23kuBmWxeRj2I6kyhK4noF85RnuFLUIoZ/gkK9Xu1jPogOuZByGK2XETAMgc3wteNj9t7Tg+kVtbHvJet+YEo75bUgw4uGX5GdxJ7r62RMcCgYEAgJfSaJm6oxFGcTCg+cj2oaeM2k+lEZCHWaiQNQSqr0ROjMOuDI0No92wg4aJXQh+1U5sc6dI5dzkSL9ZBPQFbkDRBUDINf9yGFt6Xa1g6s9FZcrwv8JXj/NtHneWDtvcqi2pb4bl48DbqKHou/hW22VJGd94gthsCxBACkmCl3cCgYEAp2/KJrDnLwAr4h6SVCufRRuNkZSRI+XITkE4xyQ/UDeL+iwCbX38Jcqa2lxCAXCLk++1xilSF/sJbBVkiDorBU9CC0tI5tPJFfHQodbePx1C0SQE8e0F+wtaeR9Z5m5KzHNs2Gciqw+2nJPU9uFQjUfGdXuIZF2bBvtXBWH+Prk='
|
|
||||||
# rsaPublickey: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAltXJI4kMQkucWCeLGK4Zyqw7VUp1JYS1GkJb0eJKCgxqJBzwjl8XpStA1hCv9BEX6SEsm/d2T6SDo+G6ySpfV0RQeZ7v32kE9+Eh0BK1Q8wU91nCa1CM9yfBhKXsQ3DKq2am5oLryNWXdKLXZPgoJbuIONG2G4oKakwUMX3aASp3Cj3rNXLea8ilXjFZ+OEp0DuZ4CsasO1MTaBS84mJhnzRNbuhHq5qyrVI02jw7Fim8siIBsmDDHgBd4l9hj6KAAr0jf9JOHaOp+KxfH76taqqaXI5lZIPG7lCP65iBuNNEqDSc21abcPhgvgK5K4xj9p5sG+V1FBISCE0dPrQIDAQAB'
|
|
||||||
# appDowloadUrl: 'http://llzby.cn/s/E9TTlQrJ'
|
|
||||||
# pcAccessUrl: 'http://llzby.cn/s/E9TTlQrJ'
|
|
||||||
# customServiceUrl: 'https://chaten.soboten.com/chat/h5/v2/index.html?sysnum=caf21f78c499463fbb54077f5c4a8efd&channelid=13&source=1&groupid=d16ef9bdcf3b46dc9726bbb00a7ee45b&partnerid=' #智齿客服 + biz_userId
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user