From e73f60cc6b957051164fd6a9bab47e88466b4d93 Mon Sep 17 00:00:00 2001
From: JiyangTang <18010816106@163.com>
Date: Fri, 16 Jun 2023 15:28:09 +0800
Subject: [PATCH] first commit
---
README.md | 18 ++
baogutang-admin/Dockerfile | 7 +
baogutang-admin/pom.xml | 153 +++++++++++++
.../admin/BaogutangAdminApplication.java | 23 ++
.../admin/domain/EdgeXAnnouncementsDto.java | 52 +++++
.../admin/schedule/EdgeXNoticeSchedule.java | 59 +++++
.../admin/services/IWxMsgPushService.java | 24 ++
.../services/impl/WxMsgPushServiceImpl.java | 81 +++++++
.../src/main/resources/bootstrap-local.yml | 19 ++
.../src/main/resources/bootstrap-prod.yml | 19 ++
.../src/main/resources/bootstrap-test.yml | 19 ++
.../src/main/resources/bootstrap.yml | 5 +
.../src/main/resources/logback-spring.xml | 114 ++++++++++
.../admin/BaogutangAdminApplicationTests.java | 13 ++
baogutang-business/Dockerfile | 7 +
baogutang-business/pom.xml | 208 ++++++++++++++++++
.../BaogutangBusinessApplication.java | 22 ++
.../controller/CallbackController.java | 23 ++
.../controller/WxMsgPushController.java | 35 +++
.../business/services/IWxMsgPushService.java | 18 ++
.../services/impl/WxMsgPushServiceImpl.java | 75 +++++++
.../src/main/resources/bootstrap-local.yml | 19 ++
.../src/main/resources/bootstrap-prod.yml | 19 ++
.../src/main/resources/bootstrap-test.yml | 19 ++
.../src/main/resources/bootstrap.yml | 5 +
.../src/main/resources/logback-spring.xml | 114 ++++++++++
baogutang-common/pom.xml | 139 ++++++++++++
.../common/annotation/LoginRequired.java | 20 ++
.../common/annotation/RequestLimit.java | 37 ++++
.../common/annotation/VerifyRequired.java | 18 ++
.../baogutang/common/aspect/LogAspect.java | 65 ++++++
.../common/aspect/LoginRequiredAspect.java | 115 ++++++++++
.../common/aspect/RequestLimitAspect.java | 127 +++++++++++
.../common/aspect/VerifyRequiredAspect.java | 100 +++++++++
.../common/components/TokenComponent.java | 109 +++++++++
.../common/config/ExecutorConfig.java | 49 +++++
.../common/config/GlobalCorsConfig.java | 37 ++++
.../common/config/GlobalMDCTaskDecorator.java | 45 ++++
.../common/config/MdcRequestIdFilter.java | 44 ++++
.../common/config/MybatisPlusConfig.java | 27 +++
.../baogutang/common/config/RedisConfig.java | 85 +++++++
.../common/constants/CacheConstant.java | 21 ++
.../common/constants/ErrorCodeEnum.java | 80 +++++++
.../common/constants/JwtConstant.java | 20 ++
.../top/baogutang/common/domain/JwtBody.java | 66 ++++++
.../top/baogutang/common/domain/Page.java | 33 +++
.../top/baogutang/common/domain/Results.java | 192 ++++++++++++++++
.../common/domain/TokenCodeEnum.java | 25 +++
.../common/exceptions/BusinessException.java | 39 ++++
.../exceptions/GlobalExceptionHandler.java | 75 +++++++
.../properties/WxMsgPushProperties.java | 24 ++
.../top/baogutang/common/utils/HttpUtils.java | 161 ++++++++++++++
.../common/utils/UserThreadLocal.java | 22 ++
.../src/main/resources/script/accquire.lua | 10 +
.../src/main/resources/script/ipLimit.lua | 25 +++
pom.xml | 155 +++++++++++++
56 files changed, 3135 insertions(+)
create mode 100644 README.md
create mode 100644 baogutang-admin/Dockerfile
create mode 100644 baogutang-admin/pom.xml
create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/BaogutangAdminApplication.java
create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java
create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java
create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/services/IWxMsgPushService.java
create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/services/impl/WxMsgPushServiceImpl.java
create mode 100644 baogutang-admin/src/main/resources/bootstrap-local.yml
create mode 100644 baogutang-admin/src/main/resources/bootstrap-prod.yml
create mode 100644 baogutang-admin/src/main/resources/bootstrap-test.yml
create mode 100644 baogutang-admin/src/main/resources/bootstrap.yml
create mode 100644 baogutang-admin/src/main/resources/logback-spring.xml
create mode 100644 baogutang-admin/src/test/java/top/baogutang/business/admin/BaogutangAdminApplicationTests.java
create mode 100644 baogutang-business/Dockerfile
create mode 100644 baogutang-business/pom.xml
create mode 100644 baogutang-business/src/main/java/top/baogutang/business/BaogutangBusinessApplication.java
create mode 100644 baogutang-business/src/main/java/top/baogutang/business/controller/CallbackController.java
create mode 100644 baogutang-business/src/main/java/top/baogutang/business/controller/WxMsgPushController.java
create mode 100644 baogutang-business/src/main/java/top/baogutang/business/services/IWxMsgPushService.java
create mode 100644 baogutang-business/src/main/java/top/baogutang/business/services/impl/WxMsgPushServiceImpl.java
create mode 100644 baogutang-business/src/main/resources/bootstrap-local.yml
create mode 100644 baogutang-business/src/main/resources/bootstrap-prod.yml
create mode 100644 baogutang-business/src/main/resources/bootstrap-test.yml
create mode 100644 baogutang-business/src/main/resources/bootstrap.yml
create mode 100644 baogutang-business/src/main/resources/logback-spring.xml
create mode 100644 baogutang-common/pom.xml
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/annotation/LoginRequired.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/annotation/RequestLimit.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/annotation/VerifyRequired.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/aspect/LogAspect.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/aspect/LoginRequiredAspect.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/aspect/RequestLimitAspect.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/aspect/VerifyRequiredAspect.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/components/TokenComponent.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/ExecutorConfig.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/GlobalCorsConfig.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/GlobalMDCTaskDecorator.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/MdcRequestIdFilter.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/MybatisPlusConfig.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/config/RedisConfig.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/constants/ErrorCodeEnum.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/constants/JwtConstant.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/domain/JwtBody.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/domain/Page.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/domain/Results.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/domain/TokenCodeEnum.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/exceptions/BusinessException.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/exceptions/GlobalExceptionHandler.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/properties/WxMsgPushProperties.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/utils/HttpUtils.java
create mode 100644 baogutang-common/src/main/java/top/baogutang/common/utils/UserThreadLocal.java
create mode 100644 baogutang-common/src/main/resources/script/accquire.lua
create mode 100644 baogutang-common/src/main/resources/script/ipLimit.lua
create mode 100644 pom.xml
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..486fe44
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# Read Me First
+
+The following was discovered as part of building this project:
+
+* The JVM level was changed from '1.8' to '17', review
+ the [JDK Version Range](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions#jdk-version-range)
+ on the wiki for more details.
+
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.0/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.0/maven-plugin/reference/html/#build-image)
+
diff --git a/baogutang-admin/Dockerfile b/baogutang-admin/Dockerfile
new file mode 100644
index 0000000..04cae7b
--- /dev/null
+++ b/baogutang-admin/Dockerfile
@@ -0,0 +1,7 @@
+FROM openjdk:8
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+COPY ./baogutang-admin/target/baogutang-admin-1.0.0-SNAPSHOT.jar /apps/baogutang-admin.jar
+WORKDIR /apps
+RUN bash -c 'touch /baogutang-admin.jar'
+CMD exec java $JAVA_OPTS -jar baogutang-admin.jar
diff --git a/baogutang-admin/pom.xml b/baogutang-admin/pom.xml
new file mode 100644
index 0000000..2f1d7f1
--- /dev/null
+++ b/baogutang-admin/pom.xml
@@ -0,0 +1,153 @@
+
+
+ 4.0.0
+
+ top.baogutang
+ baogutang-parent
+ 1.0.0-SNAPSHOT
+
+ baogutang-admin
+
+ 8
+ 8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ top.baogutang
+ baogutang-common
+ 1.0.0-SNAPSHOT
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+ com.aliyun.openservices
+ aliyun-log-logback-appender
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+ com.alibaba
+ fastjson
+
+
+
+ mysql
+ mysql-connector-java
+
+
+ org.projectlombok
+ lombok
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ io.springfox
+ springfox-boot-starter
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ com.aliyun
+ dingtalk
+ 2.0.20
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.2.5.RELEASE
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19
+
+ true
+
+
+
+
+
+
+
+ local
+
+ local
+
+
+ true
+
+
+
+ test
+
+ test
+
+
+ false
+
+
+
+ prod
+
+ prod
+
+
+ false
+
+
+
+
+
+
diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/BaogutangAdminApplication.java b/baogutang-admin/src/main/java/top/baogutang/admin/BaogutangAdminApplication.java
new file mode 100644
index 0000000..199e4fa
--- /dev/null
+++ b/baogutang-admin/src/main/java/top/baogutang/admin/BaogutangAdminApplication.java
@@ -0,0 +1,23 @@
+package top.baogutang.admin;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * @author nikooh
+ */
+@Slf4j
+@EnableScheduling
+@SpringBootApplication(scanBasePackages = "top.baogutang.*")
+@MapperScan(basePackages = {"top.baogutang.admin.dao.mapper", "top.baogutang.common.dao.mapper"})
+public class BaogutangAdminApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BaogutangAdminApplication.class, args);
+ log.info("<<<<<<<<<<<<<<<==BAO_GU_TANG后台管理服务启动成功!!!==>>>>>>>>>>>>>>>");
+ }
+
+}
diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java b/baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java
new file mode 100644
index 0000000..98816c4
--- /dev/null
+++ b/baogutang-admin/src/main/java/top/baogutang/admin/domain/EdgeXAnnouncementsDto.java
@@ -0,0 +1,52 @@
+package top.baogutang.admin.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/16 : 12:09
+ */
+@Data
+public class EdgeXAnnouncementsDto implements Serializable {
+
+ private static final long serialVersionUID = 2069054276884655439L;
+
+ /**
+ * id
+ */
+ private Long id;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 类型
+ */
+ private String type;
+
+ /**
+ * 封面
+ */
+ private String cover;
+
+ /**
+ * 创作者
+ */
+ private String creator;
+
+ /**
+ * 内容
+ */
+ private String content;
+
+ /**
+ * 创建时间
+ */
+ private Date createdAt;
+}
diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java
new file mode 100644
index 0000000..3a28028
--- /dev/null
+++ b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java
@@ -0,0 +1,59 @@
+package top.baogutang.admin.schedule;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.zjiecode.wxpusher.client.bean.Message;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import top.baogutang.admin.domain.EdgeXAnnouncementsDto;
+import top.baogutang.admin.services.IWxMsgPushService;
+import top.baogutang.common.domain.Page;
+import top.baogutang.common.domain.Results;
+import top.baogutang.common.properties.WxMsgPushProperties;
+import top.baogutang.common.utils.HttpUtils;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ * @description: EDGEX公告
+ * @author: nikooh
+ * @date: 2023/06/16 : 11:41
+ */
+@Slf4j
+@Component
+@RefreshScope
+public class EdgeXNoticeSchedule {
+
+ @Resource
+ private IWxMsgPushService wxMsgPushService;
+
+ @Resource
+ private WxMsgPushProperties wxMsgPushProperties;
+
+ /**
+ * 每分钟查询edgeX公告
+ */
+ @Scheduled(cron = "0 0/1 * * * ? ")
+ public void edgeXNotice() {
+ Results> results = HttpUtils.get("https://art-api.edge-x.cn/api/v1/art/announcements?pageNum=1&pageSize=1", new TypeReference>>() {
+ });
+ log.info(">>>>>>>>>>请求获取edgeX公告返回数据:{}<<<<<<<<<<", JSON.toJSONString(results));
+ if (Objects.isNull(results)) {
+ return;
+ }
+ if (!Boolean.TRUE.equals(results.isSuccess())) {
+ return;
+ }
+ if (Objects.isNull(results.getData()) || CollectionUtils.isEmpty(results.getData().getList())) {
+ return;
+ }
+ EdgeXAnnouncementsDto announcementsDto = results.getData().getList().get(0);
+ if (Math.abs(announcementsDto.getCreatedAt().getTime() - System.currentTimeMillis()) <= 60000) {
+ wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds());
+ }
+ }
+}
diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/services/IWxMsgPushService.java b/baogutang-admin/src/main/java/top/baogutang/admin/services/IWxMsgPushService.java
new file mode 100644
index 0000000..485c9b1
--- /dev/null
+++ b/baogutang-admin/src/main/java/top/baogutang/admin/services/IWxMsgPushService.java
@@ -0,0 +1,24 @@
+package top.baogutang.admin.services;
+
+
+import java.util.Set;
+
+/**
+ * @description: 微信消息推送service
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:27
+ */
+public interface IWxMsgPushService {
+
+ /**
+ * 微信消息推送
+ *
+ * @param msgType 消息类型
+ * @param summary 消息主题
+ * @param msgContent 消息内容
+ * @param topicIdSet 消息模版id
+ * @return 推送结果
+ */
+ Boolean msgPush(Integer msgType, String summary, String msgContent, Set topicIdSet);
+
+}
diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/services/impl/WxMsgPushServiceImpl.java b/baogutang-admin/src/main/java/top/baogutang/admin/services/impl/WxMsgPushServiceImpl.java
new file mode 100644
index 0000000..69096cc
--- /dev/null
+++ b/baogutang-admin/src/main/java/top/baogutang/admin/services/impl/WxMsgPushServiceImpl.java
@@ -0,0 +1,81 @@
+package top.baogutang.admin.services.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.zjiecode.wxpusher.client.WxPusher;
+import com.zjiecode.wxpusher.client.bean.Message;
+import com.zjiecode.wxpusher.client.bean.MessageResult;
+import com.zjiecode.wxpusher.client.bean.Result;
+import com.zjiecode.wxpusher.client.bean.WxUser;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Service;
+import top.baogutang.admin.services.IWxMsgPushService;
+import com.zjiecode.wxpusher.client.bean.Page;
+import top.baogutang.common.exceptions.BusinessException;
+import top.baogutang.common.properties.WxMsgPushProperties;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:27
+ */
+@Slf4j
+@RefreshScope
+@Service
+public class WxMsgPushServiceImpl implements IWxMsgPushService {
+
+ @Resource
+ private WxMsgPushProperties wxMsgPushProperties;
+
+ @Override
+ public Boolean msgPush(Integer msgType, String summary, String msgContent, Set topicIdSet) {
+ Message message = new Message();
+ Set userUidSet = this.queryUids(wxMsgPushProperties.getAppToken());
+ if (CollectionUtils.isEmpty(userUidSet)) {
+ return Boolean.TRUE;
+ }
+ message.setUids(userUidSet);
+ message.setAppToken(wxMsgPushProperties.getAppToken());
+ message.setSummary(summary);
+ message.setContentType(msgType);
+ message.setContent(msgContent);
+ Result> result = null;
+ try {
+ result = WxPusher.send(message);
+ } catch (Exception e) {
+ log.error(">>>>>>>>>>推送消息异常:{}<<<<<<<<<<", e.getMessage(), e);
+ return Boolean.FALSE;
+ }
+ log.info(">>>>>>>>>>消息推送结果:{}<<<<<<<<<<", JSON.toJSONString(result));
+ if (Objects.nonNull(result) && result.isSuccess()) {
+ return Boolean.TRUE;
+ }
+ return Boolean.FALSE;
+ }
+
+ private Set queryUids(String appToken) {
+ //分页查询全部用户
+ Result> wxUsersResult = null;
+ try {
+ wxUsersResult = WxPusher.queryWxUser(appToken, 1, Integer.MAX_VALUE);
+ } catch (Exception e) {
+ log.error(">>>>>>>>>>查询用户信息失败:{}<<<<<<<<<<", e.getMessage(), e);
+ throw new BusinessException("查询用户信息失败");
+ }
+ log.info(">>>>>>>>>>查询用户列表结果:{}<<<<<<<<<<", JSON.toJSONString(wxUsersResult));
+ if (Objects.nonNull(wxUsersResult) && Objects.nonNull(wxUsersResult.getData()) && CollectionUtils.isNotEmpty(wxUsersResult.getData().getRecords())) {
+ return wxUsersResult.getData().getRecords().stream()
+ .map(WxUser::getUid)
+ .collect(Collectors.toSet());
+ }
+ return Collections.emptySet();
+ }
+}
diff --git a/baogutang-admin/src/main/resources/bootstrap-local.yml b/baogutang-admin/src/main/resources/bootstrap-local.yml
new file mode 100644
index 0000000..152de4e
--- /dev/null
+++ b/baogutang-admin/src/main/resources/bootstrap-local.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-admin
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: adcc486c-d6fb-465a-a4f6-3fea7234433b
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-admin/src/main/resources/bootstrap-prod.yml b/baogutang-admin/src/main/resources/bootstrap-prod.yml
new file mode 100644
index 0000000..c74d3b2
--- /dev/null
+++ b/baogutang-admin/src/main/resources/bootstrap-prod.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-admin
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: 50b370f0-6fc9-4e1d-9a19-df276cff9eac
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-admin/src/main/resources/bootstrap-test.yml b/baogutang-admin/src/main/resources/bootstrap-test.yml
new file mode 100644
index 0000000..a636c66
--- /dev/null
+++ b/baogutang-admin/src/main/resources/bootstrap-test.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-admin
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: 7e44b734-781d-4c21-a524-4bad1557d95f
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-admin/src/main/resources/bootstrap.yml b/baogutang-admin/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..6b429df
--- /dev/null
+++ b/baogutang-admin/src/main/resources/bootstrap.yml
@@ -0,0 +1,5 @@
+spring:
+ profiles:
+ active: @profileActive@
+ main:
+ allow-bean-definition-overriding: true
\ No newline at end of file
diff --git a/baogutang-admin/src/main/resources/logback-spring.xml b/baogutang-admin/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..e040eb0
--- /dev/null
+++ b/baogutang-admin/src/main/resources/logback-spring.xml
@@ -0,0 +1,114 @@
+
+
+
+ logback
+
+
+
+
+
+ %date{yyyy-MM-dd HH:mm:ss.SSS} [%X{X-Request-Id}] [%thread] %-5level %logger - %msg%n
+
+
+
+
+ ${log.path}/app.log
+
+ ${log.path}/%d{yyyy-MM-dd,aux}/app-%d{yyyy-MM-dd}.%i.log
+
+
+ 50MB
+
+
+ 60
+
+
+ %date{HH:mm:ss.SSS} [%X{X-Request-Id}] [%thread] %-5level %logger - %msg%n
+
+
+
+
+ 10000
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cn-shanghai.log.aliyuncs.com
+ LTAI5tRN9T5Tz1QExcSpUaBc
+ LniIMK15XEOc6Nn5mOrtX399FkVfQd
+ baogutang
+ ${appEnv}
+
+
+ ${appId}
+
+
+
+ 3000
+ 4096
+ 3145728
+ 104857600
+ 3
+ 8
+
+
+ Asia/Shanghai
+
+ yyyy-MM-dd HH:mm:ss.SSS
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{X-Request-Id}] [%thread] %logger{0}: %msg
+
+
+
+
+ INFO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baogutang-admin/src/test/java/top/baogutang/business/admin/BaogutangAdminApplicationTests.java b/baogutang-admin/src/test/java/top/baogutang/business/admin/BaogutangAdminApplicationTests.java
new file mode 100644
index 0000000..df1dcbe
--- /dev/null
+++ b/baogutang-admin/src/test/java/top/baogutang/business/admin/BaogutangAdminApplicationTests.java
@@ -0,0 +1,13 @@
+package top.baogutang.business.admin;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class BaogutangAdminApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/baogutang-business/Dockerfile b/baogutang-business/Dockerfile
new file mode 100644
index 0000000..cbc3dec
--- /dev/null
+++ b/baogutang-business/Dockerfile
@@ -0,0 +1,7 @@
+FROM openjdk:8
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+COPY ./baogutang-business/target/baogutang-business-1.0.0-SNAPSHOT.jar /apps/baogutang-business.jar
+WORKDIR /apps
+RUN bash -c 'touch /baogutang-business.jar'
+CMD exec java $JAVA_OPTS -jar baogutang-business.jar
diff --git a/baogutang-business/pom.xml b/baogutang-business/pom.xml
new file mode 100644
index 0000000..3837c4c
--- /dev/null
+++ b/baogutang-business/pom.xml
@@ -0,0 +1,208 @@
+
+
+ 4.0.0
+
+ top.baogutang
+ baogutang-parent
+ 1.0.0-SNAPSHOT
+
+
+ baogutang-business
+
+
+ 8
+ 8
+ 8
+
+
+
+ top.baogutang
+ baogutang-common
+ 1.0.0-SNAPSHOT
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.yaml
+ snakeyaml
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+ com.aliyun.openservices
+ aliyun-log-logback-appender
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+ com.alibaba
+ fastjson
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+ org.projectlombok
+ lombok
+ compile
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+
+ io.springfox
+ springfox-boot-starter
+
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+ **/*.pfx
+ **/*.cer
+
+
+
+ src/main/resources
+ false
+
+ **/*.pfx
+ **/*.cer
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.2.5.RELEASE
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+ UTF-8
+
+
+ p12
+ crt
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19
+
+ true
+
+
+
+ org.mybatis.generator
+ mybatis-generator-maven-plugin
+ 1.4.0
+
+
+ io.github.javthon
+ mybatis-generator-yml-maven-plugin
+ 0.0.1
+
+ src/main/resources/generatorConfig.yml
+
+
+
+
+
+
+
+ local
+
+ local
+
+
+ true
+
+
+
+ test
+
+ test
+
+
+ false
+
+
+
+ prod
+
+ prod
+
+
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/baogutang-business/src/main/java/top/baogutang/business/BaogutangBusinessApplication.java b/baogutang-business/src/main/java/top/baogutang/business/BaogutangBusinessApplication.java
new file mode 100644
index 0000000..5621958
--- /dev/null
+++ b/baogutang-business/src/main/java/top/baogutang/business/BaogutangBusinessApplication.java
@@ -0,0 +1,22 @@
+package top.baogutang.business;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 11:22
+ */
+@Slf4j
+@SpringBootApplication(scanBasePackages = "top.baogutang.*")
+@MapperScan(basePackages = {"top.baogutang.business.dao.mapper", "top.baogutang.common.dao.mapper"})
+public class BaogutangBusinessApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BaogutangBusinessApplication.class, args);
+ log.info("<<<<<<<<<<<<<<<==BAO_GU_TANG客户端服务启动成功!!!==>>>>>>>>>>>>>>>");
+ }
+}
diff --git a/baogutang-business/src/main/java/top/baogutang/business/controller/CallbackController.java b/baogutang-business/src/main/java/top/baogutang/business/controller/CallbackController.java
new file mode 100644
index 0000000..6aaad28
--- /dev/null
+++ b/baogutang-business/src/main/java/top/baogutang/business/controller/CallbackController.java
@@ -0,0 +1,23 @@
+package top.baogutang.business.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import top.baogutang.common.domain.Results;
+
+/**
+ * @description: 回调控制器
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:10
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/v1/callback")
+public class CallbackController {
+
+
+ @RequestMapping("/wx/msgPush")
+ public Results wxMsgPushCallback() {
+ return Results.ok(null);
+ }
+}
diff --git a/baogutang-business/src/main/java/top/baogutang/business/controller/WxMsgPushController.java b/baogutang-business/src/main/java/top/baogutang/business/controller/WxMsgPushController.java
new file mode 100644
index 0000000..34f4ae2
--- /dev/null
+++ b/baogutang-business/src/main/java/top/baogutang/business/controller/WxMsgPushController.java
@@ -0,0 +1,35 @@
+package top.baogutang.business.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.view.RedirectView;
+import top.baogutang.business.services.IWxMsgPushService;
+
+import javax.annotation.Resource;
+
+/**
+ * @description: 微信消息推送控制器
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:24
+ */
+@Slf4j
+@Controller
+@RequestMapping("/api/v1/wx/msgPush")
+public class WxMsgPushController {
+
+ @Resource
+ private IWxMsgPushService wxMsgPushService;
+
+
+ /**
+ * 创建一个带参数的二维码,用户扫码的时候,回调里面会携带二维码的参数.
+ *
+ * @return 二维码
+ */
+ @GetMapping("/qrCode")
+ public RedirectView getQrCode() {
+ return new RedirectView(wxMsgPushService.getOrCode());
+ }
+}
diff --git a/baogutang-business/src/main/java/top/baogutang/business/services/IWxMsgPushService.java b/baogutang-business/src/main/java/top/baogutang/business/services/IWxMsgPushService.java
new file mode 100644
index 0000000..7020d54
--- /dev/null
+++ b/baogutang-business/src/main/java/top/baogutang/business/services/IWxMsgPushService.java
@@ -0,0 +1,18 @@
+package top.baogutang.business.services;
+
+
+/**
+ * @description: 微信消息推送service
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:27
+ */
+public interface IWxMsgPushService {
+
+ /**
+ * 创建一个带参数的二维码,用户扫码的时候,回调里面会携带二维码的参数.
+ *
+ * @return 二维码
+ */
+ String getOrCode();
+
+}
diff --git a/baogutang-business/src/main/java/top/baogutang/business/services/impl/WxMsgPushServiceImpl.java b/baogutang-business/src/main/java/top/baogutang/business/services/impl/WxMsgPushServiceImpl.java
new file mode 100644
index 0000000..640f7d1
--- /dev/null
+++ b/baogutang-business/src/main/java/top/baogutang/business/services/impl/WxMsgPushServiceImpl.java
@@ -0,0 +1,75 @@
+package top.baogutang.business.services.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.zjiecode.wxpusher.client.WxPusher;
+import com.zjiecode.wxpusher.client.bean.CreateQrcodeReq;
+import com.zjiecode.wxpusher.client.bean.CreateQrcodeResp;
+import com.zjiecode.wxpusher.client.bean.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+import top.baogutang.business.services.IWxMsgPushService;
+import top.baogutang.common.constants.ErrorCodeEnum;
+import top.baogutang.common.exceptions.BusinessException;
+import top.baogutang.common.properties.WxMsgPushProperties;
+
+import javax.annotation.Resource;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static top.baogutang.common.constants.CacheConstant.WX_MSG_PUSH_QR_CODE_PREFIX;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/16 : 10:27
+ */
+@Slf4j
+@RefreshScope
+@Service
+public class WxMsgPushServiceImpl implements IWxMsgPushService {
+
+ /**
+ * 二维码有效时间
+ */
+ private static final Integer QR_CODE_EXPIRE_TIME = 10 * 24 * 60 * 60;
+
+ @Resource
+ private WxMsgPushProperties wxMsgPushProperties;
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Override
+ public String getOrCode() {
+ String cacheKey = String.format(WX_MSG_PUSH_QR_CODE_PREFIX, wxMsgPushProperties.getAppToken());
+ Object cacheUrlObj = redisTemplate.opsForValue().get(cacheKey);
+ if (Objects.nonNull(cacheUrlObj)) {
+ return (String) cacheUrlObj;
+ }
+ CreateQrcodeReq createQrcodeReq = new CreateQrcodeReq();
+ //必填,应用的appToken
+ createQrcodeReq.setAppToken(wxMsgPushProperties.getAppToken());
+ //必填,携带的参数
+ createQrcodeReq.setExtra("Niko's MP");
+ //可选,二维码有效时间,默认1800 s,最大30天,单位是s
+ createQrcodeReq.setValidTime(QR_CODE_EXPIRE_TIME);
+ Result respResult = null;
+ try {
+ respResult = WxPusher.createAppTempQrcode(createQrcodeReq);
+ } catch (Exception e) {
+ log.error(">>>>>>>>>>创建二维码异常:{}<<<<<<<<<<", e.getMessage(), e);
+ throw new BusinessException(ErrorCodeEnum.E_BIZ_ERROR);
+ }
+ log.info(">>>>>>>>>>创建临时二维码请求参数:{},响应参数:{}<<<<<<<<<<", JSON.toJSONString(createQrcodeReq), JSON.toJSONString(respResult));
+ if (respResult.isSuccess()) {
+ //创建成功
+ CreateQrcodeResp createQrcodeResp = respResult.getData();
+ redisTemplate.opsForValue().set(cacheKey, createQrcodeResp.getUrl(), QR_CODE_EXPIRE_TIME, TimeUnit.SECONDS);
+ return createQrcodeResp.getUrl();
+ }
+ throw new BusinessException(ErrorCodeEnum.E_BIZ_ERROR);
+ }
+}
diff --git a/baogutang-business/src/main/resources/bootstrap-local.yml b/baogutang-business/src/main/resources/bootstrap-local.yml
new file mode 100644
index 0000000..034519c
--- /dev/null
+++ b/baogutang-business/src/main/resources/bootstrap-local.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-business
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: adcc486c-d6fb-465a-a4f6-3fea7234433b
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-business/src/main/resources/bootstrap-prod.yml b/baogutang-business/src/main/resources/bootstrap-prod.yml
new file mode 100644
index 0000000..25bbba7
--- /dev/null
+++ b/baogutang-business/src/main/resources/bootstrap-prod.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-business
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: 50b370f0-6fc9-4e1d-9a19-df276cff9eac
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-business/src/main/resources/bootstrap-test.yml b/baogutang-business/src/main/resources/bootstrap-test.yml
new file mode 100644
index 0000000..80c633a
--- /dev/null
+++ b/baogutang-business/src/main/resources/bootstrap-test.yml
@@ -0,0 +1,19 @@
+spring:
+ application:
+ name: baogutang-business
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 42.51.4.235:8848
+ config:
+ server-addr: 42.51.4.235:8848
+ namespace: 7e44b734-781d-4c21-a524-4bad1557d95f
+ file-extension: yml
+ refresh-enabled: true
+ group: DEFAULT_GROUP
+ username: nacos
+ password: 199312
+# shared-configs:
+# - data-id: goods-blindbox.yml
+# refresh: true
+
diff --git a/baogutang-business/src/main/resources/bootstrap.yml b/baogutang-business/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..6b429df
--- /dev/null
+++ b/baogutang-business/src/main/resources/bootstrap.yml
@@ -0,0 +1,5 @@
+spring:
+ profiles:
+ active: @profileActive@
+ main:
+ allow-bean-definition-overriding: true
\ No newline at end of file
diff --git a/baogutang-business/src/main/resources/logback-spring.xml b/baogutang-business/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..e040eb0
--- /dev/null
+++ b/baogutang-business/src/main/resources/logback-spring.xml
@@ -0,0 +1,114 @@
+
+
+
+ logback
+
+
+
+
+
+ %date{yyyy-MM-dd HH:mm:ss.SSS} [%X{X-Request-Id}] [%thread] %-5level %logger - %msg%n
+
+
+
+
+ ${log.path}/app.log
+
+ ${log.path}/%d{yyyy-MM-dd,aux}/app-%d{yyyy-MM-dd}.%i.log
+
+
+ 50MB
+
+
+ 60
+
+
+ %date{HH:mm:ss.SSS} [%X{X-Request-Id}] [%thread] %-5level %logger - %msg%n
+
+
+
+
+ 10000
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cn-shanghai.log.aliyuncs.com
+ LTAI5tRN9T5Tz1QExcSpUaBc
+ LniIMK15XEOc6Nn5mOrtX399FkVfQd
+ baogutang
+ ${appEnv}
+
+
+ ${appId}
+
+
+
+ 3000
+ 4096
+ 3145728
+ 104857600
+ 3
+ 8
+
+
+ Asia/Shanghai
+
+ yyyy-MM-dd HH:mm:ss.SSS
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{X-Request-Id}] [%thread] %logger{0}: %msg
+
+
+
+
+ INFO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baogutang-common/pom.xml b/baogutang-common/pom.xml
new file mode 100644
index 0000000..912d22d
--- /dev/null
+++ b/baogutang-common/pom.xml
@@ -0,0 +1,139 @@
+
+
+ 4.0.0
+
+ top.baogutang
+ baogutang-parent
+ 1.0.0-SNAPSHOT
+
+
+ baogutang-common
+
+
+ 8
+ 8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+ org.springframework.boot
+ spring-boot-starter-integration
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.springframework.cloud
+ spring-cloud-context
+
+
+ org.springframework.integration
+ spring-integration-redis
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ com.alibaba
+ fastjson
+
+
+ org.projectlombok
+ lombok
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.commons
+ commons-pool2
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ commons-lang
+ commons-lang
+
+
+ io.swagger
+ swagger-annotations
+ 1.5.22
+
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+ com.aliyun.openservices
+ ons-client
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+
+
+ com.aliyun
+ aliyun-java-sdk-green
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+
+
+
+ com.aliyun
+ tea-openapi
+ 0.2.2
+
+
+
+ io.searchbox
+ jest
+ 6.3.1
+
+
+
+ io.searchbox
+ jest-common
+ 6.3.1
+
+
+ com.zjiecode
+ wxpusher-java-sdk
+ 2.1.4
+
+
+
+
\ No newline at end of file
diff --git a/baogutang-common/src/main/java/top/baogutang/common/annotation/LoginRequired.java b/baogutang-common/src/main/java/top/baogutang/common/annotation/LoginRequired.java
new file mode 100644
index 0000000..178ed97
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/annotation/LoginRequired.java
@@ -0,0 +1,20 @@
+package top.baogutang.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 11:31
+ */
+@Documented
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LoginRequired {
+
+ boolean required() default true;
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/annotation/RequestLimit.java b/baogutang-common/src/main/java/top/baogutang/common/annotation/RequestLimit.java
new file mode 100644
index 0000000..49dfd73
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/annotation/RequestLimit.java
@@ -0,0 +1,37 @@
+package top.baogutang.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:04
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface RequestLimit {
+
+ /**
+ * 指定时间内不可重复提交,单位秒
+ */
+ long timeout() default 1;
+
+ /**
+ * 时间单位
+ */
+ TimeUnit timeUnit() default TimeUnit.SECONDS;
+
+ /**
+ * 指定key
+ */
+ String key() default "";
+
+ /**
+ * 是否限制单个人的, 包含token
+ */
+ boolean includeToken() default true;
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/annotation/VerifyRequired.java b/baogutang-common/src/main/java/top/baogutang/common/annotation/VerifyRequired.java
new file mode 100644
index 0000000..d72fd2d
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/annotation/VerifyRequired.java
@@ -0,0 +1,18 @@
+package top.baogutang.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:07
+ */
+@Documented
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface VerifyRequired {
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/aspect/LogAspect.java b/baogutang-common/src/main/java/top/baogutang/common/aspect/LogAspect.java
new file mode 100644
index 0000000..5e73c6d
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/aspect/LogAspect.java
@@ -0,0 +1,65 @@
+package top.baogutang.common.aspect;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import top.baogutang.common.domain.Results;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:16
+ */
+@Slf4j
+@Aspect
+@Component
+public class LogAspect {
+
+
+ @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
+ public void logPointCut() {
+ //pointCut
+
+ }
+
+ @Around("logPointCut()")
+ public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
+ Object result;
+ RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+ ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+ assert sra != null;
+ HttpServletRequest request = sra.getRequest();
+ String requestId = MDC.get("X-Request-Id");
+ long startMills = System.currentTimeMillis();
+ long cost = 0;
+ try {
+ result = pjp.proceed();
+ cost = System.currentTimeMillis() - startMills;
+ log.info("请求结束!本次请求耗时:{},url: {}, method: {}, params: {},user:{}, token: {}, 响应结果:{}",
+ cost, request.getRequestURL().toString(),
+ request.getMethod(), pjp.getArgs(), JSON.toJSONString(request.getAttribute("user")), request.getHeader("authorization"),
+ JSON.toJSONString(result, SerializerFeature.DisableCircularReferenceDetect));
+ if (result instanceof Results) {
+ Results r = (Results) result;
+ r.setRid(requestId);
+ }
+ } catch (Exception e) {
+ log.error("请求异常!!!本次请求耗时:{},error:{},url: {}, method: {}, params: {},user:{}, token: {}", cost, e, request.getRequestURL().toString(),
+ request.getMethod(), pjp.getArgs(), JSON.toJSONString(request.getAttribute("user")), request.getHeader("token"));
+ throw e;
+ }
+ return result;
+ }
+
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/aspect/LoginRequiredAspect.java b/baogutang-common/src/main/java/top/baogutang/common/aspect/LoginRequiredAspect.java
new file mode 100644
index 0000000..a9b3fb3
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/aspect/LoginRequiredAspect.java
@@ -0,0 +1,115 @@
+package top.baogutang.common.aspect;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import top.baogutang.common.annotation.LoginRequired;
+import top.baogutang.common.components.TokenComponent;
+import top.baogutang.common.constants.CacheConstant;
+import top.baogutang.common.domain.JwtBody;
+import top.baogutang.common.domain.TokenCodeEnum;
+import top.baogutang.common.exceptions.BusinessException;
+import top.baogutang.common.utils.UserThreadLocal;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+import static top.baogutang.common.constants.JwtConstant.AUTHORIZATION;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 11:32
+ */
+@Slf4j
+@Aspect
+@Component
+public class LoginRequiredAspect {
+
+ @Resource
+ private TokenComponent tokenComponent;
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Pointcut("@annotation(top.baogutang.common.annotation.LoginRequired)")
+ public void point() {
+ }
+
+ @Before(value = "point() && @annotation(loginRequired)")
+ public void verifyTokenForClass(LoginRequired loginRequired) {
+ if (loginRequired.required()) {
+ checkToken();
+ } else {
+ checkTokenWithOutRequired();
+ }
+ }
+
+ @After("point()")
+ public void after() {
+ UserThreadLocal.remove();
+ }
+
+ private void checkToken() {
+
+ ServletRequestAttributes requestAttributes =
+ (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (Objects.isNull(requestAttributes)) {
+ return;
+ }
+ HttpServletRequest request = requestAttributes.getRequest();
+ String token = request.getHeader(AUTHORIZATION);
+ if (StringUtils.isEmpty(token)) {
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_TOKEN_EMPTY.getCode(), TokenCodeEnum.AUTH_TOKEN_EMPTY.getMessage());
+ }
+
+ log.info("request url:{},method:{}", request.getRequestURL(), request.getMethod());
+ JwtBody body = tokenComponent.parseToken(token);
+ Long userId = body.getId();
+ Object val = redisTemplate.opsForValue().get(CacheConstant.TOKEN + userId);
+ if (Objects.isNull(val)) {
+ redisTemplate.opsForValue().set(CacheConstant.TOKEN + userId, token);
+ } else {
+ //比对token、不相同则判断token生产时间,取最新的覆盖
+ String redisToken = String.valueOf(val);
+ if (!token.equals(redisToken)) {
+ JwtBody redisBody = tokenComponent.parseToken(redisToken);
+ if (body.getIat() > redisBody.getIat()) {
+ log.info("newTokenCover,currentBody:{} redisBody:{}", JSON.toJSONString(body), JSON.toJSONString(redisBody));
+ redisTemplate.opsForValue().set(CacheConstant.TOKEN + userId, token);
+ } else {
+ log.info("FoundOldToken,currentBody:{} redisBody:{}", JSON.toJSONString(body), JSON.toJSONString(redisBody));
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_FAILED.getCode(), TokenCodeEnum.AUTH_FAILED.getMessage());
+ }
+ }
+ }
+ UserThreadLocal.set(body.getId());
+ }
+
+ private void checkTokenWithOutRequired() {
+ ServletRequestAttributes requestAttributes =
+ (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (Objects.isNull(requestAttributes)) {
+ return;
+ }
+ HttpServletRequest request = requestAttributes.getRequest();
+ String token = request.getHeader(AUTHORIZATION);
+ if (StringUtils.isNotEmpty(token)) {
+ log.info("request url:{},method:{}", request.getRequestURL(), request.getMethod());
+ JwtBody body = tokenComponent.parseToken(token);
+ UserThreadLocal.set(body.getId());
+ }
+ }
+
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/aspect/RequestLimitAspect.java b/baogutang-common/src/main/java/top/baogutang/common/aspect/RequestLimitAspect.java
new file mode 100644
index 0000000..ff9cc76
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/aspect/RequestLimitAspect.java
@@ -0,0 +1,127 @@
+package top.baogutang.common.aspect;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import top.baogutang.common.annotation.RequestLimit;
+import top.baogutang.common.domain.Results;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:05
+ */
+@Slf4j
+@Aspect
+@Component
+public class RequestLimitAspect {
+
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Pointcut("@annotation(top.baogutang.common.annotation.RequestLimit)")
+ public void limit() {
+ }
+
+ @Around("limit()")
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ String ip = getIpAddress(request);
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ Method method = signature.getMethod();
+ RequestLimit requestLimit = method.getAnnotation(RequestLimit.class);
+ if (requestLimit != null) {
+ String key = requestLimit.key();
+ if (StringUtils.isEmpty(key)) {
+ String className = method.getDeclaringClass().getName();
+ String name = method.getName();
+ String args = Arrays.toString(point.getArgs());
+ String ipKey = String.format("%s#%s#%s", className, name, args);
+ int hashCode = Math.abs(ipKey.hashCode());
+ key = String.format("%s_%d", ip, hashCode);
+ }
+ if (requestLimit.includeToken()) {
+ String token = request.getHeader("authorization");
+ if (token != null) {
+ key = key.concat("_").concat(DigestUtils.md5Hex(token));
+ }
+ }
+ long timeout = requestLimit.timeout();
+ TimeUnit timeUnit = requestLimit.timeUnit();
+ if (timeout < 0) {
+ //过期时间5s
+ timeout = 5;
+ }
+ Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, "1", timeout, timeUnit);
+ if (!Boolean.TRUE.equals(lock)) {
+ return Results.failed("正在赶来中,请稍后再试~");
+ }
+ }
+ return point.proceed();
+ }
+
+ /**
+ * 获取请求用户的IP地址
+ *
+ * @param request request
+ * @return return
+ */
+ public String getIpAddress(HttpServletRequest request) {
+
+ String ipAddresses = request.getHeader("x-forwarded-for");
+
+ ipAddresses = getString(request, ipAddresses);
+
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+ //X-Real-IP:nginx服务代理
+ ipAddresses = request.getHeader("X-Real-IP");
+ }
+
+ //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
+ if (ipAddresses != null && ipAddresses.length() != 0) {
+ ipAddresses = ipAddresses.split(",")[0];
+ }
+
+ //还是不能获取到,最后再通过request.getRemoteAddr();获取
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+ ipAddresses = request.getRemoteAddr();
+ }
+
+ return ipAddresses;
+ }
+
+ public static String getString(HttpServletRequest request, String ipAddresses) {
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+ //Proxy-Client-IP:apache 服务代理
+ ipAddresses = request.getHeader("Proxy-Client-IP");
+ }
+
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+ //WL-Proxy-Client-IP:weblogic 服务代理
+ ipAddresses = request.getHeader("WL-Proxy-Client-IP");
+ }
+
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
+ //HTTP_CLIENT_IP:有些代理服务器
+ ipAddresses = request.getHeader("HTTP_CLIENT_IP");
+ }
+ return ipAddresses;
+ }
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/aspect/VerifyRequiredAspect.java b/baogutang-common/src/main/java/top/baogutang/common/aspect/VerifyRequiredAspect.java
new file mode 100644
index 0000000..b2feb61
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/aspect/VerifyRequiredAspect.java
@@ -0,0 +1,100 @@
+package top.baogutang.common.aspect;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import top.baogutang.common.annotation.VerifyRequired;
+import top.baogutang.common.components.TokenComponent;
+import top.baogutang.common.constants.CacheConstant;
+import top.baogutang.common.domain.JwtBody;
+import top.baogutang.common.domain.Results;
+import top.baogutang.common.domain.TokenCodeEnum;
+import top.baogutang.common.exceptions.BusinessException;
+import top.baogutang.common.utils.UserThreadLocal;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+import static top.baogutang.common.constants.ErrorCodeEnum.E_BIZ_NEED_VERIFY;
+import static top.baogutang.common.constants.JwtConstant.AUTHORIZATION;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:07
+ */
+@Slf4j
+@Aspect
+@Component
+public class VerifyRequiredAspect {
+
+
+ @Resource
+ private TokenComponent tokenComponent;
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Pointcut("@annotation(top.baogutang.common.annotation.VerifyRequired)")
+ public void verify() {
+ }
+
+ @Around("verify()")
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ Method method = signature.getMethod();
+ VerifyRequired verifyRequired = method.getAnnotation(VerifyRequired.class);
+ if (verifyRequired != null) {
+ String token = request.getHeader(AUTHORIZATION);
+ if (StringUtils.isBlank(token)) {
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_TOKEN_EMPTY.getCode(), TokenCodeEnum.AUTH_TOKEN_EMPTY.getMessage());
+ }
+ JwtBody body = tokenComponent.parseToken(token);
+ Long userId = body.getId();
+ UserThreadLocal.set(userId);
+ if (Objects.isNull(redisTemplate.opsForValue().get(CacheConstant.USER_VERIFY_KEY_PREFIX + userId))) {
+ return Results.failed(E_BIZ_NEED_VERIFY.getCode(), E_BIZ_NEED_VERIFY.getMsg());
+ }
+ Object val = redisTemplate.opsForValue().get(CacheConstant.TOKEN + userId);
+ if (Objects.isNull(val)) {
+ redisTemplate.opsForValue().set(CacheConstant.TOKEN + userId, token);
+ } else {
+ //比对token、不相同则判断token生产时间,取最新的覆盖
+ String redisToken = String.valueOf(val);
+ if (!token.equals(redisToken)) {
+ JwtBody redisBody = tokenComponent.parseToken(redisToken);
+ if (body.getIat() > redisBody.getIat()) {
+ log.info("VerifyNewTokenCover,currentBody:{} redisBody:{}", JSON.toJSONString(body), JSON.toJSONString(redisBody));
+ redisTemplate.opsForValue().set(CacheConstant.TOKEN + userId, token);
+ } else {
+ log.info("FoundOldToken,currentBody:{} redisBody:{}", JSON.toJSONString(body), JSON.toJSONString(redisBody));
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_FAILED.getCode(), TokenCodeEnum.AUTH_FAILED.getMessage());
+ }
+ }
+ }
+
+ }
+ return point.proceed();
+ }
+
+ @After("verify()")
+ public void after() {
+ UserThreadLocal.remove();
+ }
+
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/components/TokenComponent.java b/baogutang-common/src/main/java/top/baogutang/common/components/TokenComponent.java
new file mode 100644
index 0000000..ccd1174
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/components/TokenComponent.java
@@ -0,0 +1,109 @@
+package top.baogutang.common.components;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Base64Utils;
+import top.baogutang.common.domain.JwtBody;
+import top.baogutang.common.domain.TokenCodeEnum;
+import top.baogutang.common.exceptions.BusinessException;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static top.baogutang.common.constants.JwtConstant.ALGORITHM_FAMILY_NAME;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 11:45
+ */
+@Slf4j
+@Component
+public class TokenComponent {
+ @Value("${jwt.publicKey:1}")
+ private String publicKey;
+
+ public JwtBody parseToken(String token) {
+ log.info("parse token:{}", token);
+ Jws claimsJws;
+ try {
+ claimsJws = Jwts.parser().setSigningKey(publicKeyFromBase64()).parseClaimsJws(token);
+ } catch (ExpiredJwtException expiredJwtException) {
+ return new JwtBody(expiredJwtException.getClaims());
+
+ } catch (JwtException e) {
+ if (e.getMessage().contains("expired")) {
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_TIME_OUT.getCode(), TokenCodeEnum.AUTH_TIME_OUT.getMessage());
+ }
+ throw new BusinessException(
+ TokenCodeEnum.AUTH_FAILED.getCode(), TokenCodeEnum.AUTH_FAILED.getMessage());
+ }
+ return new JwtBody(claimsJws.getBody());
+ }
+
+ public static String createToken(String data, long secondTime, String subject) {
+ JwtBuilder jwtBuilder = Jwts.builder();
+ subject = subject != null ? subject : UUID.randomUUID().toString();
+ Map map = new HashMap<>();
+ if (StringUtils.isNotEmpty(data)) {
+ map.put("data", data);
+ }
+ jwtBuilder.setClaims(map).setSubject(subject);
+ long currentTime = System.currentTimeMillis();
+ if (secondTime == 0) {
+ currentTime += 30 * 60 * 1000;
+ } else {
+ currentTime += secondTime * 1000;
+ }
+ Date newDate = new Date(currentTime);
+ jwtBuilder.setExpiration(newDate);
+ return jwtBuilder.signWith(SignatureAlgorithm.ES256, privateKeyFromBase64()).compact();
+ }
+
+ private static PrivateKey privateKeyFromBase64() {
+ try {
+ byte[] keyBytes = Base64Utils.decodeFromString("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn9N3dA834ctlm7jkBXcRvR4+/hnYjZvYO1s5hisWG0yhRANCAAR91zvPpA/9Mc4DtxAWwWsnhj1rGk0XmTNqdnfPQJmLazYXaUvEuYuR+SNf6pl0OH2jLoAsXUFYtIFUzV/qv9ph");
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_FAMILY_NAME);
+ return keyFactory.generatePrivate(keySpec);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 公钥64位序列化
+ *
+ * @return PublicKey
+ */
+ private PublicKey publicKeyFromBase64() {
+ try {
+ byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_FAMILY_NAME);
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/ExecutorConfig.java b/baogutang-common/src/main/java/top/baogutang/common/config/ExecutorConfig.java
new file mode 100644
index 0000000..ddf797a
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/ExecutorConfig.java
@@ -0,0 +1,49 @@
+package top.baogutang.common.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @description: 线程池配置
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:18
+ */
+@Slf4j
+@Configuration
+public class ExecutorConfig {
+
+ @Value("${spring.application.name}")
+ private String appName;
+
+ @Value("${thread.pool.core.pool.size:10}")
+ private Integer corePoolSize;
+
+ @Value("${thread.pool.max.pool.size:20}")
+ private Integer maxPoolSize;
+
+ @Value("${thread.pool.keep.alive.second:10}")
+ private Integer keepAliveSecond;
+
+ @Value("${thread.pool.queue.capacity:200}")
+ private Integer queueCapacity;
+
+ @Bean("commonExecutor")
+ public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setThreadNamePrefix(appName);
+ executor.setCorePoolSize(corePoolSize);
+ executor.setMaxPoolSize(maxPoolSize);
+ executor.setKeepAliveSeconds(keepAliveSecond);
+ executor.setQueueCapacity(queueCapacity);
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+ executor.setWaitForTasksToCompleteOnShutdown(true);
+ executor.initialize();
+ return executor;
+ }
+
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/GlobalCorsConfig.java b/baogutang-common/src/main/java/top/baogutang/common/config/GlobalCorsConfig.java
new file mode 100644
index 0000000..b89c0e1
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/GlobalCorsConfig.java
@@ -0,0 +1,37 @@
+package top.baogutang.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @description: 全局跨域配置
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:19
+ */
+@Configuration
+public class GlobalCorsConfig {
+
+ @Bean
+ public WebMvcConfigurer corsConfigurer() {
+ return new WebMvcConfigurer() {
+ @Override
+ //重写父类提供的跨域请求处理的接口
+ public void addCorsMappings(CorsRegistry registry) {
+ //添加映射路径
+ registry.addMapping("/**")
+ //放行哪些原始域
+ .allowedOrigins("*")
+ //是否发送Cookie信息
+ .allowCredentials(true)
+ //放行哪些原始域(请求方式)
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+ //放行哪些原始域(头部信息)
+ .allowedHeaders("*")
+ //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
+ .exposedHeaders("Header1", "Header2");
+ }
+ };
+ }
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/GlobalMDCTaskDecorator.java b/baogutang-common/src/main/java/top/baogutang/common/config/GlobalMDCTaskDecorator.java
new file mode 100644
index 0000000..7390929
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/GlobalMDCTaskDecorator.java
@@ -0,0 +1,45 @@
+package top.baogutang.common.config;
+
+import org.slf4j.MDC;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.TaskDecorator;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.Map;
+
+/**
+ * @description: 多线程链路ID
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:20
+ */
+@Configuration
+public class GlobalMDCTaskDecorator implements TaskDecorator, BeanPostProcessor {
+
+
+ @Override
+ public Runnable decorate(Runnable runnable) {
+ Map mdcContext = MDC.getCopyOfContextMap();
+ return () -> {
+ try {
+ if (mdcContext != null) {
+ MDC.setContextMap(mdcContext);
+ }
+ runnable.run();
+ } finally {
+ MDC.clear();
+ }
+ };
+ }
+
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof ThreadPoolTaskExecutor) {
+ ((ThreadPoolTaskExecutor) bean).setTaskDecorator(this);
+ }
+ return bean;
+ }
+
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/MdcRequestIdFilter.java b/baogutang-common/src/main/java/top/baogutang/common/config/MdcRequestIdFilter.java
new file mode 100644
index 0000000..5f6516f
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/MdcRequestIdFilter.java
@@ -0,0 +1,44 @@
+package top.baogutang.common.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * @description:
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:25
+ */
+@Slf4j
+@Component
+@Order(1)
+public class MdcRequestIdFilter extends OncePerRequestFilter {
+
+ private static final String REQUEST_ID_KEY = "X-Request-Id";
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+ try {
+ String traceId = request.getHeader(REQUEST_ID_KEY);
+ if (traceId == null) {
+ traceId = UUID.randomUUID().toString().replace("-", "");
+ log.info("requestId为空,自动生成 {}", traceId);
+ request.setAttribute(REQUEST_ID_KEY, traceId);
+ }
+ MDC.put(REQUEST_ID_KEY, traceId);
+ filterChain.doFilter(request, response);
+ } finally {
+ MDC.remove(REQUEST_ID_KEY);
+ }
+
+ }
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/MybatisPlusConfig.java b/baogutang-common/src/main/java/top/baogutang/common/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..16f5b7a
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/MybatisPlusConfig.java
@@ -0,0 +1,27 @@
+package top.baogutang.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+
+/**
+ * @description:
+ * @author: developer
+ * @date: 2022/05/26 : 15:51
+ */
+@Configuration
+public class MybatisPlusConfig {
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ //分页插件
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ //乐观锁插件
+ interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
+ return interceptor;
+ }
+}
diff --git a/baogutang-common/src/main/java/top/baogutang/common/config/RedisConfig.java b/baogutang-common/src/main/java/top/baogutang/common/config/RedisConfig.java
new file mode 100644
index 0000000..d47831f
--- /dev/null
+++ b/baogutang-common/src/main/java/top/baogutang/common/config/RedisConfig.java
@@ -0,0 +1,85 @@
+package top.baogutang.common.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.integration.redis.util.RedisLockRegistry;
+import org.springframework.scripting.support.ResourceScriptSource;
+
+import java.net.UnknownHostException;
+
+/**
+ * @description: 缓存配置
+ * @author: nikooh
+ * @date: 2023/06/15 : 12:21
+ */
+@Slf4j
+@EnableCaching
+@Configuration
+public class RedisConfig {
+
+
+ @Bean
+ @SuppressWarnings("all")
+ public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
+ // 为了开发方便,直接使用
+ RedisTemplate template = new RedisTemplate();
+ template.setConnectionFactory(redisConnectionFactory);
+
+ // Json 配置序列化
+ // 使用 jackson 解析任意的对象
+ Jackson2JsonRedisSerializer