Bläddra i källkod

【项目创建】

ChenYL 11 månader sedan
incheckning
98efcf65d3
41 ändrade filer med 1727 tillägg och 0 borttagningar
  1. 38 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 7 0
      .idea/encodings.xml
  4. 5 0
      .idea/inspectionProfiles/Project_Default.xml
  5. 14 0
      .idea/misc.xml
  6. 6 0
      .idea/vcs.xml
  7. 1 0
      doc/sql/db.sql
  8. 243 0
      pom.xml
  9. 24 0
      src/main/java/com/dataeasy/server/Application.java
  10. 17 0
      src/main/java/com/dataeasy/server/common/annotation/EnumValue.java
  11. 15 0
      src/main/java/com/dataeasy/server/common/annotation/IgnoreResponseWrapper.java
  12. 25 0
      src/main/java/com/dataeasy/server/common/constant/ResponseCodeEnum.java
  13. 30 0
      src/main/java/com/dataeasy/server/common/exception/BusinessException.java
  14. 19 0
      src/main/java/com/dataeasy/server/common/exception/LoginException.java
  15. 19 0
      src/main/java/com/dataeasy/server/common/exception/TokenException.java
  16. 65 0
      src/main/java/com/dataeasy/server/common/pojo/BaseEntity.java
  17. 39 0
      src/main/java/com/dataeasy/server/common/pojo/BaseQuery.java
  18. 113 0
      src/main/java/com/dataeasy/server/common/pojo/JsonResponse.java
  19. 113 0
      src/main/java/com/dataeasy/server/common/typehandler/EnumValueTypeHandler.java
  20. 73 0
      src/main/java/com/dataeasy/server/common/utils/Assert.java
  21. 10 0
      src/main/java/com/dataeasy/server/common/valid/Delete.java
  22. 10 0
      src/main/java/com/dataeasy/server/common/valid/Query.java
  23. 10 0
      src/main/java/com/dataeasy/server/common/valid/Save.java
  24. 10 0
      src/main/java/com/dataeasy/server/common/valid/Update.java
  25. 67 0
      src/main/java/com/dataeasy/server/core/aop/GlobalExceptionHandler.java
  26. 46 0
      src/main/java/com/dataeasy/server/core/aop/ResponseControllerAdvice.java
  27. 52 0
      src/main/java/com/dataeasy/server/core/aop/WebOperateLogAspect.java
  28. 34 0
      src/main/java/com/dataeasy/server/core/config/BizConfig.java
  29. 71 0
      src/main/java/com/dataeasy/server/core/config/FeignConfig.java
  30. 27 0
      src/main/java/com/dataeasy/server/core/config/MyBatisConfig.java
  31. 39 0
      src/main/java/com/dataeasy/server/core/config/WebMvcConfig.java
  32. 61 0
      src/main/java/com/dataeasy/server/core/interceptor/AuthInterceptor.java
  33. 116 0
      src/main/java/com/dataeasy/server/core/interceptor/MybatisAuditDataInterceptor.java
  34. 63 0
      src/main/java/com/dataeasy/server/utiis/CacheUtils.java
  35. 89 0
      src/main/java/com/dataeasy/server/utiis/DateUtils.java
  36. 31 0
      src/main/java/com/dataeasy/server/utiis/SpringUtils.java
  37. 57 0
      src/main/java/com/dataeasy/server/utiis/TokenUtils.java
  38. 28 0
      src/main/java/com/dataeasy/server/utiis/UserUtils.java
  39. 13 0
      src/main/resources/application-dev.yaml
  40. 0 0
      src/main/resources/application-prod.yaml
  41. 24 0
      src/main/resources/application.yaml

+ 38 - 0
.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

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml

+ 7 - 0
.idea/encodings.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+  </component>
+</project>

+ 5 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,5 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+  </profile>
+</component>

+ 14 - 0
.idea/misc.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
doc/sql/db.sql

@@ -0,0 +1 @@
+CREATE DATABASE `data_easy` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

+ 243 - 0
pom.xml

@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.3.5</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>com.dataeasy</groupId>
+    <artifactId>server</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>21</maven.compiler.source>
+        <maven.compiler.target>21</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>21</maven.compiler.source>
+        <maven.compiler.target>21</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <java.version>21</java.version>
+        <spring-cloud.version>2023.0.3</spring-cloud.version>
+        <jwt.version>4.4.0</jwt.version>
+        <tk-mybatis.version>5.0.1</tk-mybatis.version>
+        <jasypt.version>3.0.5</jasypt.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-graphql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-tx</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>tk.mybatis</groupId>
+            <artifactId>mapper-spring-boot-starter</artifactId>
+            <version>${tk-mybatis.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>${jwt.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.ulisesbocchio</groupId>
+            <artifactId>jasypt-spring-boot-starter</artifactId>
+            <version>${jasypt.version}</version>
+        </dependency>
+    </dependencies>
+
+    <!-- 配置阿里云仓库 -->
+    <repositories>
+        <repository>
+            <id>aliyun-repos</id>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+    <pluginRepositories>
+        <pluginRepository>
+            <id>aliyun-repos</id>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <!--引入第三方jar包时,不添加则引入的第三方jar不会被打入jar包中-->
+                    <includeSystemScope>true</includeSystemScope>
+                    <!--排除第三方jar文件-->
+                    <includes>
+                        <include>
+                            <groupId>nothing</groupId>
+                            <artifactId>nothing</artifactId>
+                        </include>
+                    </includes>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 2、完成对Java代码的编译,可以指定项目源码的jdk版本,编译后的jdk版本,以及编码 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <!-- 源代码使用的JDK版本 -->
+                    <source>${java.version}</source>
+                    <!-- 需要生成的目标class文件的编译版本 -->
+                    <target>${java.version}</target>
+                    <!-- 字符集编码 -->
+                    <encoding>UTF-8</encoding>
+                    <!-- 用来传递编译器自身不包含但是却支持的参数选项 -->
+                    <!--                    <compilerArguments>-->
+                    <!--                        <verbose/>-->
+                    <!--                        &lt;!&ndash; windwos环境(二选一) &ndash;&gt;-->
+                    <!--                        <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>-->
+                    <!--                        &lt;!&ndash; Linux环境(二选一) &ndash;&gt;-->
+                    <!--                        <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>-->
+                    <!--                    </compilerArguments>-->
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                            <version>${lombok.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+
+            <!-- 3、将所有依赖的jar文件复制到target/lib目录 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <!--复制到哪个路径,${project.build.directory} 缺醒为 target,其他内置参数见下面解释-->
+                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>false</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 4、指定启动类,指定配置文件,将依赖打成外部jar包 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <!-- 是否要把第三方jar加入到类构建路径 -->
+                            <addClasspath>true</addClasspath>
+                            <!-- 外部依赖jar包的最终位置 -->
+                            <classpathPrefix>lib/</classpathPrefix>
+                            <!-- 项目启动类 -->
+                            <mainClass>com.punchsettle.server.Application</mainClass>
+                        </manifest>
+                    </archive>
+                    <!--资源文件不打进jar包中,做到配置跟项目分离的效果-->
+                    <!--                    <excludes>-->
+                    <!--                        &lt;!&ndash; 业务jar中过滤application.properties/yml文件,在jar包外控制 &ndash;&gt;-->
+                    <!--                        <exclude>*.properties</exclude>-->
+                    <!--                        <exclude>*.xml</exclude>-->
+                    <!--                        <exclude>*.yml</exclude>-->
+                    <!--                    </excludes>-->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 24 - 0
src/main/java/com/dataeasy/server/Application.java

@@ -0,0 +1,24 @@
+package com.dataeasy.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 程序运行入口
+ * @date 2025/2/14 9:57
+ */
+@EnableCaching
+@EnableScheduling
+@EnableFeignClients
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}

+ 17 - 0
src/main/java/com/dataeasy/server/common/annotation/EnumValue.java

@@ -0,0 +1,17 @@
+package com.dataeasy.server.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 数据库枚举值转换注解
+ * @date 2024/12/13 10:55
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnumValue {
+}

+ 15 - 0
src/main/java/com/dataeasy/server/common/annotation/IgnoreResponseWrapper.java

@@ -0,0 +1,15 @@
+package com.dataeasy.server.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;
+
+/**
+ * 忽略接口返回统一处理
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IgnoreResponseWrapper {}

+ 25 - 0
src/main/java/com/dataeasy/server/common/constant/ResponseCodeEnum.java

@@ -0,0 +1,25 @@
+package com.dataeasy.server.common.constant;
+
+/**
+ * 基本响应码
+ */
+public enum ResponseCodeEnum {
+
+    SUCCESS("0", "操作成功"), FAIL("999", "操作失败");
+
+    private String code;
+    private String msg;
+
+    ResponseCodeEnum(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 30 - 0
src/main/java/com/dataeasy/server/common/exception/BusinessException.java

@@ -0,0 +1,30 @@
+package com.dataeasy.server.common.exception;
+
+/**
+ * 业务异常
+ *
+ * @author tyuio
+ */
+public class BusinessException extends RuntimeException {
+
+    public BusinessException(String message) {
+        super(message);
+    }
+
+    /**
+     * 构造业务异常信息
+     * @param message
+     * @return
+     */
+    public static BusinessException fail(String message) {
+        return new BusinessException(message);
+    }
+
+    /**
+     * 抛出业务异常
+     * @param message
+     */
+    public static void throwFail(String message) {
+    	throw fail(message);
+    }
+}

+ 19 - 0
src/main/java/com/dataeasy/server/common/exception/LoginException.java

@@ -0,0 +1,19 @@
+package com.dataeasy.server.common.exception;
+
+/**
+ * @className AuthException
+ * @description 登录校验异常
+ * @author ChenYL 
+ * @date 2023/07/29 20:27
+ * @version V1.0
+**/
+public class LoginException extends RuntimeException {
+
+    public LoginException(String message) {
+        super(message);
+    }
+
+    public static LoginException fail(String message) {
+        return new LoginException(message);
+    }
+}

+ 19 - 0
src/main/java/com/dataeasy/server/common/exception/TokenException.java

@@ -0,0 +1,19 @@
+package com.dataeasy.server.common.exception;
+
+/**
+ * @className AuthException
+ * @description 登录校验异常
+ * @author ChenYL
+ * @date 2023/07/29 20:27
+ * @version V1.0
+ **/
+public class TokenException extends RuntimeException {
+
+    public TokenException(String message) {
+        super(message);
+    }
+
+    public static TokenException fail(String message) {
+        return new TokenException(message);
+    }
+}

+ 65 - 0
src/main/java/com/dataeasy/server/common/pojo/BaseEntity.java

@@ -0,0 +1,65 @@
+package com.dataeasy.server.common.pojo;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Id;
+import lombok.Data;
+import tk.mybatis.mapper.annotation.KeySql;
+import tk.mybatis.mapper.annotation.LogicDelete;
+
+import java.sql.Timestamp;
+
+/**
+ * @description 实体类基类(6个通用审计字段)
+ * @version 1.0.0
+ * @date 2024/11/25 10:57
+ * @author tyuio
+ */
+@Data
+public class BaseEntity {
+
+    /**
+     * 主键
+     */
+    @Id
+    @KeySql(useGeneratedKeys = true)
+    @Column(name = "id")
+    private Long id;
+
+    /**
+     * 创建人
+     */
+    @Column(name = "created_by")
+    private Long createdBy;
+
+    /**
+     * 创建时间
+     */
+    @Column(name = "creation_time")
+    private Timestamp creationTime;
+
+    /**
+     * 最后更新人
+     */
+    @Column(name = "last_updated_by")
+    private Long lastUpdatedBy;
+
+    /**
+     * 最后更新时间
+     */
+    @Column(name = "last_update_time")
+    private Timestamp lastUpdateTime;
+
+    /**
+     * 版本号
+     */
+    @Column(name = "version")
+    private Integer version;
+
+    /**
+     * 逻辑删除标志(0-未删除,1-已删除)
+     */
+    @LogicDelete
+    @Column(name = "delete_flag")
+    private Boolean deleteFlag;
+
+}

+ 39 - 0
src/main/java/com/dataeasy/server/common/pojo/BaseQuery.java

@@ -0,0 +1,39 @@
+package com.dataeasy.server.common.pojo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 基础查询类
+ * @date 2024/12/19 23:24
+ */
+@Data
+@EqualsAndHashCode
+public class BaseQuery {
+
+    @NotBlank(message = "开始时间不能为空")
+    private String startDate;
+
+    @NotBlank(message = "结束时间不能为空")
+    private String endDate;
+
+    public String getStartDateTime() {
+        // 即符合yyyy-MM-dd格式
+        if (StringUtils.hasText(startDate) && startDate.length() == 10) {
+            return String.format("%s 00:00:00.000", startDate);
+        }
+        return startDate;
+    }
+
+    public String getEndDateTime() {
+        // 即符合yyyy-MM-dd格式
+        if (StringUtils.hasText(endDate) && endDate.length() == 10) {
+            return String.format("%s 23:59:59.999", endDate);
+        }
+        return endDate;
+    }
+}

+ 113 - 0
src/main/java/com/dataeasy/server/common/pojo/JsonResponse.java

@@ -0,0 +1,113 @@
+package com.dataeasy.server.common.pojo;
+
+import com.dataeasy.server.common.constant.ResponseCodeEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * json 统一响应体
+ *
+ * @param <T>
+ */
+@Data
+@EqualsAndHashCode
+public class JsonResponse<T> implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -5372948141725666083L;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss:SSS", timezone = "GMT+8")
+    private Date timestamp = new Date();
+
+    /**
+     * 是否成功标志位 true-成功 false-失败
+     */
+    private Boolean success;
+
+    /**
+     * 响应编码
+     */
+    private String code;
+
+    /**
+     * 错误信息
+     */
+    private String msg;
+
+    /**
+     * 返回数据
+     */
+    private T data;
+
+    public JsonResponse(Boolean success, String code, String msg) {
+        this.success = success;
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public JsonResponse(Boolean success, String code, String msg, T data) {
+        this.success = success;
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    /**
+     * 返回成功响应体
+     *
+     * @param <T>
+     * @return
+     */
+    public static <T> JsonResponse<T> success() {
+        return new JsonResponse<>(true, ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMsg());
+    }
+
+    /**
+     * 返回成功响应体
+     *
+     * @param data 响应数据
+     * @param <T>
+     * @return
+     */
+    public static <T> JsonResponse<T> success(T data) {
+        return new JsonResponse<>(true, ResponseCodeEnum.SUCCESS.getCode(), ResponseCodeEnum.SUCCESS.getMsg(), data);
+    }
+
+    /**
+     * 返回错误响应体
+     *
+     * @param <T>
+     * @return
+     */
+    public static <T> JsonResponse<T> fail() {
+        return new JsonResponse<>(false, ResponseCodeEnum.FAIL.getCode(), ResponseCodeEnum.FAIL.getMsg());
+    }
+
+    /**
+     * 返回错误响应体
+     *
+     * @param msg 错误信息
+     * @param <T>
+     * @return
+     */
+    public static <T> JsonResponse<T> fail(String msg) {
+        return new JsonResponse<>(false, ResponseCodeEnum.FAIL.getCode(), msg);
+    }
+
+    /**
+     * 返回错误响应体
+     *
+     * @param code 错误编码
+     * @param msg 错误信息
+     * @param <T>
+     * @return
+     */
+    public static <T> JsonResponse<T> fail(String code, String msg) {
+        return new JsonResponse<>(false, code, msg);
+    }
+}

+ 113 - 0
src/main/java/com/dataeasy/server/common/typehandler/EnumValueTypeHandler.java

@@ -0,0 +1,113 @@
+package com.dataeasy.server.common.typehandler;
+
+import com.dataeasy.server.common.annotation.EnumValue;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+
+import java.lang.reflect.Field;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 数据库枚举值转换器
+ * @date 2024/12/13 10:57
+ */
+public class EnumValueTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
+
+    private final Class<E> type;
+
+    private final E[] enums;
+
+    public EnumValueTypeHandler(Class<E> type) {
+        if (type == null) {
+            throw new IllegalArgumentException("Type argument cannot be null");
+        }
+        this.type = type;
+        this.enums = type.getEnumConstants();
+        if (this.enums == null) {
+            throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
+        }
+    }
+
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
+        Field[] declaredFields = parameter.getClass().getDeclaredFields();
+        for (Field declaredField : declaredFields) {
+            EnumValue annotation = declaredField.getAnnotation(EnumValue.class);
+            if (annotation == null) {
+                continue;
+            }
+            declaredField.setAccessible(true);
+            Object paramValue = null;
+            try {
+                // 获取到设置了EnumValue注解字段的value值
+                paramValue = declaredField.get(parameter);
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            ps.setObject(i, paramValue);
+            return;
+        }
+    }
+
+    @Override
+    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        Field[] declaredFields = type.getDeclaredFields();
+        Field enumField = null;
+        Object value4Db = null;
+        for (Field declaredField : declaredFields) {
+            EnumValue annotation = declaredField.getAnnotation(EnumValue.class);
+            if (annotation == null) {
+                continue;
+            }
+            enumField = declaredField;
+            value4Db = rs.getObject(columnName, enumField.getType());
+            break;
+        }
+        if (enumField == null) {
+            return getResultByOrdinal(rs.getInt(columnName), rs.wasNull());
+        }
+        enumField.setAccessible(true);
+        for (E anEnum : enums) {
+            try {
+                Object value = enumField.get(anEnum);
+                if (value.equals(value4Db)) {
+                    return anEnum;
+                }
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return getResultByOrdinal(rs.getInt(columnName), rs.wasNull());
+    }
+
+    private E getResultByOrdinal(int anInt, boolean b) {
+        int ordinal = anInt;
+        if (ordinal == 0 && b) {
+            return null;
+        }
+        return toOrdinalEnum(ordinal);
+    }
+
+    @Override
+    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return getResultByOrdinal(rs.getInt(columnIndex), rs.wasNull());
+    }
+
+    @Override
+    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return getResultByOrdinal(cs.getInt(columnIndex), cs.wasNull());
+    }
+
+    private E toOrdinalEnum(int ordinal) {
+        try {
+            return enums[ordinal];
+        } catch (Exception ex) {
+            throw new IllegalArgumentException("Cannot convert " + ordinal + " to " + type.getSimpleName() + " by ordinal value.", ex);
+        }
+    }
+}

+ 73 - 0
src/main/java/com/dataeasy/server/common/utils/Assert.java

@@ -0,0 +1,73 @@
+package com.dataeasy.server.common.utils;
+
+
+import com.dataeasy.server.common.exception.BusinessException;
+
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 断言工具类
+ * @date 2024/11/26 19:43
+ */
+public class Assert {
+
+    /**
+     * 判断对象是否为空
+     * @param object 待判断对象
+     * @param errorMsg 异常提示信息
+     * @throws IllegalArgumentException
+     */
+    public static void isNull(Object object, String errorMsg) throws IllegalArgumentException {
+        if (Objects.isNull(object)) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+    }
+
+    /**
+     * 判断对象是否为空
+     * @param object 待判断对象
+     * @throws IllegalArgumentException
+     */
+    public static void isNull(Object object) throws IllegalArgumentException {
+        isNull(object, "传入的对象参数不能为空");
+    }
+
+    /**
+     * 判断对象是否为空
+     * @param object 待判断对象
+     * @param errorMsg 异常提示信息
+     * @throws BusinessException
+     */
+    public static void isNullInBusiness(Object object, String errorMsg) throws BusinessException {
+        if (Objects.isNull(object)) {
+            throw new BusinessException(errorMsg);
+        }
+    }
+
+    /**
+     * 判断集合是否为空
+     * @param collection 待判断对象
+     * @param errorMsg 异常提示信息
+     * @return
+     * @param <T>
+     * @throws IllegalArgumentException
+     */
+    public static <T> void notEmpty(Collection<T> collection, String errorMsg) throws IllegalArgumentException {
+        if (collection == null || collection.isEmpty()) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+    }
+
+    /**
+     * 判断集合是否为空
+     * @param collection 待判断对象
+     * @param <T>
+     * @throws IllegalArgumentException
+     */
+    public static <T> void notEmpty(Collection<T> collection) throws IllegalArgumentException {
+        notEmpty(collection, "传入的集合参数不能为空");
+    }
+}

+ 10 - 0
src/main/java/com/dataeasy/server/common/valid/Delete.java

@@ -0,0 +1,10 @@
+package com.dataeasy.server.common.valid;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 删除 校验器分组
+ * @date 2024/11/26 15:23
+ */
+public interface Delete {
+}

+ 10 - 0
src/main/java/com/dataeasy/server/common/valid/Query.java

@@ -0,0 +1,10 @@
+package com.dataeasy.server.common.valid;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 查询 校验器分组
+ * @date 2024/11/26 15:21
+ */
+public interface Query {
+}

+ 10 - 0
src/main/java/com/dataeasy/server/common/valid/Save.java

@@ -0,0 +1,10 @@
+package com.dataeasy.server.common.valid;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 新增 校验器分组
+ * @date 2024/11/26 15:22
+ */
+public interface Save {
+}

+ 10 - 0
src/main/java/com/dataeasy/server/common/valid/Update.java

@@ -0,0 +1,10 @@
+package com.dataeasy.server.common.valid;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 更新 校验器分组
+ * @date 2024/11/26 15:22
+ */
+public interface Update {
+}

+ 67 - 0
src/main/java/com/dataeasy/server/core/aop/GlobalExceptionHandler.java

@@ -0,0 +1,67 @@
+package com.dataeasy.server.core.aop;
+
+import com.dataeasy.server.common.exception.BusinessException;
+import com.dataeasy.server.common.exception.LoginException;
+import com.dataeasy.server.common.pojo.JsonResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 全局异常处理
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 业务异常处理
+     *
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(BusinessException.class)
+    public JsonResponse businessExceptionHandler(Exception e) {
+        log.error(e.getMessage(), e);
+        return JsonResponse.fail(e.getMessage());
+    }
+
+    /**
+     * 登录异常处理
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(LoginException.class)
+    public ResponseEntity<Object> loginExceptionHandler(LoginException e) {
+        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(JsonResponse.fail(e.getMessage()));
+    }
+
+    /**
+     * 方法参数校验异常处理
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public JsonResponse methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
+        List<ObjectError> allErrors = e.getAllErrors();
+        String errorMsg = allErrors.stream().map(error -> error.getDefaultMessage())
+                .collect(Collectors.joining(";"));
+        return JsonResponse.fail(String.format("参数错误:%s", errorMsg));
+    }
+
+    /**
+     * 全局异常处理
+     */
+    @ExceptionHandler(Exception.class)
+    public JsonResponse exceptionHandler(Exception e) {
+        log.error(e.getMessage(), e);
+        return JsonResponse.fail("系统异常,请稍后再试");
+    }
+}

+ 46 - 0
src/main/java/com/dataeasy/server/core/aop/ResponseControllerAdvice.java

@@ -0,0 +1,46 @@
+package com.dataeasy.server.core.aop;
+
+import com.dataeasy.server.common.annotation.IgnoreResponseWrapper;
+import com.dataeasy.server.common.pojo.JsonResponse;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * 接口返回统一处理
+ */
+@RestControllerAdvice(basePackages = {"com.punchsettle.server.service.controller"})
+public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
+    @Override
+    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
+        return returnType.getMethodAnnotation(IgnoreResponseWrapper.class) == null;
+    }
+
+    @Override
+    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
+        Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
+        ServerHttpResponse response) {
+        if (body instanceof JsonResponse || body instanceof ResponseEntity) {
+            return body;
+        }
+
+        Class<?> returnClass = returnType.getParameterType();
+        if (String.class.equals(returnClass)) {
+            ObjectMapper objectMapper = new ObjectMapper();
+            try {
+                return objectMapper.writeValueAsString(JsonResponse.success(body));
+            } catch (JsonProcessingException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return JsonResponse.success(body);
+    }
+}

+ 52 - 0
src/main/java/com/dataeasy/server/core/aop/WebOperateLogAspect.java

@@ -0,0 +1,52 @@
+package com.dataeasy.server.core.aop;
+
+import jakarta.servlet.http.HttpServletRequest;
+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.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Arrays;
+
+@Slf4j
+@Aspect
+@Component
+public class WebOperateLogAspect {
+
+    @Pointcut("execution(* com.punchsettle.server.service.controller..*.*(..))")
+    public void pointcut() {}
+
+    @Around("pointcut()")
+    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        long startTime = System.currentTimeMillis();
+
+        ServletRequestAttributes requestAttributes =
+            (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = requestAttributes.getRequest();
+
+        String requestURI = request.getRequestURI();
+        Object[] args = Arrays.stream(joinPoint.getArgs()).filter(arg -> !(arg instanceof MultipartFile)).toArray();
+        Object result = null;
+        Exception exception = null;
+        try {
+            result = joinPoint.proceed();
+        } catch (Exception e) {
+            exception = e;
+        }
+        long cost = System.currentTimeMillis() - startTime;
+
+        // 耗时、URI、入参、出参
+        log.info("{}|{}|{}|{}", cost, requestURI, args, result);
+
+        if (exception != null) {
+            throw exception;
+        }
+
+        return result;
+    }
+}

+ 34 - 0
src/main/java/com/dataeasy/server/core/config/BizConfig.java

@@ -0,0 +1,34 @@
+package com.dataeasy.server.core.config;
+
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Getter
+@Configuration
+public class BizConfig {
+
+    /**
+     * 微信小程序appid
+     */
+    @Value("${biz.wechat.mini-program.app-id}")
+    private String wechatMiniProgramAppId;
+
+    /**
+     * 微信小程序secret
+     */
+    @Value("${biz.wechat.mini-program.secret}")
+    private String wechatMiniProgramSecret;
+
+    /**
+     * 生成token的密钥
+     */
+    @Value("${biz.token.password}")
+    private String TokenPassword;
+
+    /**
+     * token过期时间
+     */
+    @Value("${biz.token.expire:1}")
+    private Integer TokenExpire;
+}

+ 71 - 0
src/main/java/com/dataeasy/server/core/config/FeignConfig.java

@@ -0,0 +1,71 @@
+package com.dataeasy.server.core.config;
+
+import feign.Logger;
+import feign.RequestInterceptor;
+import feign.codec.Decoder;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.support.SpringDecoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @className FeignConfig
+ * @description Feign配置
+ * @author ChenYL
+ * @date 2023/07/23 20:55
+ * @version V1.0
+ **/
+@Configuration
+public class FeignConfig {
+
+    @Autowired
+    private BizConfig bizConfig;
+
+    @Bean("myInterceptor")
+    public RequestInterceptor requestInterceptor() {
+        return template -> {
+            template.query("appid", bizConfig.getWechatMiniProgramAppId()).query("secret",
+                bizConfig.getWechatMiniProgramSecret());
+        };
+    }
+
+    /**
+     * 调整Feign日志输出 注:FeignClient只能输出debug等级的日志
+     * 
+     * @return
+     */
+    @Bean
+    public Logger.Level devLogLevel() {
+        return Logger.Level.FULL;
+    }
+
+    /**
+     * 增加转换支持
+     * 
+     * @return
+     */
+    @Bean
+    public Decoder feignDecoder() {
+        Jackson2HttpConverter jackson2HttpConverter = new Jackson2HttpConverter();
+        ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jackson2HttpConverter);
+        return new SpringDecoder(objectFactory);
+    }
+
+    /**
+     * content-type = text/plain 增加JSON转换支持
+     */
+    public class Jackson2HttpConverter extends MappingJackson2HttpMessageConverter {
+        public Jackson2HttpConverter() {
+            List<MediaType> mediaTypes = new ArrayList<>();
+            mediaTypes.add(MediaType.TEXT_PLAIN);
+            setSupportedMediaTypes(mediaTypes);
+        }
+    }
+}

+ 27 - 0
src/main/java/com/dataeasy/server/core/config/MyBatisConfig.java

@@ -0,0 +1,27 @@
+package com.dataeasy.server.core.config;
+
+import com.dataeasy.server.core.interceptor.MybatisAuditDataInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import tk.mybatis.mapper.autoconfigure.ConfigurationCustomizer;
+import tk.mybatis.spring.annotation.MapperScan;
+
+/**
+ * mybatis配置扫描路径
+ */
+@Configuration
+@MapperScan(basePackages = "com.dataeasy.server.atomic.mapper")
+public class MyBatisConfig {
+
+    @Bean
+    public ConfigurationCustomizer configurationCustomizer() {
+        // 添加审计数据插件
+        return new ConfigurationCustomizer() {
+            @Override
+            public void customize(org.apache.ibatis.session.Configuration configuration) {
+                MybatisAuditDataInterceptor auditDataInterceptor = new MybatisAuditDataInterceptor();
+                configuration.addInterceptor(auditDataInterceptor);
+            }
+        };
+    }
+}

+ 39 - 0
src/main/java/com/dataeasy/server/core/config/WebMvcConfig.java

@@ -0,0 +1,39 @@
+package com.dataeasy.server.core.config;
+
+import com.dataeasy.server.core.interceptor.AuthInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    @Autowired
+    private AuthInterceptor authInterceptor;
+
+    /**
+     * 登录校验拦截
+     * @param registry
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(authInterceptor)
+                .excludePathPatterns("/health/**", "/wechat/miniprogram/login");
+    }
+
+    /**
+     * 跨域配置
+     * @param registry
+     */
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**") // 对所有路径生效
+                .allowedOriginPatterns("*") // 允许所有来源
+                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法
+                .allowedHeaders("*") // 允许的头部
+                .allowCredentials(true) // 是否允许发送Cookie
+                .maxAge(3600); // 预检请求的有效期,单位为秒
+    }
+}

+ 61 - 0
src/main/java/com/dataeasy/server/core/interceptor/AuthInterceptor.java

@@ -0,0 +1,61 @@
+package com.dataeasy.server.core.interceptor;
+
+import com.auth0.jwt.interfaces.Claim;
+import com.dataeasy.server.common.exception.LoginException;
+import com.dataeasy.server.common.utils.Assert;
+import com.dataeasy.server.utiis.TokenUtils;
+import com.dataeasy.server.utiis.UserUtils;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import java.util.Map;
+
+/**
+ * @author ChenYL
+ * @version V1.0
+ * @className AuthInterceptor
+ * @description 登录权限拦截
+ * @date 2023/07/29 16:22
+ **/
+@Slf4j
+@Component
+public class AuthInterceptor implements HandlerInterceptor {
+
+//    @Autowired
+//    private IUserService userService;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+            throws Exception {
+
+        // 判断请求头中是否有token
+//        String token = request.getHeader("Authorization");
+//        if (!StringUtils.hasText(token)) {
+//            throw LoginException.fail("登录校验异常,原因:没有token凭据");
+//        }
+//
+//        // token解析获取用户ID
+//        Long currentUserId = null;
+//        try {
+//            Map<String, Claim> verify = TokenUtils.verify(token);
+//            currentUserId = verify.get("userId").asLong();
+//        } catch (Exception e) {
+//            log.error("登录校验异常,token:{}", token, e);
+//            throw LoginException.fail("登录校验异常");
+//        }
+//
+//        // 校验系统中是否存在该用户
+//        User currentUser = userService.getById(currentUserId);
+//        Assert.isNullInBusiness(currentUser, "不存在的用户");
+//
+//        // 把用户信息设置如入上下文
+//        UserUtils.setCurrentId(currentUser.getId());
+
+        return true;
+    }
+}

+ 116 - 0
src/main/java/com/dataeasy/server/core/interceptor/MybatisAuditDataInterceptor.java

@@ -0,0 +1,116 @@
+package com.dataeasy.server.core.interceptor;
+
+import com.dataeasy.server.common.pojo.BaseEntity;
+import com.dataeasy.server.utiis.UserUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+
+import java.sql.Timestamp;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2024/11/25 9:56
+ * @description 审计数据拦截器 Mybatis插入/更新时自动填充创建人、创建时间、最后修改人、最后修改时间
+ */
+@Intercepts({
+        @Signature(
+                type = Executor.class,
+                method = "update",
+                args = {MappedStatement.class, Object.class}),
+})
+@Slf4j
+public class MybatisAuditDataInterceptor implements Interceptor {
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        // 对应上面类注解的args,获取需要的MappedStatement对象
+        final Object[] args = invocation.getArgs();
+        MappedStatement statement = (MappedStatement) args[0];
+
+        // 插入对象,即实体类如:SysUser
+        Object obj = args[1];
+
+        /**
+         * 插入或更新的时候,赋予createBy、updateBy、creationTime、lastUpdateTime值
+         */
+        Long currentUserId = Optional.ofNullable(UserUtils.getCurrentUserId()).orElse(1L);
+        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
+
+        // 识别SQL类型,看是INSERT还是UPDATE
+        if (SqlCommandType.INSERT.equals(statement.getSqlCommandType())) {
+            // 单个插入,BaseEntity是我的实体类的父类,该类有id、createBy、updateBy等通用属性
+            if (obj instanceof BaseEntity) {
+                BaseEntity entity = ((BaseEntity) obj);
+                assignInsertDefaultValue(entity, currentUserId, currentTime);
+            }
+            // 批量插入
+            if (obj instanceof Map) {
+                Map<?, ?> map = (Map<?, ?>) obj;
+                List<?> list = (List<?>) map.get("list");
+                if (list != null) {
+                    for (Object entity : list) {
+                        assignInsertDefaultValue((BaseEntity) entity, currentUserId, currentTime);
+                    }
+                }
+            }
+        }
+
+        if (SqlCommandType.UPDATE.equals(statement.getSqlCommandType())) {
+            // 单个更新
+            if (obj instanceof BaseEntity) {
+                BaseEntity entity = ((BaseEntity) obj);
+                assignUpdateDefaultValue(entity, currentUserId, currentTime);
+            }
+            // 批量更新
+            if (obj instanceof Map) {
+                Map<?, ?> map = (Map<?, ?>) obj;
+                List<?> list = (List<?>) map.get("list");
+                if (list != null) {
+                    for (Object item : list) {
+                        BaseEntity entity = ((BaseEntity) item);
+                        assignUpdateDefaultValue(entity, currentUserId, currentTime);
+                    }
+                }
+            }
+        }
+
+        return invocation.proceed();
+    }
+
+    /**
+     * 插入时 赋予createdBy、creationTime、lastUpdatedBy、lastUpdateTime值
+     * @param entity 实体对象
+     * @param currentUserId 当前用户ID
+     * @param currentTime 当前时间时间
+     */
+    private void assignInsertDefaultValue(BaseEntity entity, Long currentUserId, Timestamp currentTime) {
+        entity.setCreatedBy(currentUserId);
+        entity.setCreationTime(currentTime);
+        entity.setLastUpdatedBy(currentUserId);
+        entity.setLastUpdateTime(currentTime);
+        entity.setVersion(1);
+        entity.setDeleteFlag(false);
+    }
+
+    /**
+     * 更新时 赋予lastUpdatedBy、lastUpdateTime值
+     * @param entity 实体对象
+     * @param currentUserId 当前用户ID
+     * @param currentTime 当前时间时间
+     */
+    private void assignUpdateDefaultValue(BaseEntity entity, Long currentUserId, Timestamp currentTime) {
+        entity.setLastUpdatedBy(currentUserId);
+        entity.setLastUpdateTime(currentTime);
+    }
+
+}

+ 63 - 0
src/main/java/com/dataeasy/server/utiis/CacheUtils.java

@@ -0,0 +1,63 @@
+package com.dataeasy.server.utiis;
+
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+
+/**
+ * 缓存工具类
+ */
+public class CacheUtils {
+
+    private static CacheManager cacheManager;
+
+    static {
+        cacheManager = SpringUtils.getBean(CacheManager.class);
+    }
+
+    /**
+     * 添加缓存
+     *
+     * @param cacheName 缓存名称
+     * @param key 缓存key
+     * @param value 缓存值
+     */
+    public static void put(String cacheName, String key, Object value) {
+        Cache cache = cacheManager.getCache(cacheName);
+        cache.put(key, value);
+    }
+
+    /**
+     * 获取缓存(泛型)
+     *
+     * @param cacheName 缓存名称
+     * @param key 缓存key
+     * @param clazz 缓存类
+     * @param <T> 返回值泛型
+     * @return
+     */
+    public static <T> T get(String cacheName, String key, Class<T> clazz) {
+        Cache cache = cacheManager.getCache(cacheName);
+        if (cache == null) {
+            return null;
+        }
+        Cache.ValueWrapper wrapper = cache.get(key);
+        if (wrapper == null) {
+            return null;
+        }
+        return (T)wrapper.get();
+    }
+
+    /**
+     * 失效缓存
+     *
+     * @param cacheName 缓存名称
+     * @param key 缓存key
+     */
+    public static void evict(String cacheName, String key) {
+        Cache cache = cacheManager.getCache(cacheName);
+        if (cache != null) {
+            cache.evict(key);
+        }
+    }
+
+}

+ 89 - 0
src/main/java/com/dataeasy/server/utiis/DateUtils.java

@@ -0,0 +1,89 @@
+package com.dataeasy.server.utiis;
+
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @description 日期工具
+ * @date 2024/11/25 15:51
+ */
+public class DateUtils {
+
+    /**
+     * 完整的日期时间格式(yyyy-MM-dd HH:mm:ss)
+     */
+    public static final String ALL_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 日期格式(yyyy-MM-dd)
+     */
+    public static final String DATE_FORMAT = "yyyy-MM-dd";
+
+    /**
+     * 创建完整的日期时间格式化器(yyyy-MM-dd HH:mm:ss)
+     * @return
+     */
+    public static SimpleDateFormat buildDateTimeFormat() {
+        return new SimpleDateFormat(ALL_DATE_TIME_FORMAT);
+    }
+
+    /**
+     * 创建日期格式化器(yyyy-MM-dd)
+     * @return
+     */
+    public static SimpleDateFormat buildDateFormat() {
+        return new SimpleDateFormat(DATE_FORMAT);
+    }
+
+    /**
+     * 获取一周的时间范围
+     * @return 返回日期字符串列表
+     */
+    public static List<LocalDate> getWeeklyDateRange() {
+        LocalDate today = LocalDate.now();
+
+        // 获取本周的第一天(假设周一为一周的第一天)
+        LocalDate firstDayOfWeek = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+
+        // 打印本周的所有日期
+        List<LocalDate> list = new ArrayList<>(7);
+        for (int i = 0; i < 7; i++) {
+            LocalDate date = firstDayOfWeek.plusDays(i);
+            list.add(date);
+        }
+        return list;
+    }
+
+    /**
+     * 获取昨天的日期
+     * @return
+     */
+    public static LocalDate getYesterdayDate() {
+        LocalDate today = LocalDate.now();
+        return today.minusDays(1);
+    }
+
+    /**
+     * 获取上周的周一日期
+     * @return
+     */
+    public static LocalDate getLastWeekMonday(LocalDate date) {
+        // 获取上周的周一日期
+        return date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+    }
+
+    /**
+     * 获取上周的周日日期
+     * @return
+     */
+    public static LocalDate getLastWeekSunday(LocalDate date) {
+        return getLastWeekMonday(date).plusDays(6);
+    }
+
+}

+ 31 - 0
src/main/java/com/dataeasy/server/utiis/SpringUtils.java

@@ -0,0 +1,31 @@
+package com.dataeasy.server.utiis;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Spring上下文 工具类
+ */
+@Component
+public class SpringUtils implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 通过class获取Bean.
+     *
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(Class<T> clazz) {
+        return applicationContext.getBean(clazz);
+    }
+}

+ 57 - 0
src/main/java/com/dataeasy/server/utiis/TokenUtils.java

@@ -0,0 +1,57 @@
+package com.dataeasy.server.utiis;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.Claim;
+import com.dataeasy.server.core.config.BizConfig;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @className JwtUtils
+ * @description Token凭证工具
+ * @author ChenYL
+ * @date 2023/07/29 16:25
+ * @version V1.0
+ **/
+public class TokenUtils {
+
+    /**
+     * token算法
+     */
+    private static Algorithm tokenAlgorithm;
+
+    /**
+     * token校验工具
+     */
+    private static JWTVerifier jwtVerifier;
+
+    static {
+        BizConfig bizConfig = SpringUtils.getBean(BizConfig.class);
+        tokenAlgorithm = Algorithm.HMAC256(bizConfig.getTokenPassword());
+        jwtVerifier = JWT.require(tokenAlgorithm).build();
+    }
+
+    /**
+     * 创建token
+     * 
+     * @param userId
+     * @param expiresAt
+     * @return
+     */
+    public static String createToken(Long userId, Date expiresAt) {
+        return JWT.create().withClaim("userId", userId).withExpiresAt(expiresAt).sign(tokenAlgorithm);
+    }
+
+    /**
+     * 校验token
+     * 
+     * @param token
+     * @return
+     */
+    public static Map<String, Claim> verify(String token) {
+        return jwtVerifier.verify(token).getClaims();
+    }
+}

+ 28 - 0
src/main/java/com/dataeasy/server/utiis/UserUtils.java

@@ -0,0 +1,28 @@
+package com.dataeasy.server.utiis;
+
+/**
+ * @author tyuio
+ * @version 1.0.0
+ * @date 2024/11/25 10:15
+ * @description 用户信息相关工具类
+ */
+public class UserUtils {
+
+    public static final ThreadLocal<Long> threadLocal = new ThreadLocal<>();
+
+    /**
+     * 设置当前用户的ID
+     * @param id
+     */
+    public static void setCurrentId(Long id) {
+        threadLocal.set(id);
+    }
+
+    /**
+     * 获取当前用户的ID
+     * @return
+     */
+    public static Long getCurrentUserId() {
+        return threadLocal.get();
+    }
+}

+ 13 - 0
src/main/resources/application-dev.yaml

@@ -0,0 +1,13 @@
+spring:
+  datasource:
+    username: root
+    url: jdbc:mysql://localhost:3306/data_easy?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
+
+
+biz:
+  wechat:
+    mini-program:
+      app-id: 0123456789
+      secret: 0123456789
+  token:
+    password: 0123456789

+ 0 - 0
src/main/resources/application-prod.yaml


+ 24 - 0
src/main/resources/application.yaml

@@ -0,0 +1,24 @@
+server:
+  port: 8080
+spring:
+  profiles:
+    active: prod
+  application:
+    name: data-easy-server
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+  cache:
+    type: caffeine
+
+jasypt:
+  encryptor:
+    algorithm: PBEWithMD5AndDES
+    salt-generator-classname: org.jasypt.salt.RandomSaltGenerator
+    iv-generator-classname: org.jasypt.iv.RandomIvGenerator
+
+biz:
+  wechat:
+    mini-program:
+      url: https://api.weixin.qq.com
+  token:
+    expire: 7