From dc534d7ee6c58e8e74102162d96535a8009c3a24 Mon Sep 17 00:00:00 2001
From: ivmiku <124345843+ivmiku@users.noreply.github.com>
Date: Sat, 3 Aug 2024 20:30:51 +0800
Subject: [PATCH] repo init
---
.gitignore | 38 ++++
.idea/.gitignore | 8 +
.idea/ApifoxUploaderProjectSetting.xml | 13 ++
.idea/encodings.xml | 13 ++
.idea/inspectionProfiles/Project_Default.xml | 66 ++++++
.idea/misc.xml | 14 ++
commons/pom.xml | 31 +++
.../com/ivmiku/tutorial/response/Result.java | 53 +++++
.../ivmiku/tutorial/response/ResultCode.java | 17 ++
gateway-8133/pom.xml | 111 ++++++++++
.../java/com/ivmiku/tutorial/Main8133.java | 11 +
.../tutorial/component/ForwardAuthFilter.java | 28 +++
.../tutorial/component/StpInterfaceImpl.java | 27 +++
.../tutorial/config/SaTokenConfigure.java | 36 ++++
.../tutorial/config/SentinelConfig.java | 80 ++++++++
.../main/resources/application-dep.properties | 16 ++
.../main/resources/application-dev.properties | 15 ++
.../src/main/resources/application.properties | 1 +
pom.xml | 189 ++++++++++++++++++
user-8072/pom.xml | 141 +++++++++++++
.../java/com/ivmiku/tutorial/Main8072.java | 13 ++
.../ivmiku/tutorial/config/RedisConfig.java | 30 +++
.../tutorial/config/WxMaConfiguration.java | 128 ++++++++++++
.../tutorial/config/WxMaProperties.java | 42 ++++
.../tutorial/controller/UserController.java | 59 ++++++
.../java/com/ivmiku/tutorial/entity/User.java | 14 ++
.../ivmiku/tutorial/mapper/UserMapper.java | 7 +
.../utils/GlobalExceptionHandler.java | 61 ++++++
.../com/ivmiku/tutorial/utils/RedisUtil.java | 22 ++
.../main/resources/application-dep.properties | 21 ++
.../main/resources/application-dev.properties | 15 ++
.../src/main/resources/application.properties | 1 +
32 files changed, 1321 insertions(+)
create mode 100644 .gitignore
create mode 100644 .idea/.gitignore
create mode 100644 .idea/ApifoxUploaderProjectSetting.xml
create mode 100644 .idea/encodings.xml
create mode 100644 .idea/inspectionProfiles/Project_Default.xml
create mode 100644 .idea/misc.xml
create mode 100644 commons/pom.xml
create mode 100644 commons/src/main/java/com/ivmiku/tutorial/response/Result.java
create mode 100644 commons/src/main/java/com/ivmiku/tutorial/response/ResultCode.java
create mode 100644 gateway-8133/pom.xml
create mode 100644 gateway-8133/src/main/java/com/ivmiku/tutorial/Main8133.java
create mode 100644 gateway-8133/src/main/java/com/ivmiku/tutorial/component/ForwardAuthFilter.java
create mode 100644 gateway-8133/src/main/java/com/ivmiku/tutorial/component/StpInterfaceImpl.java
create mode 100644 gateway-8133/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java
create mode 100644 gateway-8133/src/main/java/com/ivmiku/tutorial/config/SentinelConfig.java
create mode 100644 gateway-8133/src/main/resources/application-dep.properties
create mode 100644 gateway-8133/src/main/resources/application-dev.properties
create mode 100644 gateway-8133/src/main/resources/application.properties
create mode 100644 pom.xml
create mode 100644 user-8072/pom.xml
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/Main8072.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/config/RedisConfig.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaConfiguration.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaProperties.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java
create mode 100644 user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
create mode 100644 user-8072/src/main/resources/application-dep.properties
create mode 100644 user-8072/src/main/resources/application-dev.properties
create mode 100644 user-8072/src/main/resources/application.properties
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/ApifoxUploaderProjectSetting.xml b/.idea/ApifoxUploaderProjectSetting.xml
new file mode 100644
index 0000000..67e678c
--- /dev/null
+++ b/.idea/ApifoxUploaderProjectSetting.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..240ee29
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..85fda15
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..fdc35ea
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/commons/pom.xml b/commons/pom.xml
new file mode 100644
index 0000000..1bf709a
--- /dev/null
+++ b/commons/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ com.ivmiku.tutorial
+ first-tutorial
+ 1.0-SNAPSHOT
+
+
+ commons
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
\ No newline at end of file
diff --git a/commons/src/main/java/com/ivmiku/tutorial/response/Result.java b/commons/src/main/java/com/ivmiku/tutorial/response/Result.java
new file mode 100644
index 0000000..479a967
--- /dev/null
+++ b/commons/src/main/java/com/ivmiku/tutorial/response/Result.java
@@ -0,0 +1,53 @@
+package com.ivmiku.tutorial.response;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result implements Serializable {
+ @JSONField(ordinal = 1)
+ private int code;
+ @JSONField(ordinal = 2)
+ private String message;
+ @JSONField(ordinal = 3)
+ private Object data = null;
+
+ public Result(ResultCode resultCode) {
+ this.code = resultCode.getCode();
+ this.message = resultCode.getMessage();
+ }
+
+ public Result(ResultCode resultCode, Object data) {
+ this.code = resultCode.getCode();
+ this.message = resultCode.getMessage();
+ this.data = data;
+ }
+
+ public static Result ok(){
+ return new Result(200, "success", null);
+ }
+
+ public static Result error(){
+ return new Result(-1, "error", null);
+ }
+
+ public static Result ok(Object data){
+ return new Result(200, "success", data);
+ }
+
+ public static Result ok(String message){
+ return new Result(200, message, null);
+ }
+
+ public static Result error(String message){
+ return new Result(-1, message, null);
+ }
+
+
+}
diff --git a/commons/src/main/java/com/ivmiku/tutorial/response/ResultCode.java b/commons/src/main/java/com/ivmiku/tutorial/response/ResultCode.java
new file mode 100644
index 0000000..3f03573
--- /dev/null
+++ b/commons/src/main/java/com/ivmiku/tutorial/response/ResultCode.java
@@ -0,0 +1,17 @@
+package com.ivmiku.tutorial.response;
+
+import lombok.Getter;
+
+@Getter
+public enum ResultCode {
+ OK(200, "success"),
+ ERROR(-1, "error");
+
+ private int code;
+ private String message;
+
+ ResultCode(int code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git a/gateway-8133/pom.xml b/gateway-8133/pom.xml
new file mode 100644
index 0000000..35a8bee
--- /dev/null
+++ b/gateway-8133/pom.xml
@@ -0,0 +1,111 @@
+
+
+ 4.0.0
+
+ com.ivmiku.tutorial
+ first-tutorial
+ 1.0-SNAPSHOT
+
+
+ gateway-8133
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ cn.dev33
+ sa-token-reactor-spring-boot3-starter
+ 1.38.0
+
+
+
+ cn.dev33
+ sa-token-redis-jackson
+ 1.38.0
+
+
+ org.apache.commons
+ commons-pool2
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ io.micrometer
+ micrometer-tracing
+
+
+
+ io.micrometer
+ micrometer-tracing-bridge-brave
+
+
+
+ io.micrometer
+ micrometer-observation
+
+
+
+ io.zipkin.reporter2
+ zipkin-reporter-brave
+
+
+ com.alibaba.csp
+ sentinel-transport-simple-http
+ 1.8.6
+
+
+ com.alibaba.csp
+ sentinel-spring-cloud-gateway-adapter
+ 1.8.6
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.0.13
+
+ com.ivmiku.tutorial.Main8133
+ JAR
+
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gateway-8133/src/main/java/com/ivmiku/tutorial/Main8133.java b/gateway-8133/src/main/java/com/ivmiku/tutorial/Main8133.java
new file mode 100644
index 0000000..954215d
--- /dev/null
+++ b/gateway-8133/src/main/java/com/ivmiku/tutorial/Main8133.java
@@ -0,0 +1,11 @@
+package com.ivmiku.tutorial;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Main8133 {
+ public static void main(String[] args) {
+ SpringApplication.run(Main8133.class, args);
+ }
+}
\ No newline at end of file
diff --git a/gateway-8133/src/main/java/com/ivmiku/tutorial/component/ForwardAuthFilter.java b/gateway-8133/src/main/java/com/ivmiku/tutorial/component/ForwardAuthFilter.java
new file mode 100644
index 0000000..affa686
--- /dev/null
+++ b/gateway-8133/src/main/java/com/ivmiku/tutorial/component/ForwardAuthFilter.java
@@ -0,0 +1,28 @@
+package com.ivmiku.tutorial.component;
+
+import cn.dev33.satoken.same.SaSameUtil;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * 全局过滤器,为请求添加 Same-Token
+ */
+@Component
+public class ForwardAuthFilter implements GlobalFilter {
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ ServerHttpRequest newRequest = exchange
+ .getRequest()
+ .mutate()
+ // 为请求追加 Same-Token 参数
+ .header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken())
+ .build();
+ ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
+ return chain.filter(newExchange);
+ }
+}
+
diff --git a/gateway-8133/src/main/java/com/ivmiku/tutorial/component/StpInterfaceImpl.java b/gateway-8133/src/main/java/com/ivmiku/tutorial/component/StpInterfaceImpl.java
new file mode 100644
index 0000000..aa3adaf
--- /dev/null
+++ b/gateway-8133/src/main/java/com/ivmiku/tutorial/component/StpInterfaceImpl.java
@@ -0,0 +1,27 @@
+package com.ivmiku.tutorial.component;
+
+import cn.dev33.satoken.stp.StpInterface;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 自定义权限验证接口扩展
+ */
+@Component
+public class StpInterfaceImpl implements StpInterface {
+
+ @Override
+ public List getPermissionList(Object loginId, String loginType) {
+ // 返回此 loginId 拥有的权限列表
+ return null;
+ }
+
+ @Override
+ public List getRoleList(Object loginId, String loginType) {
+ // 返回此 loginId 拥有的角色列表
+ return null;
+ }
+
+}
+
diff --git a/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java b/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java
new file mode 100644
index 0000000..59bfbdc
--- /dev/null
+++ b/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java
@@ -0,0 +1,36 @@
+package com.ivmiku.tutorial.config;
+
+import cn.dev33.satoken.reactor.filter.SaReactorFilter;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * [Sa-Token 权限认证] 配置类
+ * @author click33
+ */
+@Configuration
+public class SaTokenConfigure {
+ // 注册 Sa-Token全局过滤器
+ @Bean
+ public SaReactorFilter getSaReactorFilter() {
+ return new SaReactorFilter()
+ // 拦截地址
+ .addInclude("/**") /* 拦截全部path */
+ // 开放地址
+ .addExclude("/favicon.ico")
+ // 鉴权方法:每次访问进入
+ .setAuth(obj -> {
+ // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
+ SaRouter.match("/**", "/user/**", r -> StpUtil.checkLogin());
+ })
+ // 异常处理方法:每次setAuth函数出现异常时进入
+ .setError(e -> {
+ return SaResult.error(e.getMessage());
+ })
+ ;
+ }
+}
+
diff --git a/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SentinelConfig.java b/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SentinelConfig.java
new file mode 100644
index 0000000..62aaecc
--- /dev/null
+++ b/gateway-8133/src/main/java/com/ivmiku/tutorial/config/SentinelConfig.java
@@ -0,0 +1,80 @@
+package com.ivmiku.tutorial.config;
+
+import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
+import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
+import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayParamFlowItem;
+import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
+import jakarta.annotation.PostConstruct;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.codec.ServerCodecConfigurer;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.reactive.result.view.ViewResolver;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.*;
+
+@Configuration
+public class SentinelConfig {
+ private final List viewResolvers;
+ private final ServerCodecConfigurer serverCodecConfigurer;
+
+ public SentinelConfig(ObjectProvider> viewResolversProvider,
+ ServerCodecConfigurer serverCodecConfigurer) {
+ this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
+ this.serverCodecConfigurer = serverCodecConfigurer;
+ }
+
+ @Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
+ // Register the block exception handler for Spring Cloud Gateway.
+ return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
+ }
+
+ @Bean
+ @Order(-1)
+ public GlobalFilter sentinelGatewayFilter() {
+ return new SentinelGatewayFilter();
+ }
+
+ @PostConstruct
+ public void doInit() {
+ Set rules = new HashSet<>();
+ rules.add(new GatewayFlowRule("user")
+ .setCount(1)
+ .setIntervalSec(1)
+ );
+ rules.add(new GatewayFlowRule("user")
+ .setCount(2)
+ .setIntervalSec(2)
+ .setBurst(2)
+ .setParamItem(new GatewayParamFlowItem()
+ .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
+ )
+ );
+ GatewayRuleManager.loadRules(rules);
+ BlockRequestHandler handler = new BlockRequestHandler() {
+ @Override
+ public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
+ Map map = new HashMap<>();
+ map.put("code", -1);
+ map.put("message", "系统繁忙,请稍后再试!");
+ return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));
+ }
+ };
+ GatewayCallbackManager.setBlockHandler(handler);
+ }
+}
diff --git a/gateway-8133/src/main/resources/application-dep.properties b/gateway-8133/src/main/resources/application-dep.properties
new file mode 100644
index 0000000..55f6029
--- /dev/null
+++ b/gateway-8133/src/main/resources/application-dep.properties
@@ -0,0 +1,16 @@
+server.port=8133
+
+spring.application.name=gateway
+spring.cloud.nacos.discovery.server-addr=nacos:8848
+
+spring.data.redis.host=redis
+spring.data.redis.port=6379
+spring.data.redis.database=0
+spring.data.redis.password=Shuodedaoli114514
+
+spring.cloud.gateway.routes[0].id=user
+spring.cloud.gateway.routes[0].uri=lb://user
+spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
+
+management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
+management.tracing.sampling.probability=1.0
\ No newline at end of file
diff --git a/gateway-8133/src/main/resources/application-dev.properties b/gateway-8133/src/main/resources/application-dev.properties
new file mode 100644
index 0000000..12528ab
--- /dev/null
+++ b/gateway-8133/src/main/resources/application-dev.properties
@@ -0,0 +1,15 @@
+server.port=8133
+
+spring.application.name=gateway
+spring.cloud.nacos.discovery.server-addr=localhost:8848
+
+spring.data.redis.host=localhost
+spring.data.redis.port=6379
+spring.data.redis.database=0
+
+spring.cloud.gateway.routes[0].id=user
+spring.cloud.gateway.routes[0].uri=lb://user
+spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
+
+management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans
+management.tracing.sampling.probability=1.0
\ No newline at end of file
diff --git a/gateway-8133/src/main/resources/application.properties b/gateway-8133/src/main/resources/application.properties
new file mode 100644
index 0000000..0896b37
--- /dev/null
+++ b/gateway-8133/src/main/resources/application.properties
@@ -0,0 +1 @@
+spring.profiles.active=dep
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..8db85ab
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,189 @@
+
+
+ 4.0.0
+
+ com.ivmiku.tutorial
+ first-tutorial
+ 1.0-SNAPSHOT
+ pom
+
+ gateway-8133
+ user-8072
+ commons
+
+
+
+ 21
+ 21
+ UTF-8
+ 21
+ 21
+ UTF-8
+ 5.8.22
+ 1.18.30
+ 3.5.6
+ 8.0.11
+ 4.2.3
+ 2.0.40
+ 1.0.2
+ 3.1.5
+
+
+
+
+
+
+ 3.1.7
+ 2022.0.4
+
+ 2022.0.0.0-RC2
+ 1.2.0
+ 1.12.0
+ 12.5
+ 2.17.0
+ 1.38.0
+ 3.2.13
+ 4.6.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring.boot.version}
+ pom
+ import
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+
+ com.alibaba.cloud
+ spring-cloud-alibaba-dependencies
+ ${spring.cloud.alibaba.version}
+ pom
+ import
+
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ ${mybatis.springboot.version}
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+
+ javax.persistence
+ persistence-api
+ ${persistence-api.version}
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ ${fastjson2.version}
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${spring.boot.test.version}
+ test
+
+
+
+
+ io.micrometer
+ micrometer-tracing-bom
+ ${micrometer-tracing.version}
+ pom
+ import
+
+
+
+ io.micrometer
+ micrometer-tracing
+ ${micrometer-tracing.version}
+
+
+
+ io.micrometer
+ micrometer-tracing-bridge-brave
+ ${micrometer-tracing.version}
+
+
+
+ io.micrometer
+ micrometer-observation
+ ${micrometer-observation.version}
+
+
+
+ io.github.openfeign
+ feign-micrometer
+ ${feign-micrometer.version}
+
+
+
+ io.zipkin.reporter2
+ zipkin-reporter-brave
+ ${zipkin-reporter-brave.version}
+
+
+
+ cn.dev33
+ sa-token-spring-boot3-starter
+ ${satoken-version}
+
+
+
+ org.apache.dubbo
+ dubbo-registry-nacos
+ ${dubbo.version}
+
+
+
+ org.apache.dubbo
+ dubbo-bom
+ ${dubbo.version}
+ pom
+ import
+
+
+ com.github.binarywang
+ weixin-java-miniapp
+ ${wx.version}
+
+
+
+
\ No newline at end of file
diff --git a/user-8072/pom.xml b/user-8072/pom.xml
new file mode 100644
index 0000000..578e8f0
--- /dev/null
+++ b/user-8072/pom.xml
@@ -0,0 +1,141 @@
+
+
+ 4.0.0
+
+ com.ivmiku.tutorial
+ first-tutorial
+ 1.0-SNAPSHOT
+
+
+ user-8072
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ cn.dev33
+ sa-token-spring-boot3-starter
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+ cn.dev33
+ sa-token-redis-jackson
+ 1.38.0
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+ org.apache.dubbo
+ dubbo-spring-boot-starter
+
+
+
+ org.apache.dubbo
+ dubbo-registry-nacos
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ io.micrometer
+ micrometer-tracing
+
+
+
+ io.micrometer
+ micrometer-tracing-bridge-brave
+
+
+
+ io.micrometer
+ micrometer-observation
+
+
+
+ io.zipkin.reporter2
+ zipkin-reporter-brave
+
+
+ org.apache.dubbo
+ dubbo-spring-boot-tracing-brave-zipkin-starter
+ 3.2.13
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+ com.github.binarywang
+ weixin-java-miniapp
+
+
+ com.ivmiku.tutorial
+ commons
+ 1.0-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.0.13
+
+ com.ivmiku.tutorial.Main8072
+ JAR
+
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/Main8072.java b/user-8072/src/main/java/com/ivmiku/tutorial/Main8072.java
new file mode 100644
index 0000000..31a15fe
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/Main8072.java
@@ -0,0 +1,13 @@
+package com.ivmiku.tutorial;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.ivmiku.tutorial.mapper")
+public class Main8072 {
+ public static void main(String[] args) {
+ SpringApplication.run(Main8072.class, args);
+ }
+}
\ No newline at end of file
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/RedisConfig.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/RedisConfig.java
new file mode 100644
index 0000000..a1348ca
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/RedisConfig.java
@@ -0,0 +1,30 @@
+package com.ivmiku.tutorial.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+
+@Configuration
+public class RedisConfig {
+
+ @Bean
+ public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setConnectionFactory(lettuceConnectionFactory);
+ // 设置key序列化方式string,RedisSerializer.string() 等价于 new StringRedisSerializer()
+ redisTemplate.setKeySerializer(RedisSerializer.string());
+ // 设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化,RedisSerializer.json() 等价于 new GenericJackson2JsonRedisSerializer()
+ redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
+ // 设置hash的key的序列化方式
+ redisTemplate.setHashKeySerializer(RedisSerializer.string());
+ // 设置hash的value的序列化方式
+ redisTemplate.setHashValueSerializer(RedisSerializer.json());
+ // 使配置生效
+ redisTemplate.afterPropertiesSet();
+ return redisTemplate;
+ }
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaConfiguration.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaConfiguration.java
new file mode 100644
index 0000000..1fec235
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaConfiguration.java
@@ -0,0 +1,128 @@
+package com.ivmiku.tutorial.config;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
+import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
+import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
+import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(WxMaProperties.class)
+public class WxMaConfiguration {
+ private final WxMaProperties properties;
+
+ @Autowired
+ public WxMaConfiguration(WxMaProperties properties) {
+ this.properties = properties;
+ }
+
+ @Bean
+ public WxMaService wxMaService() {
+ List configs = this.properties.getConfigs();
+ if (configs == null) {
+ throw new WxRuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
+ }
+ WxMaService maService = new WxMaServiceImpl();
+ maService.setMultiConfigs(
+ configs.stream()
+ .map(a -> {
+ WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
+// WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
+ // 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
+ config.setAppid(a.getAppid());
+ config.setSecret(a.getSecret());
+ config.setToken(a.getToken());
+ config.setAesKey(a.getAesKey());
+ config.setMsgDataFormat(a.getMsgDataFormat());
+ return config;
+ }).collect(Collectors.toMap(WxMaDefaultConfigImpl::getAppid, a -> a, (o, n) -> o)));
+ return maService;
+ }
+
+ @Bean
+ public WxMaMessageRouter wxMaMessageRouter(WxMaService wxMaService) {
+ final WxMaMessageRouter router = new WxMaMessageRouter(wxMaService);
+ router
+ .rule().handler(logHandler).next()
+ .rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
+ .rule().async(false).content("文本").handler(textHandler).end()
+ .rule().async(false).content("图片").handler(picHandler).end()
+ .rule().async(false).content("二维码").handler(qrcodeHandler).end();
+ return router;
+ }
+
+ private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
+ service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
+ .templateId("此处更换为自己的模板id")
+ .data(Lists.newArrayList(
+ new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
+ .toUser(wxMessage.getFromUser())
+ .build());
+ return null;
+ };
+
+ private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
+ log.info("收到消息:" + wxMessage.toString());
+ service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
+ .toUser(wxMessage.getFromUser()).build());
+ return null;
+ };
+
+ private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
+ service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
+ .toUser(wxMessage.getFromUser()).build());
+ return null;
+ };
+
+ private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
+ try {
+ WxMediaUploadResult uploadResult = service.getMediaService()
+ .uploadMedia("image", "png",
+ ClassLoader.getSystemResourceAsStream("tmp.png"));
+ service.getMsgService().sendKefuMsg(
+ WxMaKefuMessage
+ .newImageBuilder()
+ .mediaId(uploadResult.getMediaId())
+ .toUser(wxMessage.getFromUser())
+ .build());
+ } catch (WxErrorException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ };
+
+ private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
+ try {
+ final File file = service.getQrcodeService().createQrcode("123", 430);
+ WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
+ service.getMsgService().sendKefuMsg(
+ WxMaKefuMessage
+ .newImageBuilder()
+ .mediaId(uploadResult.getMediaId())
+ .toUser(wxMessage.getFromUser())
+ .build());
+ } catch (WxErrorException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ };
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaProperties.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaProperties.java
new file mode 100644
index 0000000..8f0d290
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/WxMaProperties.java
@@ -0,0 +1,42 @@
+package com.ivmiku.tutorial.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+@Data
+@ConfigurationProperties(prefix = "wx.miniapp")
+public class WxMaProperties {
+
+ private List configs;
+
+ @Data
+ public static class Config {
+ /**
+ * 设置微信小程序的appid
+ */
+ private String appid;
+
+ /**
+ * 设置微信小程序的Secret
+ */
+ private String secret;
+
+ /**
+ * 设置微信小程序消息服务器配置的token
+ */
+ private String token;
+
+ /**
+ * 设置微信小程序消息服务器配置的EncodingAESKey
+ */
+ private String aesKey;
+
+ /**
+ * 消息格式,XML或者JSON
+ */
+ private String msgDataFormat;
+ }
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java b/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
new file mode 100644
index 0000000..f9aedfd
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
@@ -0,0 +1,59 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.entity.User;
+import com.ivmiku.tutorial.mapper.UserMapper;
+import com.ivmiku.tutorial.response.Result;
+import com.ivmiku.tutorial.utils.RedisUtil;
+import jakarta.annotation.Resource;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+
+@RestController
+@RequestMapping("/user")
+public class UserController {
+ @Resource
+ private WxMaService wxMaService;
+
+ @Resource
+ private UserMapper userMapper;
+
+ @Resource
+ private RedisUtil redisUtil;
+
+ @GetMapping("/login")
+ public Object login(@RequestParam(name = "code") String code, @RequestParam(name = "rawdata") String rawData, @RequestParam(name = "signature") String signature
+) {
+ WxMaJscode2SessionResult session;
+ try {
+ session = wxMaService.getUserService().getSessionInfo(code);
+ } catch (WxErrorException e) {
+ return JSON.toJSON(Result.error(e.getMessage()));
+ }
+ StpUtil.login(session.getOpenid());
+ HashMap map = new HashMap<>();
+ if (userMapper.selectById(session.getOpenid()) == null) {
+ if (!wxMaService.getUserService().checkUserInfo(session.getSessionKey(), rawData, signature)) {
+ WxMaConfigHolder.remove();//清理ThreadLocal
+ return JSON.toJSON(Result.error("用户数据验证错误!"));
+ }
+ JSONObject raw = JSONObject.parseObject(rawData);
+ User user = new User();
+ user.setOpenid(session.getOpenid());
+ user.setNickname(raw.getString("nickname"));
+ user.setAvatarUrl(raw.getString("avatarUrl"));
+ userMapper.insert(user);
+ }
+ map.put("token", StpUtil.getTokenValue());
+ redisUtil.insertKey(session.getOpenid(), session.getSessionKey());
+ WxMaConfigHolder.remove();
+ return JSON.toJSON(Result.ok(map));
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
new file mode 100644
index 0000000..35dbcc2
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
@@ -0,0 +1,14 @@
+package com.ivmiku.tutorial.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@TableName("user")
+@Data
+public class User {
+ @TableId
+ private String openid;
+ private String nickname;
+ private String avatarUrl;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
new file mode 100644
index 0000000..f220728
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
@@ -0,0 +1,7 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.User;
+
+public interface UserMapper extends BaseMapper {
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java b/user-8072/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java
new file mode 100644
index 0000000..bc0f099
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java
@@ -0,0 +1,61 @@
+package com.ivmiku.tutorial.utils;
+
+import cn.dev33.satoken.exception.SaTokenException;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.response.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+import java.sql.SQLException;
+import java.text.ParseException;
+
+/**
+ * @author Aurora
+ */
+@Slf4j
+@ControllerAdvice
+public class GlobalExceptionHandler {
+ @ExceptionHandler(value = SaTokenException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object SaTokenExceptionHandler(SaTokenException e) {
+ log.error("SaTokenException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("身份认证错误:" + e.getMessage()));
+ }
+
+ @ExceptionHandler(value = ParseException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object parseExceptionHandler(ParseException e) {
+
+ log.error("ParseException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("请检查日期是否合法"));
+ }
+
+ @ExceptionHandler(value = SQLException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object SQLExceptionHandler(SQLException e) {
+ log.error("SQLException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("数据库出错!(内部错误)\n" + e.getMessage()));
+ }
+
+ @ExceptionHandler(value = BlockException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object sentinelHandler(BlockException e) {
+ return JSON.toJSON(Result.error("系统繁忙,请稍后再试"));
+ }
+
+ @ExceptionHandler(value = Exception.class)
+ @ResponseBody
+ public Object exceptionHandler(Exception e) {
+ log.error("Exception:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("服务器内部错误:" + e.getClass() + ":" + e.getMessage()));
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java b/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
new file mode 100644
index 0000000..8ff2877
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
@@ -0,0 +1,22 @@
+package com.ivmiku.tutorial.utils;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Aurora
+ */
+@Component
+public class RedisUtil {
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ public void insertKey(String userId, String sessionKey) {
+ redisTemplate.opsForValue().set("sessionkey:" + userId, sessionKey);
+ }
+
+ public String getKey(String userId) {
+ return (String) redisTemplate.opsForValue().get("sessionkey:" + userId);
+ }
+}
diff --git a/user-8072/src/main/resources/application-dep.properties b/user-8072/src/main/resources/application-dep.properties
new file mode 100644
index 0000000..2e28acd
--- /dev/null
+++ b/user-8072/src/main/resources/application-dep.properties
@@ -0,0 +1,21 @@
+wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
+wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
+
+spring.data.redis.host=redis
+spring.data.redis.port=6379
+spring.data.redis.database=0
+
+spring.application.name=user
+
+server.port=8072
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.username=root
+spring.datasource.password=Shuodedaoli114514
+spring.datasource.url=jdbc:mysql://mysql:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
+
+spring.cloud.nacos.discovery.server-addr=nacos:8848
+spring.cloud.nacos.discovery.enabled=true
+
+management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
+management.tracing.sampling.probability=1.0
\ No newline at end of file
diff --git a/user-8072/src/main/resources/application-dev.properties b/user-8072/src/main/resources/application-dev.properties
new file mode 100644
index 0000000..bf4864f
--- /dev/null
+++ b/user-8072/src/main/resources/application-dev.properties
@@ -0,0 +1,15 @@
+wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
+wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
+
+spring.data.redis.host=localhost
+spring.data.redis.port=6379
+spring.data.redis.database=0
+
+spring.application.name=user
+
+server.port=8072
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.username=root
+spring.datasource.password=12345abcde
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
diff --git a/user-8072/src/main/resources/application.properties b/user-8072/src/main/resources/application.properties
new file mode 100644
index 0000000..0896b37
--- /dev/null
+++ b/user-8072/src/main/resources/application.properties
@@ -0,0 +1 @@
+spring.profiles.active=dep
\ No newline at end of file