Ver código fonte

first commit

沈永艺 3 anos atrás
commit
769e06392d
100 arquivos alterados com 84690 adições e 0 exclusões
  1. 3 0
      PCS/docker/api/Dockerfile
  2. 49 0
      PCS/docker/docker-compose.yaml
  3. 9 0
      PCS/docker/mysql/conf.d/my.cnf
  4. 7921 0
      PCS/docker/mysql/init/pas.sql
  5. 3 0
      PCS/docker/web/Dockerfile
  6. 36 0
      PCS/docker/web/default.conf
  7. 183 0
      PCS/pom.xml
  8. 68707 0
      PCS/sql/pas.sql
  9. 20 0
      PCS/src/main/java/cn/cslg/permission/Application.java
  10. 32 0
      PCS/src/main/java/cn/cslg/permission/common/GlobalException.java
  11. 13 0
      PCS/src/main/java/cn/cslg/permission/common/config/AsyncExceptionHandler.java
  12. 53 0
      PCS/src/main/java/cn/cslg/permission/common/config/AsyncTaskPoolConfig.java
  13. 24 0
      PCS/src/main/java/cn/cslg/permission/common/config/MetaObjectHandlerConfig.java
  14. 20 0
      PCS/src/main/java/cn/cslg/permission/common/config/MybatisPlusConfig.java
  15. 35 0
      PCS/src/main/java/cn/cslg/permission/common/config/SaTokenConfigure.java
  16. 18 0
      PCS/src/main/java/cn/cslg/permission/common/config/SpringDocConfig.java
  17. 13 0
      PCS/src/main/java/cn/cslg/permission/common/config/WebSocketConfig.java
  18. 849 0
      PCS/src/main/java/cn/cslg/permission/common/core/Convert.java
  19. 14 0
      PCS/src/main/java/cn/cslg/permission/common/core/annotation/AnnotationParse.java
  20. 13 0
      PCS/src/main/java/cn/cslg/permission/common/core/annotation/Permission.java
  21. 52 0
      PCS/src/main/java/cn/cslg/permission/common/core/annotation/PermissionAspect.java
  22. 146 0
      PCS/src/main/java/cn/cslg/permission/common/core/base/Constants.java
  23. 9 0
      PCS/src/main/java/cn/cslg/permission/common/core/base/DocFlag.java
  24. 15 0
      PCS/src/main/java/cn/cslg/permission/common/core/base/EStatus.java
  25. 20 0
      PCS/src/main/java/cn/cslg/permission/common/core/base/RedisConf.java
  26. 116 0
      PCS/src/main/java/cn/cslg/permission/common/core/base/RequestHolder.java
  27. 90 0
      PCS/src/main/java/cn/cslg/permission/common/core/exception/BaseException.java
  28. 16 0
      PCS/src/main/java/cn/cslg/permission/common/core/exception/CustomException.java
  29. 16 0
      PCS/src/main/java/cn/cslg/permission/common/core/exception/PermissionException.java
  30. 47 0
      PCS/src/main/java/cn/cslg/permission/common/model/BaseEntity.java
  31. 13 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/AreaAddressDTO.java
  32. 31 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/ClassNumberDTO.java
  33. 8 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/CommonData.java
  34. 12 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/CustomFieldDTO.java
  35. 13 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/CustomFieldLabelDTO.java
  36. 9 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/LabelDTO.java
  37. 13 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/PageDTO.java
  38. 11 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/PatentQueryFieldSourceDTO.java
  39. 9 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/ProjectFieldOrderDTO.java
  40. 19 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/TaskWebSocketDTO.java
  41. 12 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/UploadFileDTO.java
  42. 147 0
      PCS/src/main/java/cn/cslg/permission/common/utils/BackupUtils.java
  43. 769 0
      PCS/src/main/java/cn/cslg/permission/common/utils/DateUtils.java
  44. 163 0
      PCS/src/main/java/cn/cslg/permission/common/utils/ExcelUtils.java
  45. 149 0
      PCS/src/main/java/cn/cslg/permission/common/utils/FileUtils.java
  46. 7 0
      PCS/src/main/java/cn/cslg/permission/common/utils/FormatUtil.java
  47. 313 0
      PCS/src/main/java/cn/cslg/permission/common/utils/JsonUtils.java
  48. 1325 0
      PCS/src/main/java/cn/cslg/permission/common/utils/RedisUtil.java
  49. 47 0
      PCS/src/main/java/cn/cslg/permission/common/utils/RequestDataHelper.java
  50. 86 0
      PCS/src/main/java/cn/cslg/permission/common/utils/Response.java
  51. 49 0
      PCS/src/main/java/cn/cslg/permission/common/utils/ResponseEnum.java
  52. 117 0
      PCS/src/main/java/cn/cslg/permission/common/utils/ServletUtils.java
  53. 729 0
      PCS/src/main/java/cn/cslg/permission/common/utils/SoMap.java
  54. 77 0
      PCS/src/main/java/cn/cslg/permission/common/utils/SpringContextUtil.java
  55. 129 0
      PCS/src/main/java/cn/cslg/permission/common/utils/SpringUtils.java
  56. 966 0
      PCS/src/main/java/cn/cslg/permission/common/utils/StpAdminUtil.java
  57. 501 0
      PCS/src/main/java/cn/cslg/permission/common/utils/StringUtils.java
  58. 18 0
      PCS/src/main/java/cn/cslg/permission/common/utils/TestUtils.java
  59. 113 0
      PCS/src/main/java/cn/cslg/permission/common/utils/WebSocketServer.java
  60. 22 0
      PCS/src/main/java/cn/cslg/permission/entity/PermissionApplicationEntity.java
  61. 4 0
      PCS/src/main/java/cn/cslg/permission/entity/PermissionFunctionEntity.java
  62. 18 0
      PCS/src/main/resources/application-dev.yml
  63. 19 0
      PCS/src/main/resources/application-docker.yml
  64. 22 0
      PCS/src/main/resources/application-prod.yml
  65. 19 0
      PCS/src/main/resources/application-test.yml
  66. 46 0
      PCS/src/main/resources/application.yml
  67. 2 0
      PCS/src/main/resources/config/cron.setting
  68. 110 0
      PCS/src/main/resources/config/logback-spring.xml
  69. 1 0
      PCS/src/main/resources/static/map/上海市.json
  70. 1 0
      PCS/src/main/resources/static/map/中国.json
  71. 1 0
      PCS/src/main/resources/static/map/云南省.json
  72. 1 0
      PCS/src/main/resources/static/map/全球.json
  73. 1 0
      PCS/src/main/resources/static/map/内蒙古自治区.json
  74. 1 0
      PCS/src/main/resources/static/map/北京市.json
  75. 1 0
      PCS/src/main/resources/static/map/台湾省.json
  76. 1 0
      PCS/src/main/resources/static/map/吉林省.json
  77. 1 0
      PCS/src/main/resources/static/map/四川省.json
  78. 1 0
      PCS/src/main/resources/static/map/天津市.json
  79. 1 0
      PCS/src/main/resources/static/map/宁夏回族自治区.json
  80. 1 0
      PCS/src/main/resources/static/map/安徽省.json
  81. 1 0
      PCS/src/main/resources/static/map/山东省.json
  82. 1 0
      PCS/src/main/resources/static/map/山西省.json
  83. 1 0
      PCS/src/main/resources/static/map/广东省.json
  84. 1 0
      PCS/src/main/resources/static/map/广西壮族自治区.json
  85. 1 0
      PCS/src/main/resources/static/map/新疆维吾尔自治区.json
  86. 1 0
      PCS/src/main/resources/static/map/江苏省.json
  87. 1 0
      PCS/src/main/resources/static/map/江西省.json
  88. 1 0
      PCS/src/main/resources/static/map/河北省.json
  89. 1 0
      PCS/src/main/resources/static/map/河南省.json
  90. 1 0
      PCS/src/main/resources/static/map/浙江省.json
  91. 1 0
      PCS/src/main/resources/static/map/海南省.json
  92. 1 0
      PCS/src/main/resources/static/map/湖北省.json
  93. 1 0
      PCS/src/main/resources/static/map/湖南省.json
  94. 1 0
      PCS/src/main/resources/static/map/澳门特别行政区.json
  95. 1 0
      PCS/src/main/resources/static/map/甘肃省.json
  96. 1 0
      PCS/src/main/resources/static/map/福建省.json
  97. 1 0
      PCS/src/main/resources/static/map/西藏自治区.json
  98. 1 0
      PCS/src/main/resources/static/map/贵州省.json
  99. 1 0
      PCS/src/main/resources/static/map/辽宁省.json
  100. 0 0
      PCS/src/main/resources/static/map/重庆市.json

+ 3 - 0
PCS/docker/api/Dockerfile

@@ -0,0 +1,3 @@
+FROM java:8
+ADD pas-0.0.1-SNAPSHOT.jar app.jar
+ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=docker"]

+ 49 - 0
PCS/docker/docker-compose.yaml

@@ -0,0 +1,49 @@
+version: "3"
+services:
+  pas-mysql:
+    container_name: pas-mysql
+    image: mysql:8
+    ports:
+      - "3307:3306"
+    environment:
+      TZ: Asia/Shanghai
+      MYSQL_ROOT_PASSWORD: cslg_docker_123456
+      MYSQL_DATABASE: pas
+    volumes:
+      - "./mysql/conf.d/:/etc/mysql/conf.d/"
+      - "./mysql/init/:/docker-entrypoint-initdb.d/"
+    privileged: true
+    restart: always
+  pas-redis:
+    container_name: pas-redis
+    image: redis
+    ports:
+      - "6380:6379"
+    command:
+      --requirepass "cslg_docker_123456"
+    restart: always
+  pas-api:
+    container_name: pas-api
+    build:
+      context: ./api
+    ports:
+      - "8879:8879"
+    environment:
+      TZ: Asia/Shanghai
+    volumes:
+      - "./api/logs:/logs"
+      - "./api/file:/file"
+      - "./api/backup:/backup"
+    restart: always
+    depends_on:
+      - pas-mysql
+      - pas-redis
+  pas-web:
+    container_name: pas-web
+    build:
+      context: ./web
+    ports:
+      - "8085:80"
+    volumes:
+      - "./web/nginx:/var/log/nginx"
+    restart: always

+ 9 - 0
PCS/docker/mysql/conf.d/my.cnf

@@ -0,0 +1,9 @@
+[mysqld]
+skip-name-resolve
+group_concat_max_len = 4294967295
+innodb_buffer_pool_size = 16G
+join_buffer_size = 128M
+sort_buffer_size = 2M
+read_rnd_buffer_size = 2M
+max_allowed_packet = 100M
+sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

Diferenças do arquivo suprimidas por serem muito extensas
+ 7921 - 0
PCS/docker/mysql/init/pas.sql


+ 3 - 0
PCS/docker/web/Dockerfile

@@ -0,0 +1,3 @@
+FROM nginx
+COPY dist/ /usr/share/nginx/html/
+COPY default.conf /etc/nginx/conf.d/default.conf

+ 36 - 0
PCS/docker/web/default.conf

@@ -0,0 +1,36 @@
+server {
+    listen       80;
+    server_name localhost;
+	client_max_body_size 1000m;
+	gzip_static on;
+    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
+    gzip_proxied  any;
+    gzip_vary on;
+    gzip_comp_level 6;
+    gzip_buffers 16 8k;
+    gzip_http_version 1.1;
+	add_header Access-Control-Allow-Origin *;
+	add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
+	add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
+	if ($request_method = 'OPTIONS') {
+		return 204;
+	}
+    location / {
+        root   /usr/share/nginx/html;
+        try_files $uri $uri/ /index.html;
+    }
+	location /api/v2 {
+		proxy_pass   http://pas-api:8879;
+	    proxy_set_header Upgrade $http_upgrade;
+	    proxy_set_header Connection "upgrade";
+		proxy_connect_timeout 86400s;
+		proxy_read_timeout 86400s;
+		proxy_send_timeout 86400s;
+	}
+    location /pdfjs {
+		proxy_pass   http://pas-api:8879;
+	}
+    location /file {
+		proxy_pass   http://pas-api:8879;
+	}
+}

+ 183 - 0
PCS/pom.xml

@@ -0,0 +1,183 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.6.4</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>cn.cslg</groupId>
+    <artifactId>pas</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>pas</name>
+    <description>常熟理工学院 专利分析系统</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <jwt.version>0.9.0</jwt.version>
+        <commons.io.version>2.5</commons.io.version>
+        <mybatisplus.version>3.4.3.4</mybatisplus.version>
+        <google.code.gson.version>2.7</google.code.gson.version>
+        <hutool.version>5.6.5</hutool.version>
+        <okhttps.version>3.1.1</okhttps.version>
+        <poi.version>4.1.2</poi.version>
+        <poi-tl.version>1.10.3</poi-tl.version>
+        <druid.version>1.1.10</druid.version>
+        <fastjson.version>2.0.0</fastjson.version>
+        <sa-token.version>1.29.0</sa-token.version>
+        <springdoc.version>1.6.6</springdoc.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-ui</artifactId>
+            <version>${springdoc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.deepoove</groupId>
+            <artifactId>poi-tl</artifactId>
+            <version>${poi-tl.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-spring-boot-starter</artifactId>
+            <version>${sa-token.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-dao-redis-jackson</artifactId>
+            <version>${sa-token.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${druid.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+            <version>1.21</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>${jwt.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ejlchina</groupId>
+            <artifactId>okhttps</artifactId>
+            <version>${okhttps.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>${google.code.gson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>${mybatisplus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 指定该Main Class为全局的唯一入口 -->
+                    <mainClass>cn.cslg.pas.Application</mainClass>
+                    <layout>ZIP</layout>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <!--阿里云镜像源(因需要提交到GithubActions,会引起依赖下载过慢的问题)-->
+    <repositories>
+        <repository>
+            <id>nexus-aliyun</id>
+            <name>nexus-aliyun</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+</project>

Diferenças do arquivo suprimidas por serem muito extensas
+ 68707 - 0
PCS/sql/pas.sql


+ 20 - 0
PCS/src/main/java/cn/cslg/permission/Application.java

@@ -0,0 +1,20 @@
+package cn.cslg.permission;
+
+import cn.hutool.cron.CronUtil;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+        CronUtil.setMatchSecond(true);
+        CronUtil.start();
+        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "后台程序已启动,请运行前台");
+    }
+
+}

+ 32 - 0
PCS/src/main/java/cn/cslg/permission/common/GlobalException.java

@@ -0,0 +1,32 @@
+package cn.cslg.permission.common;
+
+import cn.cslg.permission.common.core.exception.PermissionException;
+import cn.cslg.permission.common.utils.Response;
+import cn.cslg.permission.common.utils.ResponseEnum;
+import cn.dev33.satoken.exception.NotLoginException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 全局异常处理
+ */
+@RestControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
+public class GlobalException {
+
+    // 全局异常拦截(拦截项目中的所有异常)
+    @ExceptionHandler
+    public String handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        // 打印堆栈,以供调试
+        e.printStackTrace();
+        if (e instanceof NotLoginException) {
+            return Response.error(ResponseEnum.UNAUTHORIZED);
+        } else if (e instanceof PermissionException) {
+            return Response.error(ResponseEnum.NOT_PERMISSION);
+        } else {
+            return Response.error(ResponseEnum.SYSTEM_ERROR);
+        }
+    }
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/config/AsyncExceptionHandler.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.config;
+
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+
+import java.lang.reflect.Method;
+
+public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
+
+    @Override
+    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
+        ex.printStackTrace();
+    }
+}

+ 53 - 0
PCS/src/main/java/cn/cslg/permission/common/config/AsyncTaskPoolConfig.java

@@ -0,0 +1,53 @@
+package cn.cslg.permission.common.config;
+
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@EnableAsync
+@Configuration
+public class AsyncTaskPoolConfig implements AsyncConfigurer {
+
+    @Bean("singleThreadAsyncTaskExecutor")
+    public AsyncTaskExecutor singleThreadAsyncTaskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(1);
+        executor.setMaxPoolSize(1);
+        executor.setQueueCapacity(64);
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.initialize();
+        return executor;
+    }
+
+    @Override
+    public Executor getAsyncExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        //配置核心线程数
+        executor.setCorePoolSize(8);
+        //配置最大线程数
+        executor.setMaxPoolSize(16);
+        //配置队列大小
+        executor.setQueueCapacity(64);
+        //配置线程池中的线程的名称前缀
+        executor.setThreadNamePrefix("async-service-");
+
+        // 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务
+        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        //执行初始化
+        executor.initialize();
+        return executor;
+    }
+
+    @Override
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+        return new AsyncExceptionHandler();
+    }
+}

+ 24 - 0
PCS/src/main/java/cn/cslg/permission/common/config/MetaObjectHandlerConfig.java

@@ -0,0 +1,24 @@
+package cn.cslg.permission.common.config;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+@Slf4j
+@Component
+public class MetaObjectHandlerConfig implements MetaObjectHandler {
+
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        setFieldValByName("createTime", new Date(), metaObject);
+        setFieldValByName("updateTime", new Date(), metaObject);
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        setFieldValByName("updateTime", new Date(), metaObject);
+    }
+}

+ 20 - 0
PCS/src/main/java/cn/cslg/permission/common/config/MybatisPlusConfig.java

@@ -0,0 +1,20 @@
+package cn.cslg.permission.common.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("cn.cslg.pas.mapper")
+public class MybatisPlusConfig {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+}

+ 35 - 0
PCS/src/main/java/cn/cslg/permission/common/config/SaTokenConfigure.java

@@ -0,0 +1,35 @@
+package cn.cslg.permission.common.config;
+
+import cn.cslg.permission.common.core.base.Constants;
+import cn.cslg.permission.common.utils.Response;
+import cn.cslg.permission.common.utils.ResponseEnum;
+import cn.cslg.permission.common.utils.StpAdminUtil;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.stp.StpUtil;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SaTokenConfigure {
+
+    @Bean
+    public SaServletFilter getSaServletFilter() {
+        return new SaServletFilter()
+                .addInclude(Constants.API_VERSION_V2 + "/**")
+                .addExclude("/favicon.ico")
+                .setAuth(obj -> {
+                    SaRouter.match(Constants.API_VERSION_V2 + "/**").notMatch(
+                            Constants.API_VERSION_V2 + "/ws/**",
+                            Constants.API_VERSION_V2 + "/test/**",
+                            Constants.API_VERSION_V2 + "/oauth2/**",
+                            Constants.API_VERSION_V2 + "/admin/**",
+                            Constants.API_VERSION_V2 + "/common/download",
+                            Constants.API_VERSION_V2 + "/common/export"
+                    ).check(StpUtil::checkLogin);
+                    SaRouter.match(Constants.API_VERSION_V2 + "/admin/**", Constants.API_VERSION_V2 + "/admin/login", StpAdminUtil::checkLogin);
+                })
+                .setError(e -> Response.error(ResponseEnum.UNAUTHORIZED));
+    }
+
+}

+ 18 - 0
PCS/src/main/java/cn/cslg/permission/common/config/SpringDocConfig.java

@@ -0,0 +1,18 @@
+package cn.cslg.permission.common.config;
+
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SpringDocConfig {
+
+    @Bean
+    public OpenAPI apiInfo() {
+        return new OpenAPI().info(new Info().title("接口文档").description("接口文档").version("v1.0.0"));
+    }
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/config/WebSocketConfig.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+@Configuration
+public class WebSocketConfig {
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+}

+ 849 - 0
PCS/src/main/java/cn/cslg/permission/common/core/Convert.java

@@ -0,0 +1,849 @@
+package cn.cslg.permission.common.core;
+
+import cn.cslg.permission.common.utils.StringUtils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.NumberFormat;
+import java.util.Set;
+
+/**
+ * 类型转换器
+ */
+public class Convert {
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static String toStr(Object value, String defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof String) {
+            return (String) value;
+        }
+        return value.toString();
+    }
+
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static String toStr(Object value) {
+        return toStr(value, null);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Character toChar(Object value, Character defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof Character) {
+            return (Character) value;
+        }
+
+        final String valueStr = toStr(value, null);
+        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Character toChar(Object value) {
+        return toChar(value, null);
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Byte toByte(Object value, Byte defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Byte) {
+            return (Byte) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Byte.parseByte(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Byte toByte(Object value) {
+        return toByte(value, null);
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Short toShort(Object value, Short defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Short) {
+            return (Short) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Short.parseShort(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Short toShort(Object value) {
+        return toShort(value, null);
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Number toNumber(Object value, Number defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Number) {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return NumberFormat.getInstance().parse(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Number toNumber(Object value) {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Integer toInt(Object value, Integer defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Integer toInt(Object value) {
+        return toInt(value, null);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String str) {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String str) {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param split 分隔符
+     * @param split 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Integer[]{};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param split 分隔符
+     * @param str   被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Long[]{};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String str) {
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param split 分隔符
+     * @param split 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String split, String str) {
+        return str.split(split);
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Long toLong(Object value, Long defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).longValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Long toLong(Object value) {
+        return toLong(value, null);
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Double toDouble(Object value, Double defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Double) {
+            return (Double) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Double toDouble(Object value) {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Float toFloat(Object value, Float defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Float) {
+            return (Float) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Float.parseFloat(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Float toFloat(Object value) {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 转换为boolean<br>
+     * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        switch (valueStr) {
+            case "true":
+                return true;
+            case "false":
+                return false;
+            case "yes":
+                return true;
+            case "ok":
+                return true;
+            case "no":
+                return false;
+            case "1":
+                return true;
+            case "0":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为boolean<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value) {
+        return toBool(value, null);
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     *
+     * @param clazz        Enum的Class
+     * @param value        值
+     * @param defaultValue 默认值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass())) {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Enum.valueOf(clazz, valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     *
+     * @param clazz Enum的Class
+     * @param value 值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger) {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long) {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigInteger(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value) {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long) {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double) {
+            return new BigDecimal((Double) value);
+        }
+        if (value instanceof Integer) {
+            return new BigDecimal((Integer) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigDecimal(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value) {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj 对象
+     * @return 字符串
+     */
+//    public static String utf8Str(Object obj)
+//    {
+//        return str(obj, CharsetKit.CHARSET_UTF_8);
+//    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj         对象
+     * @param charsetName 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, String charsetName) {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj     对象
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, Charset charset) {
+        if (null == obj) {
+            return null;
+        }
+
+        if (obj instanceof String) {
+            return (String) obj;
+        } else if (obj instanceof byte[] || obj instanceof Byte[]) {
+            return str((Byte[]) obj, charset);
+        } else if (obj instanceof ByteBuffer) {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将byte数组转为字符串
+     *
+     * @param bytes   byte数组
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(byte[] bytes, String charset) {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 解码字节码
+     *
+     * @param data    字符串
+     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+     * @return 解码后的字符串
+     */
+    public static String str(byte[] data, Charset charset) {
+        if (data == null) {
+            return null;
+        }
+
+        if (null == charset) {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, String charset) {
+        if (data == null) {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, Charset charset) {
+        if (null == charset) {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    // ----------------------------------------------------------------------- 全角半角转换
+
+    /**
+     * 半角转全角
+     *
+     * @param input String.
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input) {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 半角转全角
+     *
+     * @param input         String
+     * @param notConvertSet 不替换的字符集合
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet) {
+        char c[] = input.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == ' ') {
+                c[i] = '\u3000';
+            } else if (c[i] < '\177') {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 全角转半角
+     *
+     * @param input String.
+     * @return 半角字符串
+     */
+    public static String toDBC(String input) {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 替换全角为半角
+     *
+     * @param text          文本
+     * @param notConvertSet 不替换的字符集合
+     * @return 替换后的字符
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet) {
+        char c[] = text.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == '\u3000') {
+                c[i] = ' ';
+            } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        String returnString = new String(c);
+
+        return returnString;
+    }
+
+    /**
+     * 数字金额大写转换 先写个完整的然后将如零拾替换成零
+     *
+     * @param n 数字
+     * @return 中文大写数字
+     */
+    public static String digitUppercase(double n) {
+        String[] fraction = {"角", "分"};
+        String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
+        String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
+
+        String head = n < 0 ? "负" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++) {
+            s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
+        }
+        if (s.length() < 1) {
+            s = "整";
+        }
+        int integerPart = (int) Math.floor(n);
+
+        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
+            String p = "";
+            for (int j = 0; j < unit[1].length && n > 0; j++) {
+                p = digit[integerPart % 10] + unit[1][j] + p;
+                integerPart = integerPart / 10;
+            }
+            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
+        }
+        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
+    }
+}

+ 14 - 0
PCS/src/main/java/cn/cslg/permission/common/core/annotation/AnnotationParse.java

@@ -0,0 +1,14 @@
+package cn.cslg.permission.common.core.annotation;
+
+import java.lang.reflect.Method;
+
+public class AnnotationParse {
+
+    public static int[] permissionParse(Method method) throws Exception {
+        if(method.isAnnotationPresent(Permission.class)){
+            Permission annotation = method.getAnnotation(Permission.class);
+            return annotation.roles();
+        }
+        return null;
+    }
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/core/annotation/Permission.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Permission {
+    int[] roles();
+}

+ 52 - 0
PCS/src/main/java/cn/cslg/permission/common/core/annotation/PermissionAspect.java

@@ -0,0 +1,52 @@
+package cn.cslg.permission.common.core.annotation;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Aspect
+@Component
+public class PermissionAspect {
+
+//    @Autowired
+//    private ProjectUserService projectUserService;
+//    @Autowired
+//    private ProjectService projectService;
+//    @Autowired
+//    private CacheUtils cacheUtils;
+//
+//    @Pointcut("execution(public * cn.cslg.pas.controller.*.*(..))")
+//    public void privilege() {
+//    }
+//
+//    @ResponseBody
+//    @Around("privilege()")
+//    public Object isAccessMethod(ProceedingJoinPoint joinPoint) throws Throwable {
+//        //获取访问目标方法
+//        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+//        Method targetMethod = methodSignature.getMethod();
+//        final int[] methodAccess = AnnotationParse.permissionParse(targetMethod);
+//        if (methodAccess != null && methodAccess.length != 0) {
+//            HttpServletRequest request = RequestHolder.getRequest();
+//            if (request != null) {
+//                String projectId = request.getHeader("x-project-id");
+//                Integer userId = StpUtil.getLoginIdAsInt();
+//                if (StringUtils.isNotEmpty(projectId)) {
+//                    Project project = projectService.getById(projectId);
+//                    User user = cacheUtils.getLoginUser(userId);
+//                    ProjectUser projectUser = projectUserService.getProjectUserByProjectIdAndUserId(Integer.parseInt(projectId), userId);
+//                    if (projectUser != null && project != null && user != null) {
+//                        if (project.getCreateBy().equals(userId)) {
+//                            return joinPoint.proceed();
+//                        }
+//                        if (Arrays.stream(methodAccess).noneMatch(item -> item == projectUser.getType())) {
+//                            throw new PermissionException("用户操作拦截");
+//                        }
+//                    }
+//                }
+//            }
+//        }
+//        return joinPoint.proceed();
+//    }
+}

+ 146 - 0
PCS/src/main/java/cn/cslg/permission/common/core/base/Constants.java

@@ -0,0 +1,146 @@
+package cn.cslg.permission.common.core.base;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Constants {
+
+    public static final String ADMIN_USERNAME = "admin";
+
+    public static final String PROJECT_INFO_FILE_NAME = "project.json";
+    public static final String PROJECT_REPORT_DIRECTORY_NAME = "project-report";
+    public static final String PROJECT_REPORT_FILE_NAME = "project-report.json";
+    public static final String PROJECT_FILE_DIRECTORY_NAME = "project-file";
+    public static final String PROJECT_FILE_FILE_NAME = "project-file.json";
+    public static final String PROJECT_PATENT_LINK_FILE_NAME = "project-patent-link.json";
+    public static final String PATENT_IMAGE_DIRECTORY_NAME = "patent-image";
+    public static final String PATENT_IMAGE_FILE_NAME = "patent-image.json";
+    public static final String PATENT_INSTRUCTION_DIRECTORY_NAME = "patent-instruction";
+    public static final String PATENT_INSTRUCTION_FILE_NAME = "patent-instruction.json";
+    public static final String PATENT_APPLICANT_MERGE_LINK_FILE_NAME = "patent-applicant-merge-link.json";
+    public static final String PATENT_APPLICANT_FILE_NAME = "patent-applicant.json";
+    public static final String PATENT_APPLICANT_LINK_FILE_NAME = "patent-applicant-link.json";
+    public static final String PATENT_FILE_NAME = "patent.json";
+    public static final String PATENT_ID_PATENT_NO_FILE_NAME = "patent-id-patentno.json";
+    public static final String PATENT_AFFAIR_FILE_NAME = "patent-affair.json";
+    public static final String PATENT_AGENCY_FILE_NAME = "patent-agency.json";
+    public static final String PATENT_AGENT_LINK_FILE_NAME = "patent-agent-link.json";
+    public static final String PATENT_AGENT_FILE_NAME = "patent-agent.json";
+    public static final String PATENT_INSTRUCTION_TEXT_FILE_NAME = "patent-instruction-text.json";
+    public static final String PATENT_INVENTOR_LINK_FILE_NAME = "patent-inventor-link.json";
+    public static final String PATENT_INVENTOR_MERGE_FILE_NAME = "patent-inventor-merge.json";
+    public static final String PATENT_INVENTOR_FILE_NAME = "patent-inventor.json";
+    public static final String PATENT_LICENSOR_FILE_NAME = "patent-licensor.json";
+    public static final String PATENT_PLEDGE_FILE_NAME = "patent-pledge.json";
+    public static final String PATENT_RIGHT_FILE_NAME = "patent-right.json";
+    public static final String PATENT_FAMILY_LINK_FILE_NAME = "patent-family-link.json";
+    public static final String PATENT_FAMILY_FILE_NAME = "patent-family.json";
+    public static final String PATENT_CLASS_NUMBER_FILE_NAME = "patent-class-number.json";
+    public static final String PATENT_LABEL_FILE_NAME = "patent-label.json";
+    public static final String PROJECT_FIELD_FILE_NAME = "project-field.json";
+    public static final String PROJECT_FIELD_OPTION_FILE_NAME = "project-field-option.json";
+    public static final String PROJECT_FIELD_TREE_FILE_NAME = "project-field-tree.json";
+    public static final String PROJECT_FIELD_TEXT_FILE_NAME = "project-field-text.json";
+    public static final String PROJECT_FIELD_PATENT_LINK_FILE_NAME = "project-field-patent-link.json";
+
+    public static final String API_VERSION_V2 = "/api/v2";
+
+    public static final Integer PATENT_CLASS_NUMBER_IPC = 1;
+    public static final Integer PATENT_CLASS_NUMBER_CPC = 2;
+    public static final Integer PATENT_CLASS_NUMBER_UPC = 3;
+    public static final Integer PATENT_CLASS_NUMBER_LOC = 4;
+
+    /**
+     * 分隔符-竖线
+     */
+    public static final String SEPARATOR_VERTICAL_BAR = " | ";
+
+    /**
+     * 系统字段类型-查询检索
+     */
+    public static final String SYSTEM_FIELD_QUERY = "query";
+
+    /**
+     * 系统字段类型-专利导出
+     */
+    public static final String SYSTEM_FIELD_EXPORT = "export";
+
+    /**
+     * 系统字段类型-专利列表
+     */
+    public static final String SYSTEM_FIELD_PATENT_LIST = "list";
+
+    /**
+     * 系统字段类型-专题库字段
+     */
+    public static final String SYSTEM_FIELD_PROJECT = "project";
+
+    /**
+     * 专题库导入专利任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT = 1;
+
+    /**
+     * 专利说明书导入任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT_INSTRUCTION = 3;
+
+    /**
+     * 专利导出任务名称
+     */
+    public static final Integer TASK_EXPORT_PATENT = 2;
+
+    /**
+     * 日期位移值
+     */
+    public static final Map<String, Integer> DATE_OFFSET = new HashMap<String, Integer>() {{
+        put("月", -1);
+        put("季", -3);
+        put("半年", -6);
+        put("年", -12);
+        put("2年", -24);
+        put("3年", -36);
+        put("5年", -60);
+    }};
+
+    /**
+     * 专利类型
+     */
+    public static final String PATENT_TYPE = "PATENT_TYPE";
+
+    /**
+     * 机构类型
+     */
+    public static final String ORGAN_TYPE = "ORGAN_TYPE";
+
+    /**
+     * 许可人/被许可人
+     */
+    public static final String LICENSOR_TYPE = "LICENSOR_TYPE";
+
+    /**
+     * 简单法律状态
+     */
+    public static final String PATENT_SIMPLE_STATUS = "PATENT_SIMPLE_STATUS";
+
+    /**
+     * 国家
+     */
+    public static final String COUNTRIES = "COUNTRIES";
+
+    /**
+     * 法律状态
+     */
+    public static final String PATENT_STATUS = "PATENT_STATUS";
+
+    /**
+     * 企业应用场景
+     */
+    public static final String ENTERPRISE_APPLICATION_SCENARIO = "ENTERPRISE_APPLICATION_SCENARIO";
+
+    /**
+     * 调查类型
+     */
+    public static final String INVESTIGATION_TYPE = "INVESTIGATION_TYPE";
+
+}

+ 9 - 0
PCS/src/main/java/cn/cslg/permission/common/core/base/DocFlag.java

@@ -0,0 +1,9 @@
+package cn.cslg.permission.common.core.base;
+
+public class DocFlag {
+    public final static String classify = "^@=classify-\\d+:.*@$";
+    public final static String titleNumber = "^@=index-\\d+(.\\d+)*:.*@$";
+    public final static String content = "^\\d+.*";
+//    public final  static String content="^\\d+.根据权利要求";
+//    public final  static String nocontent="^(?:(?!^\\d+.根据权利要求).)*";//不以开头
+}

+ 15 - 0
PCS/src/main/java/cn/cslg/permission/common/core/base/EStatus.java

@@ -0,0 +1,15 @@
+package cn.cslg.permission.common.core.base;
+
+/**
+ * 状态枚举类
+ */
+public class EStatus {
+    /**
+     * 删除的
+     */
+    public static final int DISABLED = 0;
+    /**
+     * 激活的
+     */
+    public static final int ENABLE = 1;
+}

+ 20 - 0
PCS/src/main/java/cn/cslg/permission/common/core/base/RedisConf.java

@@ -0,0 +1,20 @@
+package cn.cslg.permission.common.core.base;
+
+
+/**
+ * Redis常量类
+ */
+public class RedisConf {
+
+    public static final String SYMBOL_COLON = ":";
+    public static final String SYMBOL_LINE = "-";
+    public final static String COMMON_DATA = "common-data";
+    public final static String LOGIN_USER = "login-user";
+    public final static String VERIFY_CODE = "verify-code";
+    public final static String SELECT_PATENT = "select-patent";
+    public final static String ANALYSIS_COUNT = "analysis-count";
+    public final static String AREA_LIST = "area-list";
+    public final static String USER_FIELD = "user-field";
+    public final static String FIELD_ORDER = "field-order";
+    public final static String USER_IMPORT = "user-import";
+}

+ 116 - 0
PCS/src/main/java/cn/cslg/permission/common/core/base/RequestHolder.java

@@ -0,0 +1,116 @@
+package cn.cslg.permission.common.core.base;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@Slf4j
+public class RequestHolder {
+
+    /**
+     * 获取request
+     *
+     * @return HttpServletRequest
+     */
+    public static HttpServletRequest getRequest() {
+        log.debug("getRequest -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return null;
+        }
+        return servletRequestAttributes.getRequest();
+    }
+
+    /**
+     * 获取Response
+     *
+     * @return HttpServletRequest
+     */
+    public static HttpServletResponse getResponse() {
+        log.debug("getResponse -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return null;
+        }
+        return servletRequestAttributes.getResponse();
+    }
+
+    /**
+     * 获取session
+     *
+     * @return HttpSession
+     */
+    public static HttpSession getSession() {
+        log.debug("getSession -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        HttpServletRequest request = null;
+        if (null == (request = getRequest())) {
+            return null;
+        }
+        return request.getSession();
+    }
+
+    /**
+     * 获取session的Attribute
+     *
+     * @param name session的key
+     * @return Object
+     */
+    public static Object getSession(String name) {
+        log.debug("getSession -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return null;
+        }
+        return servletRequestAttributes.getAttribute(name, RequestAttributes.SCOPE_SESSION);
+    }
+
+    /**
+     * 添加session
+     *
+     * @param name
+     * @param value
+     */
+    public static void setSession(String name, Object value) {
+        log.debug("setSession -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return;
+        }
+        servletRequestAttributes.setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
+    }
+
+    /**
+     * 清除指定session
+     *
+     * @param name
+     * @return void
+     */
+    public static void removeSession(String name) {
+        log.debug("removeSession -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return;
+        }
+        servletRequestAttributes.removeAttribute(name, RequestAttributes.SCOPE_SESSION);
+    }
+
+    /**
+     * 获取所有session key
+     *
+     * @return String[]
+     */
+    public static String[] getSessionKeys() {
+        log.debug("getSessionKeys -- Thread id :{}, name : {}", Thread.currentThread().getId(), Thread.currentThread().getName());
+        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
+        if (null == servletRequestAttributes) {
+            return null;
+        }
+        return servletRequestAttributes.getAttributeNames(RequestAttributes.SCOPE_SESSION);
+    }
+
+}

+ 90 - 0
PCS/src/main/java/cn/cslg/permission/common/core/exception/BaseException.java

@@ -0,0 +1,90 @@
+package cn.cslg.permission.common.core.exception;
+
+import cn.cslg.permission.common.utils.SpringUtils;
+import cn.cslg.permission.common.utils.StringUtils;
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+/**
+ * 基础异常
+ */
+public class BaseException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 所属模块
+     */
+    private String module;
+
+    /**
+     * 错误码
+     */
+    private String code;
+
+    /**
+     * 错误码对应的参数
+     */
+    private Object[] args;
+
+    /**
+     * 错误消息
+     */
+    private String defaultMessage;
+
+    public BaseException(String module, String code, Object[] args, String defaultMessage) {
+        this.module = module;
+        this.code = code;
+        this.args = args;
+        this.defaultMessage = defaultMessage;
+    }
+
+    public BaseException(String module, String code, Object[] args) {
+        this(module, code, args, null);
+    }
+
+    public BaseException(String module, String defaultMessage) {
+        this(module, null, null, defaultMessage);
+    }
+
+    public BaseException(String code, Object[] args) {
+        this(null, code, args, null);
+    }
+
+    public BaseException(String defaultMessage) {
+        this(null, null, null, defaultMessage);
+    }
+
+    @Override
+    public String getMessage() {
+        String message = null;
+        if (!StringUtils.isEmpty(code)) {
+            message = message(code, args);
+        }
+        if (message == null) {
+            message = defaultMessage;
+        }
+        return message;
+    }
+
+    public static String message(String code, Object... args) {
+        MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
+        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
+    }
+
+    public String getModule() {
+        return module;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public Object[] getArgs() {
+        return args;
+    }
+
+    public String getDefaultMessage() {
+        return defaultMessage;
+    }
+}
+

+ 16 - 0
PCS/src/main/java/cn/cslg/permission/common/core/exception/CustomException.java

@@ -0,0 +1,16 @@
+package cn.cslg.permission.common.core.exception;
+
+public class CustomException extends RuntimeException {
+
+    public CustomException(String message) {
+        super(message);
+    }
+
+    public CustomException(Throwable cause) {
+        super(cause);
+    }
+
+    public CustomException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

+ 16 - 0
PCS/src/main/java/cn/cslg/permission/common/core/exception/PermissionException.java

@@ -0,0 +1,16 @@
+package cn.cslg.permission.common.core.exception;
+
+public class PermissionException extends RuntimeException {
+
+    public PermissionException(String message) {
+        super(message);
+    }
+
+    public PermissionException(Throwable cause) {
+        super(cause);
+    }
+
+    public PermissionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

+ 47 - 0
PCS/src/main/java/cn/cslg/permission/common/model/BaseEntity.java

@@ -0,0 +1,47 @@
+package cn.cslg.permission.common.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * Entity基类
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class BaseEntity<T extends Model> extends Model {
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4851055162892178225L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 创建人
+     */
+    @TableField(value = "CREATE_USER")
+    private Integer createUser;
+
+    /**
+     * 创建时间
+     */
+    @TableField(value = "CREATE_TIME")
+    private Date createTime;
+
+    /**
+     * 删除标记(1是0否)
+     */
+    @TableField(value = "IS_DELETE")
+    private int isDelete;
+
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/AreaAddressDTO.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class AreaAddressDTO {
+    private Integer provinceId;
+    private Integer cityId;
+    private Integer areaId;
+    private String provinceName;
+    private String cityName;
+    private String areaName;
+}

+ 31 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/ClassNumberDTO.java

@@ -0,0 +1,31 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class ClassNumberDTO {
+    /**
+     * 部
+     */
+    private String a;
+    /**
+     * 大类
+     */
+    private String b;
+    /**
+     * 小类
+     */
+    private String c;
+    /**
+     * 大组
+     */
+    private String d;
+    /**
+     * 小组
+     */
+    private String e;
+    /**
+     * 分类号
+     */
+    private String classNumber;
+}

+ 8 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/CommonData.java

@@ -0,0 +1,8 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class CommonData {
+
+}

+ 12 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/CustomFieldDTO.java

@@ -0,0 +1,12 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class CustomFieldDTO {
+    private String name;
+    private Integer type;
+    private List<String> selected;
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/CustomFieldLabelDTO.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class CustomFieldLabelDTO {
+    private Integer id;
+    private Integer type;
+    private String name;
+    private List<LabelDTO> selected;
+}

+ 9 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/LabelDTO.java

@@ -0,0 +1,9 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class LabelDTO {
+    private String label;
+    private Integer value;
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/PageDTO.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PageDTO<T> {
+    private Integer total;
+    private Long size;
+    private Long current;
+    private List<T> records;
+}

+ 11 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/PatentQueryFieldSourceDTO.java

@@ -0,0 +1,11 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class PatentQueryFieldSourceDTO {
+    private String value;
+    private String label;
+    private Integer count;
+    private String ids;
+}

+ 9 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/ProjectFieldOrderDTO.java

@@ -0,0 +1,9 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class ProjectFieldOrderDTO {
+    private Integer id;
+    private Integer order;
+}

+ 19 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/TaskWebSocketDTO.java

@@ -0,0 +1,19 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+public class TaskWebSocketDTO {
+    private Integer projectId;
+    private Integer total;
+    private Integer index;
+    private Integer taskId;
+    private Boolean complete;
+    private String url;
+    private String fileName;
+    private Integer taskType;
+    private Long percentage;
+    private String oldName;
+}

+ 12 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/UploadFileDTO.java

@@ -0,0 +1,12 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class UploadFileDTO {
+    private String name;
+    private String fileName;
+    private String path;
+    private String extName;
+    private Long fileSize;
+}

+ 147 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/BackupUtils.java

@@ -0,0 +1,147 @@
+package cn.cslg.permission.common.utils;
+
+import cn.hutool.core.io.FileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+@Slf4j
+public class BackupUtils {
+
+    private final static String BACKUP_CONFIG = "backup-config.yml";
+
+    private static Backup getBackupConfig() {
+        try {
+            ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+            File file = ah.getSource();
+            String rootPath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + BACKUP_CONFIG;
+            Yaml yaml = new Yaml();
+            InputStream in = FileUtil.getInputStream(rootPath);
+            Backup backup = yaml.loadAs(in, Backup.class);
+            if (in != null) {
+                in.close();
+            }
+            return backup;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static void main(String[] args) {
+        System.out.println(getBackupConfig());
+    }
+
+    public void run() {
+        Backup backup = getBackupConfig();
+        if (backup == null) {
+            log.info("数据库备份配置文件不存在");
+            return;
+        }
+        log.info("数据库备份配置文件:{}", backup);
+        if (backup.isEnable()) {
+            String path = FileUtils.getStaticPath(FileUtils.BACKUP_FILE);
+            String fileName = DateUtils.getNowTimeFormat(DateUtils.YYYYMMDDHHMMSS) + ".sql";
+            try {
+                String cmd = String.format("mysqldump --skip-opt -h%s -P%s -u%s -p%s %s > %s", backup.getHost(), backup.getPort(), backup.getUsername(), backup.getPassword(), backup.getDb(), path + FileUtils.FILE_SEPARATOR + fileName);
+                String[] command;
+                if (backup.getOs() == 0) {
+                    command = new String[]{"cmd", "/c", String.valueOf(cmd)};
+                } else {
+                    command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
+                }
+                Runtime.getRuntime().exec(command);
+                log.info("备份数据库成功");
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("备份数据库失败");
+            }
+        }
+    }
+
+    public static class Backup {
+        private String host;
+        private String port;
+        private String db;
+        private String username;
+        private String password;
+        private int os;
+        private boolean enable;
+
+        @Override
+        public String toString() {
+            return "Backup{" +
+                    "host='" + host + '\'' +
+                    ", port='" + port + '\'' +
+                    ", db='" + db + '\'' +
+                    ", username='" + username + '\'' +
+                    ", password='" + password + '\'' +
+                    ", os=" + os +
+                    ", enable=" + enable +
+                    '}';
+        }
+
+        public boolean isEnable() {
+            return enable;
+        }
+
+        public void setEnable(boolean enable) {
+            this.enable = enable;
+        }
+
+        public String getHost() {
+            return host;
+        }
+
+        public void setHost(String host) {
+            this.host = host;
+        }
+
+        public String getPort() {
+            return port;
+        }
+
+        public void setPort(String port) {
+            this.port = port;
+        }
+
+        public String getDb() {
+            return db;
+        }
+
+        public void setDb(String db) {
+            this.db = db;
+        }
+
+        public String getUsername() {
+            return username;
+        }
+
+        public void setUsername(String username) {
+            this.username = username;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        public void setPassword(String password) {
+            this.password = password;
+        }
+
+        public int getOs() {
+            return os;
+        }
+
+        public void setOs(int os) {
+            this.os = os;
+        }
+    }
+
+}

+ 769 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/DateUtils.java

@@ -0,0 +1,769 @@
+package cn.cslg.permission.common.utils;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+public class DateUtils {
+
+    public static final String STARTTIME = " 00:00:00";
+    public static final String ENDTIME = " 23:59:59";
+    public final static String FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";
+    public final static String[] REPLACE_STRING = new String[]{"GMT+0800", "GMT+08:00"};
+    public final static String SPLIT_STRING = "(中国标准时间)";
+    public static Logger log = LoggerFactory.getLogger(DateUtils.class);
+
+    public static String YYYY = "yyyy";
+
+    public static String YYYY_MM = "yyyy-MM";
+
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static String YYYYMMDD = "yyyyMMdd";
+
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    public static String getDateSourceName(Date startTime, Date endTime, Integer offset, Integer index) {
+        String ret = null;
+        switch (offset) {
+            case -1:
+                ret = DateUtil.format(startTime, "yyyy-MM");
+                break;
+            case -3:
+                ret = String.format("%s-Q%s", DateUtil.format(startTime, "yyyy"), (index % 4) + 1);
+                break;
+            case -6:
+                ret = String.format("%s-%s", DateUtil.format(startTime, "yyyy"), index % 2 == 0 ? "H1" : "H2");
+                break;
+            case -12:
+                ret = DateUtil.format(startTime, "yyyy");
+                break;
+            case -24:
+            case -36:
+            case -60:
+                ret = String.format("%s-%s", DateUtil.format(DateUtil.offsetMonth(endTime, offset / 12 * -1), "yyyy"), DateUtil.format(startTime, "yyyy"));
+                break;
+        }
+        return ret;
+    }
+
+    private DateUtils() {
+    }
+
+    public static Integer getWeek(String beginDateStr, String endDateStr, String date) {
+        DateTime beginDate = DateUtil.parseDate(beginDateStr);
+        DateTime endDate = DateUtil.parseDate(endDateStr);
+        DateTime currentDate = DateUtil.parseDate(date);
+        int week = 1;
+        if (DateUtil.isIn(currentDate, beginDate, endDate)) {
+            Date endDateOfWeek = DateUtil.endOfWeek(beginDate);
+            while (!DateUtil.isIn(currentDate, beginDate, endDateOfWeek)) {
+                ++week;
+                endDateOfWeek = DateUtil.endOfWeek(DateUtil.offsetDay(endDateOfWeek, 1));
+            }
+            return week;
+        }
+        return -1;
+    }
+
+    public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
+        Calendar date = Calendar.getInstance();
+        date.setTime(nowTime);
+        Calendar begin = Calendar.getInstance();
+        begin.setTime(beginTime);
+        Calendar end = Calendar.getInstance();
+        end.setTime(endTime);
+        return date.after(begin) && date.before(end);
+    }
+
+    /**
+     * 获取现在的时间 yyyy-MM-dd HH:mm:ss
+     *
+     * @return
+     */
+    public static String getNowTime() {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = new Date(System.currentTimeMillis());
+        return formate.format(date);
+    }
+
+    /**
+     * 获取当前Date型日期
+     *
+     * @return Date() 当前日期
+     */
+    public static Date getNowDate() {
+        return new Date();
+    }
+
+    public static Integer getDateTime() {
+        return (int) (new Date().getTime() / 1000);
+    }
+
+    public static Integer getDateTime(String date) {
+        int dateTime = 0;
+        if (date.contains("/")) {
+            dateTime = Math.toIntExact(strToDateTime(date, parsePatterns[4]).getTime() / 1000);
+        } else if (date.contains("-")) {
+            dateTime = Math.toIntExact(strToDateTime(date, YYYY_MM_DD).getTime() / 1000);
+        }
+        return dateTime;
+    }
+
+    /**
+     * @return
+     * @author 陌溪
+     * @date 2018年6月14日
+     */
+    public static String getNowTimeFormat(String format) {
+        SimpleDateFormat formate = new SimpleDateFormat(format);
+        Date date = new Date(System.currentTimeMillis());
+        return formate.format(date);
+    }
+
+
+    public static Date str2Date(String dateString) {
+        try {
+            dateString = dateString.split(Pattern.quote(SPLIT_STRING))[0].replace(REPLACE_STRING[0], REPLACE_STRING[1]);
+            SimpleDateFormat sf1 = new SimpleDateFormat("E MMM dd yyyy HH:mm:ss z", Locale.US);
+            Date date = sf1.parse(dateString);
+            return date;
+        } catch (Exception e) {
+            throw new RuntimeException("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+        }
+    }
+
+    public static Date strToDate(String dateString) {
+        try {
+            SimpleDateFormat sf1;
+            if (dateString.contains("-")) {
+                sf1 = new SimpleDateFormat("yyyy-MM-dd");
+            } else if (dateString.contains("//")) {
+                sf1 = new SimpleDateFormat("yyyy/MM/dd");
+            } else if (dateString.contains(":")) {
+                sf1 = new SimpleDateFormat("yyyy:MM:dd");
+            } else if (dateString.contains(".")) {
+                sf1 = new SimpleDateFormat("yyyy.MM.dd");
+            } else {
+                sf1 = new SimpleDateFormat("yyyyMMdd");
+            }
+
+            Date date = sf1.parse(dateString);
+            return date;
+        } catch (Exception e) {
+            throw new RuntimeException("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+        }
+    }
+
+    /**
+     * 获取今天开始的时间
+     *
+     * @return
+     */
+    public static String getToDayStartTime() {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis());
+        return formate.format(date);
+    }
+
+    /**
+     * 获取今天结束的时间
+     *
+     * @return
+     */
+    public static String getToDayEndTime() {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis());
+        return formate.format(date);
+    }
+
+    /**
+     * 获取昨天开始的时间
+     *
+     * @return
+     */
+    public static String getYestodayStartTime() {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return formate.format(date);
+    }
+
+    /**
+     * 获取昨天结束的时间
+     *
+     * @return
+     */
+    public static String getYestodayEndTime() {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return formate.format(date);
+    }
+
+    /**
+     * 获取某天开始的时间
+     *
+     * @return
+     */
+    public static String getOneDayStartTime(String oneDay) {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return formate.format(date);
+    }
+
+    /**
+     * 获取某天开始的日期
+     *
+     * @param oneDay
+     * @return
+     */
+    public static String getOneDayStartTime(Date oneDay) {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return formate.format(oneDay);
+    }
+
+    /**
+     * 获取某天结束的时间
+     *
+     * @return
+     */
+    public static String getOneDayEndTime(String oneDay) {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return formate.format(date);
+    }
+
+    /**
+     * 获取某天结束的日期
+     *
+     * @param oneDay
+     * @return
+     */
+    public static String getOneDayEndTime(Date oneDay) {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return formate.format(oneDay);
+    }
+
+
+    /**
+     * 获取本周开始的时间
+     *
+     * @return
+     */
+    public static Date getWeekStartTime() {
+        // 获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        return cal.getTime();
+    }
+
+    /**
+     * 将  String 转换成  date
+     *
+     * @param dateTime
+     * @return
+     */
+    public static Date strToDateTime(String dateTime) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    public static Date strToDateTime(String dateTime, String fmt) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat(fmt);
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 将  date 转换成  时间戳
+     *
+     * @return
+     */
+    public static Long dateToStamp(String s) throws ParseException {
+
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = simpleDateFormat.parse(s);
+        long ts = date.getTime();
+        return ts;
+    }
+
+    /**
+     * Date 转换成  String
+     *
+     * @param dateTime
+     * @return
+     */
+    public static String dateTimeToStr(Date dateTime) {
+
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return format.format(dateTime);
+    }
+
+    public static String dateTimeToStr(Date dateTime, String fmt) {
+
+        SimpleDateFormat format = new SimpleDateFormat(fmt);
+        return format.format(dateTime);
+    }
+
+    /**
+     * 获取本周开始的时间的字符串
+     *
+     * @return
+     */
+    public static String getWeekStartTimeStr() {
+        // 获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return formate.format(cal.getTime());
+    }
+
+    /**
+     * 获取本周结束的时间
+     *
+     * @return
+     */
+    public static Date getWeekEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本周结束的时间的字符串
+     *
+     * @return
+     */
+    public static String getWeekEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return formate.format(cal.getTime());
+    }
+
+    /**
+     * 获取上周开始的时间的字符串
+     *
+     * @return
+     */
+    public static String getLastWeekStartTimeStr() {
+        int weeks = -1;
+        int mondayPlus = getMondayPlus();
+        GregorianCalendar currentDate = new GregorianCalendar();
+        currentDate.add(GregorianCalendar.DATE, mondayPlus + 7 * weeks);
+        Date monday = currentDate.getTime();
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return formate.format(monday);
+    }
+
+    /**
+     * 获取本月开始的时间
+     *
+     * @return
+     */
+    public static Date getMonthStartTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月开始的时间的字符串
+     *
+     * @return
+     */
+    public static String getMonthStartTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return formate.format(cal.getTime());
+    }
+
+    /**
+     * 获取本月结束的时间
+     *
+     * @return
+     */
+    public static Date getMonthEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月结束的时间的字符串
+     *
+     * @return
+     */
+    public static String getMonthEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return formate.format(cal.getTime());
+    }
+
+    /**
+     * 获取当月的 天数
+     */
+    public static int getCurrentMonthDay() {
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        int maxDate = a.get(Calendar.DATE);
+        return maxDate;
+    }
+
+    /**
+     * 得到二个日期间的间隔天数
+     *
+     * @param date1
+     * @param date2
+     * @return
+     */
+    public static int getDayByTwoDay(String date1, String date2) {
+        SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
+        Long day = 0L;
+        try {
+            Date date = myFormatter.parse(date1);
+            Date mydate = myFormatter.parse(date2);
+            day = (date.getTime() - mydate.getTime()) / (24 * 60 * 60 * 1000);
+        } catch (Exception e) {
+            return 0;
+        }
+        return day.intValue();
+    }
+
+    /**
+     * 得到两个日期相差的秒数
+     *
+     * @param lastDate
+     * @param date
+     * @return
+     */
+    public static int getSecondByTwoDay(Date lastDate, Date date) {
+        Long second = 0L;
+        try {
+            second = (lastDate.getTime() - date.getTime()) / 1000;
+        } catch (Exception e) {
+            return 0;
+        }
+        return second.intValue();
+    }
+
+    /**
+     * 判断某个日期属于本周的第几天 (星期一代表第一天)
+     *
+     * @param dateTime
+     * @return
+     * @throws ParseException
+     */
+    public static int getDaysByWeek(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        int day = cal.get(Calendar.DAY_OF_WEEK);
+        day = day - 1;
+        if (day == 0) {
+            day = 7;
+        }
+        return day;
+    }
+
+    /**
+     * 判断某个日期属于本月的第几天
+     *
+     * @param dateTime
+     * @return
+     * @throws ParseException
+     */
+    public static int getDaysByMonth(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        int day = cal.get(Calendar.DAY_OF_MONTH);
+        return day;
+    }
+
+    /**
+     * 根据年 月 获取对应的月份 天数
+     */
+    public static int getDaysByYearMonth(int year, int month) {
+
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.YEAR, year);
+        a.set(Calendar.MONTH, month - 1);
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        int maxDate = a.get(Calendar.DATE);
+        return maxDate;
+    }
+
+
+    /**
+     * 获取当前的年
+     *
+     * @return
+     */
+    public static Integer getYears() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.YEAR);
+
+    }
+
+    /**
+     * 获取当前的月
+     *
+     * @return
+     */
+    public static Integer getMonth() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.MONTH) + 1;
+
+    }
+
+    /**
+     * 获取当前天
+     *
+     * @return
+     */
+    public static Integer getDay() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * wx支付的过期时间
+     *
+     * @param hour
+     * @return
+     */
+    @SuppressWarnings("unused")
+    public static String getTime(double hour) {
+        Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
+        long time = (long) (System.currentTimeMillis() + hour * 60 * 60 * 1000L);
+        Date date = new Date(time);
+        SimpleDateFormat formate = new SimpleDateFormat("yyyyMMddHHmmss");
+        String format = formate.format(date);
+        return format;
+    }
+
+    /**
+     * 获得当前日期与本周日相差的天数
+     *
+     * @return
+     */
+    private static int getMondayPlus() {
+        Calendar cd = Calendar.getInstance();
+        // 获得今天是一周的第几天,星期日是第一天,星期二是第二天......
+        // 因为按中国礼拜一作为第一天所以这里减1
+        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 1;
+        if (dayOfWeek == 1) {
+            return 0;
+        } else {
+            return 1 - dayOfWeek;
+        }
+    }
+
+    /**
+     * 获取几天之后的日期
+     *
+     * @param date yyyy-MM-dd HH:mm:ss
+     * @param day  加减的天数
+     * @return
+     */
+    public static Date getDate(String date, int day) {
+        SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar cal = Calendar.getInstance();
+        try {
+            Date beforeDate = formate.parse(date);
+            cal.setTime(beforeDate);
+            cal.add(Calendar.DAY_OF_MONTH, day);
+            //cal.set(beforeDate.getYear(), beforeDate.getMonth(), beforeDate.getDay()+day, beforeDate.getHours(),beforeDate.getSeconds(), beforeDate.getMinutes());
+            Date newDate = cal.getTime();
+            return newDate;
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取某个日期 在加上 秒数的时间
+     *
+     * @param beforeDate yyyy-MM-dd HH:mm:ss
+     * @param timeSecond 加减的秒数
+     * @return
+     */
+    public static String getDateStr(Date beforeDate, Long timeSecond) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            // 返回毫秒数 + 添加的毫秒数
+            Long time = beforeDate.getTime() + timeSecond * 1000;
+            return format.format(time);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+        return "";
+    }
+
+    /**
+     * 把date转换成字符串
+     *
+     * @param date
+     * @param code 例如  yyyy-MM-dd 00:00:00
+     * @return
+     */
+    public static String formateDate(Date date, String code) {
+        SimpleDateFormat formate = new SimpleDateFormat(code);
+        return formate.format(date);
+
+    }
+
+    public static String formatDate(Integer timestamp, String code) {
+        if (timestamp == null || timestamp == 0) {
+            return "";
+        }
+        return formateDate(new Date(timestamp * 1000L), code);
+    }
+
+    /**
+     * 获取过去N天内的日期数组
+     *
+     * @param intervals intervals天内
+     * @param formatStr 格式化字符串   yyyy-MM-dd
+     * @return 日期数组
+     */
+    public static ArrayList<String> getDaysByN(int intervals, String formatStr) {
+        ArrayList<String> pastDaysList = new ArrayList<>();
+        for (int i = intervals - 1; i >= 0; i--) {
+            pastDaysList.add(getPastDate(i, formatStr));
+        }
+        return pastDaysList;
+    }
+
+    /**
+     * 获取过去第几天的日期
+     *
+     * @param past
+     * @return
+     */
+    public static String getPastDate(int past, String formatStr) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
+        Date today = calendar.getTime();
+        SimpleDateFormat format = new SimpleDateFormat(formatStr);
+        String result = format.format(today);
+        return result;
+    }
+
+    /**
+     * 获取某个时间段内所有日期
+     *
+     * @param begin
+     * @param end
+     * @return
+     */
+    public static List<String> getDayBetweenDates(String begin, String end) {
+        Date dBegin = strToDateTime(begin);
+        Date dEnd = strToDateTime(end);
+        List<String> lDate = new ArrayList<>();
+        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
+        lDate.add(sd.format(dBegin));
+        Calendar calBegin = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calBegin.setTime(dBegin);
+        Calendar calEnd = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calEnd.setTime(dEnd);
+        // 测试此日期是否在指定日期之后
+        while (dEnd.after(calBegin.getTime())) {
+            // 根据日历的规则,为给定的日历字段添加或减去指定的时间量
+            calBegin.add(Calendar.DAY_OF_MONTH, 1);
+            lDate.add(sd.format(calBegin.getTime()));
+        }
+        return lDate;
+    }
+
+    /**
+     * 获取服务器启动时间
+     */
+    public static Date getServerStartDate() {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 计算两个时间差
+     */
+    public static String getDatePoor(Date endDate, Date nowDate) {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 获得两个时间的毫秒时间差异
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 计算差多少天
+        long day = diff / nd;
+        // 计算差多少小时
+        long hour = diff % nd / nh;
+        // 计算差多少分钟
+        long min = diff % nd % nh / nm;
+        // 计算差多少秒//输出结果
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "天" + hour + "小时" + min + "分钟";
+    }
+
+    public static long getTimeDiff(Date date) {
+        long NTime = date.getTime();
+        long OTime = getNowDate().getTime();
+        return (NTime - OTime) / 1000 / 60;
+    }
+
+    public static Date setDateHourAndMinute(Date date, int hour, int minute) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, 0);
+        return calendar.getTime();
+    }
+}

+ 163 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/ExcelUtils.java

@@ -0,0 +1,163 @@
+package cn.cslg.permission.common.utils;
+
+import cn.cslg.permission.common.utils.DateUtils;
+import cn.cslg.permission.common.utils.FileUtils;
+import cn.cslg.permission.common.utils.SpringUtils;
+import cn.hutool.core.util.IdUtil;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+
+import java.awt.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelUtils {
+
+    public static Map<String, PictureData> getDataFromExcel(String filePath) throws IOException {
+        //判断是否为excel类型文件
+        if (!filePath.endsWith(".xls") && !filePath.endsWith(".xlsx") && !filePath.endsWith(".XLS") && !filePath.endsWith(".XLSX")) {
+            System.out.println("文件不是excel类型");
+        }
+        FileInputStream fis = null;
+        Workbook wookbook = null;
+        Sheet sheet = null;
+        try {
+            //获取一个绝对地址的流
+            fis = new FileInputStream(filePath);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            //2003版本的excel,用.xls结尾
+            wookbook = new HSSFWorkbook(fis);//得到工作簿
+
+        } catch (Exception ex) {
+            //ex.printStackTrace();
+            try {
+                //2007版本的excel,用.xlsx结尾
+                fis = new FileInputStream(filePath);
+                wookbook = new XSSFWorkbook(fis);//得到工作簿
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        Map<String, PictureData> maplist = null;
+        sheet = wookbook.getSheetAt(0);
+        // 判断用07还是03的方法获取图片
+        if (filePath.endsWith(".xls") || filePath.endsWith(".XLS")) {
+            maplist = getPictures1((HSSFSheet) sheet);
+        } else if (filePath.endsWith(".xlsx") || filePath.endsWith(".XLSX")) {
+            maplist = getPictures2((XSSFSheet) sheet);
+        }
+        wookbook.close();
+        return maplist;
+    }
+
+    /**
+     * 获取图片和位置 (xls)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures1(HSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap<String, PictureData>();
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    PictureData pdata = picture.getPictureData();
+                    String key = String.valueOf(cAnchor.getRow1());
+                    map.put(key, pdata);
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 获取图片和位置 (xlsx)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures2(XSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap<String, PictureData>();
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    XSSFPicture picture = (XSSFPicture) shape;
+                    Dimension d = picture.getImageDimension();
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    String key = String.valueOf(marker.getRow());
+                    map.put(key, picture.getPictureData());
+                }
+            }
+        }
+        return map;
+    }
+
+    public static Map<String, String> savePicture(PictureData pictureData) throws IOException {
+        FileUtils fileUtils = SpringUtils.getBean(FileUtils.class);
+        Map<String, String> result = new HashMap<>();
+        String ext = pictureData.suggestFileExtension();
+        byte[] data = pictureData.getData();
+        String picName = IdUtil.simpleUUID() + "." + ext;
+        String date = DateUtils.getNowTimeFormat("yyyyMMdd");
+        String folderPath = fileUtils.getSavePath(date);
+        String filePath = FileUtils.FILE_SEPARATOR + date + FileUtils.FILE_SEPARATOR + picName;
+        File directory = new File(folderPath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        FileOutputStream out = new FileOutputStream(folderPath + picName);
+        out.write(data);
+        out.close();
+        result.put("path", filePath);
+        result.put("name", picName);
+        return result;
+    }
+
+    /**
+     * @param
+     * @param x           单元格x轴坐标
+     * @param y           单元格y轴坐标
+     * @param pictureData 图片二进制数据
+     * @param picType     图片格式
+     */
+    public static void writePicture(Sheet sheet, int x, int y, byte[] pictureData, int picType) {
+        Drawing drawingPatriarch = sheet.createDrawingPatriarch();
+        //设置图片单元格位置
+        ClientAnchor anchor = drawingPatriarch.createAnchor(0, 0, 0, 0, x, y, x + 1, y + 1);
+        //随单元格改变位置和大小
+        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
+        //添加图片
+        int pictureIndex = sheet.getWorkbook().addPicture(pictureData, picType);
+        drawingPatriarch.createPicture(anchor, pictureIndex);
+    }
+
+    public static void setExcelCellStyle(HSSFCellStyle cellStyle) {
+        cellStyle.setBorderBottom(BorderStyle.THIN);
+        cellStyle.setBorderLeft(BorderStyle.THIN);
+        cellStyle.setBorderRight(BorderStyle.THIN);
+        cellStyle.setBorderTop(BorderStyle.THIN);
+    }
+}

+ 149 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/FileUtils.java

@@ -0,0 +1,149 @@
+package cn.cslg.permission.common.utils;
+
+import cn.cslg.permission.common.model.dto.UploadFileDTO;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.IdUtil;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class FileUtils {
+
+    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+    public static final String COMMON_FILE = "file";
+    public static final String BACKUP_FILE = "backup";
+
+    public static String getStaticPath(String fileName) {
+        //ApplicationHome类 返回target目录层级
+        ApplicationHome ah = new ApplicationHome(FileUtils.class);
+        //获取 applicationHome 内的路径 ...\target\classes 到这一层级下
+        File file = ah.getSource();
+        //获取 file的parentFile 即最后一级之前的所有层级路径(包括盘符) 这里能获得到的最终层级为  ...\target 后续用FILE_SEPARATOR(系统路径分割通配符 即 "\") 以及fileName拼接生成存放文件的目录层级 即为根目录 root
+        String rootPath = file.getParentFile().toString() + FILE_SEPARATOR + fileName;
+        //根据上方生成的根目录路径 生成对应文件夹 没有就新建
+        File root = new File(rootPath);
+        if (!root.exists()) {
+            root.mkdir();
+        }
+        //返回的最终形式为 盘符:\项目层级\target\file
+        return rootPath;
+    }
+
+    public UploadFileDTO uploadFile(MultipartFile file) {
+        UploadFileDTO fileDTO = new UploadFileDTO();
+        //以下操作为 先取得传入文件的完整文件名 (文件名 + 后缀) 然后用FileUtil分别取出 文件名 和 不带 "." 的后缀 然后将这些内容装配进 实体中
+        //file.getOriginFilename 获取源文件
+        //FileUtil.getPrefix 返回主文件名
+        fileDTO.setName(FileUtil.getPrefix(file.getOriginalFilename()));
+        //FileUtil.extName 获取文件的扩展名(后缀名),扩展名不带 "."
+        fileDTO.setExtName(FileUtil.extName(file.getOriginalFilename()));
+        //获取目录名 用时间作为目录名称
+        String directoryName = this.getDirectoryName();
+        //用IdUtil生成的UUID 与实体中的 extName(后缀名) 拼接后作为文件名 simpleUUID与randomUUID的区别是 simpleUUID 没有 "-"
+        String fileName = IdUtil.simpleUUID() + "." + fileDTO.getExtName();
+        //将完整文件名进行装配
+        fileDTO.setFileName(fileName);
+        //生成存储文件的路径
+        String savePath = this.getSavePath(directoryName);
+        //根据生成存储文件的路径 生成对应文件夹 没有就新建
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        this.saveFile(file, savePath + fileName);
+        fileDTO.setPath(FILE_SEPARATOR + directoryName + FILE_SEPARATOR + fileName);
+        fileDTO.setFileSize(file.getSize());
+        return fileDTO;
+    }
+
+    public String createDirectory() {
+        String directoryName = this.getDirectoryName();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public void saveFile(MultipartFile file, String path) {
+        try {
+            file.transferTo(new File(path));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String getTempPath(String fileName) {
+        String tempPath = getStaticPath(COMMON_FILE) + FILE_SEPARATOR + "temp";
+        File file = new File(tempPath);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+        return tempPath + FILE_SEPARATOR + fileName;
+    }
+
+    public String getSavePath(String directoryName) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String getDirectory(String fileName) {
+        return FILE_SEPARATOR + this.createDirectory() + FILE_SEPARATOR + fileName;
+    }
+
+    public String getDirectory2(String directoryName) {
+        return FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String getSystemPath(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+
+    public String getSystemPath() {
+        return getStaticPath(COMMON_FILE);
+    }
+
+    public String getDirectoryName() {
+        return DateUtils.getNowTimeFormat("yyyyMMdd");
+    }
+
+    public String getPath(String url) {
+        return getStaticPath(COMMON_FILE) + url;
+    }
+
+    public String analysisJsonFile() {
+        ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+        File file = ah.getSource();
+        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "uploadSetting.json";
+        BufferedReader reader = null;
+        StringBuilder last = new StringBuilder();
+        InputStreamReader inputStreamReader;
+        try (FileInputStream fileInputStream = new FileInputStream(settingFilePath)) {
+            inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
+
+            reader = new BufferedReader(inputStreamReader);
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                last.append(tempString);
+            }
+            reader.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return last.toString();
+    }
+
+}
+

+ 7 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/FormatUtil.java

@@ -0,0 +1,7 @@
+package cn.cslg.permission.common.utils;
+
+public class FormatUtil {
+    public static String toString(Object o) {
+        return o == null ? "" : o.toString();
+    }
+}

+ 313 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/JsonUtils.java

@@ -0,0 +1,313 @@
+package cn.cslg.permission.common.utils;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * json解析的工具类
+ */
+public class JsonUtils {
+
+    // 定义jackson对象
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+    public static Logger log = LoggerFactory.getLogger(JsonUtils.class);
+
+    /**
+     * 把对象转换为json数据
+     *
+     * @param obj
+     * @return 2018年5月7日  下午5:27:16
+     */
+    public static String objectToJson(Object obj) {
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        try {
+            String json = gson.toJson(obj);
+            return json;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object转换成Map
+     *
+     * @param obj
+     * @return
+     */
+    public static Map<String, Object> objectToMap(Object obj) {
+
+        try {
+            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+            String json = gson.toJson(obj);
+            return jsonToMap(json);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object类型的map转换成String类型
+     *
+     * @param map
+     * @return
+     */
+    public static Map<String, String> mapToMap(Map<String, Object> map) {
+        Map<String, String> returnMap = new HashMap<>();
+        for (String key : map.keySet()) {
+            returnMap.put(key, String.valueOf(map.get(key)));
+        }
+        return returnMap;
+    }
+
+    /**
+     * 任意类型转换成Map
+     * @return
+     */
+    public static Map<String, String> object2Map(Object obj) {
+        Map<String, String> hashMap = new HashMap();
+        try {
+            Class c = obj.getClass();
+            Method m[] = c.getDeclaredMethods();
+            for (int i = 0; i < m.length; i++) {
+                if (m[i].getName().indexOf("get")==0) {
+                    // 得到Map的key
+                    String suffixKey = m[i].getName().substring(4);
+                    String prefixKey = m[i].getName().substring(3,4).toLowerCase();
+                    hashMap.put(prefixKey + suffixKey, String.valueOf(m[i].invoke(obj, new Object[0])));
+                }
+            }
+        } catch (Throwable e) {
+            log.error(e.getMessage());
+        }
+        return hashMap;
+    }
+
+
+    /**
+     * 把json字符串转化为对象
+     *
+     * @param jsonString
+     * @param clazz
+     * @return
+     */
+    public static Object jsonToObject(String jsonString, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        Object obj = null;
+        try {
+            obj = gson.fromJson(jsonString, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return obj;
+    }
+
+    /**
+     * josn转arrayList
+     *
+     * @param jsonArray
+     * @return
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+            Type listType = new TypeToken<ArrayList<?>>() {
+            }.getType();
+
+            list = gson.fromJson(jsonArray, listType);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * JSON 转 ArrayList
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+
+            list = (ArrayList<?>) gson.fromJson(jsonArray, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * 把json转换为map类型的数据
+     *
+     * @param json
+     * @return
+     */
+    public static Map<String, Object> jsonToMap(String json) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, Object> map = null;
+        try {
+            Type type = new TypeToken<Map<String, Object>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将Json转换成Map<String, ?>
+     *
+     * @param json
+     * @param clazz
+     * @return
+     */
+    public static Map<String, ?> jsonToMap(String json, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, ?> map = null;
+        try {
+            Type type = new TypeToken<Map<String, ?>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将map转换成pojo
+     *
+     * @param map
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T mapToPojo(Map<String, Object> map, Class<T> beanType) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+
+        JsonElement jsonElement = gson.toJsonTree(map);
+        T pojo = gson.fromJson(jsonElement, beanType);
+
+        return pojo;
+    }
+
+    /**
+     * 将json结果集转化为对象
+     *
+     * @param jsonData
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
+        try {
+            T t = MAPPER.readValue(jsonData, beanType);
+            return t;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将json数据转换成pojo对象list
+     *
+     * @param jsonData
+     * @param beanType
+     * @return
+     */
+    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
+        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
+        try {
+            List<T> list = MAPPER.readValue(jsonData, javaType);
+            return list;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 将任意pojo转化成map
+     *
+     * @param t pojo对象
+     * @return
+     */
+    public static <T> Map<String, Object> pojoToMap(T t) {
+        Map<String, Object> result = new HashMap<String, Object>();
+        Method[] methods = t.getClass().getMethods();
+        try {
+            for (Method method : methods) {
+                Class<?>[] paramClass = method.getParameterTypes();
+                // 如果方法带参数,则跳过
+                if (paramClass.length > 0) {
+                    continue;
+                }
+                String methodName = method.getName();
+                if (methodName.startsWith("get")) {
+                    Object value = method.invoke(t);
+                    result.put(methodName, value);
+                }
+            }
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1325 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/RedisUtil.java


+ 47 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/RequestDataHelper.java

@@ -0,0 +1,47 @@
+package cn.cslg.permission.common.utils;
+
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+
+import java.util.Map;
+
+/**
+ * 请求参数传递辅助类
+ */
+public class RequestDataHelper {
+    /**
+     * 请求参数存取
+     */
+    private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();
+
+    /**
+     * 设置请求参数
+     *
+     * @param requestData 请求参数 MAP 对象
+     */
+    public static void setRequestData(Map<String, Object> requestData) {
+        REQUEST_DATA.set(requestData);
+    }
+
+    /**
+     * 获取请求参数
+     *
+     * @param param 请求参数
+     * @return 请求参数 MAP 对象
+     */
+    public static <T> T getRequestData(String param) {
+        Map<String, Object> dataMap = getRequestData();
+        if (CollectionUtils.isNotEmpty(dataMap)) {
+            return (T) dataMap.get(param);
+        }
+        return null;
+    }
+
+    /**
+     * 获取请求参数
+     *
+     * @return 请求参数 MAP 对象
+     */
+    public static Map<String, Object> getRequestData() {
+        return REQUEST_DATA.get();
+    }
+}

+ 86 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/Response.java

@@ -0,0 +1,86 @@
+package cn.cslg.permission.common.utils;
+
+public class Response {
+
+    private Integer code;
+    private Object data;
+    private String message;
+
+    public static String success() {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String success(Object data) {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String websocket(Object data, ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error() {
+        Response response = new Response();
+        response.setData(Boolean.FALSE);
+        response.setResultEnum(ResponseEnum.ERROR);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public Response(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Response() {
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    private void setResultEnum(ResponseEnum responseEnum) {
+        this.code = responseEnum.getCode();
+        this.message = responseEnum.getMessage();
+    }
+}

+ 49 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/ResponseEnum.java

@@ -0,0 +1,49 @@
+package cn.cslg.permission.common.utils;
+
+public enum ResponseEnum {
+
+    SUCCESS(200, "请求成功"),
+    WEB_SOCKET_SUCCESS(2, "WebSocket请求成功"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_SUCCESS(900, "WebSocket请求成功"),
+    PROJECT_IMPORT_TASK_SUCCESS(901, "WebSocket请求成功"),
+    PROJECT_EXPORT_TASK_SUCCESS(902, "WebSocket请求成功"),
+    PATENT_IMPORT_TASK_SUCCESS(903, "WebSocket请求成功"),
+    PATENT_EXPORT_TASK_SUCCESS(904, "WebSocket请求成功"),
+    UNAUTHORIZED(401, "未登录"),
+    NOT_PERMISSION(402, "无操作权限"),
+    FORBIDDEN(403, "拒绝访问"),
+    USERNAME_ERROR(0, "用户名不存在"),
+    PASSWORD_ERROR(0, "密码错误"),
+    VERIFY_CODE_ERROR(0, "验证码错误"),
+    QUERY_CACHE_ERROR(0, "专利检索缓存失效,请重试"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_ERROR(800, "导入说明书失败"),
+    PROJECT_EXPORT_TASK_ERROR(802, "专题库数据导出失败"),
+    PATENT_IMPORT_TASK_ERROR(803, "专利导入专利失败"),
+    PATENT_EXPORT_TASK_ERROR(804, "专利导出专利失败"),
+    SYSTEM_ERROR(500, "系统异常"),
+    ERROR(0, "请求失败");
+
+    private Integer code;
+    private String message;
+
+    ResponseEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 117 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/ServletUtils.java

@@ -0,0 +1,117 @@
+package cn.cslg.permission.common.utils;
+
+import cn.cslg.permission.common.core.Convert;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+
+/**
+ * 客户端工具类
+ */
+public class ServletUtils {
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name) {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name, String defaultValue) {
+        return Convert.toStr(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name) {
+        return Convert.toInt(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name, Integer defaultValue) {
+        return Convert.toInt(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取request
+     */
+    public static HttpServletRequest getRequest() {
+        return getRequestAttributes().getRequest();
+    }
+
+    /**
+     * 获取response
+     */
+    public static HttpServletResponse getResponse() {
+        return getRequestAttributes().getResponse();
+    }
+
+    /**
+     * 获取session
+     */
+    public static HttpSession getSession() {
+        return getRequest().getSession();
+    }
+
+    public static ServletRequestAttributes getRequestAttributes() {
+        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+        return (ServletRequestAttributes) attributes;
+    }
+
+    /**
+     * 将字符串渲染到客户端
+     *
+     * @param response 渲染对象
+     * @param string   待渲染的字符串
+     * @return null
+     */
+    public static String renderString(HttpServletResponse response, String string) {
+        try {
+            response.setStatus(200);
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(string);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 是否是Ajax异步请求
+     *
+     * @param request
+     */
+//    public static boolean isAjaxRequest(HttpServletRequest request) {
+//        String accept = request.getHeader("accept");
+//        if (accept != null && accept.indexOf("application/json") != -1) {
+//            return true;
+//        }
+//
+//        String xRequestedWith = request.getHeader("X-Requested-With");
+//        if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
+//            return true;
+//        }
+//
+//        String uri = request.getRequestURI();
+//        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
+//            return true;
+//        }
+//
+//        String ajax = request.getParameter("__ajax");
+//        if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
+//            return true;
+//        }
+//        return false;
+//    }
+}

+ 729 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/SoMap.java

@@ -0,0 +1,729 @@
+package cn.cslg.permission.common.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Map< String, Object> 是最常用的一种Map类型,但是它写着麻烦 
+ * <p>所以特封装此类,继承Map,进行一些扩展,可以让Map更灵活使用 
+ * <p>最新:2020-12-10 新增部分构造方法
+ * @author kong
+ */
+public class SoMap extends LinkedHashMap<String, Object> {
+
+	private static final long serialVersionUID = 1L;
+
+	public SoMap() {
+	}
+	
+	/** 以下元素会在isNull函数中被判定为Null, */
+	public static final Object[] NULL_ELEMENT_ARRAY = {null, ""};
+	public static final List<Object> NULL_ELEMENT_LIST;
+
+	static {
+		NULL_ELEMENT_LIST = Arrays.asList(NULL_ELEMENT_ARRAY);
+	}
+
+	// ============================= 读值 =============================
+
+	/** 获取一个值 */
+	@Override
+	public Object get(Object key) {
+		if("this".equals(key)) {
+			return this;
+		}
+		return super.get(key);
+	}
+
+	/** 如果为空,则返回默认值 */
+	public Object get(Object key, Object defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return value;
+	}
+	
+	/** 转为String并返回 */
+	public String getString(String key) {
+		Object value = get(key);
+		if(value == null) {
+			return null;
+		}
+		return String.valueOf(value);
+	}
+
+	/** 如果为空,则返回默认值 */
+	public String getString(String key, String defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return String.valueOf(value);
+	}
+
+	/** 转为int并返回 */
+	public int getInt(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0;
+		}
+		return Integer.valueOf(String.valueOf(value));
+	}
+	/** 转为int并返回,同时指定默认值 */
+	public int getInt(String key, int defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return Integer.valueOf(String.valueOf(value));
+	}
+
+	/** 转为long并返回 */
+	public long getLong(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0;
+		}
+		return Long.valueOf(String.valueOf(value));
+	}
+
+	/** 转为double并返回 */
+	public double getDouble(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0.0;
+		}
+		return Double.valueOf(String.valueOf(value));
+	}
+
+	/** 转为boolean并返回 */
+	public boolean getBoolean(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return false;
+		}
+		return Boolean.valueOf(String.valueOf(value));
+	}
+
+	/** 转为Date并返回,根据自定义格式 */
+	public Date getDateByFormat(String key, String format) {
+		try {
+			return new SimpleDateFormat(format).parse(getString(key));
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/** 转为Date并返回,根据格式: yyyy-MM-dd */
+	public Date getDate(String key) {
+		return getDateByFormat(key, "yyyy-MM-dd");
+	}
+
+	/** 转为Date并返回,根据格式: yyyy-MM-dd HH:mm:ss */
+	public Date getDateTime(String key) {
+		return getDateByFormat(key, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/** 转为Map并返回 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public SoMap getMap(String key) {
+		Object value = get(key);
+		if(value == null) {
+			return SoMap.getSoMap();
+		}
+		if(value instanceof Map) {
+			return SoMap.getSoMap((Map)value);
+		}
+		if(value instanceof String) {
+			return SoMap.getSoMap().setJsonString((String)value);
+		}
+		throw new RuntimeException("值无法转化为SoMap: " + value);
+	}
+
+	/** 获取集合(必须原先就是个集合,否则会创建个新集合并返回) */
+	@SuppressWarnings("unchecked")
+	public List<Object> getList(String key) {
+		Object value = get(key);
+		List<Object> list = null;
+		if(value == null || value.equals("")) {
+			list = new ArrayList<Object>();
+		}
+		else if(value instanceof List) {
+			list = (List<Object>)value;
+		} else {
+			list = new ArrayList<Object>();
+			list.add(value);
+		}
+		return list;
+	}
+
+	/** 获取集合 (指定泛型类型) */
+	public <T> List<T> getList(String key, Class<T> cs) {
+		List<Object> list = getList(key);
+		List<T> list2 = new ArrayList<T>();
+		for (Object obj : list) {
+			T objC = getValueByClass(obj, cs);
+			list2.add(objC);
+		}
+		return list2;
+	}
+
+	/** 获取集合(逗号分隔式),(指定类型) */
+	public <T> List<T> getListByComma(String key, Class<T> cs) {
+		String listStr = getString(key);
+		if(listStr == null || listStr.equals("")) {
+			return new ArrayList<>();
+		}
+		// 开始转化
+		String [] arr = listStr.split(",");
+		List<T> list = new ArrayList<T>();
+		for (String str : arr) {
+			if(cs == int.class || cs == Integer.class || cs == long.class || cs == Long.class) {
+				str = str.trim();
+			}
+			T objC = getValueByClass(str, cs);
+			list.add(objC);
+		}
+		return list;
+	}
+
+
+	/** 根据指定类型从map中取值,返回实体对象 */
+	public <T> T getModel(Class<T> cs) {
+		try {
+			return getModelByObject(cs.newInstance());
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	/** 从map中取值,塞到一个对象中 */
+	public <T> T getModelByObject(T obj) {
+		// 获取类型 
+		Class<?> cs = obj.getClass();
+		// 循环复制  
+		for (Field field : cs.getDeclaredFields()) {
+			try {
+				// 获取对象 
+				Object value = this.get(field.getName());	
+				if(value == null) {
+					continue;
+				}
+				field.setAccessible(true);	
+				Object valueConvert = getValueByClass(value, field.getType());
+				field.set(obj, valueConvert);
+			} catch (IllegalArgumentException | IllegalAccessException e) {
+				throw new RuntimeException("属性取值出错:" + field.getName(), e);
+			}
+		}
+		return obj;
+	}
+
+	
+
+	/**
+	 * 将指定值转化为指定类型并返回
+	 * @param obj
+	 * @param cs
+	 * @param <T>
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T getValueByClass(Object obj, Class<T> cs) {
+		String obj2 = String.valueOf(obj);
+		Object obj3 = null;
+		if (cs.equals(String.class)) {
+			obj3 = obj2;
+		} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
+			obj3 = Integer.valueOf(obj2);
+		} else if (cs.equals(long.class) || cs.equals(Long.class)) {
+			obj3 = Long.valueOf(obj2);
+		} else if (cs.equals(short.class) || cs.equals(Short.class)) {
+			obj3 = Short.valueOf(obj2);
+		} else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
+			obj3 = Byte.valueOf(obj2);
+		} else if (cs.equals(float.class) || cs.equals(Float.class)) {
+			obj3 = Float.valueOf(obj2);
+		} else if (cs.equals(double.class) || cs.equals(Double.class)) {
+			obj3 = Double.valueOf(obj2);
+		} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
+			obj3 = Boolean.valueOf(obj2);
+		} else {
+			obj3 = (T)obj;
+		}
+		return (T)obj3;
+	}
+
+	
+	// ============================= 写值 =============================
+
+	/**
+	 * 给指定key添加一个默认值(只有在这个key原来无值的情况先才会set进去)
+	 */
+	public void setDefaultValue(String key, Object defaultValue) {
+		if(isNull(key)) {
+			set(key, defaultValue);
+		}
+	}
+
+	/** set一个值,连缀风格 */
+	public SoMap set(String key, Object value) {
+		// 防止敏感key 
+		if(key.toLowerCase().equals("this")) {		
+			return this;
+		}
+		put(key, value);
+		return this;
+	}
+
+	/** 将一个Map塞进SoMap */
+	public SoMap setMap(Map<String, ?> map) {
+		if(map != null) {
+			for (String key : map.keySet()) {
+				this.set(key, map.get(key));
+			}
+		}
+		return this;
+	}
+
+	/** 将一个对象解析塞进SoMap */
+	public SoMap setModel(Object model) {
+		if(model == null) {
+			return this;
+		}
+		Field[] fields = model.getClass().getDeclaredFields();
+	    for (Field field : fields) {
+	        try{
+	            field.setAccessible(true);
+	            boolean isStatic = Modifier.isStatic(field.getModifiers());
+	            if(!isStatic) {
+		            this.set(field.getName(), field.get(model));
+	            }
+	        }catch (Exception e){
+	        	throw new RuntimeException(e);
+	        }
+	    }
+		return this;
+	}
+
+	/** 将json字符串解析后塞进SoMap */
+	public SoMap setJsonString(String jsonString) {
+		try {
+			@SuppressWarnings("unchecked")
+			Map<String, Object> map = new ObjectMapper().readValue(jsonString, Map.class);
+			return this.setMap(map);
+		} catch (JsonProcessingException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	
+	// ============================= 删值 =============================
+
+	/** delete一个值,连缀风格 */
+	public SoMap delete(String key) {
+		remove(key);
+		return this;
+	}
+
+	/** 清理所有value为null的字段 */
+	public SoMap clearNull() {
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(this.isNull(key)) {
+				iterator.remove();
+				this.remove(key);
+			}
+
+		}
+		return this;
+	}
+	/** 清理指定key */
+	public SoMap clearIn(String ...keys) {
+		List<String> keys2 = Arrays.asList(keys);
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(keys2.contains(key) == true) {
+				iterator.remove();
+				this.remove(key);
+			}
+		}
+		return this;
+	}
+	/** 清理掉不在列表中的key */
+	public SoMap clearNotIn(String ...keys) {
+		List<String> keys2 = Arrays.asList(keys);
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(keys2.contains(key) == false) {
+				iterator.remove();
+				this.remove(key);
+			}
+
+		}
+		return this;
+	}
+	/** 清理掉所有key */
+	public SoMap clearAll() {
+		clear();
+		return this;
+	}
+	
+
+	// ============================= 快速构建 ============================= 
+
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap() {
+		return new SoMap();
+	}
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap(String key, Object value) {
+		return new SoMap().set(key, value);
+	}
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap(Map<String, ?> map) {
+		return new SoMap().setMap(map);
+	}
+
+	/** 将一个对象集合解析成为SoMap */
+	public static SoMap getSoMapByModel(Object model) {
+		return SoMap.getSoMap().setModel(model);
+	}
+	
+	/** 将一个对象集合解析成为SoMap集合 */
+	public static List<SoMap> getSoMapByList(List<?> list) {
+		List<SoMap> listMap = new ArrayList<SoMap>();
+		for (Object model : list) {
+			listMap.add(getSoMapByModel(model));
+		}
+		return listMap;
+	}
+	
+	/** 克隆指定key,返回一个新的SoMap */
+	public SoMap cloneKeys(String... keys) {
+		SoMap so = new SoMap();
+		for (String key : keys) {
+			so.set(key, this.get(key));
+		}
+		return so;
+	}
+	/** 克隆所有key,返回一个新的SoMap */
+	public SoMap cloneSoMap() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key, this.get(key));
+		}
+		return so;
+	}
+
+	/** 将所有key转为大写 */
+	public SoMap toUpperCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key.toUpperCase(), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key转为小写 */
+	public SoMap toLowerCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key.toLowerCase(), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中下划线转为中划线模式 (kebab-case风格) */
+	public SoMap toKebabCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordEachKebabCase(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中下划线转为小驼峰模式 */
+	public SoMap toHumpCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordEachBigFs(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中小驼峰转为下划线模式 */
+	public SoMap humpToLineCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordHumpToLine(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	
+	
+	
+	
+	// ============================= 辅助方法 =============================
+
+
+	/** 指定key是否为null,判定标准为 NULL_ELEMENT_ARRAY 中的元素  */
+	public boolean isNull(String key) {
+		return valueIsNull(get(key));
+	}
+
+	/** 指定key列表中是否包含value为null的元素,只要有一个为null,就会返回true */
+	public boolean isContainNull(String ...keys) {
+		for (String key : keys) {
+			if(this.isNull(key)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/** 与isNull()相反 */
+	public boolean isNotNull(String key) {
+		return !isNull(key);
+	}
+	/** 指定key的value是否为null,作用同isNotNull() */
+	public boolean has(String key) {
+		return !isNull(key);
+	}
+	
+	/** 指定value在此SoMap的判断标准中是否为null */
+	public boolean valueIsNull(Object value) {
+		return NULL_ELEMENT_LIST.contains(value);
+	}
+	
+	/** 验证指定key不为空,为空则抛出异常 */
+	public SoMap checkNull(String ...keys) {
+		for (String key : keys) {
+			if(this.isNull(key)) {
+				throw new RuntimeException("参数" + key + "不能为空");
+			}
+		}
+		return this;
+	}
+
+	static Pattern patternNumber = Pattern.compile("[0-9]*");
+	/** 指定key是否为数字 */
+	public boolean isNumber(String key) {
+		String value = getString(key);
+		if(value == null) {
+			return false;
+		}
+	    return patternNumber.matcher(value).matches();   
+	}
+
+	
+	
+	
+	/**
+	 * 转为JSON字符串
+	 */
+	public String toJsonString() {
+		try {
+//			SoMap so = SoMap.getSoMap(this);
+			return new ObjectMapper().writeValueAsString(this);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+//	/**
+//	 * 转为JSON字符串, 带格式的 
+//	 */
+//	public String toJsonFormatString() {
+//		try {
+//			return JSON.toJSONString(this, true); 
+//		} catch (Exception e) {
+//			throw new RuntimeException(e);
+//		}
+//	}
+
+	// ============================= web辅助 =============================
+
+
+	/**
+	 * 返回当前request请求的的所有参数 
+	 * @return
+	 */
+	public static SoMap getRequestSoMap() {
+		// 大善人SpringMVC提供的封装 
+		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+		if(servletRequestAttributes == null) {
+			throw new RuntimeException("当前线程非JavaWeb环境");
+		}
+		// 当前request
+		HttpServletRequest request = servletRequestAttributes.getRequest(); 
+		if (request.getAttribute("currentSoMap") == null || request.getAttribute("currentSoMap") instanceof SoMap == false ) {
+			initRequestSoMap(request);
+		}
+		return (SoMap)request.getAttribute("currentSoMap");
+	}
+
+	/** 初始化当前request的 SoMap */
+	private static void initRequestSoMap(HttpServletRequest request) {
+		SoMap soMap = new SoMap();
+		Map<String, String[]> parameterMap = request.getParameterMap();	// 获取所有参数 
+		for (String key : parameterMap.keySet()) {
+			try {
+				String[] values = parameterMap.get(key); // 获得values 
+				if(values.length == 1) {
+					soMap.set(key, values[0]);
+				} else {
+					List<String> list = new ArrayList<String>();
+					for (String v : values) {
+						list.add(v);
+					}
+					soMap.set(key, list);
+				}
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+		request.setAttribute("currentSoMap", soMap);
+	}
+	
+	/**
+	 * 验证返回当前线程是否为JavaWeb环境 
+	 * @return
+	 */
+	public static boolean isJavaWeb() {
+		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装 
+		if(servletRequestAttributes == null) {
+			return false;
+		}
+		return true;
+	}
+	
+
+
+	// ============================= 常见key (以下key经常用,所以封装以下,方便写代码) =============================
+
+	/** get 当前页  */
+	public int getKeyPageNo() {
+		int pageNo = getInt("pageNo", 1);
+		if(pageNo <= 0) {
+			pageNo = 1;
+		}
+		return pageNo;
+	}
+	/** get 页大小  */
+	public int getKeyPageSize() {
+		int pageSize = getInt("pageSize", 10);
+		if(pageSize <= 0 || pageSize > 1000) {
+			pageSize = 10;
+		}
+		return pageSize;
+	}
+
+	/** get 排序方式 */
+	public int getKeySortType() {
+		return getInt("sortType");
+	}
+
+
+
+
+	
+
+	// ============================= 工具方法 =============================
+	
+
+	/**
+	 * 将一个一维集合转换为树形集合 
+	 * @param list         集合
+	 * @param idKey        id标识key
+	 * @param parentIdKey  父id标识key
+	 * @param childListKey 子节点标识key
+	 * @return 转换后的tree集合 
+	 */
+	public static List<SoMap> listToTree(List<SoMap> list, String idKey, String parentIdKey, String childListKey) {
+		// 声明新的集合,存储tree形数据 
+		List<SoMap> newTreeList = new ArrayList<SoMap>();
+		// 声明hash-Map,方便查找数据 
+		SoMap hash = new SoMap();
+		// 将数组转为Object的形式,key为数组中的id 
+		for (int i = 0; i < list.size(); i++) {
+			SoMap json = (SoMap) list.get(i);
+			hash.put(json.getString(idKey), json);
+		}
+		// 遍历结果集
+		for (int j = 0; j < list.size(); j++) {
+			// 单条记录
+			SoMap aVal = (SoMap) list.get(j);
+			// 在hash中取出key为单条记录中pid的值
+			SoMap hashVp = (SoMap) hash.get(aVal.get(parentIdKey, "").toString());
+			// 如果记录的pid存在,则说明它有父节点,将她添加到孩子节点的集合中
+			if (hashVp != null) {
+				// 检查是否有child属性,有则添加,没有则新建 
+				if (hashVp.get(childListKey) != null) {
+					@SuppressWarnings("unchecked")
+					List<SoMap> ch = (List<SoMap>) hashVp.get(childListKey);
+					ch.add(aVal);
+					hashVp.put(childListKey, ch);
+				} else {
+					List<SoMap> ch = new ArrayList<SoMap>();
+					ch.add(aVal);
+					hashVp.put(childListKey, ch);
+				}
+			} else {
+				newTreeList.add(aVal);
+			}
+		}
+		return newTreeList;
+	}
+	
+	
+
+	/** 指定字符串的字符串下划线转大写模式 */
+	private static String wordEachBig(String str){
+		String newStr = "";
+		for (String s : str.split("_")) {
+			newStr += wordFirstBig(s);
+		}
+		return newStr;
+	}
+	/** 返回下划线转小驼峰形式 */
+	private static String wordEachBigFs(String str){
+		return wordFirstSmall(wordEachBig(str));
+	}
+
+	/** 将指定单词首字母大写 */
+	private static String wordFirstBig(String str) {
+		return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
+	}
+
+	/** 将指定单词首字母小写 */
+	private static String wordFirstSmall(String str) {
+		return str.substring(0, 1).toLowerCase() + str.substring(1, str.length());
+	}
+
+	/** 下划线转中划线 */
+	private static String wordEachKebabCase(String str) {
+		return str.replaceAll("_", "-");
+	}
+
+	/** 驼峰转下划线  */
+	private static String wordHumpToLine(String str) {
+		return str.replaceAll("[A-Z]", "_$0").toLowerCase();
+	}
+	
+
+}

+ 77 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/SpringContextUtil.java

@@ -0,0 +1,77 @@
+package cn.cslg.permission.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class SpringContextUtil implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringContextUtil.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取applicationContext
+     */
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+    /**
+     * 通过name获取 Bean.
+     */
+    public static Object getBean(String name) {
+        Object o = null;
+        try {
+            o = getApplicationContext().getBean(name);
+        } catch (NoSuchBeanDefinitionException e) {
+            // e.printStackTrace();
+        }
+        return o;
+    }
+
+    /**
+     * 通过class获取Bean.
+     */
+    public static <T> T getBean(Class<T> clazz) {
+        return getApplicationContext().getBean(clazz);
+    }
+
+    /**
+     * 通过name,以及Clazz返回指定的Bean
+     */
+    public static <T> T getBean(String name, Class<T> clazz) {
+        return getApplicationContext().getBean(name, clazz);
+    }
+
+    /**
+     * 通过name获取 Bean.
+     */
+    public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
+        return getApplicationContext().getBeansOfType(clazz);
+    }
+
+    /**
+     * 获取配置文件配置项的值
+     *
+     * @param key 配置项key
+     */
+    public static String getEnvironmentProperty(String key) {
+        return getApplicationContext().getEnvironment().getProperty(key);
+    }
+
+    /**
+     * 获取spring.profiles.active
+     */
+    public static String getActiveProfile() {
+        return getApplicationContext().getEnvironment().getActiveProfiles()[0];
+    }
+}

+ 129 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/SpringUtils.java

@@ -0,0 +1,129 @@
+package cn.cslg.permission.common.utils;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
+    /**
+     * Spring应用上下文环境
+     */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws BeansException
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws BeansException
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name) {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     *
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker) {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 获取当前的环境配置,无配置返回null
+     *
+     * @return 当前的环境配置
+     */
+    public static String[] getActiveProfiles() {
+        return applicationContext.getEnvironment().getActiveProfiles();
+    }
+
+    /**
+     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
+     *
+     * @return 当前的环境配置
+     */
+    public static String getActiveProfile() {
+        final String[] activeProfiles = getActiveProfiles();
+        return StringUtils.isNotNull(activeProfiles) ? activeProfiles[0] : null;
+    }
+}
+

+ 966 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/StpAdminUtil.java

@@ -0,0 +1,966 @@
+package cn.cslg.permission.common.utils;
+
+import java.util.List;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.SaTokenInfo;
+import cn.dev33.satoken.stp.StpLogic;
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Sa-Token 权限认证工具类
+ *
+ * @author kong
+ */
+public class StpAdminUtil {
+
+    /**
+     * 账号类型标识
+     */
+    public static final String TYPE = "admin";
+
+    /**
+     * 底层的 StpLogic 对象
+     */
+    public static StpLogic stpLogic = new StpLogic(TYPE);
+
+    /**
+     * 获取当前 StpLogic 的账号类型
+     *
+     * @return See Note
+     */
+    public static String getLoginType() {
+        return stpLogic.getLoginType();
+    }
+
+    /**
+     * 重置 StpLogic 对象
+     *
+     * @param stpLogic /
+     */
+    public static void setStpLogic(StpLogic stpLogic) {
+        StpUtil.stpLogic = stpLogic;
+        // 防止自定义 stpLogic 被覆盖
+        SaManager.putStpLogic(stpLogic);
+    }
+
+
+    // =================== 获取token 相关 ===================
+
+    /**
+     * 返回token名称
+     *
+     * @return 此StpLogic的token名称
+     */
+    public static String getTokenName() {
+        return stpLogic.getTokenName();
+    }
+
+    /**
+     * 在当前会话写入当前TokenValue
+     *
+     * @param tokenValue token值
+     */
+    public static void setTokenValue(String tokenValue) {
+        stpLogic.setTokenValue(tokenValue);
+    }
+
+    /**
+     * 在当前会话写入当前TokenValue
+     *
+     * @param tokenValue    token值
+     * @param cookieTimeout Cookie存活时间(秒)
+     */
+    public static void setTokenValue(String tokenValue, int cookieTimeout) {
+        stpLogic.setTokenValue(tokenValue, cookieTimeout);
+    }
+
+    /**
+     * 获取当前TokenValue
+     *
+     * @return 当前tokenValue
+     */
+    public static String getTokenValue() {
+        return stpLogic.getTokenValue();
+    }
+
+    /**
+     * 获取当前TokenValue (不裁剪前缀)
+     *
+     * @return /
+     */
+    public static String getTokenValueNotCut() {
+        return stpLogic.getTokenValueNotCut();
+    }
+
+    /**
+     * 获取当前会话的Token信息
+     *
+     * @return token信息
+     */
+    public static SaTokenInfo getTokenInfo() {
+        return stpLogic.getTokenInfo();
+    }
+
+
+    // =================== 登录相关操作 ===================
+
+    // --- 登录
+
+    /**
+     * 会话登录
+     *
+     * @param id 账号id,建议的类型:(long | int | String)
+     */
+    public static void login(Object id) {
+        stpLogic.login(id);
+    }
+
+    /**
+     * 会话登录,并指定登录设备
+     *
+     * @param id     账号id,建议的类型:(long | int | String)
+     * @param device 设备标识
+     */
+    public static void login(Object id, String device) {
+        stpLogic.login(id, device);
+    }
+
+    /**
+     * 会话登录,并指定是否 [记住我]
+     *
+     * @param id              账号id,建议的类型:(long | int | String)
+     * @param isLastingCookie 是否为持久Cookie
+     */
+    public static void login(Object id, boolean isLastingCookie) {
+        stpLogic.login(id, isLastingCookie);
+    }
+
+    /**
+     * 会话登录,并指定所有登录参数Model
+     *
+     * @param id         登录id,建议的类型:(long | int | String)
+     * @param loginModel 此次登录的参数Model
+     */
+    public static void login(Object id, SaLoginModel loginModel) {
+        stpLogic.login(id, loginModel);
+    }
+
+    /**
+     * 创建指定账号id的登录会话
+     *
+     * @param id 登录id,建议的类型:(long | int | String)
+     * @return 返回会话令牌
+     */
+    public static String createLoginSession(Object id) {
+        return stpLogic.createLoginSession(id);
+    }
+
+    /**
+     * 创建指定账号id的登录会话
+     *
+     * @param id         登录id,建议的类型:(long | int | String)
+     * @param loginModel 此次登录的参数Model
+     * @return 返回会话令牌
+     */
+    public static String createLoginSession(Object id, SaLoginModel loginModel) {
+        return stpLogic.createLoginSession(id, loginModel);
+    }
+
+    // --- 注销
+
+    /**
+     * 会话注销
+     */
+    public static void logout() {
+        stpLogic.logout();
+    }
+
+    /**
+     * 会话注销,根据账号id
+     *
+     * @param loginId 账号id
+     */
+    public static void logout(Object loginId) {
+        stpLogic.logout(loginId);
+    }
+
+    /**
+     * 会话注销,根据账号id 和 设备标识
+     *
+     * @param loginId 账号id
+     * @param device  设备标识 (填null代表所有注销设备)
+     */
+    public static void logout(Object loginId, String device) {
+        stpLogic.logout(loginId, device);
+    }
+
+    /**
+     * 会话注销,根据指定 Token
+     *
+     * @param tokenValue 指定token
+     */
+    public static void logoutByTokenValue(String tokenValue) {
+        stpLogic.logoutByTokenValue(tokenValue);
+    }
+
+    /**
+     * 踢人下线,根据账号id
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+     *
+     * @param loginId 账号id
+     */
+    public static void kickout(Object loginId) {
+        stpLogic.kickout(loginId);
+    }
+
+    /**
+     * 踢人下线,根据账号id 和 设备标识
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+     *
+     * @param loginId 账号id
+     * @param device  设备标识 (填null代表踢出所有设备)
+     */
+    public static void kickout(Object loginId, String device) {
+        stpLogic.kickout(loginId, device);
+    }
+
+    /**
+     * 踢人下线,根据指定 Token
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+     *
+     * @param tokenValue 指定token
+     */
+    public static void kickoutByTokenValue(String tokenValue) {
+        stpLogic.kickoutByTokenValue(tokenValue);
+    }
+
+    /**
+     * 顶人下线,根据账号id 和 设备标识
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-4 </p>
+     *
+     * @param loginId 账号id
+     * @param device  设备标识 (填null代表顶替所有设备)
+     */
+    public static void replaced(Object loginId, String device) {
+        stpLogic.replaced(loginId, device);
+    }
+
+
+    // 查询相关
+
+    /**
+     * 当前会话是否已经登录
+     *
+     * @return 是否已登录
+     */
+    public static boolean isLogin() {
+        return stpLogic.isLogin();
+    }
+
+    /**
+     * 检验当前会话是否已经登录,如未登录,则抛出异常
+     */
+    public static void checkLogin() {
+        stpLogic.checkLogin();
+    }
+
+    /**
+     * 获取当前会话账号id, 如果未登录,则抛出异常
+     *
+     * @return 账号id
+     */
+    public static Object getLoginId() {
+        return stpLogic.getLoginId();
+    }
+
+    /**
+     * 获取当前会话账号id, 如果未登录,则返回默认值
+     *
+     * @param <T>          返回类型
+     * @param defaultValue 默认值
+     * @return 登录id
+     */
+    public static <T> T getLoginId(T defaultValue) {
+        return stpLogic.getLoginId(defaultValue);
+    }
+
+    /**
+     * 获取当前会话账号id, 如果未登录,则返回null
+     *
+     * @return 账号id
+     */
+    public static Object getLoginIdDefaultNull() {
+        return stpLogic.getLoginIdDefaultNull();
+    }
+
+    /**
+     * 获取当前会话账号id, 并转换为String类型
+     *
+     * @return 账号id
+     */
+    public static String getLoginIdAsString() {
+        return stpLogic.getLoginIdAsString();
+    }
+
+    /**
+     * 获取当前会话账号id, 并转换为int类型
+     *
+     * @return 账号id
+     */
+    public static int getLoginIdAsInt() {
+        return stpLogic.getLoginIdAsInt();
+    }
+
+    /**
+     * 获取当前会话账号id, 并转换为long类型
+     *
+     * @return 账号id
+     */
+    public static long getLoginIdAsLong() {
+        return stpLogic.getLoginIdAsLong();
+    }
+
+    /**
+     * 获取指定Token对应的账号id,如果未登录,则返回 null
+     *
+     * @param tokenValue token
+     * @return 账号id
+     */
+    public static Object getLoginIdByToken(String tokenValue) {
+        return stpLogic.getLoginIdByToken(tokenValue);
+    }
+
+
+    // =================== User-Session 相关 ===================
+
+    /**
+     * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回
+     *
+     * @param loginId  账号id
+     * @param isCreate 是否新建
+     * @return Session对象
+     */
+    public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
+        return stpLogic.getSessionByLoginId(loginId, isCreate);
+    }
+
+    /**
+     * 获取指定key的Session, 如果Session尚未创建,则返回null
+     *
+     * @param sessionId SessionId
+     * @return Session对象
+     */
+    public static SaSession getSessionBySessionId(String sessionId) {
+        return stpLogic.getSessionBySessionId(sessionId);
+    }
+
+    /**
+     * 获取指定账号id的Session,如果Session尚未创建,则新建并返回
+     *
+     * @param loginId 账号id
+     * @return Session对象
+     */
+    public static SaSession getSessionByLoginId(Object loginId) {
+        return stpLogic.getSessionByLoginId(loginId);
+    }
+
+    /**
+     * 获取当前会话的Session, 如果Session尚未创建,isCreate=是否新建并返回
+     *
+     * @param isCreate 是否新建
+     * @return Session对象
+     */
+    public static SaSession getSession(boolean isCreate) {
+        return stpLogic.getSession(isCreate);
+    }
+
+    /**
+     * 获取当前会话的Session,如果Session尚未创建,则新建并返回
+     *
+     * @return Session对象
+     */
+    public static SaSession getSession() {
+        return stpLogic.getSession();
+    }
+
+
+    // =================== Token-Session 相关 ===================
+
+    /**
+     * 获取指定Token-Session,如果Session尚未创建,则新建并返回
+     *
+     * @param tokenValue Token值
+     * @return Session对象
+     */
+    public static SaSession getTokenSessionByToken(String tokenValue) {
+        return stpLogic.getTokenSessionByToken(tokenValue);
+    }
+
+    /**
+     * 获取当前Token-Session,如果Session尚未创建,则新建并返回
+     *
+     * @return Session对象
+     */
+    public static SaSession getTokenSession() {
+        return stpLogic.getTokenSession();
+    }
+
+
+    // =================== [临时有效期] 验证相关 ===================
+
+    /**
+     * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常
+     */
+    public static void checkActivityTimeout() {
+        stpLogic.checkActivityTimeout();
+    }
+
+    /**
+     * 续签当前token:(将 [最后操作时间] 更新为当前时间戳)
+     * <h1>请注意: 即时token已经 [临时过期] 也可续签成功,
+     * 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可 </h1>
+     */
+    public static void updateLastActivityToNow() {
+        stpLogic.updateLastActivityToNow();
+    }
+
+
+    // =================== 过期时间相关 ===================
+
+    /**
+     * 获取当前登录者的 token 剩余有效时间 (单位: 秒)
+     *
+     * @return token剩余有效时间
+     */
+    public static long getTokenTimeout() {
+        return stpLogic.getTokenTimeout();
+    }
+
+    /**
+     * 获取当前登录者的 User-Session 剩余有效时间 (单位: 秒)
+     *
+     * @return token剩余有效时间
+     */
+    public static long getSessionTimeout() {
+        return stpLogic.getSessionTimeout();
+    }
+
+    /**
+     * 获取当前 Token-Session 剩余有效时间 (单位: 秒)
+     *
+     * @return token剩余有效时间
+     */
+    public static long getTokenSessionTimeout() {
+        return stpLogic.getTokenSessionTimeout();
+    }
+
+    /**
+     * 获取当前 token [临时过期] 剩余有效时间 (单位: 秒)
+     *
+     * @return token [临时过期] 剩余有效时间
+     */
+    public static long getTokenActivityTimeout() {
+        return stpLogic.getTokenActivityTimeout();
+    }
+
+
+    // =================== 角色验证操作 ===================
+
+    /**
+     * 获取:当前账号的角色集合
+     *
+     * @return /
+     */
+    public static List<String> getRoleList() {
+        return stpLogic.getRoleList();
+    }
+
+    /**
+     * 获取:指定账号的角色集合
+     *
+     * @param loginId 指定账号id
+     * @return /
+     */
+    public static List<String> getRoleList(Object loginId) {
+        return stpLogic.getRoleList(loginId);
+    }
+
+    /**
+     * 判断:当前账号是否拥有指定角色, 返回true或false
+     *
+     * @param role 角色标识
+     * @return 是否含有指定角色标识
+     */
+    public static boolean hasRole(String role) {
+        return stpLogic.hasRole(role);
+    }
+
+    /**
+     * 判断:指定账号是否含有指定角色标识, 返回true或false
+     *
+     * @param loginId 账号id
+     * @param role    角色标识
+     * @return 是否含有指定角色标识
+     */
+    public static boolean hasRole(Object loginId, String role) {
+        return stpLogic.hasRole(loginId, role);
+    }
+
+    /**
+     * 判断:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
+     *
+     * @param roleArray 角色标识数组
+     * @return true或false
+     */
+    public static boolean hasRoleAnd(String... roleArray) {
+        return stpLogic.hasRoleAnd(roleArray);
+    }
+
+    /**
+     * 判断:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
+     *
+     * @param roleArray 角色标识数组
+     * @return true或false
+     */
+    public static boolean hasRoleOr(String... roleArray) {
+        return stpLogic.hasRoleOr(roleArray);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
+     *
+     * @param role 角色标识
+     */
+    public static void checkRole(String role) {
+        stpLogic.checkRole(role);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
+     *
+     * @param roleArray 角色标识数组
+     */
+    public static void checkRoleAnd(String... roleArray) {
+        stpLogic.checkRoleAnd(roleArray);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
+     *
+     * @param roleArray 角色标识数组
+     */
+    public static void checkRoleOr(String... roleArray) {
+        stpLogic.checkRoleOr(roleArray);
+    }
+
+
+    // =================== 权限验证操作 ===================
+
+    /**
+     * 获取:当前账号的权限码集合
+     *
+     * @return /
+     */
+    public static List<String> getPermissionList() {
+        return stpLogic.getPermissionList();
+    }
+
+    /**
+     * 获取:指定账号的权限码集合
+     *
+     * @param loginId 指定账号id
+     * @return /
+     */
+    public static List<String> getPermissionList(Object loginId) {
+        return stpLogic.getPermissionList(loginId);
+    }
+
+    /**
+     * 判断:当前账号是否含有指定权限, 返回true或false
+     *
+     * @param permission 权限码
+     * @return 是否含有指定权限
+     */
+    public static boolean hasPermission(String permission) {
+        return stpLogic.hasPermission(permission);
+    }
+
+    /**
+     * 判断:指定账号id是否含有指定权限, 返回true或false
+     *
+     * @param loginId    账号id
+     * @param permission 权限码
+     * @return 是否含有指定权限
+     */
+    public static boolean hasPermission(Object loginId, String permission) {
+        return stpLogic.hasPermission(loginId, permission);
+    }
+
+    /**
+     * 判断:当前账号是否含有指定权限, [指定多个,必须全部具有]
+     *
+     * @param permissionArray 权限码数组
+     * @return true 或 false
+     */
+    public static boolean hasPermissionAnd(String... permissionArray) {
+        return stpLogic.hasPermissionAnd(permissionArray);
+    }
+
+    /**
+     * 判断:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
+     *
+     * @param permissionArray 权限码数组
+     * @return true 或 false
+     */
+    public static boolean hasPermissionOr(String... permissionArray) {
+        return stpLogic.hasPermissionOr(permissionArray);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
+     *
+     * @param permission 权限码
+     */
+    public static void checkPermission(String permission) {
+        stpLogic.checkPermission(permission);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]
+     *
+     * @param permissionArray 权限码数组
+     */
+    public static void checkPermissionAnd(String... permissionArray) {
+        stpLogic.checkPermissionAnd(permissionArray);
+    }
+
+    /**
+     * 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
+     *
+     * @param permissionArray 权限码数组
+     */
+    public static void checkPermissionOr(String... permissionArray) {
+        stpLogic.checkPermissionOr(permissionArray);
+    }
+
+
+    // =================== id 反查token 相关操作 ===================
+
+    /**
+     * 获取指定账号id的tokenValue
+     * <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
+     * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
+     *
+     * @param loginId 账号id
+     * @return token值
+     */
+    public static String getTokenValueByLoginId(Object loginId) {
+        return stpLogic.getTokenValueByLoginId(loginId);
+    }
+
+    /**
+     * 获取指定账号id指定设备端的tokenValue
+     * <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
+     * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId
+     *
+     * @param loginId 账号id
+     * @param device  设备标识
+     * @return token值
+     */
+    public static String getTokenValueByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueByLoginId(loginId, device);
+    }
+
+    /**
+     * 获取指定账号id的tokenValue集合
+     *
+     * @param loginId 账号id
+     * @return 此loginId的所有相关token
+     */
+    public static List<String> getTokenValueListByLoginId(Object loginId) {
+        return stpLogic.getTokenValueListByLoginId(loginId);
+    }
+
+    /**
+     * 获取指定账号id指定设备端的tokenValue 集合
+     *
+     * @param loginId 账号id
+     * @param device  设备标识
+     * @return 此loginId的所有相关token
+     */
+    public static List<String> getTokenValueListByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueListByLoginId(loginId, device);
+    }
+
+    /**
+     * 返回当前会话的登录设备
+     *
+     * @return 当前令牌的登录设备
+     */
+    public static String getLoginDevice() {
+        return stpLogic.getLoginDevice();
+    }
+
+
+    // =================== 会话管理 ===================
+
+    /**
+     * 根据条件查询Token
+     *
+     * @param keyword 关键字
+     * @param start   开始处索引 (-1代表查询所有)
+     * @param size    获取数量
+     * @return token集合
+     */
+    public static List<String> searchTokenValue(String keyword, int start, int size) {
+        return stpLogic.searchTokenValue(keyword, start, size);
+    }
+
+    /**
+     * 根据条件查询SessionId
+     *
+     * @param keyword 关键字
+     * @param start   开始处索引 (-1代表查询所有)
+     * @param size    获取数量
+     * @return sessionId集合
+     */
+    public static List<String> searchSessionId(String keyword, int start, int size) {
+        return stpLogic.searchSessionId(keyword, start, size);
+    }
+
+    /**
+     * 根据条件查询Token专属Session的Id
+     *
+     * @param keyword 关键字
+     * @param start   开始处索引 (-1代表查询所有)
+     * @param size    获取数量
+     * @return sessionId集合
+     */
+    public static List<String> searchTokenSessionId(String keyword, int start, int size) {
+        return stpLogic.searchTokenSessionId(keyword, start, size);
+    }
+
+
+    // ------------------- 账号封禁 -------------------
+
+    /**
+     * 封禁指定账号
+     * <p> 此方法不会直接将此账号id踢下线,而是在对方再次登录时抛出`DisableLoginException`异常
+     *
+     * @param loginId     指定账号id
+     * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁)
+     */
+    public static void disable(Object loginId, long disableTime) {
+        stpLogic.disable(loginId, disableTime);
+    }
+
+    /**
+     * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
+     *
+     * @param loginId 账号id
+     * @return see note
+     */
+    public static boolean isDisable(Object loginId) {
+        return stpLogic.isDisable(loginId);
+    }
+
+    /**
+     * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+     *
+     * @param loginId 账号id
+     * @return see note
+     */
+    public static long getDisableTime(Object loginId) {
+        return stpLogic.getDisableTime(loginId);
+    }
+
+    /**
+     * 解封指定账号
+     *
+     * @param loginId 账号id
+     */
+    public static void untieDisable(Object loginId) {
+        stpLogic.untieDisable(loginId);
+    }
+
+
+    // =================== 身份切换 ===================
+
+    /**
+     * 临时切换身份为指定账号id
+     *
+     * @param loginId 指定loginId
+     */
+    public static void switchTo(Object loginId) {
+        stpLogic.switchTo(loginId);
+    }
+
+    /**
+     * 结束临时切换身份
+     */
+    public static void endSwitch() {
+        stpLogic.endSwitch();
+    }
+
+    /**
+     * 当前是否正处于[身份临时切换]中
+     *
+     * @return 是否正处于[身份临时切换]中
+     */
+    public static boolean isSwitch() {
+        return stpLogic.isSwitch();
+    }
+
+    /**
+     * 在一个代码段里方法内,临时切换身份为指定账号id
+     *
+     * @param loginId  指定账号id
+     * @param function 要执行的方法
+     */
+    public static void switchTo(Object loginId, SaFunction function) {
+        stpLogic.switchTo(loginId, function);
+    }
+
+
+    // ------------------- 二级认证 -------------------
+
+    /**
+     * 在当前会话 开启二级认证
+     *
+     * @param safeTime 维持时间 (单位: 秒)
+     */
+    public static void openSafe(long safeTime) {
+        stpLogic.openSafe(safeTime);
+    }
+
+    /**
+     * 当前会话 是否处于二级认证时间内
+     *
+     * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时
+     */
+    public static boolean isSafe() {
+        return stpLogic.isSafe();
+    }
+
+    /**
+     * 检查当前会话是否已通过二级认证,如未通过则抛出异常
+     */
+    public static void checkSafe() {
+        stpLogic.checkSafe();
+    }
+
+    /**
+     * 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证)
+     *
+     * @return 剩余有效时间
+     */
+    public static long getSafeTime() {
+        return stpLogic.getSafeTime();
+    }
+
+    /**
+     * 在当前会话 结束二级认证
+     */
+    public static void closeSafe() {
+        stpLogic.closeSafe();
+    }
+
+
+    // =================== 历史API,兼容旧版本 ===================
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.getLoginType() ,使用方式保持不变 </h1>
+     * <p>
+     * 获取当前StpLogin的loginKey
+     *
+     * @return 当前StpLogin的loginKey
+     */
+    @Deprecated
+    public static String getLoginKey() {
+        return stpLogic.getLoginType();
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+     * <p>
+     * 在当前会话上登录id
+     *
+     * @param loginId 登录id,建议的类型:(long | int | String)
+     */
+    @Deprecated
+    public static void setLoginId(Object loginId) {
+        stpLogic.login(loginId);
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+     * <p>
+     * 在当前会话上登录id, 并指定登录设备
+     *
+     * @param loginId 登录id,建议的类型:(long | int | String)
+     * @param device  设备标识
+     */
+    @Deprecated
+    public static void setLoginId(Object loginId, String device) {
+        stpLogic.login(loginId, device);
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+     * <p>
+     * 在当前会话上登录id, 并指定登录设备
+     *
+     * @param loginId         登录id,建议的类型:(long | int | String)
+     * @param isLastingCookie 是否为持久Cookie
+     */
+    @Deprecated
+    public static void setLoginId(Object loginId, boolean isLastingCookie) {
+        stpLogic.login(loginId, isLastingCookie);
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+     * <p>
+     * 在当前会话上登录id, 并指定所有登录参数Model
+     *
+     * @param loginId    登录id,建议的类型:(long | int | String)
+     * @param loginModel 此次登录的参数Model
+     */
+    @Deprecated
+    public static void setLoginId(Object loginId, SaLoginModel loginModel) {
+        stpLogic.login(loginId, loginModel);
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.kickout() ,使用方式保持不变 </h1>
+     * <p>
+     * 会话注销,根据账号id (踢人下线)
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
+     *
+     * @param loginId 账号id
+     */
+    @Deprecated
+    public static void logoutByLoginId(Object loginId) {
+        stpLogic.kickout(loginId);
+    }
+
+    /**
+     * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.kickout() ,使用方式保持不变 </h1>
+     * <p>
+     * 会话注销,根据账号id and 设备标识 (踢人下线)
+     * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 </p>
+     *
+     * @param loginId 账号id
+     * @param device  设备标识 (填null代表所有注销设备)
+     */
+    @Deprecated
+    public static void logoutByLoginId(Object loginId, String device) {
+        stpLogic.kickout(loginId, device);
+    }
+
+}
+

+ 501 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/StringUtils.java

@@ -0,0 +1,501 @@
+package cn.cslg.permission.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+@Slf4j
+public class StringUtils {
+
+    private final static int NUM_32 = 32;
+    //集群号
+    private static int machineId = 1;
+    /** 下划线 */
+    private static final char SEPARATOR = '_';
+
+    /**
+     * 下划线转驼峰命名
+     */
+    public static String toUnderScoreCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (i > 0) {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            } else {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1)) {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object) {
+        return !isNull(object);
+    }
+
+    public static boolean isNull(Object object) {
+        return object == null;
+    }
+
+
+    /**
+     * 把String 转换为 long
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static long getLong(String str, Long defaultData) {
+        Long lnum = defaultData;
+
+        if (isEmpty(str)) {
+            return lnum;
+        }
+        try {
+            lnum = Long.valueOf(str.trim()).longValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String 转换为 long======== " + str);
+        }
+        return lnum;
+
+    }
+
+    /**
+     * 转换成Boolean类型
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static Boolean getBoolean(String str, Boolean defaultData) {
+        Boolean lnum = defaultData;
+
+        if (isEmpty(str)) {
+            return lnum;
+        }
+        try {
+            lnum = Boolean.valueOf(str.trim()).booleanValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String 转换为 long======== " + str);
+        }
+        return lnum;
+
+    }
+
+    /**
+     * 把String转换成int数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static int getInt(String str, Integer defaultData) {
+        int inum = defaultData;
+        if (isEmpty(str)) {
+            return inum;
+        }
+        try {
+            inum = Integer.valueOf(str.trim()).intValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String转换成int数据========== " + str);
+        }
+        return inum;
+    }
+
+    /**
+     * 把String转换成double数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static double getDouble(String str, Double defaultData) {
+        double dnum = defaultData;
+        if (isEmpty(str)) {
+            return dnum;
+        }
+        try {
+            dnum = Double.valueOf(str.trim()).doubleValue();
+        } catch (NumberFormatException e) {
+            log.error("把String转换成double数据: {}", str);
+        }
+        return dnum;
+    }
+
+    /**
+     * 把String转换成float数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static float getFloat(String str, Float defaultData) {
+        float dnum = defaultData;
+        if (isEmpty(str)) {
+            return dnum;
+        }
+        try {
+            dnum = Float.valueOf(str.trim()).floatValue();
+        } catch (NumberFormatException e) {
+            log.error("把String转换成float数据: {}", str);
+        }
+        return dnum;
+    }
+
+    /**
+     * 判断字符串是否为空
+     *
+     * @param s
+     * @return
+     */
+    public static Boolean isEmpty(String s) {
+        if (s == null || s.length() <= 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 判断字符串是否为空
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNotEmpty(String str) {
+        return !StringUtils.isEmpty(str);
+    }
+
+    /**
+     * 按code截取字符串
+     *
+     * @return
+     */
+    public static String[] split(String str, String code) {
+        String[] split;
+        if (isEmpty(str)) {
+            split = null;
+        } else {
+            split = str.split(code);
+        }
+        return split;
+    }
+
+    /**
+     * 把字符串按code 转换为List<Long>
+     *
+     * @param str
+     * @return
+     */
+    public static List<Long> changeStringToLong(String str, String code) {
+        String[] split = split(str, code);
+        List<Long> lnums = new ArrayList<>();
+        for (String s : split) {
+            if (!isEmpty(s)) {
+                long lnum = getLong(s, 0L);
+                lnums.add(lnum);
+            }
+
+        }
+        return lnums;
+    }
+
+    /**
+     * 把字符串按code 转换为List<String>
+     *
+     * @param str
+     * @return
+     */
+    public static List<String> changeStringToString(String str, String code) {
+        String[] split = split(str, code);
+        List<String> lnums = new ArrayList<>();
+        for (String s : split) {
+            //long lnum = getLong(s, 0l);
+            lnums.add(s);
+        }
+        return lnums;
+    }
+
+    /**
+     * 把字符串按code 转换为List<Long>
+     *
+     * @param str
+     * @return
+     */
+    public static List<Integer> changeStringToInteger(String str, String code) {
+        if (isEmpty(str)) {
+            return new ArrayList<>();
+        }
+        String[] split = split(str, code);
+        List<Integer> inums = new ArrayList<>();
+        for (String s : split) {
+            int inum = getInt(s, 0);
+            inums.add(inum);
+        }
+        return inums;
+    }
+
+
+    /**
+     * 生成唯一订单号
+     *
+     * @return
+     */
+    public static String getOrderNumberByUUID() {
+
+        int hashCodeV = UUID.randomUUID().toString().hashCode();
+        //有可能是负数
+        if (hashCodeV < 0) {
+            hashCodeV = -hashCodeV;
+        }
+        String orderNumber = machineId + String.format("%015d", hashCodeV);
+        return orderNumber;
+    }
+
+    /**
+     * 生成唯一商户退款单号
+     *
+     * @return
+     */
+    public static String getOutRefundNoByUUID() {
+
+        int hashCodeV = UUID.randomUUID().toString().hashCode();
+        //有可能是负数
+        if (hashCodeV < 0) {
+            hashCodeV = -hashCodeV;
+        }
+        String out_refund_no = "BACK" + machineId + String.format("%015d", hashCodeV);
+        return out_refund_no;
+
+    }
+
+    /**
+     * 获取UUID,去掉了-
+     *
+     * @return
+     */
+    public static String getUUID() {
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        log.debug("获取32位的UUID的调试日志-->>" + uuid);
+        return uuid;
+    }
+
+    /**
+     * 获取雪花UID
+     *
+     * @return
+     */
+//    public static Long getSnowflakeId() {
+//        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0);
+//        return snowflakeIdWorker.nextId();
+//    }
+
+    /**
+     * list小于0的数据就过滤了
+     * 把list的数组变成1,3,4,5,6
+     *
+     * @param list
+     * @param code
+     * @return
+     */
+    public static String listToString(List<Long> list, String code) {
+        String s = "";
+        if (list == null || list.size() <= 0) {
+            return s;
+        }
+        for (Long l : list) {
+            if (l.longValue() > 0) {
+                s = s + l + code;
+            }
+        }
+        return s;
+    }
+
+    /**
+     * 按code把list的数组转换成字符串
+     *
+     * @param list
+     * @param code
+     * @return
+     */
+    public static String listTranformString(List<String> list, String code) {
+        String s = "";
+        if (list == null || list.size() <= 0) {
+            return s;
+        }
+        s = String.join(code, list);
+        return s;
+    }
+
+    /**
+     * 判断是否为非空字符串
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNotBlank(String str) {
+        return !StringUtils.isBlank(str);
+    }
+
+    /**
+     * 校验uid列表,检查里面元素是否满足限定长度为32
+     *
+     * @param collection
+     * @return
+     */
+    public static boolean checkUidList(Collection<String> collection) {
+        if (collection.size() == 0) {
+            return false;
+        }
+        for (String uid : collection) {
+            if (uid.trim().length() != NUM_32) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断是否为空字符串
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isBlank(String str) {
+        int strLen;
+        if (str == null || (strLen = str.length()) == 0) {
+            return true;
+        }
+        for (int i = 0; i < strLen; i++) {
+            if ((Character.isWhitespace(str.charAt(i)) == false)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断一个字符串是否为数字
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNumeric(String str) {
+        try {
+            //把字符串强制转换为数字
+            Integer.valueOf(str);
+            //如果是数字,返回True
+            return true;
+        } catch (Exception e) {
+            //如果抛出异常,返回False
+            return false;
+        }
+    }
+
+    /**
+     * 某个子串是否在字符串内
+     *
+     * @param str
+     * @param searchChar
+     * @return
+     */
+    public static boolean contains(String str, String searchChar) {
+        if (isEmpty(str)) {
+            return false;
+        }
+        return str.indexOf(searchChar) >= 0;
+    }
+
+    /**
+     * 切割字符串
+     *
+     * @param str
+     * @param start
+     * @return
+     */
+    public static String substring(String str, int start) {
+        if (str == null) {
+            return null;
+        }
+        // handle negatives, which means last n characters
+        if (start < 0) {
+            start = str.length() + start;
+        }
+        if (start < 0) {
+            start = 0;
+        }
+        if (start > str.length()) {
+            return "";
+        }
+        return str.substring(start);
+    }
+
+    /**
+     * 判断评论是否为垃圾评论(仅通过单一字符重复出现来判断,以后可以扩展更多的检测方法)
+     *
+     * @param content
+     * @return
+     */
+    public static Boolean isCommentSpam(String content) {
+        if (content == null) {
+            return true;
+        }
+        char[] chars = content.toCharArray();
+        // 最大重复次数
+        Integer maxCount = 4;
+        for (int a = 0; a < chars.length; a++) {
+            Integer count = 1;
+            for (int b = a; b < chars.length - 1; b++) {
+                if (chars[b + 1] == chars[b]) {
+                    count++;
+                    // 判断字符重复的次数是否大于阈值
+                    if (count >= maxCount) {
+                        return true;
+                    }
+                    continue;
+                } else {
+                    break;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static <T> String join(List<T> list, String separator) {
+        return org.apache.commons.lang3.StringUtils.join(list, separator);
+    }
+    public static <T> String join(String[] list, String separator) {
+        return org.apache.commons.lang3.StringUtils.join(list, separator);
+    }
+}

+ 18 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/TestUtils.java

@@ -0,0 +1,18 @@
+package cn.cslg.permission.common.utils;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.SecureUtil;
+import org.springframework.boot.system.ApplicationHome;
+
+import java.io.File;
+
+public class TestUtils {
+
+    public static void main(String[] args) {
+        ApplicationHome ah = new ApplicationHome(TestUtils.class);
+        File file = ah.getSource();
+        System.out.println(file.getParentFile().toString());
+        System.out.println(FileUtil.getWebRoot());
+    }
+}

+ 113 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/WebSocketServer.java

@@ -0,0 +1,113 @@
+package cn.cslg.permission.common.utils;
+
+import cn.cslg.permission.common.core.base.Constants;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+@Slf4j
+@Component
+@ServerEndpoint(Constants.API_VERSION_V2 + "/ws/{sid}")
+public class WebSocketServer {
+
+    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
+    private static int onlineCount = 0;
+    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
+    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet
+            = new CopyOnWriteArraySet<WebSocketServer>();
+    //与某个客户端的连接会话,需要通过它来给客户端发送数据
+    private Session session;
+    //接收sid
+    private String sid = "";
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("sid") String sid) {
+        this.session = session;
+        webSocketSet.add(this);     //加入set中
+        addOnlineCount();           //在线数加1
+        log.info("有新窗口开始监听:" + sid + ",当前在线人数为" + getOnlineCount());
+        this.sid = sid;
+        try {
+            sendMessage(Response.success("连接成功"));
+        } catch (IOException e) {
+            log.error("websocket IO异常");
+        }
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose() {
+        webSocketSet.remove(this);  //从set中删除
+        subOnlineCount();           //在线数减1
+        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
+    }
+
+    /**
+     * 收到客户端消息后调用的方法
+     *
+     * @param message 客户端发送过来的消息
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        log.info("收到来自窗口" + sid + "的信息:" + message);
+        //群发消息
+        for (WebSocketServer item : webSocketSet) {
+            try {
+                item.sendMessage(message);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("发生错误");
+        error.printStackTrace();
+    }
+
+    //实现服务器主动推送
+    public synchronized void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+    //群发自定义消息
+    public synchronized static void sendInfo(String message, @PathParam("sid") String sid) {
+        log.info("推送消息到窗口" + sid + ",推送内容:" + message);
+        for (WebSocketServer item : webSocketSet) {
+            try {
+                //这里可以设定只推送给这个sid的,为null则全部推送
+                if (sid == null || "null".equals(sid)) {
+                    item.sendMessage(message);
+                } else if (item.sid.equals(sid)) {
+                    item.sendMessage(message);
+                }
+            } catch (IOException e) {
+                continue;
+            }
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketServer.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketServer.onlineCount--;
+    }
+}
+

+ 22 - 0
PCS/src/main/java/cn/cslg/permission/entity/PermissionApplicationEntity.java

@@ -0,0 +1,22 @@
+package cn.cslg.permission.entity;
+
+import cn.cslg.permission.common.model.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class PermissionApplicationEntity extends BaseEntity {
+    /**
+     * 应用名称
+     */
+    @TableField(value = "APPLICATION_NAME")
+    private String applicationName;
+
+    /**
+     * 应用描述
+     */
+    @TableField(value = "APPLICATION_DESCRIPTION")
+    private String applicationDescription;
+}

+ 4 - 0
PCS/src/main/java/cn/cslg/permission/entity/PermissionFunctionEntity.java

@@ -0,0 +1,4 @@
+package cn.cslg.permission.entity;
+
+public class PermissionFunctionEntity {
+}

+ 18 - 0
PCS/src/main/resources/application-dev.yml

@@ -0,0 +1,18 @@
+spring:
+  redis:
+    host: 192.168.0.57
+    port: 6379
+    database: 8
+    timeout: 1000
+  datasource:
+    url: jdbc:mysql://192.168.0.57:3306/syy?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: 123456
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      stat-view-servlet:
+        login-username: admin
+        login-password: 123456
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"

+ 19 - 0
PCS/src/main/resources/application-docker.yml

@@ -0,0 +1,19 @@
+spring:
+  redis:
+    host: pas-redis
+    port: 6379
+    database: 0
+    timeout: 1000
+    password: cslg_docker_123456
+  datasource:
+    url: jdbc:mysql://pas-mysql:3306/pas?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: cslg_docker_123456
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      stat-view-servlet:
+        login-username: admin
+        login-password: cslg123456+
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"

+ 22 - 0
PCS/src/main/resources/application-prod.yml

@@ -0,0 +1,22 @@
+spring:
+  redis:
+    host: 172.27.247.174
+    port: 6379
+    database: 3
+    password: Xx0GWxdWQJxx6Swe
+    timeout: 1000
+  datasource:
+    url: jdbc:mysql://172.27.247.174:3306/pas-prod?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: TU5x6IeBi7rl
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      stat-view-servlet:
+        login-username: admin
+        login-password: Cslg2022+
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
+springdoc:
+  api-docs:
+    enabled: false

+ 19 - 0
PCS/src/main/resources/application-test.yml

@@ -0,0 +1,19 @@
+spring:
+  redis:
+    host: 172.27.247.174
+    port: 6379
+    database: 4
+    password: Xx0GWxdWQJxx6Swe
+    timeout: 1000
+  datasource:
+    url: jdbc:mysql://172.27.247.174:3306/pas?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: TU5x6IeBi7rl
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      stat-view-servlet:
+        login-username: admin
+        login-password: Cslg2022+
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"

+ 46 - 0
PCS/src/main/resources/application.yml

@@ -0,0 +1,46 @@
+server:
+  servlet:
+    context-path: /
+  port: 8880
+sa-token:
+  activity-timeout: 18000
+  token-name: token
+  token-style: tik
+spring:
+  thymeleaf:
+    cache: false
+    mode: HTML5
+  aop:
+    auto: true
+    proxy-target-class: true
+  application:
+    name: pas
+  servlet:
+    multipart:
+      max-file-size: 1000MB
+      max-request-size: 1000MB
+  profiles:
+    active: dev
+  jackson:
+    default-property-inclusion: non_null
+    serialization:
+      INDENT_OUTPUT: true
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: Asia/Shanghai
+logging:
+  config: classpath:config/logback-spring.xml
+  level:
+    cn.cslg.pas.mapper: debug
+#mybatis
+mybatis-plus:
+  typeAliasesPackage: cn.cslg.pas.domain
+  global-config:
+    db-config:
+      id-type: AUTO
+      logic-delete-value: 0
+      logic-not-delete-value: 1
+  configuration:
+    #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+  mapper-locations: classpath:mapper/*.xml

+ 2 - 0
PCS/src/main/resources/config/cron.setting

@@ -0,0 +1,2 @@
+[cn.cslg.permission.common.utils]
+BackupUtils.run = 00 03 * * *

+ 110 - 0
PCS/src/main/resources/config/logback-spring.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <contextName>${APP_NAME}</contextName>
+
+    <springProperty name="APP_NAME" scope="context" source="spring.application.name"/>
+    <springProperty name="LOG_FILE" scope="context" source="logging.file" defaultValue="./logs/${APP_NAME}"/>
+    <springProperty name="LOG_POINT_FILE" scope="context" source="logging.file" defaultValue="./logs/point"/>
+    <springProperty name="LOG_MAXFILESIZE" scope="context" source="logback.filesize" defaultValue="50MB"/>
+    <springProperty name="LOG_FILEMAXDAY" scope="context" source="logback.filemaxday" defaultValue="7"/>
+    <springProperty name="ServerIP" scope="context" source="server.address" defaultValue="0.0.0.0"/>
+    <springProperty name="ServerPort" scope="context" source="server.port" defaultValue="0000"/>
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%clr(%X{traceid}){yellow},%clr(%X{X-B3-TraceId}){yellow}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+    <property name="CONSOLE_LOG_PATTERN_NO_COLOR"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%X{traceid},%X{X-B3-TraceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+
+
+    <!-- 控制台日志 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <withJansi>true</withJansi>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-error.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <MaxFileSize>100MB</MaxFileSize>
+        </triggeringPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-info.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-debug.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="ERROR"/>
+        <appender-ref ref="INFO"/>
+        <appender-ref ref="DEBUG"/>
+    </root>
+
+</configuration>

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/上海市.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/中国.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/云南省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/全球.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/内蒙古自治区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/北京市.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/台湾省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/吉林省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/四川省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/天津市.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/宁夏回族自治区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/安徽省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/山东省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/山西省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/广东省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/广西壮族自治区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/新疆维吾尔自治区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/江苏省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/江西省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/河北省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/河南省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/浙江省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/海南省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/湖北省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/湖南省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/澳门特别行政区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/甘肃省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/福建省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/西藏自治区.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/贵州省.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
PCS/src/main/resources/static/map/辽宁省.json


+ 0 - 0
PCS/src/main/resources/static/map/重庆市.json


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff