初始化
This commit is contained in:
340
pom.xml
Normal file
340
pom.xml
Normal file
@@ -0,0 +1,340 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!--灿能微服务生态系统-->
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>pqs</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<modules>
|
||||
<module>pqs-common</module>
|
||||
<module>pqs-gateway</module>
|
||||
<module>pqs-user</module>
|
||||
<module>pqs-auth</module>
|
||||
<module>pqs-system</module>
|
||||
<module>pqs-harmonic</module>
|
||||
<module>pqs-device</module>
|
||||
<module>pqs-energy</module>
|
||||
<module>pqs-event</module>
|
||||
<module>pqs-job</module>
|
||||
<module>pqs-job/job-api</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
<name>灿能微服务生态系统</name>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>nexus-releases</id>
|
||||
<name>Nexus Release Repository</name>
|
||||
<url>http://192.168.1.13:8001/nexus/content/repositories/releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>nexus-snapshots</id>
|
||||
<name>Nexus Snapshot Repository</name>
|
||||
<url>http://192.168.1.13:8001/nexus/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<properties>
|
||||
<!--nacos的ip:port-->
|
||||
<nacos.url>192.168.1.13:18854</nacos.url>
|
||||
<!-- <nacos.url>192.168.1.14:18848</nacos.url>-->
|
||||
<!--服务器发布内容为空-->
|
||||
<!-- <nacos.namespace></nacos.namespace>-->
|
||||
<nacos.namespace>fd74182b-1fce-4dba-afa7-2623b0376205</nacos.namespace>
|
||||
<!--sentinel:port-->
|
||||
<sentinel.url>192.168.1.14:8080</sentinel.url>
|
||||
<!--微服务发布地址-->
|
||||
<server.url>192.168.1.13</server.url>
|
||||
<!--网关地址,主要用于配置swagger中认证token-->
|
||||
<gateway.url>192.168.1.13:10215</gateway.url>
|
||||
<!--docker远程守护进程的url-->
|
||||
<docker.url>http://${server.url}:2375</docker.url>
|
||||
<!--docker远程harbor,url-->
|
||||
<docker.repostory>${server.url}:8090</docker.repostory>
|
||||
<!--docker远程项目仓库名-->
|
||||
<docker.registry.name>njcn</docker.registry.name>
|
||||
<docker.operate>site</docker.operate>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<!--三剑客版本-->
|
||||
<springboot.version>2.3.12.RELEASE</springboot.version>
|
||||
<springcloud.version>Hoxton.SR12</springcloud.version>
|
||||
<springcloud.alibaba.version>2.2.7.RELEASE</springcloud.alibaba.version>
|
||||
<hutool.version>5.7.9</hutool.version>
|
||||
<knife4j.version>3.0.2</knife4j.version>
|
||||
<knife4j.aggregation.version>2.0.8</knife4j.aggregation.version>
|
||||
<lombok.version>1.18.18</lombok.version>
|
||||
<mybatis.version>2.1.3</mybatis.version>
|
||||
<druid.version>1.2.5</druid.version>
|
||||
<mysql.version>8.0.19</mysql.version>
|
||||
<mybatis-plus.version>3.4.2</mybatis-plus.version>
|
||||
<mybatis-plus-generator.version>3.5.1</mybatis-plus-generator.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<feignOkhttp.version>11.2</feignOkhttp.version>
|
||||
<antisamy.version>1.6.4</antisamy.version>
|
||||
<kaptcha.version>2.3.2</kaptcha.version>
|
||||
<bcprov-jdk15on.version>1.68</bcprov-jdk15on.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<commons-io.version>2.8.0</commons-io.version>
|
||||
<commons-codec.version>1.15</commons-codec.version>
|
||||
<sentinel.datasource.nacos.version>1.8.1</sentinel.datasource.nacos.version>
|
||||
<jackson>2.12.4</jackson>
|
||||
<easyexcel>2.2.6</easyexcel>
|
||||
<influxdb-java.version>2.18</influxdb-java.version>
|
||||
<echarts.version>3.0.0.6</echarts.version>
|
||||
<gson.version>2.8.9</gson.version>
|
||||
<xxl-job.version>2.3.0</xxl-job.version>
|
||||
<mqtt.version>1.2.7</mqtt.version>
|
||||
<easypoi.version>4.4.0</easypoi.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!--三剑客依赖******start-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${springcloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>${springcloud.alibaba.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!--三剑客依赖******end-->
|
||||
<!--java工具包-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!--java简化开发工具-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
<!--后端接口文档整合了swagger-->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>${knife4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-ui</artifactId>
|
||||
<version>${knife4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
|
||||
<!--在引用时请在maven中央仓库搜索aggregation最新版本号-->
|
||||
<version>${knife4j.aggregation.version}</version>
|
||||
</dependency>
|
||||
<!--数据库相关********satrt-->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis.version}</version>
|
||||
</dependency>
|
||||
<!--druid连接池-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
<!--mysql驱动-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
<!--mariaDB驱动-->
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>${mariadb.version}</version>
|
||||
</dependency>
|
||||
<!--oracle驱动-->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>${oracle.version}</version>
|
||||
</dependency>
|
||||
<!-- 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.nls</groupId>
|
||||
<artifactId>orai18n</artifactId>
|
||||
<version>21.1.0.0</version>
|
||||
</dependency>
|
||||
<!-- mybatis-plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>${mybatis-plus-generator.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
<version>${velocity.version}</version>
|
||||
</dependency>
|
||||
<!--数据库相关********end-->
|
||||
<!--jjwt-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<!--openFeign的底层连接方式,测试效率最高 -->
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<version>${feignOkhttp.version}</version>
|
||||
</dependency>
|
||||
<!--防止XSS攻击的antiSamy-->
|
||||
<dependency>
|
||||
<groupId>org.owasp.antisamy</groupId>
|
||||
<artifactId>antisamy</artifactId>
|
||||
<version>${antisamy.version}</version>
|
||||
</dependency>
|
||||
<!--图形验证码-->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
<!-- 国密加解密工具包 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>${bcprov-jdk15on.version}</version>
|
||||
</dependency>
|
||||
<!-- commons通用包 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons-io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>${commons-codec.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
<version>${sentinel.datasource.nacos.version}</version>
|
||||
</dependency>
|
||||
<!--jackson依赖-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<!--此处需要注意的事,databind自身依赖的jackson-core/jackson-annotations由于版本偏低,会出现异常-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.abel533</groupId>
|
||||
<artifactId>ECharts</artifactId>
|
||||
<version>${echarts.version}</version>
|
||||
</dependency>
|
||||
<!-- echarts绘图所需,可以将包含function的对象转为json -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
<!-- xxl-job-core -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>${xxl-job.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.tocrhz</groupId>
|
||||
<artifactId>mqtt-spring-boot-starter</artifactId>
|
||||
<version>${mqtt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.afterturn</groupId>
|
||||
<artifactId>easypoi-spring-boot-starter</artifactId>
|
||||
<version>${easypoi.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.2.2.RELEASE</version>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
<addResources>true</addResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
7
pqs-auth/Dockerfile
Normal file
7
pqs-auth/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM openjdk:8-jdk-alpine
|
||||
RUN set -xe \&& apk --no-cache add ttf-dejavu fontconfig
|
||||
ADD target/auth.jar auth.jar
|
||||
ENTRYPOINT ["java","-jar","/auth.jar"]
|
||||
EXPOSE 10214
|
||||
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo 'Asia/Shanghai' >/etc/timezone
|
||||
|
||||
136
pqs-auth/pom.xml
Normal file
136
pqs-auth/pom.xml
Normal file
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>pqs-auth</artifactId>
|
||||
<name>认证授权服务模块</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-swagger</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-microservice</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-db</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-redis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>user-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- OAuth2 认证服务器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth.boot</groupId>
|
||||
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-jose</artifactId>
|
||||
</dependency>
|
||||
<!--图形验证码-->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>auth</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<nonFilteredFileExtensions>
|
||||
<!--这里是文件后缀-->
|
||||
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
|
||||
</nonFilteredFileExtensions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.spotify</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<executions>
|
||||
<!--执行mvn package,即执行 mvn clean package docker:build-->
|
||||
<execution>
|
||||
<id>build-image</id>
|
||||
<phase>${docker.operate}</phase>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<!--<serverId>36dockerHarbor</serverId>-->
|
||||
<registryUrl>http://${docker.repostory}</registryUrl>
|
||||
<!-- 镜像名称 -->
|
||||
<imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}</imageName>
|
||||
<!-- 指定标签 -->
|
||||
<imageTags>
|
||||
<imageTag>latest</imageTag>
|
||||
</imageTags>
|
||||
<!-- 指定远程 Docker API地址 -->
|
||||
<dockerHost>${docker.url}</dockerHost>
|
||||
<dockerDirectory>${basedir}/</dockerDirectory>
|
||||
<!-- 复制 jar包到docker容器指定目录-->
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>/ROOT</targetPath>
|
||||
<!-- 用于指定需要复制的根目录,${project.build.directory}表示target目录 -->
|
||||
<directory>${project.build.directory}</directory>
|
||||
<!-- 用于指定需要复制的文件,${project.build.finalName}.jar就是打包后的target目录下的jar包名称 -->
|
||||
<include>${project.build.finalName}.jar</include>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
|
||||
|
||||
</project>
|
||||
24
pqs-auth/src/main/java/com/njcn/auth/AuthApplication.java
Normal file
24
pqs-auth/src/main/java/com/njcn/auth/AuthApplication.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.njcn.auth;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月14日 20:33
|
||||
*/
|
||||
@Slf4j
|
||||
@MapperScan("com.njcn.**.mapper")
|
||||
@EnableFeignClients(basePackages = "com.njcn")
|
||||
@SpringBootApplication(scanBasePackages = "com.njcn")
|
||||
public class AuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AuthApplication.class,args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.njcn.auth.config;
|
||||
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.auth.filter.CustomClientCredentialsTokenEndpointFilter;
|
||||
import com.njcn.auth.pojo.bo.BusinessUser;
|
||||
import com.njcn.auth.security.clientdetails.ClientDetailsServiceImpl;
|
||||
import com.njcn.auth.security.extension.captcha.CaptchaTokenGranter;
|
||||
import com.njcn.auth.security.extension.refresh.PreAuthenticatedUserDetailsService;
|
||||
import com.njcn.auth.service.UserDetailsServiceImpl;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.enums.auth.ClientEnum;
|
||||
import com.njcn.redis.utils.RedisUtil;
|
||||
import com.njcn.user.enums.UserResponseEnum;
|
||||
import com.njcn.web.utils.WebUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
|
||||
import org.springframework.security.oauth2.provider.TokenGranter;
|
||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
|
||||
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
||||
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年05月11日 13:16
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@EnableAuthorizationServer
|
||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
private final ClientDetailsServiceImpl clientDetailsService;
|
||||
|
||||
private final UserDetailsServiceImpl userDetailsService;
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
|
||||
/**
|
||||
* 客户端信息配置
|
||||
*/
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void configure(ClientDetailsServiceConfigurer clients) {
|
||||
clients.withClientDetails(clientDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
||||
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
|
||||
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
|
||||
tokenEnhancers.add(tokenEnhancer());
|
||||
tokenEnhancers.add(jwtAccessTokenConverter());
|
||||
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
|
||||
// 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者
|
||||
List<TokenGranter> granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
|
||||
|
||||
// 添加验证码授权模式授权者
|
||||
granterList.add(new CaptchaTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(),
|
||||
endpoints.getOAuth2RequestFactory(), authenticationManager, redisUtil
|
||||
));
|
||||
|
||||
//todo... 后续可以扩展更多授权模式,比如:微信小程序、移动app
|
||||
|
||||
|
||||
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
|
||||
endpoints.authenticationManager(authenticationManager)
|
||||
.accessTokenConverter(jwtAccessTokenConverter())
|
||||
//设置grant_type类型集合
|
||||
.tokenEnhancer(tokenEnhancerChain)
|
||||
.tokenGranter(compositeTokenGranter)
|
||||
/**refresh_token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
|
||||
*1.重复使用:access_token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
|
||||
*2.非重复使用:access_token过期刷新时, refresh_token过期时间延续,在refresh_token有效期内刷新而无需失效再次登录
|
||||
*/
|
||||
.reuseRefreshTokens(true)
|
||||
.tokenServices(tokenServices(endpoints));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public DefaultTokenServices tokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
|
||||
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
|
||||
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
|
||||
tokenEnhancers.add(tokenEnhancer());
|
||||
tokenEnhancers.add(jwtAccessTokenConverter());
|
||||
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
|
||||
|
||||
DefaultTokenServices tokenServices = new DefaultTokenServices();
|
||||
tokenServices.setTokenStore(endpoints.getTokenStore());
|
||||
tokenServices.setSupportRefreshToken(true);
|
||||
tokenServices.setClientDetailsService(clientDetailsService);
|
||||
tokenServices.setTokenEnhancer(tokenEnhancerChain);
|
||||
|
||||
// 多用户体系下,刷新token再次认证客户端ID和 UserDetailService 的映射Map
|
||||
Map<String, UserDetailsService> clientUserDetailsServiceMap = new HashMap<>();
|
||||
|
||||
// 系统管理客户端
|
||||
clientUserDetailsServiceMap.put(ClientEnum.WEB_CLIENT.getClientId(), userDetailsService);
|
||||
clientUserDetailsServiceMap.put(ClientEnum.WEB_CLIENT_TEST.getClientId(), userDetailsService);
|
||||
clientUserDetailsServiceMap.put(ClientEnum.APP_CLIENT.getClientId(), userDetailsService);
|
||||
clientUserDetailsServiceMap.put(ClientEnum.SCREEN_CLIENT.getClientId(), userDetailsService);
|
||||
clientUserDetailsServiceMap.put(ClientEnum.WE_CHAT_APP_CLIENT.getClientId(), userDetailsService);
|
||||
|
||||
//todo .. 后面扩展微信小程序、app实现服务
|
||||
// 刷新token模式下,重写预认证提供者替换其AuthenticationManager,可自定义根据客户端ID和认证方式区分用户体系获取认证用户信息
|
||||
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
|
||||
provider.setPreAuthenticatedUserDetailsService(new PreAuthenticatedUserDetailsService<>(clientUserDetailsServiceMap));
|
||||
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
|
||||
return tokenServices;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用非对称加密算法对token签名
|
||||
*/
|
||||
@Bean
|
||||
public JwtAccessTokenConverter jwtAccessTokenConverter() {
|
||||
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
|
||||
converter.setKeyPair(keyPair());
|
||||
return converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从classpath下的密钥库中获取密钥对(公钥+私钥)
|
||||
*/
|
||||
@Bean
|
||||
public KeyPair keyPair() {
|
||||
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("njcn.jks"), "njcnpqs".toCharArray());
|
||||
return factory.getKeyPair("njcn", "njcnpqs".toCharArray());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 自定义认证异常响应数据
|
||||
*/
|
||||
@Bean
|
||||
public AuthenticationEntryPoint authenticationEntryPoint() {
|
||||
return (request, response, e) -> {
|
||||
WebUtil.responseInfo(response, UserResponseEnum.CLIENT_AUTHENTICATION_FAILED.getCode(), UserResponseEnum.CLIENT_AUTHENTICATION_FAILED.getMessage());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JWT内容增强
|
||||
*/
|
||||
@Bean
|
||||
public TokenEnhancer tokenEnhancer() {
|
||||
return (accessToken, authentication) -> {
|
||||
String clientId = authentication.getOAuth2Request().getClientId();
|
||||
BusinessUser user = (BusinessUser) authentication.getUserAuthentication().getPrincipal();
|
||||
Map<String, Object> map = new HashMap<>(8);
|
||||
map.put(SecurityConstants.USER_INDEX_KEY, user.getUserIndex());
|
||||
map.put(SecurityConstants.USER_TYPE, user.getType());
|
||||
map.put(SecurityConstants.USER_NICKNAME_KEY, user.getNickName());
|
||||
map.put(SecurityConstants.CLIENT_ID_KEY, clientId);
|
||||
map.put(SecurityConstants.DEPT_INDEX_KEY, user.getDeptIndex());
|
||||
if (StrUtil.isNotBlank(user.getAuthenticationMethod())) {
|
||||
map.put(SecurityConstants.AUTHENTICATION_METHOD, user.getAuthenticationMethod());
|
||||
}
|
||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
|
||||
return accessToken;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 配置自定义密码认证过滤器
|
||||
* @param security .
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerSecurityConfigurer security) {
|
||||
CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security);
|
||||
endpointFilter.afterPropertiesSet();
|
||||
endpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint());
|
||||
security.addTokenEndpointAuthenticationFilter(endpointFilter);
|
||||
|
||||
security
|
||||
.authenticationEntryPoint(authenticationEntryPoint())
|
||||
/* .allowFormAuthenticationForClients()*/ //如果使用表单认证则需要加上
|
||||
.tokenKeyAccess("permitAll()")
|
||||
.checkTokenAccess("isAuthenticated()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
public DaoAuthenticationProvider authenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setHideUserNotFoundExceptions(false);
|
||||
provider.setUserDetailsService(userDetailsService);
|
||||
provider.setPasswordEncoder(passwordEncoder);
|
||||
return provider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.njcn.auth.config;
|
||||
|
||||
import com.njcn.auth.security.sm4.Sm4AuthenticationProvider;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final UserDetailsService sysUserDetailsService;
|
||||
|
||||
private final Sm4AuthenticationProvider sm4AuthenticationProvider;
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/oauth/getPublicKey","/oauth/logout","/auth/getImgCode","/judgeToken/guangZhou").permitAll()
|
||||
// @link https://gitee.com/xiaoym/knife4j/issues/I1Q5X6 (接口文档knife4j需要放行的规则)
|
||||
.antMatchers("/webjars/**","/doc.html","/swagger-resources/**","/v2/api-docs").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证管理对象
|
||||
*
|
||||
* @throws Exception .
|
||||
* @return .
|
||||
*/
|
||||
@Override
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder auth) {
|
||||
auth.authenticationProvider(daoAuthenticationProvider());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 用户名密码认证授权提供者
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(sysUserDetailsService);
|
||||
provider.setPasswordEncoder(passwordEncoder());
|
||||
provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写父类自定义AuthenticationManager 将provider注入进去
|
||||
* 当然我们也可以考虑不重写 在父类的manager里面注入provider
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager(){
|
||||
return new ProviderManager(sm4AuthenticationProvider);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 密码编码器
|
||||
* <p>
|
||||
* 委托方式,根据密码的前缀选择对应的encoder,例如:{bcypt}前缀->标识BCYPT算法加密;{noop}->标识不使用任何加密即明文的方式
|
||||
* 密码判读 DaoAuthenticationProvider#additionalAuthenticationChecks
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.njcn.auth.controller;
|
||||
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.njcn.auth.service.UserTokenService;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.dto.UserTokenInfo;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.HttpResultUtil;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.njcn.common.utils.sm.DesUtils;
|
||||
import com.njcn.redis.utils.RedisUtil;
|
||||
import com.njcn.user.api.UserFeignClient;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.Principal;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
*/
|
||||
@Api(tags = "认证中心")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/oauth")
|
||||
@AllArgsConstructor
|
||||
public class AuthController extends BaseController {
|
||||
|
||||
|
||||
private final TokenEndpoint tokenEndpoint;
|
||||
|
||||
private final KeyPair keyPair;
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
private final UserFeignClient userFeignClient;
|
||||
|
||||
private final UserTokenService userTokenService;
|
||||
|
||||
|
||||
@ApiIgnore
|
||||
@ApiOperation("登录认证")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = SecurityConstants.GRANT_TYPE, defaultValue = "password", value = "授权模式", required = true),
|
||||
@ApiImplicitParam(name = SecurityConstants.CLIENT_ID, defaultValue = "njcn", value = "Oauth2客户端ID", required = true),
|
||||
@ApiImplicitParam(name = SecurityConstants.CLIENT_SECRET, defaultValue = "njcnpqs", value = "Oauth2客户端秘钥", required = true),
|
||||
@ApiImplicitParam(name = SecurityConstants.REFRESH_TOKEN, value = "刷新token"),
|
||||
@ApiImplicitParam(name = SecurityConstants.USERNAME, value = "登录用户名"),
|
||||
@ApiImplicitParam(name = SecurityConstants.PASSWORD, value = "登录密码"),
|
||||
@ApiImplicitParam(name = SecurityConstants.IMAGE_CODE, value = "图形验证码"),
|
||||
})
|
||||
@PostMapping("/token")
|
||||
public Object postAccessToken(@ApiIgnore Principal principal, @RequestParam @ApiIgnore Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
|
||||
String methodDescribe = getMethodDescribe("postAccessToken");
|
||||
String username = parameters.get(SecurityConstants.USERNAME);
|
||||
String grantType = parameters.get(SecurityConstants.GRANT_TYPE);
|
||||
//正式环境需删除,均是加密的用户名
|
||||
if (!grantType.equalsIgnoreCase(SecurityConstants.PASSWORD)) {
|
||||
username = DesUtils.aesDecrypt(username);
|
||||
}
|
||||
if (grantType.equalsIgnoreCase(SecurityConstants.REFRESH_TOKEN_KEY)) {
|
||||
//如果是刷新token,需要去黑名单校验
|
||||
userTokenService.judgeRefreshToken(parameters.get(SecurityConstants.REFRESH_TOKEN_KEY));
|
||||
}
|
||||
RequestUtil.saveLoginName(username);
|
||||
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
|
||||
//用户的登录名&密码校验成功后,判断当前该用户是否可以正常使用系统
|
||||
userFeignClient.judgeUserStatus(username);
|
||||
//登录成功后,记录token信息,并处理踢人效果
|
||||
userTokenService.recordUserInfo(oAuth2AccessToken);
|
||||
if (!grantType.equalsIgnoreCase(SecurityConstants.PASSWORD)) {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, oAuth2AccessToken, methodDescribe);
|
||||
} else {
|
||||
return oAuth2AccessToken;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("用户登出系统")
|
||||
@DeleteMapping("/logout")
|
||||
public HttpResult<Object> logout() {
|
||||
String methodDescribe = getMethodDescribe("logout");
|
||||
String userIndex = RequestUtil.getUserIndex();
|
||||
String username = RequestUtil.getUsername();
|
||||
LogUtil.njcnDebug(log, "{},用户名为:{}", methodDescribe, username);
|
||||
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
|
||||
String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX + userIndex;
|
||||
Object onlineTokenInfoOld = redisUtil.getObjectByKey(onlineUserKey);
|
||||
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
|
||||
UserTokenInfo userTokenInfo;
|
||||
if (!Objects.isNull(onlineTokenInfoOld)) {
|
||||
//清除在线token信息
|
||||
redisUtil.delete(onlineUserKey);
|
||||
userTokenInfo = (UserTokenInfo) onlineTokenInfoOld;
|
||||
if (CollectionUtils.isEmpty(blackUsers)) {
|
||||
blackUsers = new ArrayList<>();
|
||||
}
|
||||
blackUsers.add(userTokenInfo);
|
||||
LocalDateTime refreshTokenExpire = userTokenInfo.getRefreshTokenExpire();
|
||||
long lifeTime = Math.abs(refreshTokenExpire.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
|
||||
redisUtil.saveByKeyWithExpire(blackUserKey, blackUsers, lifeTime);
|
||||
}
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文档隐藏该接口
|
||||
*/
|
||||
@ApiIgnore
|
||||
@ApiOperation("RSA公钥获取接口")
|
||||
@GetMapping("/getPublicKey")
|
||||
public Map<String, Object> getPublicKey() {
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAKey key = new RSAKey.Builder(publicKey).build();
|
||||
return new JWKSet(key).toJSONObject();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.njcn.auth.controller;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.njcn.common.pojo.annotation.OperateInfo;
|
||||
import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.HttpResultUtil;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年04月27日 11:22
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@Api(tags = "校验第三方token")
|
||||
@RequestMapping("/judgeToken")
|
||||
public class JudgeThirdToken extends BaseController {
|
||||
|
||||
/**
|
||||
* 校验广州超高压token有效性
|
||||
*
|
||||
* @param token token数据
|
||||
*/
|
||||
@OperateInfo(info = LogEnum.SYSTEM_COMMON)
|
||||
@PostMapping("/guangZhou")
|
||||
@ApiOperation("校验广州超高压token有效性")
|
||||
@ApiImplicitParam(name = "token", value = "", required = true)
|
||||
public HttpResult<Object> guangZhou(String token) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
String methodDescribe = getMethodDescribe("guangZhou");
|
||||
LogUtil.njcnDebug(log, "{},token:{}", methodDescribe, token);
|
||||
|
||||
// 请求地址
|
||||
String url = "http://10.121.17.9:9080/ehv/auth_valid";
|
||||
|
||||
// 请求头设置,x-www-form-urlencoded格式的数据
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
//提交参数设置
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("token", token);
|
||||
|
||||
// 组装请求体
|
||||
HttpEntity<MultiValueMap<String, String>> request =
|
||||
new HttpEntity<>(map, headers);
|
||||
|
||||
// 发送post请求,并打印结果,以String类型接收响应结果JSON字符串
|
||||
String result = restTemplate.postForObject(url, request, String.class);
|
||||
JSONObject resultJson = new JSONObject(result);
|
||||
System.out.println(result);
|
||||
if (resultJson.getInt("status") == 1) {
|
||||
//成功
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
|
||||
} else {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, methodDescribe);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.njcn.auth.controller;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
import com.njcn.auth.utils.AuthPubUtil;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.redis.utils.RedisUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月04日 15:25
|
||||
*/
|
||||
@Api(tags = "认证中心")
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/auth")
|
||||
@AllArgsConstructor
|
||||
public class KaptchaController {
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
@ApiIgnore
|
||||
@ApiOperation("获取图形验证码")
|
||||
@GetMapping("/getImgCode")
|
||||
public void getImgCode(@ApiIgnore HttpServletResponse resp, @ApiIgnore HttpServletRequest request) {
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = resp.getOutputStream();
|
||||
// resp.setContentType("image/jpeg");"/pqs-auth/auth/getImgCode",
|
||||
if (null != out) {
|
||||
Properties props = new Properties();
|
||||
Producer kaptchaProducer;
|
||||
ImageIO.setUseCache(false);
|
||||
props.put("kaptcha.border", "no");
|
||||
props.put("kaptcha.textproducer.font.color", "black");
|
||||
/*props.put("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");*/
|
||||
/*props.put("kaptcha.noise.impl", "com.sso.utils.ComplexNoise");*/
|
||||
props.put("kaptcha.textproducer.char.space", "5");
|
||||
props.put("kaptcha.textproducer.char.length", "4");
|
||||
Config config = new Config(props);
|
||||
kaptchaProducer = config.getProducerImpl();
|
||||
//此处需要固定采用字母和数字混合
|
||||
String capText = AuthPubUtil.getKaptchaText(4);
|
||||
String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
String ip = request.getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
|
||||
String key = userAgent + ip;
|
||||
redisUtil.delete(key);
|
||||
redisUtil.saveByKeyWithExpire(key, capText, 30*60L);
|
||||
BufferedImage bi = kaptchaProducer.createImage(capText);
|
||||
ImageIO.write(bi, "jpg", out);
|
||||
out.flush();
|
||||
}
|
||||
} catch (IOException ioException) {
|
||||
log.error("获取图形验证码异常,异常为:{}", ioException.toString());
|
||||
} finally {
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.njcn.auth.exception;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.nimbusds.jose.JWSObject;
|
||||
import com.njcn.common.pojo.constant.LogInfo;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.HttpResultUtil;
|
||||
import com.njcn.user.api.UserFeignClient;
|
||||
import com.njcn.user.enums.UserResponseEnum;
|
||||
import com.njcn.web.service.ILogService;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年05月17日 12:46
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
@RequiredArgsConstructor
|
||||
public class AuthExceptionHandler {
|
||||
|
||||
private final UserFeignClient userFeignClient;
|
||||
|
||||
private final ILogService logService;
|
||||
|
||||
/**
|
||||
* 用户名和密码非法
|
||||
*/
|
||||
@ExceptionHandler(InvalidGrantException.class)
|
||||
public HttpResult<String> handleInvalidGrantException(HttpServletRequest httpServletRequest, InvalidGrantException invalidGrantException) {
|
||||
String loginName = invalidGrantException.getMessage();
|
||||
logService.recodeAuthExceptionLog(invalidGrantException, httpServletRequest, UserResponseEnum.LOGIN_WRONG_PWD.getMessage(), loginName);
|
||||
HttpResult<String> result = userFeignClient.updateUserLoginErrorTimes(loginName);
|
||||
if (result.getData().equals(UserResponseEnum.LOGIN_USER_LOCKED.getMessage())) {
|
||||
return HttpResultUtil.assembleResult(UserResponseEnum.LOGIN_USER_LOCKED.getCode(), null, UserResponseEnum.LOGIN_USER_LOCKED.getMessage());
|
||||
} else {
|
||||
return HttpResultUtil.assembleResult(UserResponseEnum.LOGIN_WRONG_PWD.getCode(), null, UserResponseEnum.LOGIN_WRONG_PWD.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 不支持的认证方式
|
||||
* <p>
|
||||
* 不支持的认证方式 目前支持:用户名密码:password、刷新token:refresh-token
|
||||
*/
|
||||
@ExceptionHandler(UnsupportedGrantTypeException.class)
|
||||
public HttpResult<String> unsupportedGrantTypeExceptionException(HttpServletRequest httpServletRequest, UnsupportedGrantTypeException unsupportedGrantTypeException) {
|
||||
String loginName = RequestUtil.getLoginName(httpServletRequest);
|
||||
logService.recodeAuthExceptionLog(unsupportedGrantTypeException, httpServletRequest, UserResponseEnum.UNSUPPORTED_GRANT_TYPE.getMessage(), loginName);
|
||||
return HttpResultUtil.assembleResult(UserResponseEnum.UNSUPPORTED_GRANT_TYPE.getCode(), null, UserResponseEnum.UNSUPPORTED_GRANT_TYPE.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* oAuth2中token校验异常
|
||||
*/
|
||||
@SneakyThrows
|
||||
@ExceptionHandler(InvalidTokenException.class)
|
||||
public HttpResult<String> invalidTokenExceptionException(HttpServletRequest httpServletRequest, InvalidTokenException invalidTokenException) {
|
||||
final String EXPIRED_KEY = "Invalid refresh token (expired):";
|
||||
if (invalidTokenException.getMessage().startsWith(EXPIRED_KEY)) {
|
||||
String message = invalidTokenException.getMessage();
|
||||
message = message.substring(EXPIRED_KEY.length());
|
||||
JWSObject jwsObject = JWSObject.parse(message);
|
||||
String payload = jwsObject.getPayload().toString();
|
||||
JSONObject jsonObject = JSONUtil.parseObj(payload);
|
||||
logService.recodeAuthExceptionLog(invalidTokenException, httpServletRequest, UserResponseEnum.REFRESH_TOKEN_EXPIRE_JWT.getMessage(), jsonObject.getStr(SecurityConstants.USER_NAME_KEY));
|
||||
return HttpResultUtil.assembleResult(UserResponseEnum.REFRESH_TOKEN_EXPIRE_JWT.getCode(), null, UserResponseEnum.REFRESH_TOKEN_EXPIRE_JWT.getMessage());
|
||||
}
|
||||
logService.recodeAuthExceptionLog(invalidTokenException, httpServletRequest, UserResponseEnum.PARSE_TOKEN_FORBIDDEN_JWT.getMessage(), LogInfo.UNKNOWN_USER);
|
||||
return HttpResultUtil.assembleResult(UserResponseEnum.PARSE_TOKEN_FORBIDDEN_JWT.getCode(), null, UserResponseEnum.PARSE_TOKEN_FORBIDDEN_JWT.getMessage());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.auth.filter;
|
||||
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @createTime 2021年05月24日 15:39
|
||||
*/
|
||||
public class CustomClientCredentialsTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
|
||||
|
||||
private final AuthorizationServerSecurityConfigurer configurer;
|
||||
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
|
||||
public CustomClientCredentialsTokenEndpointFilter(AuthorizationServerSecurityConfigurer configurer) {
|
||||
this.configurer = configurer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
super.setAuthenticationEntryPoint(null);
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthenticationManager getAuthenticationManager() {
|
||||
return configurer.and().getSharedObject(AuthenticationManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
setAuthenticationFailureHandler((request, response, e) -> authenticationEntryPoint.commence(request, response, e));
|
||||
setAuthenticationSuccessHandler((request, response, authentication) -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.njcn.auth.pojo.bo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @createTime 2021年04月28日 13:31
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BusinessUser implements UserDetails {
|
||||
|
||||
private String userIndex;
|
||||
|
||||
private String username;
|
||||
|
||||
private String nickName;
|
||||
|
||||
private String password;
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String deptIndex;
|
||||
|
||||
private Collection<? extends GrantedAuthority> authorities;
|
||||
|
||||
private boolean accountNonExpired;
|
||||
|
||||
private boolean accountNonLocked;
|
||||
|
||||
private boolean credentialsNonExpired;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String standBy;
|
||||
|
||||
private String authenticationMethod;
|
||||
|
||||
private Integer type;
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities(){
|
||||
return authorities;
|
||||
}
|
||||
|
||||
|
||||
public BusinessUser(String username, String password, List<GrantedAuthority> authorities) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authorities =authorities;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.njcn.auth.security.clientdetails;
|
||||
|
||||
|
||||
import com.njcn.common.pojo.enums.auth.PasswordEncoderTypeEnum;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.user.api.AuthClientFeignClient;
|
||||
import com.njcn.user.pojo.po.AuthClient;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
import org.springframework.security.oauth2.provider.NoSuchClientException;
|
||||
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* OAuth2 客户端信息
|
||||
* @author hongawen
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ClientDetailsServiceImpl implements ClientDetailsService {
|
||||
|
||||
private final AuthClientFeignClient authClientFeignClient;
|
||||
|
||||
@Override
|
||||
public ClientDetails loadClientByClientId(String clientName) {
|
||||
try {
|
||||
HttpResult<AuthClient> authClientResult = authClientFeignClient.getAuthClientByName(clientName);
|
||||
AuthClient authClient = authClientResult.getData();
|
||||
BaseClientDetails clientDetails = new BaseClientDetails(
|
||||
authClient.getName(),
|
||||
authClient.getResourceIds(),
|
||||
authClient.getScope(),
|
||||
authClient.getAuthorizedGrantTypes(),
|
||||
authClient.getAuthorities(),
|
||||
authClient.getWebServerRedirectUri()
|
||||
);
|
||||
clientDetails.setClientSecret(PasswordEncoderTypeEnum.BCRYPT.getPrefix() + authClient.getClientSecret());
|
||||
clientDetails.setAccessTokenValiditySeconds(authClient.getAccessTokenValidity());
|
||||
clientDetails.setRefreshTokenValiditySeconds(authClient.getRefreshTokenValidity());
|
||||
return clientDetails;
|
||||
} catch (EmptyResultDataAccessException var4) {
|
||||
throw new NoSuchClientException("No client with requested id: " + clientName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
PasswordEncoder delegatingPasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
String njcnpqs = delegatingPasswordEncoder.encode("njcnpqs");
|
||||
//{bcrypt}$2a$10$xIP3g5Rc11zDdclsKXpQXuOobvZ9gaw2Mix1rkOm1MJN1.hTVY7ci
|
||||
System.out.println(njcnpqs);
|
||||
System.out.println(delegatingPasswordEncoder.matches("njcnpqs","{bcrypt}$2a$10$xIP3g5Rc11zDdclsKXpQXuOobvZ9gaw2Mix1rkOm1MJN1.hTVY7ci"));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.njcn.auth.security.extension.captcha;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.common.utils.sm.DesUtils;
|
||||
import com.njcn.common.utils.sm.Sm2;
|
||||
import com.njcn.redis.utils.RedisUtil;
|
||||
import com.njcn.user.enums.UserResponseEnum;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.authentication.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
|
||||
import org.springframework.security.oauth2.provider.*;
|
||||
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月15日 14:23
|
||||
*/
|
||||
@Slf4j
|
||||
public class CaptchaTokenGranter extends AbstractTokenGranter {
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
public CaptchaTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
|
||||
OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager,
|
||||
RedisUtil redisUtil
|
||||
) {
|
||||
//SecurityConstants.GRANT_CAPTCHA:申明为授权码模式
|
||||
super(tokenServices, clientDetailsService, requestFactory, SecurityConstants.GRANT_CAPTCHA);
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.redisUtil = redisUtil;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
|
||||
Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
|
||||
String username = parameters.get(SecurityConstants.USERNAME);
|
||||
username = DesUtils.aesDecrypt(username);
|
||||
if (!judgeImageCode(parameters.get(SecurityConstants.IMAGE_CODE), RequestUtil.getRequest())) {
|
||||
throw new BusinessException(UserResponseEnum.LOGIN_WRONG_CODE);
|
||||
}
|
||||
String password = parameters.get(SecurityConstants.PASSWORD);
|
||||
String ip = RequestUtil.getRequest().getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
|
||||
//密码处理
|
||||
String privateKey = redisUtil.getStringByKey(username + ip);
|
||||
// //秘钥用完即删
|
||||
redisUtil.delete(username + ip);
|
||||
//对SM2解密面进行验证
|
||||
password = Sm2.getPasswordSM2Verify(privateKey, password);
|
||||
if (StrUtil.isBlankIfStr(password)) {
|
||||
throw new BusinessException(UserResponseEnum.PASSWORD_TRANSPORT_ERROR);
|
||||
}
|
||||
//正式环境放行
|
||||
parameters.remove(SecurityConstants.PASSWORD);
|
||||
Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
|
||||
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
|
||||
try {
|
||||
userAuth = authenticationManager.authenticate(userAuth);
|
||||
} catch (AccountStatusException | BadCredentialsException ase) {
|
||||
//covers expired, locked, disabled cases
|
||||
throw new InvalidGrantException(ase.getMessage());
|
||||
}
|
||||
// If the username/password are wrong the spec says we should send 400/invalid grant
|
||||
if (userAuth == null || !userAuth.isAuthenticated()) {
|
||||
throw new InvalidGrantException("Could not authenticate user: " + username);
|
||||
}
|
||||
|
||||
OAuth2Request storedOauth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
|
||||
return new OAuth2Authentication(storedOauth2Request, userAuth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param imageCode 图形验证码
|
||||
*/
|
||||
private boolean judgeImageCode(String imageCode, HttpServletRequest request) {
|
||||
if (StrUtil.isBlankIfStr(imageCode)) {
|
||||
return false;
|
||||
}
|
||||
String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
String ip = request.getHeader(SecurityConstants.REQUEST_HEADER_KEY_CLIENT_REAL_IP);
|
||||
String key = userAgent + ip;
|
||||
String redisImageCode = redisUtil.getStringByKey(key);
|
||||
if (imageCode.equalsIgnoreCase(redisImageCode)) {
|
||||
redisUtil.delete(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.njcn.auth.security.extension.refresh;
|
||||
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.enums.auth.AuthenticationMethodEnum;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 刷新token再次认证 UserDetailsService
|
||||
*
|
||||
* @author hongawen
|
||||
* @date 2021/10/2
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class PreAuthenticatedUserDetailsService<T extends Authentication> implements AuthenticationUserDetailsService<T>, InitializingBean {
|
||||
|
||||
/**
|
||||
* 客户端ID和用户服务 UserDetailService 的映射
|
||||
*
|
||||
* @see com.njcn.auth.config.AuthorizationServerConfig#tokenServices(AuthorizationServerEndpointsConfigurer)
|
||||
*/
|
||||
private Map<String, UserDetailsService> userDetailsServiceMap;
|
||||
|
||||
public PreAuthenticatedUserDetailsService(Map<String, UserDetailsService> userDetailsServiceMap) {
|
||||
Assert.notNull(userDetailsServiceMap, "userDetailsService cannot be null.");
|
||||
this.userDetailsServiceMap = userDetailsServiceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.userDetailsServiceMap, "UserDetailsService must be set");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写PreAuthenticatedAuthenticationProvider 的 preAuthenticatedUserDetailsService 属性,可根据客户端和认证方式选择用户服务 UserDetailService 获取用户信息 UserDetail
|
||||
*
|
||||
* @param authentication .
|
||||
* @return .
|
||||
* @throws UsernameNotFoundException .
|
||||
*/
|
||||
@Override
|
||||
public UserDetails loadUserDetails(T authentication) throws UsernameNotFoundException {
|
||||
String clientId = RequestUtil.getOAuth2ClientId();
|
||||
// 获取认证方式,默认是用户名 username
|
||||
UserDetailsService userDetailsService = userDetailsServiceMap.get(clientId);
|
||||
return userDetailsService.loadUserByUsername(authentication.getName());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.njcn.auth.security.sm4;
|
||||
|
||||
import com.njcn.auth.pojo.bo.BusinessUser;
|
||||
import com.njcn.common.utils.sm.Sm4Utils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月08日 15:43
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class Sm4AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
|
||||
/**
|
||||
* 校验密码有效性.
|
||||
*
|
||||
* @param userDetails 用户详细信息
|
||||
* @param authentication 用户登录的密码
|
||||
* @throws AuthenticationException .
|
||||
*/
|
||||
@Override
|
||||
protected void additionalAuthenticationChecks(
|
||||
UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
if (authentication.getCredentials() == null) {
|
||||
logger.debug("Authentication failed: no credentials provided");
|
||||
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials",
|
||||
"Bad credentials"));
|
||||
}
|
||||
|
||||
String presentedPassword = authentication.getCredentials().toString();
|
||||
BusinessUser businessUser = (BusinessUser)userDetails;
|
||||
String secretKey = businessUser.getSecretKey();
|
||||
Sm4Utils sm4 = new Sm4Utils(secretKey);
|
||||
//SM4加密密码
|
||||
String sm4PwdOnce = sm4.encryptData_ECB(presentedPassword);
|
||||
//SM4加密(密码+工作秘钥)
|
||||
String sm4PwdTwice = sm4.encryptData_ECB(sm4PwdOnce + secretKey);
|
||||
if(!businessUser.getPassword().equalsIgnoreCase(sm4PwdTwice)){
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials",
|
||||
businessUser.getUsername()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param authentication 认证token
|
||||
* @throws AuthenticationException .
|
||||
*/
|
||||
@Override
|
||||
protected UserDetails retrieveUser(
|
||||
String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
UserDetails loadedUser = userDetailsService.loadUserByUsername(username);
|
||||
if (loadedUser == null) {
|
||||
throw new InternalAuthenticationServiceException(
|
||||
"UserDetailsService returned null, which is an interface contract violation");
|
||||
}
|
||||
return loadedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 授权持久化.
|
||||
*/
|
||||
@Override
|
||||
protected Authentication createSuccessAuthentication(Object principal,
|
||||
Authentication authentication, UserDetails user) {
|
||||
return super.createSuccessAuthentication(principal, authentication, user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.njcn.auth.service;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.njcn.auth.pojo.bo.BusinessUser;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.njcn.user.api.UserFeignClient;
|
||||
import com.njcn.user.pojo.dto.UserDTO;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* <p>
|
||||
* 自定义用户认证和授权
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
private final UserFeignClient userFeignClient;
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String loginName) throws UsernameNotFoundException {
|
||||
String clientId = RequestUtil.getOAuth2ClientId();
|
||||
BusinessUser businessUser = new BusinessUser(loginName, null, null);
|
||||
businessUser.setClientId(clientId);
|
||||
HttpResult<UserDTO> result = userFeignClient.getUserByName(loginName);
|
||||
LogUtil.njcnDebug(log, "用户认证时,用户名:{}获取用户信息:{}", loginName, result.toString());
|
||||
//成功获取用户信息
|
||||
UserDTO userDTO = result.getData();
|
||||
BeanUtil.copyProperties(userDTO,businessUser,true);
|
||||
businessUser.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", userDTO.getRoleName())));
|
||||
return businessUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.njcn.auth.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.nimbusds.jose.JWSObject;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.common.pojo.dto.UserTokenInfo;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.redis.utils.RedisUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月11日 10:34
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class UserTokenService {
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
|
||||
/**
|
||||
* 记录用户token信息,并经过处理后达到最新登录的使用者,将之前的token信息置为黑名单,过期状态
|
||||
* 1、从在线名单中获取该用户的token信息,key为:TOKEN_ONLINE_PREFIX+userid,value为userTokenInfo的json对象
|
||||
* 1.1 有,则表示有人使用该账户登录过
|
||||
* 1.1.1 将在线名单的用户信息添加到黑名单,并清除黑名单中已经过期的token信息
|
||||
* ,重新赋值黑名单信息,key为:TOKEN_BLACKLIST_PREFIX+userid,value为userTokenInfo的集合
|
||||
* 1.2 没有,该账号当前只有本人在登录,将当前token等信息保存到白名单
|
||||
*
|
||||
* @param oAuth2AccessToken 认证后的最新token信息
|
||||
*/
|
||||
@Async("asyncExecutor")
|
||||
public void recordUserInfo(OAuth2AccessToken oAuth2AccessToken) {
|
||||
UserTokenInfo userTokenInfo = new UserTokenInfo();
|
||||
String accessTokenValue = oAuth2AccessToken.getValue();
|
||||
JWSObject accessJwsObject ;
|
||||
try {
|
||||
accessJwsObject = JWSObject.parse(accessTokenValue);
|
||||
} catch (ParseException e) {
|
||||
throw new BusinessException(CommonResponseEnum.PARSE_TOKEN_ERROR);
|
||||
}
|
||||
JSONObject accessJson = JSONUtil.parseObj(accessJwsObject.getPayload().toString());
|
||||
String userIndex = accessJson.getStr(SecurityConstants.USER_INDEX_KEY);
|
||||
//查询是否有在线的当前用户
|
||||
String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX + userIndex;
|
||||
Object onlineTokenInfoOld = redisUtil.getObjectByKey(onlineUserKey);
|
||||
if (!Objects.isNull(onlineTokenInfoOld)) {
|
||||
//存在在线用户,将在线用户添加到黑名单列表
|
||||
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
|
||||
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
|
||||
if (CollectionUtils.isEmpty(blackUsers)) {
|
||||
blackUsers = new ArrayList<>();
|
||||
}
|
||||
blackUsers.add((UserTokenInfo) onlineTokenInfoOld);
|
||||
//筛选黑名单中是否存在过期的token信息
|
||||
blackUsers.removeIf(userTokenInfoTemp -> userTokenInfoTemp.getRefreshTokenExpire().isBefore(LocalDateTime.now()));
|
||||
//将黑名单集合重新缓存,此处根据最新的黑名单计算当前这个key的生命周期,在时间差的基础上增加5分钟的延迟时间
|
||||
LocalDateTime refreshTokenExpire = ((UserTokenInfo) onlineTokenInfoOld).getRefreshTokenExpire();
|
||||
long lifeTime = Math.abs(refreshTokenExpire.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
|
||||
redisUtil.saveByKeyWithExpire(blackUserKey, blackUsers, lifeTime);
|
||||
}
|
||||
String accessJti = accessJson.getStr(SecurityConstants.JWT_JTI);
|
||||
OAuth2RefreshToken refreshToken = oAuth2AccessToken.getRefreshToken();
|
||||
JWSObject refreshJwsObject ;
|
||||
try {
|
||||
refreshJwsObject = JWSObject.parse(refreshToken.getValue());
|
||||
} catch (ParseException e) {
|
||||
throw new BusinessException(CommonResponseEnum.PARSE_TOKEN_ERROR);
|
||||
}
|
||||
JSONObject refreshJson = JSONUtil.parseObj(refreshJwsObject.getPayload().toString());
|
||||
String refreshJti = refreshJson.getStr(SecurityConstants.JWT_JTI);
|
||||
Long refreshExpireTime = refreshJson.getLong(SecurityConstants.JWT_EXP);
|
||||
userTokenInfo.setAccessTokenJti(accessJti);
|
||||
userTokenInfo.setRefreshToken(refreshToken.getValue());
|
||||
LocalDateTime refreshLifeTime =LocalDateTime.ofEpochSecond(refreshExpireTime,0,ZoneOffset.of("+8"));
|
||||
userTokenInfo.setRefreshTokenExpire(refreshLifeTime);
|
||||
//生命周期在refreshToken的基础上,延迟5分钟
|
||||
redisUtil.saveByKeyWithExpire(onlineUserKey, userTokenInfo, refreshLifeTime.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验刷新token是否被加入黑名单
|
||||
*
|
||||
* @param refreshToken 刷新token
|
||||
*/
|
||||
public void judgeRefreshToken(String refreshToken) {
|
||||
JWSObject refreshJwsObject;
|
||||
try {
|
||||
refreshJwsObject = JWSObject.parse(refreshToken);
|
||||
} catch (ParseException e) {
|
||||
throw new BusinessException();
|
||||
}
|
||||
JSONObject refreshJson = JSONUtil.parseObj(refreshJwsObject.getPayload().toString());
|
||||
String userIndex = refreshJson.getStr(SecurityConstants.USER_INDEX_KEY);
|
||||
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
|
||||
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
|
||||
if (CollectionUtils.isNotEmpty(blackUsers)) {
|
||||
blackUsers.forEach(temp -> {
|
||||
//存在当前的刷新token,则抛出业务异常
|
||||
if(temp.getRefreshToken().equalsIgnoreCase(refreshToken)){
|
||||
throw new BusinessException(CommonResponseEnum.TOKEN_EXPIRE_JWT);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
29
pqs-auth/src/main/java/com/njcn/auth/utils/AuthPubUtil.java
Normal file
29
pqs-auth/src/main/java/com/njcn/auth/utils/AuthPubUtil.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.njcn.auth.utils;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月04日 14:00
|
||||
*/
|
||||
public class AuthPubUtil {
|
||||
|
||||
public static String getKaptchaText(int codeLength) {
|
||||
StringBuilder code = new StringBuilder();
|
||||
int letterLength = RandomUtil.randomInt(codeLength - 1) + 1;
|
||||
code.append(RandomUtil.randomString(RandomUtil.BASE_CHAR, letterLength).toUpperCase(Locale.ROOT));
|
||||
int numberLength = codeLength - letterLength;
|
||||
code.append(RandomUtil.randomString(RandomUtil.BASE_NUMBER, numberLength));
|
||||
List<String> textList = Arrays.asList(code.toString().split(""));
|
||||
//填充完字符后,打乱顺序,返回字符串
|
||||
Collections.shuffle(textList);
|
||||
return String.join("", textList);
|
||||
}
|
||||
|
||||
}
|
||||
51
pqs-auth/src/main/resources/bootstrap.yml
Normal file
51
pqs-auth/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
#当前服务的基本信息
|
||||
microservice:
|
||||
ename: @artifactId@
|
||||
name: '@name@'
|
||||
version: @version@
|
||||
sentinel:
|
||||
url: @sentinel.url@
|
||||
gateway:
|
||||
url: @gateway.url@
|
||||
server:
|
||||
port: 10214
|
||||
#feign接口开启服务熔断降级处理
|
||||
feign:
|
||||
sentinel:
|
||||
enabled: true
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: @artifactId@
|
||||
#nacos注册中心以及配置中心的指定
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: @nacos.url@
|
||||
namespace: @nacos.namespace@
|
||||
config:
|
||||
server-addr: @nacos.url@
|
||||
namespace: @nacos.namespace@
|
||||
file-extension: yaml
|
||||
shared-configs:
|
||||
- data-id: share-config.yaml
|
||||
refresh: true
|
||||
- data-Id: share-config-datasource-db.yaml
|
||||
refresh: true
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
|
||||
#项目日志的配置
|
||||
logging:
|
||||
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
|
||||
level:
|
||||
root: info
|
||||
|
||||
|
||||
#mybatis配置信息
|
||||
mybatis-plus:
|
||||
#别名扫描
|
||||
type-aliases-package: com.njcn.user.pojo
|
||||
|
||||
|
||||
BIN
pqs-auth/src/main/resources/njcn.jks
Normal file
BIN
pqs-auth/src/main/resources/njcn.jks
Normal file
Binary file not shown.
42
pqs-common/common-autocode/pom.xml
Normal file
42
pqs-common/common-autocode/pom.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-autocode</artifactId>
|
||||
<!--所有的代码生成完毕后,请按需拷贝到相应的服务模块中-->
|
||||
<name>mybatis-plus代码自动生成模块</name>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-db</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!-- mybatis-plus自动生成代码 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
</dependency>
|
||||
<!--模板引起,mp默认支持的velocity也可以切换为freemarker-->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.njcn.autocode.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* 需要生成代码的模块
|
||||
*
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月10日 16:03
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Module implements Serializable {
|
||||
|
||||
private String author;
|
||||
|
||||
private String packageName;
|
||||
|
||||
private String moduleName;
|
||||
|
||||
private List<String> tableNames;
|
||||
|
||||
private String prefix;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.njcn.autocode.utils;
|
||||
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
|
||||
import com.njcn.autocode.pojo.Module;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月10日 15:16
|
||||
*/
|
||||
public class GenerateCode {
|
||||
|
||||
private static final String TARGET_DIR = "D://code";
|
||||
|
||||
private static final String DB_URL = "jdbc:mysql://192.168.1.14:13306/pqsinfo";
|
||||
|
||||
private static final String USERNAME = "root";
|
||||
|
||||
private static final String PASSWORD = "njcnpqs";
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<Module> modules = Stream.of(
|
||||
new Module("hongawen", "com.njcn", "user", Stream.of(
|
||||
"sys_component"
|
||||
,"sys_dept"
|
||||
,"sys_function"
|
||||
,"sys_home_page"
|
||||
,"sys_role"
|
||||
,"sys_role_component"
|
||||
,"sys_role_function"
|
||||
,"sys_user"
|
||||
,"sys_user_role"
|
||||
,"sys_user_set"
|
||||
,"sys_auth_client"
|
||||
,"sys_user_strategy"
|
||||
).collect(Collectors.toList()), "sys_")
|
||||
, new Module("hongawen", "com.njcn", "system", Stream.of(
|
||||
"sys_dict_data"
|
||||
,"sys_area"
|
||||
,"sys_config"
|
||||
,"sys_dict_type"
|
||||
,"sys_task"
|
||||
,"sys_resource"
|
||||
,"sys_theme"
|
||||
).collect(Collectors.toList()), "sys_")
|
||||
).collect(Collectors.toList());
|
||||
generateJavaFile(modules);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量生成不同模块的代码
|
||||
* @param modules 模块数据
|
||||
*/
|
||||
private static void generateJavaFile(List<Module> modules) {
|
||||
for (Module module : modules) {
|
||||
//文件夹提前建好,否则会报错
|
||||
FastAutoGenerator.create(DB_URL, USERNAME, PASSWORD)
|
||||
.globalConfig(builder -> {
|
||||
builder.author(module.getAuthor()) // 设置作者
|
||||
.fileOverride() // 覆盖已生成文件
|
||||
.outputDir(TARGET_DIR); // 指定输出目录
|
||||
})
|
||||
.packageConfig(builder -> {
|
||||
builder.parent(module.getPackageName()) // 设置父包名
|
||||
.moduleName(module.getModuleName()) // 设置父包模块名
|
||||
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, TARGET_DIR+ File.separator+module.getModuleName())); // 设置mapperXml生成路径
|
||||
})
|
||||
.strategyConfig(builder -> {
|
||||
builder.addInclude(module.getTableNames()) // 设置需要生成的表名
|
||||
.addTablePrefix(module.getPrefix())// 设置过滤表前缀
|
||||
.entityBuilder()
|
||||
.superClass(com.njcn.db.bo.BaseEntity.class) //默认实体继承指定父类
|
||||
.enableLombok() //启用lombok
|
||||
.controllerBuilder()
|
||||
.superClass(com.njcn.web.controller.BaseController.class) //默认controller继承指定父类
|
||||
.enableRestStyle() //开启生成@RestController 控制器
|
||||
;
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
96
pqs-common/common-core/pom.xml
Normal file
96
pqs-common/common-core/pom.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-core</artifactId>
|
||||
<name>聚合所有服务模块公共信息</name>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--java简化开发工具-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<!--java工具包-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-json</artifactId>
|
||||
</dependency>
|
||||
<!-- Actuator监控当前应用的健康,虚拟机等信息,通过前端以可视化的界面展示出来 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<!--避免idea后端配置类报红-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--测试依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<!--国密加解密工具包-->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
<!-- commons通用包 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alibaba</groupId>-->
|
||||
<!-- <artifactId>easyexcel</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<!--API接口文档-->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-ui</artifactId>
|
||||
</dependency>
|
||||
<!--jackson依赖-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<!--此处需要注意的事,databind自身依赖的jackson-core/jackson-annotations由于版本偏低,会出现异常-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.njcn.common.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月11日 09:32
|
||||
*/
|
||||
@Data
|
||||
@Order(100)
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
@AllArgsConstructor
|
||||
public class AsyncConfiguration {
|
||||
|
||||
private final GeneralInfo generalInfo;
|
||||
|
||||
@Bean("asyncExecutor")
|
||||
public Executor asyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 核心线程数:线程池创建时候初始化的线程数
|
||||
executor.setCorePoolSize(generalInfo.getCorePoolSize());
|
||||
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
|
||||
executor.setMaxPoolSize(generalInfo.getMaxPoolSize());
|
||||
// 缓冲队列:用来缓冲执行任务的队列
|
||||
executor.setQueueCapacity(generalInfo.getQueueCapacity());
|
||||
// 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
|
||||
executor.setKeepAliveSeconds(generalInfo.getKeepAliveSeconds());
|
||||
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
|
||||
executor.setThreadNamePrefix(generalInfo.getMicroServiceName());
|
||||
// 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Bean("MQTTExecutor")
|
||||
public Executor mqttExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 核心线程数:线程池创建时候初始化的线程数
|
||||
executor.setCorePoolSize(0);
|
||||
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
|
||||
executor.setMaxPoolSize(1);
|
||||
// 缓冲队列:用来缓冲执行任务的队列
|
||||
executor.setQueueCapacity(1);
|
||||
// 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
|
||||
executor.setKeepAliveSeconds(generalInfo.getKeepAliveSeconds());
|
||||
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
|
||||
executor.setThreadNamePrefix(generalInfo.getMicroServiceName());
|
||||
// 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.common.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年08月19日 15:56
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@Order(10)
|
||||
public class GeneralInfo {
|
||||
|
||||
@Value("${microservice.ename}")
|
||||
private String microServiceName;
|
||||
|
||||
@Value("${threadPool.corePoolSize}")
|
||||
private int corePoolSize;
|
||||
|
||||
@Value("${threadPool.maxPoolSize}")
|
||||
private int maxPoolSize;
|
||||
|
||||
@Value("${threadPool.queueCapacity}")
|
||||
private int queueCapacity;
|
||||
|
||||
@Value("${threadPool.keepAliveSeconds}")
|
||||
private int keepAliveSeconds;
|
||||
|
||||
@Value("${business.wavePath}")
|
||||
private String businessWavePath;
|
||||
|
||||
@Value("${business.tempPath}")
|
||||
private String businessTempPath;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.common.pojo.annotation;
|
||||
|
||||
import com.njcn.common.pojo.constant.OperateType;
|
||||
import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年07月07日 15:51
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface OperateInfo {
|
||||
|
||||
/**
|
||||
* 默认为业务事件类型,严重度为普通
|
||||
*/
|
||||
LogEnum info() default LogEnum.BUSINESS_COMMON;
|
||||
|
||||
/**
|
||||
* 默认为查询操作类型
|
||||
*/
|
||||
String operateType() default OperateType.QUERY;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.njcn.common.pojo.constant;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年07月07日 15:33
|
||||
*/
|
||||
public interface LogInfo {
|
||||
|
||||
String UNKNOWN_OPERATE = "未知业务";
|
||||
|
||||
String UNKNOWN_USER = "未知用户";
|
||||
|
||||
String UNKNOWN_IP = "未知IP地址";
|
||||
|
||||
String UNKNOWN_CLIENT = "未知客户端";
|
||||
|
||||
String UNKNOWN_SERVER = "未知服务";
|
||||
|
||||
String UNKNOWN_DEPT = "未知部门";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.common.pojo.constant;
|
||||
|
||||
/**
|
||||
* 系统操作类型
|
||||
*
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年07月08日 17:56
|
||||
*/
|
||||
public interface OperateType {
|
||||
|
||||
String QUERY = "查询";
|
||||
|
||||
String ADD = "新增";
|
||||
|
||||
String DELETE = "删除";
|
||||
|
||||
String UPDATE = "更新";
|
||||
|
||||
String AUTHENTICATE = "认证";
|
||||
|
||||
String LOGOUT = "注销";
|
||||
|
||||
String UPLOAD = "上传";
|
||||
|
||||
String DOWNLOAD = "下载";
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package com.njcn.common.pojo.constant;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年05月19日 12:52
|
||||
*/
|
||||
public interface PatternRegex {
|
||||
|
||||
/**
|
||||
* URL
|
||||
*/
|
||||
String URL_REGEX = "[a-zA-z]+://[^\\s]*";
|
||||
|
||||
/**
|
||||
* 密码需要包含特殊字符字母数字,长度为8-16
|
||||
*/
|
||||
String PASSWORD_REGEX = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[@#_!$%^&*()?<>/|~,\\-+]).{8,16}$";
|
||||
|
||||
/**
|
||||
* 手机的密码
|
||||
*/
|
||||
String PASSWORD_PHONE_REGEX = "^.{6,18}$";
|
||||
|
||||
/**
|
||||
* 用户名中英文,长度1-16
|
||||
*/
|
||||
String USERNAME_REGEX = "^[\\u4e00-\\u9fffa-zA-Z]{1,16}$";
|
||||
|
||||
/**
|
||||
* 概览配置界面名称
|
||||
*/
|
||||
String HOMEPAGE_REGEX = "^[\\u4e00-\\u9fa5]{1,10}$";
|
||||
|
||||
/**
|
||||
* 登录名只能输入3-16位的英文字母和数字
|
||||
*/
|
||||
String LOGIN_NAME_REGEX = "^[a-zA-Z_]{1}[a-zA-Z0-9_]{2,15}$";
|
||||
|
||||
/**
|
||||
* 手机号必须有11位,并且为数字,是正常的手机·号码开头
|
||||
*/
|
||||
String PHONE_REGEX = "(?:0|86|\\+86)?1[3-9]\\d{9}";
|
||||
|
||||
/**
|
||||
* 手机号码可以为空,如果输入手机号就要正则匹配
|
||||
*/
|
||||
String PHONE_REGEX_OR_NULL = "^\\s{0}$|(?:0|86|\\+86)?1[3-9]\\d{9}";
|
||||
|
||||
/**
|
||||
* 邮箱含有@ .在@后,以.com、.con结尾(qq,163等)
|
||||
*/
|
||||
String EMAIL_REGEX = "^([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+\\.(?:com|cn)$";
|
||||
|
||||
/**
|
||||
* 邮箱可以为空,如果输入邮箱就要进行正则匹配,邮箱含有@ .在@后,以.com、.con结尾(qq,163等)
|
||||
*/
|
||||
String EMAIL_REGEX_OR_NULL = "^\\s{0}$|([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+\\.(?:com|cn)$";
|
||||
|
||||
/**
|
||||
* IP v4
|
||||
*/
|
||||
String IP_REGEX = "\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b";
|
||||
|
||||
/**
|
||||
* 角色名由数字、字母组成且长度为2-50
|
||||
*/
|
||||
String ROLE_REGEX = "^[a-zA-Z][a-zA-Z0-9]{2,50}$";
|
||||
|
||||
/**
|
||||
* 部门名称由汉字组成,长度为0-20
|
||||
*/
|
||||
String DEPT_NAME_REGEX = "^[\\u4e00-\\u9fa5]{1,20}$";
|
||||
|
||||
/**
|
||||
* 字典名称包括中文、数字、字母、括号以及点号
|
||||
*/
|
||||
String DIC_REGEX = "^[\\w\\u4E00-\\u9FA5()()_/、\\- ]+\\.?[\\w\\u4E00-\\u9FA5()()/]{0,125}$";
|
||||
|
||||
/**
|
||||
* 密码有效期(月)1-3月
|
||||
*/
|
||||
String PASS_MONTH_REGEX = "^[1-3]{1}$";
|
||||
|
||||
/**
|
||||
* 密码错误次数 1-10次
|
||||
*/
|
||||
String PASS_ERROR_REGEX = "^([1-9]|10)$";
|
||||
|
||||
/**
|
||||
* 最大并发数 1-99次
|
||||
*/
|
||||
String MAX_NUM_REGEX = "^([1-9]{1}|[0-9]{2})$";
|
||||
|
||||
/**
|
||||
* 闲置用户_修改密码 6-12
|
||||
*/
|
||||
String PASS_UPW_REGEX = "^([6-9]{1}|10|11|12)$";
|
||||
|
||||
/**
|
||||
* 临时账户休眠 1-12
|
||||
*/
|
||||
String FREE_MONTH_REGEX = "^([1-9]{1}|10|11|12)$";
|
||||
|
||||
/**
|
||||
* 审计存储空间 1-2G
|
||||
*/
|
||||
String LOG_SIZE_REGEX = "^[1-2]{1}$";
|
||||
|
||||
/**
|
||||
* 用户锁定时长20-60min
|
||||
*/
|
||||
String USER_LOCK_REGEX = "^[2-5][0-9]|60$";
|
||||
|
||||
/**
|
||||
* 台账名称 前置机名称 供电公司 变电站
|
||||
*/
|
||||
String DEV_NAME_REGEX = "[\\u4E00-\\u9FA5A-Za-z0-9ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ_\\s+\\#\\-]{1,32}$";
|
||||
|
||||
/**
|
||||
* 浮点数
|
||||
*/
|
||||
String FLOAT_REGEX = "[0-9]*(\\.?)[0-9]*";
|
||||
|
||||
/**
|
||||
* 识别码秘钥
|
||||
*/
|
||||
String SERIES_REGEX = "[^\\u4e00-\\u9fa5]{0,20}$";
|
||||
|
||||
/**
|
||||
* ip分段
|
||||
*/
|
||||
String SIP_REGEX = "[0-9]{1,3}$";
|
||||
|
||||
/**
|
||||
* 端口号
|
||||
*/
|
||||
String PORT_REGEX = "[0-9]{1,10}$";
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
String REMARK_REGEX = "[\\u4E00-\\u9FA5A-Za-z0-9_]{0,255}$";
|
||||
|
||||
/**
|
||||
* 国网平台监测点号
|
||||
*/
|
||||
String MONITOR_ID_REGEX = "[A-Za-z0-9]{0,255}$";
|
||||
|
||||
/**
|
||||
* 变压器名称
|
||||
*/
|
||||
String TRANS_NAME_REGEX = "^[0-9a-zA-Z\\u0391-\\uFFE5]{1,50}$";
|
||||
|
||||
/**
|
||||
* 变压器策略名称
|
||||
*/
|
||||
String TF_NAME_REGEX = "^[0-9a-zA-Z\\u0391-\\uFFE5]{1,16}$";
|
||||
|
||||
/**
|
||||
* 字典类型名称
|
||||
*/
|
||||
String TYPE_REGEX = "^[0-9a-zA-Z\\u0391-\\uFFE5]{1,100}$";
|
||||
|
||||
/**
|
||||
* 描述64
|
||||
*/
|
||||
String DES64_REGEX = "^.{0,64}$";
|
||||
|
||||
/**
|
||||
* 描述200
|
||||
*/
|
||||
String DES200_REGEX = "^.{0,200}$";
|
||||
|
||||
/**
|
||||
* 描述500
|
||||
*/
|
||||
String DES500_REGEX = "^.{0,500}$";
|
||||
|
||||
/**
|
||||
* mac地址
|
||||
*/
|
||||
String MAC_REGEX = "((?:[A-F0-9]{1,2}[:-]){5}[A-F0-9]{1,2})|(?:0x)(\\d{12})(?:.+ETHER)";
|
||||
|
||||
/**
|
||||
* 流量套餐
|
||||
*/
|
||||
String DATA_PLAN_REGEX = "[0-9]{0,6}$";
|
||||
|
||||
/**
|
||||
* 十六进制颜色
|
||||
*/
|
||||
String COLOR_REGEX = "^#([a-fA-F\\d]{3}|[a-fA-F\\d]{6})$";
|
||||
|
||||
/**
|
||||
* 描述64
|
||||
*/
|
||||
String DES10_REGEX = "^.{1,10}$";
|
||||
|
||||
/**
|
||||
* 大于0的正整数
|
||||
*/
|
||||
String POSITIVE = "^[0-9].*$";
|
||||
|
||||
/**
|
||||
* 资源名称
|
||||
*/
|
||||
String FUNCTION_NAME = "^[\\u4e00-\\u9fa5A-Za-z0-9_]+$";
|
||||
|
||||
/**
|
||||
* 资源路径
|
||||
*/
|
||||
String FUNCTION_URL = "^[A-Za-z0-9\\/\\-]+$";
|
||||
|
||||
/**
|
||||
* 匹配数字、字母、中文
|
||||
*/
|
||||
String NORMAL = "^[A-Za-z0-9\\u4e00-\\u9fa5]+$";
|
||||
|
||||
|
||||
/**
|
||||
* 任意字符,长度在1-20位,常用于名称、编码等常规录入
|
||||
*/
|
||||
String ALL_CHAR_1_20 = "^[-_A-Za-z0-9\\u4e00-\\u9fa5]{1,20}$";
|
||||
|
||||
/**
|
||||
* uuid 32位正则,数字 、 字母
|
||||
*/
|
||||
String SYSTEM_ID = "^[A-Za-z0-9]{32}$";
|
||||
|
||||
/**
|
||||
* 1-32位正则,数字 、 字母
|
||||
*/
|
||||
String SYSTEMS_ID = "^[A-Za-z0-9]{1,32}$";
|
||||
|
||||
/**
|
||||
* decimal(10,6) 10位数字,小数点最多6位(坐标)
|
||||
*/
|
||||
String COORDINATE="^([0-9]{1,4})([.][0-9]{1,6})?$";
|
||||
|
||||
/**
|
||||
* 时间正则(日期)
|
||||
*/
|
||||
String TIME_FORMAT = "^$|(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)$";
|
||||
|
||||
/**
|
||||
* 时间正则(秒)
|
||||
*/
|
||||
String TIME_SECOND_FORMAT = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.njcn.common.pojo.constant;
|
||||
|
||||
/**
|
||||
* 认证业务用到的常量定义
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
public interface SecurityConstants {
|
||||
|
||||
/**
|
||||
* 认证请求头key
|
||||
* 1. 获取token时,Authorization的内容是client:secret的base64的密文
|
||||
* 2. 已经认证后,Authorization的内容是access_token内容
|
||||
*/
|
||||
String AUTHORIZATION_KEY = "Authorization";
|
||||
|
||||
/**
|
||||
* JWT令牌前缀
|
||||
*/
|
||||
String AUTHORIZATION_PREFIX = "bearer ";
|
||||
|
||||
/**
|
||||
* Basic认证前缀
|
||||
*/
|
||||
String BASIC_PREFIX = "Basic ";
|
||||
|
||||
/**
|
||||
* JWT载体key
|
||||
*/
|
||||
String JWT_PAYLOAD_KEY = "payload";
|
||||
|
||||
/**
|
||||
* JWT ID 唯一标识
|
||||
*/
|
||||
String JWT_JTI = "jti";
|
||||
|
||||
/**
|
||||
* JWT ID 超时key
|
||||
*/
|
||||
String JWT_EXP = "exp";
|
||||
|
||||
/**
|
||||
* 认证成功后,返回信息包含的内容-
|
||||
*/
|
||||
String USER_INDEX_KEY = "userIndex";
|
||||
String USER_TYPE = "userType";
|
||||
String USER_NAME_KEY = "user_name";
|
||||
String USER_NICKNAME_KEY = "nickname";
|
||||
String CLIENT_ID_KEY = "client_id";
|
||||
String DEPT_INDEX_KEY = "deptIndex";
|
||||
|
||||
/**
|
||||
* 认证方式
|
||||
*/
|
||||
String AUTHENTICATION_METHOD = "authenticationMethod";
|
||||
|
||||
/**
|
||||
* JWT存储权限前缀
|
||||
*/
|
||||
String AUTHORITY_PREFIX = "ROLE_";
|
||||
|
||||
/**
|
||||
* JWT存储权限属性
|
||||
*/
|
||||
String JWT_AUTHORITIES_KEY = "authorities";
|
||||
|
||||
String GRANT_TYPE_KEY = "grant_type";
|
||||
|
||||
String REFRESH_TOKEN_KEY = "refresh_token";
|
||||
|
||||
/**
|
||||
* 黑名单token前缀
|
||||
*/
|
||||
String TOKEN_BLACKLIST_PREFIX = "auth:token:black:";
|
||||
|
||||
/**
|
||||
* 认证后token前缀
|
||||
*/
|
||||
String TOKEN_ONLINE_PREFIX = "auth:token:online:";
|
||||
|
||||
|
||||
/**
|
||||
* 真实客户端IP地址
|
||||
*/
|
||||
String REQUEST_HEADER_KEY_CLIENT_REAL_IP = "realClientIp";
|
||||
|
||||
|
||||
/**
|
||||
* 认证需要的各项参数名
|
||||
*/
|
||||
String GRANT_TYPE = "grant_type";
|
||||
String CLIENT_ID = "client_id";
|
||||
String CLIENT_SECRET = "client_secret";
|
||||
String REFRESH_TOKEN = "refresh_token";
|
||||
String USERNAME = "username";
|
||||
String PASSWORD = "password";
|
||||
String IMAGE_CODE = "imageCode";
|
||||
|
||||
|
||||
/**
|
||||
* 认证阶段保存的用户登录名
|
||||
*/
|
||||
String AUTHENTICATE_USERNAME = "authenticateUserName";
|
||||
|
||||
/**
|
||||
* 上游服务器模块名称
|
||||
*/
|
||||
String SERVER_NAME = "serverName";
|
||||
|
||||
|
||||
/**
|
||||
* 接口文档 Knife4j 测试客户端ID
|
||||
*/
|
||||
String TEST_CLIENT_ID = "client";
|
||||
|
||||
|
||||
/**
|
||||
* 授权码模式
|
||||
*/
|
||||
String GRANT_AUTHORIZATION_CODE = "authorization_code";
|
||||
|
||||
/**
|
||||
* 验证码授权模式
|
||||
*/
|
||||
String GRANT_CAPTCHA = "captcha";
|
||||
|
||||
/**
|
||||
* 密码模式
|
||||
*/
|
||||
String GRANT_PASSWORD = "password";
|
||||
|
||||
/**
|
||||
* 刷新token模式
|
||||
*/
|
||||
String GRANT_REFRESH_TOKEN = "refresh_token";
|
||||
|
||||
/**
|
||||
* 短信模式
|
||||
*/
|
||||
String GRANT_SMS_CODE = "sms_code";
|
||||
|
||||
/**
|
||||
* 微信模式
|
||||
*/
|
||||
String GRANT_WECHAT = "wechat";
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.common.pojo.constant;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月15日 13:39
|
||||
*/
|
||||
public interface ServerInfo {
|
||||
|
||||
String GATEWAY = "pqs-gateway";
|
||||
String OAUTH = "pqs-auth";
|
||||
String APP = "pqs-app";
|
||||
String SUPERVISE = "pqs-supervise";
|
||||
String COMMON = "pqs-common";
|
||||
String DEVICE = "device-boot";
|
||||
String EVENT = "event-boot";
|
||||
String HARMONIC = "harmonic-boot";
|
||||
String REPORT = "report-boot";
|
||||
String SYSTEM = "system-boot";
|
||||
String ENERGY = "energy-boot";
|
||||
String JOB_ADMIN = "job-admin";
|
||||
String USER = "user-boot";
|
||||
String JOB = "job-admin";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.common.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年07月08日 20:03
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LogInfoDTO {
|
||||
|
||||
/**
|
||||
* 登录名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
private String operate;
|
||||
|
||||
private String result;
|
||||
|
||||
private String ip;
|
||||
|
||||
private String type;
|
||||
|
||||
private String level;
|
||||
|
||||
private String operateType;
|
||||
|
||||
private String serviceName;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.common.pojo.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月18日 12:30
|
||||
*/
|
||||
@Data
|
||||
public class SimpleDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(name = "name", value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(name = "id", value = "索引")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(name = "code", value = "编码")
|
||||
private String code;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.njcn.common.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月24日 16:02
|
||||
*/
|
||||
@Data
|
||||
public class SimpleTreeDTO extends SimpleDTO implements Serializable {
|
||||
|
||||
private List<SimpleDTO> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.common.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月11日 11:29
|
||||
*/
|
||||
@Data
|
||||
public class UserTokenInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 通行token
|
||||
*/
|
||||
private String accessTokenJti;
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
*/
|
||||
private String refreshToken;
|
||||
|
||||
|
||||
/**
|
||||
* refreshToken的生命周期结点
|
||||
*/
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime refreshTokenExpire;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 模拟量通道记录类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AnalogDTO implements Serializable {
|
||||
|
||||
// 通道序号
|
||||
private Integer nIndex;
|
||||
// 通道名称
|
||||
private String szChannleName;
|
||||
// 相位名称
|
||||
private String szPhasicName;
|
||||
// 监视的通道名称
|
||||
private String szMonitoredChannleName;
|
||||
// 通道的单位
|
||||
private String szUnitName;
|
||||
// 通道的系数
|
||||
private Float fCoefficent;
|
||||
// 通道的便宜量
|
||||
private Float fOffset;
|
||||
// 起始采样时间的偏移量
|
||||
private Float fTimeOffset;
|
||||
// 采样值的最小值
|
||||
private Integer nMin;
|
||||
// 采样值的最大值
|
||||
private Integer nMax;
|
||||
// 一次变比
|
||||
private Float fPrimary;
|
||||
// 二次变比
|
||||
private Float fSecondary;
|
||||
// 一次值还是二次值标志
|
||||
private String szValueType;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* CFG配置文件总类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ComtradeCfgDTO implements Serializable {
|
||||
private Integer nChannelNum;
|
||||
private Integer nPhasic;// 模拟量通道的个数 yxb 2020-12-15
|
||||
private Integer nAnalogNum;// 模拟量通道的个数 WW 2013-05-15
|
||||
private Integer nDigitalNum;// 数字量通道的个数 WW 2013-05-15
|
||||
private Date timeStart;// 暂态记录时间 yxb 2022-06-06
|
||||
private Date timeTrige;// 暂态触发时间 yxb 2022-06-06
|
||||
|
||||
private List<AnalogDTO> lstAnalogDTO;//模拟量通道记录
|
||||
private List<DigitalDTO> lstDigitalDTO;//数字量通道记录
|
||||
|
||||
public Integer nRates;//对应采样次数
|
||||
public List<RateDTO> lstRate;//采样率合集
|
||||
|
||||
// add by sw 暂降触发时间
|
||||
private Date firstTime; // 暂降触发第一次
|
||||
private Integer firstMs; // 暂降触发第一次毫秒
|
||||
|
||||
// 波形前推周波束
|
||||
private Integer nPush = 0;
|
||||
// 最终采样率,计算的时候只用一个采样率
|
||||
private Long finalSampleRate;
|
||||
// 整个波形大小
|
||||
private Long nAllWaveNum = 0l;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 数字量通道记录类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DigitalDTO implements Serializable {
|
||||
|
||||
// 通道序号
|
||||
private Integer nIndex;
|
||||
// 通道名称
|
||||
private String szChannleName;
|
||||
// 相位名称
|
||||
private String szPhasicName;
|
||||
// 监视的通道名称
|
||||
private String szMonitoredChannleName;
|
||||
// 通道的单位
|
||||
private Integer Initial;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 特征值计算类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EigenvalueDTO implements Serializable {
|
||||
|
||||
//是特征幅值(残余电压百分比)
|
||||
private float amplitude;
|
||||
//是特征幅值(残余电压)
|
||||
private float residualVoltage;
|
||||
//额定定压(动态电压)
|
||||
private float ratedVoltage;
|
||||
//持续时间
|
||||
private float durationTime;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 突变量计算类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MutationDTO implements Serializable {
|
||||
|
||||
private List<List<Float>> listRms_Offline = new ArrayList<>();//离线数据RMS有效值数据
|
||||
private List<List<Float>> listTBL_Offline = new ArrayList<>();//离线数据突变量数据
|
||||
private double fMinMagA = 99999d;
|
||||
private double fMinMagB = 99999d;
|
||||
private double fMinMagC = 99999d;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 采样率类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RateDTO implements Serializable {
|
||||
|
||||
// 1秒钟内的采样点数
|
||||
private Long nOneSample;
|
||||
// 总采样点数
|
||||
private Long nSampleNum;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 采样值结构类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SamplingDTO implements Serializable {
|
||||
|
||||
// 数据点时间
|
||||
private String szTime;
|
||||
// 数据点序号
|
||||
private Integer nIndex;
|
||||
// Integer nValueNum; WW 2013-05-15
|
||||
// 模拟量数据个数
|
||||
private Integer nAnalogValueNum;
|
||||
// 数字量数据个数
|
||||
private Integer nDigitalValueNum;
|
||||
// 数据区 float fValue[8];
|
||||
private List<Float> fValue;// WW 2013-05-15 原来的8通道也是仅考虑了单路的情况,如果遇到多路这里会超出
|
||||
private List<Byte> DigitalValue;// WW 2013-05-15
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 采样值结构类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SamplingsDTO implements Serializable {
|
||||
|
||||
// 数据个数
|
||||
private Integer nValueNum;
|
||||
// 数据区
|
||||
private List<SamplingDTO> lstSamplingDTO;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.common.pojo.dto.wave;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 返回波形数据类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WaveDataDTO implements Serializable {
|
||||
|
||||
private ComtradeCfgDTO comtradeCfgDTO;//CFG实体类
|
||||
//波形对应的标题
|
||||
private List<String> waveTitle;
|
||||
//波形对应的值
|
||||
private List<List<Float>> listWaveData;
|
||||
//波形RMS值
|
||||
private List<List<Float>> listRmsData;
|
||||
//波形对应的相别数量
|
||||
private Integer iPhasic;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.common.pojo.enums.auth;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月15日 15:55
|
||||
*/
|
||||
@Getter
|
||||
public enum AuthenticationMethodEnum {
|
||||
|
||||
/**
|
||||
* 认证的方式
|
||||
*/
|
||||
USERNAME("username", "用户名"),
|
||||
MOBILE("mobile", "手机号"),
|
||||
OPENID("openId", "开放式认证系统唯一身份标识");
|
||||
|
||||
private final String value;
|
||||
|
||||
private final String label;
|
||||
|
||||
AuthenticationMethodEnum(String value, String label) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public static AuthenticationMethodEnum getByValue(String value) {
|
||||
AuthenticationMethodEnum authenticationMethodEnum = null;
|
||||
for (AuthenticationMethodEnum item : values()) {
|
||||
if (item.getValue().equals(value)) {
|
||||
authenticationMethodEnum = item;
|
||||
}
|
||||
}
|
||||
return authenticationMethodEnum;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.njcn.common.pojo.enums.auth;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年02月10日 14:50
|
||||
*/
|
||||
@Getter
|
||||
public enum ClientEnum {
|
||||
|
||||
/**
|
||||
* 客户端,目前仅分为web端、大屏端、移动端
|
||||
*/
|
||||
WEB_CLIENT("njcn", "web"),
|
||||
WEB_CLIENT_TEST("njcntest", "web"),
|
||||
SCREEN_CLIENT("screen", "screen"),
|
||||
APP_CLIENT("app", "app"),
|
||||
WE_CHAT_APP_CLIENT("wx", "app");
|
||||
|
||||
private final String clientId;
|
||||
|
||||
private final String clientType;
|
||||
|
||||
ClientEnum(String clientId, String clientType) {
|
||||
this.clientId = clientId;
|
||||
this.clientType = clientType;
|
||||
}
|
||||
|
||||
public static String getClientType(String clientId) {
|
||||
for (ClientEnum item : values()) {
|
||||
if (item.getClientId().equals(clientId)) {
|
||||
return item.getClientType();
|
||||
}
|
||||
}
|
||||
//默认为web端
|
||||
return "web";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.common.pojo.enums.auth;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月15日 14:03
|
||||
*/
|
||||
@Getter
|
||||
public enum PasswordEncoderTypeEnum {
|
||||
|
||||
/**
|
||||
* 密码加密类型
|
||||
*/
|
||||
BCRYPT("{bcrypt}","BCRYPT加密"),
|
||||
|
||||
NOOP("{noop}","无加密明文");
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final String desc;
|
||||
|
||||
PasswordEncoderTypeEnum(String prefix, String desc){
|
||||
this.prefix=prefix;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.common.pojo.enums.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月15日 11:37
|
||||
*/
|
||||
@Getter
|
||||
public enum DataStateEnum {
|
||||
/**
|
||||
* 正常
|
||||
*/
|
||||
ENABLE(1, "正常"),
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
DELETED(0, "删除");
|
||||
|
||||
private final Integer code;
|
||||
|
||||
private final String message;
|
||||
|
||||
DataStateEnum(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.common.pojo.enums.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年07月07日 15:37
|
||||
*/
|
||||
@Getter
|
||||
public enum LogEnum {
|
||||
|
||||
/**
|
||||
* 日志类型分为业务事件、系统事件
|
||||
* 严重度分为 严重 中等 普通
|
||||
*/
|
||||
BUSINESS_SERIOUS("业务事件", "严重"),
|
||||
BUSINESS_MEDIUM("业务事件", "中等"),
|
||||
BUSINESS_COMMON("业务事件", "普通"),
|
||||
|
||||
SYSTEM_SERIOUS("系统事件", "严重"),
|
||||
SYSTEM_MEDIUM("系统事件", "中等"),
|
||||
SYSTEM_COMMON("系统事件", "普通");
|
||||
|
||||
|
||||
private final String operateType;
|
||||
|
||||
private final String operateLevel;
|
||||
|
||||
LogEnum(String operateType, String operateLevel) {
|
||||
this.operateType = operateType;
|
||||
this.operateLevel = operateLevel;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.common.pojo.enums.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年09月06日 14:00
|
||||
*/
|
||||
@Getter
|
||||
public enum ServerEnum {
|
||||
|
||||
/**
|
||||
* 微服务模块的枚举信息
|
||||
*/
|
||||
APP("pqs-app", "APP服务模块"),
|
||||
DEVICE("device-boot", "终端服务模块"),
|
||||
EVENT("event-boot", "暂降服务模块"),
|
||||
GATEWAY("pqs-gateway", "网关服务模块"),
|
||||
HARMONIC("harmonic-boot", "谐波监测服务模块"),
|
||||
OAUTH("pqs-auth", "认证服务模块"),
|
||||
REPORT("report-boot", "报表服务模块"),
|
||||
SUPERVISE("pqs-supervise", "技术监督管理服务模块"),
|
||||
SYSTEM("system-boot", "系统配置服务模块"),
|
||||
USER("user-boot", "用户服务模块"),
|
||||
COMMON("pqs-common", "通用服务模块");
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String serverInfo;
|
||||
|
||||
ServerEnum(String name, String serverInfo) {
|
||||
this.name = name;
|
||||
this.serverInfo = serverInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.njcn.common.pojo.enums.response;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年04月13日 10:33
|
||||
*/
|
||||
@Getter
|
||||
public enum CommonResponseEnum {
|
||||
|
||||
/**
|
||||
* A0000 ~ A0099 作用于通用业务枚举
|
||||
* 通用业务的响应枚举
|
||||
*/
|
||||
SUCCESS("A0000", "成功"),
|
||||
|
||||
NO_DATA("A0001", "数据为空"),
|
||||
|
||||
FAIL("A0002", "失败"),
|
||||
|
||||
INTERNAL_ERROR("A0003", "系统内部异常"),
|
||||
|
||||
SERVICE_FALLBACK("A0004", "服务访问降级"),
|
||||
|
||||
INVALID_PARAMETER("A0005", "请求参数非法"),
|
||||
|
||||
INVALID_MEDIA("A0006", "请求参数媒体不支持"),
|
||||
|
||||
ENUM_ERROR("A0007", "枚举解析异常"),
|
||||
|
||||
NULL_POINTER_EXCEPTION("A0008", "空指针异常"),
|
||||
|
||||
ARITHMETIC_EXCEPTION("A0009", "算数运算异常"),
|
||||
|
||||
CLASS_CAST_EXCEPTION("A0010", "类型转换异常"),
|
||||
|
||||
INDEX_OUT_OF_BOUNDS_EXCEPTION("A0011", "索引下标越界异常"),
|
||||
|
||||
HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION("A0012", "请求中参数的媒体方式不支持"),
|
||||
|
||||
METHOD_ARGUMENT_NOT_VALID_EXCEPTION("A0013", "参数校验异常"),
|
||||
|
||||
ILLEGAL_ARGUMENT_EXCEPTION("A0014", "参数校验异常"),
|
||||
|
||||
SM2_CIPHER_ERROR("A0015", "SM2获取秘钥对异常"),
|
||||
|
||||
UN_DECLARE("A0016", "未声明异常"),
|
||||
|
||||
DIC_DATA("A0017", "获取字典数据失败"),
|
||||
|
||||
GET_MQTT_CLIENT_FAIL("A0018", "获取MQTT客户端失败"),
|
||||
|
||||
NO_MQTT_HANDLER("A0019", "MQTT中没有处理器Handler"),
|
||||
|
||||
NO_MQTT_PRODUCER("A0020", "MQTT没有生产者producer"),
|
||||
|
||||
JSON_CONVERT_EXCEPTION("A0021", "JSON转换异常"),
|
||||
|
||||
TOKEN_EXPIRE_JWT("A0024", "token已过期"),
|
||||
|
||||
PARSE_TOKEN_ERROR("A0025", "token解析异常"),
|
||||
|
||||
REFLECT_METHOD_EXCEPTION("A0026", "反射方法获取属性值异常"),
|
||||
|
||||
REQUEST_EMPTY("A0027", "当前请求web环境为空"),
|
||||
|
||||
EXPORT_FILE_ERROR("A00551","数据完整报表下载异常"),
|
||||
|
||||
USER_RESPONSE_ENUM("A0090", "用户响应枚举类型"),
|
||||
|
||||
GATEWAY_RESPONSE_ENUM("A0091", "网关响应枚举类型"),
|
||||
|
||||
DEVICE_RESPONSE_ENUM("A0092", "终端响应枚举类型"),
|
||||
|
||||
SYSTEM_RESPONSE_ENUM("A0093", "系统响应枚举类型"),
|
||||
|
||||
DELETE_PID_EXIST("A0094", "存在子节点"),
|
||||
|
||||
DELETE_PID_UNEXIST("A0095", "不存在子节点"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String message;
|
||||
|
||||
CommonResponseEnum(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.njcn.common.pojo.exception;
|
||||
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年04月20日 14:48
|
||||
*/
|
||||
@Data
|
||||
@Slf4j
|
||||
@NoArgsConstructor
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -1;
|
||||
|
||||
public static final String GET_CODE_METHOD = "getCode";
|
||||
|
||||
public static final String GET_MESSAGE_METHOD = "getMessage";
|
||||
|
||||
/**
|
||||
* 异常码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 异常提示信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 构造器内的枚举
|
||||
*/
|
||||
private Enum<?> anEnum;
|
||||
|
||||
/**
|
||||
* openfeign请求,返回的非常规结果集
|
||||
*/
|
||||
private HttpResult result;
|
||||
|
||||
public BusinessException(Enum<?> eEnum) {
|
||||
anEnum = eEnum;
|
||||
try {
|
||||
Method codeMethod = eEnum.getClass().getMethod(GET_CODE_METHOD);
|
||||
Method messageMethod = eEnum.getClass().getMethod(GET_MESSAGE_METHOD);
|
||||
this.code = (String) codeMethod.invoke(eEnum);
|
||||
this.message = (String) messageMethod.invoke(eEnum);
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对批量操作的业务返回
|
||||
*
|
||||
* @author cdf
|
||||
* @date 2021/7/7
|
||||
*/
|
||||
public BusinessException(Enum<?> eEnum, String msg) {
|
||||
anEnum = eEnum;
|
||||
try {
|
||||
Method codeMethod = eEnum.getClass().getMethod(GET_CODE_METHOD);
|
||||
Method messageMethod = eEnum.getClass().getMethod(GET_MESSAGE_METHOD);
|
||||
this.code = (String) codeMethod.invoke(eEnum);
|
||||
this.message = (String) messageMethod.invoke(eEnum);
|
||||
this.message = this.message.concat(": " + msg);
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BusinessException(HttpResult result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.njcn.common.pojo.response;
|
||||
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年03月25日 15:38
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class HttpResult<T> implements Serializable {
|
||||
|
||||
/**状态码*/
|
||||
private String code;
|
||||
|
||||
/**回执信息*/
|
||||
private String message;
|
||||
|
||||
/**响应数据*/
|
||||
private T data;
|
||||
|
||||
public HttpResult(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public HttpResult(Integer code, String message) {
|
||||
this.code = String.valueOf(code);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public HttpResult(T content) {
|
||||
this.code = CommonResponseEnum.SUCCESS.getCode();
|
||||
this.data = content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
|
||||
import com.njcn.common.pojo.enums.common.ServerEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年05月26日 11:44
|
||||
*/
|
||||
public class EnumUtils {
|
||||
|
||||
private final static int
|
||||
COMMON_ENUM_FLOOR = 0
|
||||
,COMMON_ENUM_CEIL = 99
|
||||
,USER_ENUM_FLOOR = 100
|
||||
,USER_ENUM_CEIL = 199
|
||||
,GATEWAY_ENUM_FLOOR = 200
|
||||
,GATEWAY_ENUM_CEIL = 249
|
||||
,DEVICE_ENUM_FLOOR = 250
|
||||
,DEVICE_ENUM_CEIL = 349
|
||||
,SYSTEM_ENUM_FLOOR = 350
|
||||
,SYSTEM_ENUM_CEIL = 449
|
||||
,HARMONIC_ENUM_CEIL = 450
|
||||
,HARMONIC_ENUM_FLOOR = 549;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 值映射为枚举
|
||||
*
|
||||
* @param enumClass 枚举类
|
||||
* @param value 枚举值
|
||||
* @param method 取值方法
|
||||
* @param <E> 对应枚举
|
||||
*/
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> enumClass, Object value, Method method) {
|
||||
E[] es = enumClass.getEnumConstants();
|
||||
for (E enumTemp : es) {
|
||||
Object evalue;
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
evalue = method.invoke(enumTemp);
|
||||
} catch (IllegalAccessException | InvocationTargetException e1) {
|
||||
throw new BusinessException(CommonResponseEnum.ENUM_ERROR);
|
||||
}
|
||||
if (value instanceof Number && evalue instanceof Number
|
||||
&& new BigDecimal(String.valueOf(value)).compareTo(new BigDecimal(String.valueOf(evalue))) == 0) {
|
||||
return enumTemp;
|
||||
}
|
||||
if (Objects.equals(evalue, value)) {
|
||||
return enumTemp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据枚举code获取CommonResponseEnum实例
|
||||
*/
|
||||
public static CommonResponseEnum getCommonResponseEnumByCode(String code) {
|
||||
code = getCode(code);
|
||||
CommonResponseEnum commonResponseEnum;
|
||||
try {
|
||||
commonResponseEnum = valueOf(CommonResponseEnum.class, code, CommonResponseEnum.class.getMethod(BusinessException.GET_CODE_METHOD));
|
||||
return Objects.isNull(commonResponseEnum) ? CommonResponseEnum.INTERNAL_ERROR : commonResponseEnum;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new BusinessException(CommonResponseEnum.INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举message获取CommonResponseEnum实例
|
||||
*/
|
||||
public static CommonResponseEnum getCommonResponseEnumByMessage(String message) {
|
||||
CommonResponseEnum commonResponseEnum;
|
||||
try {
|
||||
commonResponseEnum = valueOf(CommonResponseEnum.class, message, CommonResponseEnum.class.getMethod(BusinessException.GET_MESSAGE_METHOD));
|
||||
return Objects.isNull(commonResponseEnum) ? CommonResponseEnum.INTERNAL_ERROR : commonResponseEnum;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new BusinessException(CommonResponseEnum.INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取UserStatusEnum实例
|
||||
*/
|
||||
public static ServerEnum getServerEnumByName(Object value) {
|
||||
ServerEnum serverEnum;
|
||||
try {
|
||||
serverEnum = EnumUtils.valueOf(ServerEnum.class, value, ServerEnum.class.getMethod("getName"));
|
||||
return Objects.isNull(serverEnum) ? ServerEnum.COMMON : serverEnum;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new BusinessException(CommonResponseEnum.INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 如何通过枚举code获取响应的枚举类型
|
||||
* 比如 A0000 ~ A0099 通用业务枚举
|
||||
* 比如 A0100 ~ A0199 用户业务枚举
|
||||
* 比如 A0200 ~ A0249 网关业务枚举
|
||||
* 比如 A0250 ~ A0349 终端业务枚举
|
||||
* 比如 A0350 ~ A0449 系统业务枚举
|
||||
*/
|
||||
private static String getCode(String originalCode){
|
||||
int code = Integer.parseInt(originalCode.substring(1));
|
||||
if(PubUtils.rangeInDefined(code,0,99)){
|
||||
return originalCode;
|
||||
}else if(PubUtils.rangeInDefined(code,100,199)){
|
||||
return CommonResponseEnum.USER_RESPONSE_ENUM.getCode();
|
||||
}else if(PubUtils.rangeInDefined(code,200,249)){
|
||||
return CommonResponseEnum.GATEWAY_RESPONSE_ENUM.getCode();
|
||||
}else if(PubUtils.rangeInDefined(code,250,349)){
|
||||
return CommonResponseEnum.DEVICE_RESPONSE_ENUM.getCode();
|
||||
}else if(PubUtils.rangeInDefined(code,350,449)){
|
||||
return CommonResponseEnum.SYSTEM_RESPONSE_ENUM.getCode();
|
||||
}else{
|
||||
return originalCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年04月21日 09:16
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
private static final String PACKAGE_PREFIX = "com.njcn";
|
||||
|
||||
private static final String CONTROLLER = "controller";
|
||||
|
||||
/**
|
||||
* 遍历出当前异常在本服务中栈堆信息----异常发生最初位置
|
||||
* 本服务所有的包名均需要以com.njcn为前缀
|
||||
* 该前缀不需要做配置管理,通常项目创建之初约定完便可。
|
||||
*/
|
||||
public static String getExceptionServerStackInfo(Exception exception) {
|
||||
StackTraceElement[] stackTrace = exception.getStackTrace();
|
||||
List<StackTraceElement> originalStackTraceElements = Arrays.asList(stackTrace);
|
||||
//遍历出本服务的栈堆信息
|
||||
List<StackTraceElement> stackTraceElements = originalStackTraceElements.stream().filter(stackInfo -> stackInfo.getClassName().contains(PACKAGE_PREFIX)).collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(stackTraceElements)) {
|
||||
return stackTraceElements.get(0).toString();
|
||||
} else if (CollectionUtil.isNotEmpty(originalStackTraceElements)) {
|
||||
return originalStackTraceElements.get(0).toString();
|
||||
}
|
||||
return "未找到当前异常的堆栈信息";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 遍历出当前异常在本服务中栈堆信息----堆栈的所有信息
|
||||
* 本服务所有的包名均需要以com.njcn为前缀
|
||||
* 该前缀不需要做配置管理,通常项目创建之初约定完便可。
|
||||
*/
|
||||
public static List<String> getAllExceptionServerStackInfo(Exception exception) {
|
||||
StackTraceElement[] stackTrace = exception.getStackTrace();
|
||||
List<StackTraceElement> originalStackTraceElements = Arrays.asList(stackTrace);
|
||||
//遍历出本服务的栈堆信息
|
||||
List<StackTraceElement> stackTraceElements = originalStackTraceElements.stream().filter(stackInfo -> stackInfo.getClassName().contains(PACKAGE_PREFIX)).collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(stackTraceElements)) {
|
||||
return stackTraceElements.stream().map(StackTraceElement::toString).collect(Collectors.toList());
|
||||
} else if (CollectionUtil.isNotEmpty(originalStackTraceElements)) {
|
||||
return originalStackTraceElements.stream().map(StackTraceElement::toString).collect(Collectors.toList());
|
||||
}
|
||||
List<String> noStackInfos = new ArrayList<>();
|
||||
noStackInfos.add("未找到当前异常的堆栈信息");
|
||||
return noStackInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历出当前异常堆栈的所有信息
|
||||
* 本服务所有的包名均需要以com.njcn为前缀
|
||||
* 该前缀不需要做配置管理,通常项目创建之初约定完便可。
|
||||
*/
|
||||
public static List<String> getAllExceptionStackInfo(Exception exception) {
|
||||
StackTraceElement[] stackTrace = exception.getStackTrace();
|
||||
List<StackTraceElement> originalStackTraceElements = Arrays.asList(stackTrace);
|
||||
if (CollectionUtil.isNotEmpty(originalStackTraceElements)) {
|
||||
return originalStackTraceElements.stream().map(StackTraceElement::toString).collect(Collectors.toList());
|
||||
}
|
||||
List<String> noStackInfos = new ArrayList<>();
|
||||
noStackInfos.add("未找到当前异常的堆栈信息");
|
||||
return noStackInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历异常信息栈,获取信息栈中第一个出现的controller以及方法名称
|
||||
* 用于反射获取注解内容,比如方法名,操作类型,操作严重度
|
||||
* <p>
|
||||
* 实际情况可能会出现没有controller入口的情况导致的异常,比如网关gateway内所有请求
|
||||
*/
|
||||
public static List<String> getFirstControllerAndMethodName(Exception exception) {
|
||||
List<String> controllerInfo = new ArrayList<>();
|
||||
StackTraceElement[] stackTraces = exception.getStackTrace();
|
||||
List<StackTraceElement> stackTraceElements = Stream.of(stackTraces)
|
||||
.filter(stackInfo -> stackInfo.getClassName().contains(PACKAGE_PREFIX) && stackInfo.getClassName().contains(CONTROLLER))
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(stackTraceElements)) {
|
||||
StackTraceElement stackTraceElement = stackTraceElements.get(0);
|
||||
String stackInfo = stackTraceElement.toString();
|
||||
|
||||
String packageInfo = stackInfo.substring(stackInfo.indexOf(PACKAGE_PREFIX));
|
||||
packageInfo = packageInfo.substring(0, packageInfo.indexOf("("));
|
||||
String controllerName = packageInfo.substring(0, packageInfo.lastIndexOf(CharUtil.DOT));
|
||||
String methodName = packageInfo.substring(packageInfo.lastIndexOf(CharUtil.DOT) + 1);
|
||||
if(methodName.indexOf('$')>0){
|
||||
methodName = methodName.substring(0, methodName.indexOf('$'));
|
||||
}
|
||||
Collections.addAll(controllerInfo, controllerName, methodName);
|
||||
}
|
||||
return controllerInfo;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月10日 13:42
|
||||
*/
|
||||
public class HttpResultUtil {
|
||||
|
||||
/**
|
||||
* 组装结果集
|
||||
*/
|
||||
public static <T> HttpResult<T> assembleResult(String code, T result, String message) {
|
||||
HttpResult<T> httpResult = new HttpResult<>();
|
||||
httpResult.setCode(code);
|
||||
httpResult.setMessage(message);
|
||||
httpResult.setData(result);
|
||||
return httpResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装通用结果集
|
||||
*/
|
||||
public static <T> HttpResult<T> assembleCommonResponseResult(CommonResponseEnum responseEnum, T result, String methodDescribe) {
|
||||
String message = responseEnum.getMessage();
|
||||
if (responseEnum.equals(CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION)) {
|
||||
message = (String) result;
|
||||
}
|
||||
return assembleResult(responseEnum.getCode(), result, StrFormatter.format("{}{}{}", methodDescribe, StrUtil.C_COMMA, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常组装结果集
|
||||
*/
|
||||
public static <T> HttpResult<T> assembleBusinessExceptionResult(BusinessException businessException, T result, String methodDescribe) {
|
||||
return assembleResult(businessException.getCode(), result, StrFormatter.format("{}{}{}", methodDescribe, StrUtil.C_COMMA, businessException.getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年03月25日 16:31
|
||||
*/
|
||||
@Slf4j
|
||||
public class LogUtil {
|
||||
|
||||
/**
|
||||
* 将判断是否开启debug模式,抽取单独的方法,必要时查看敏感信息
|
||||
*
|
||||
* @param log 日志输出器
|
||||
*/
|
||||
public static void njcnDebug(Logger log, String format, Object... args) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.info(format, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将判断是否开启debug模式,抽取单独的方法,必要时查看debug级别信息
|
||||
* 批量输出堆栈日志信息
|
||||
*
|
||||
* @param log 日志输出器
|
||||
*/
|
||||
public static void njcnPatchDebug(Logger log, List<String> stackInfos) {
|
||||
if (log.isDebugEnabled()) {
|
||||
stackInfos.forEach(log::error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 区分是否开启debug模式,输出系统异常日志信息
|
||||
* 若开启debug模式,则输出所有的堆栈信息
|
||||
* 否则只输出第一行日志信息
|
||||
*
|
||||
* @param exception 异常
|
||||
*/
|
||||
public static void logExceptionStackInfo(String exceptionName, Exception exception) {
|
||||
//若开启了debug模式,则输出所有的栈堆信息
|
||||
njcnPatchDebug(log, ExceptionUtil.getAllExceptionStackInfo(exception));
|
||||
log.error("{}{},目标文件:{}",exceptionName, exception.toString(), ExceptionUtil.getExceptionServerStackInfo(exception));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.Integer.parseInt;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年04月12日 14:21
|
||||
*/
|
||||
public class PubUtils {
|
||||
|
||||
private final static ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static final String DATE = "yyyy-MM-dd";
|
||||
|
||||
private static final String TIME = "HH:mm:ss";
|
||||
|
||||
|
||||
/**
|
||||
* 生成随机码,包含字母。--> 大写
|
||||
*
|
||||
* @param length 随机码长度
|
||||
*/
|
||||
public static String randomCode(int length) {
|
||||
return RandomUtil.randomString(length).toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
* ***** ***** 验证IP是否属于某个IP段 ipSection IP段(以'-'分隔) ip 所验证的IP号码 ***** *****
|
||||
**/
|
||||
public static boolean ipExistsInRange(String ip, String ipSection) {
|
||||
ipSection = ipSection.trim();
|
||||
ip = ip.trim();
|
||||
int idx = ipSection.indexOf('-');
|
||||
String beginIp = ipSection.substring(0, idx);
|
||||
String endIp = ipSection.substring(idx + 1);
|
||||
return getIp2long(beginIp) <= getIp2long(ip) && getIp2long(ip) <= getIp2long(endIp);
|
||||
}
|
||||
|
||||
private static long getIp2long(String ip) {
|
||||
ip = ip.trim();
|
||||
String[] ips = ip.split("\\.");
|
||||
long ip2long = 0L;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ip2long = ip2long << 8 | parseInt(ips[i]);
|
||||
}
|
||||
return ip2long;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间
|
||||
*
|
||||
* @author cdf
|
||||
* @date 2021/7/26
|
||||
*/
|
||||
public static String getNow() {
|
||||
DateFormat bf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return bf.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前web的IP
|
||||
*/
|
||||
public static String getLocalIp() {
|
||||
String host;
|
||||
try {
|
||||
host = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
host = "127.0.0.1";
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JSON转为实体对象
|
||||
*
|
||||
* @param jsonStr json
|
||||
* @param targetType 对象类型
|
||||
* @param <T> 对象
|
||||
*/
|
||||
public static <T> T json2obj(String jsonStr, Type targetType) {
|
||||
try {
|
||||
JavaType javaType = TypeFactory.defaultInstance().constructType(targetType);
|
||||
MAPPER.registerModule(new JavaTimeModule());
|
||||
MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
return MAPPER.readValue(jsonStr, javaType);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("将JSON转换为对象时发生错误:" + jsonStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个数字是否在区间内
|
||||
*
|
||||
* @param current 待判断数字
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
*/
|
||||
public static boolean rangeInDefined(int current, int min, int max) {
|
||||
return Math.max(min, current) == Math.min(current, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将起始日期字符串 yyyy-MM-dd 转为 yyyy-MM-dd HH:mm:ss的LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime beginTimeToLocalDateTime(String beginTime){
|
||||
beginTime = beginTime + StrUtil.SPACE + "00:00:00";
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME);
|
||||
return LocalDateTime.parse(beginTime, dateTimeFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将截止日期字符串 yyyy-MM-dd 转为 yyyy-MM-dd HH:mm:ss的LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime endTimeToLocalDateTime(String endTime){
|
||||
endTime = endTime + StrUtil.SPACE + "23:59:59";
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME);
|
||||
return LocalDateTime.parse(endTime, dateTimeFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串日期转为LocalDate日期(只用于日期转换)
|
||||
*/
|
||||
public static LocalDate localDateFormat(String time){
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE);
|
||||
return LocalDate.parse(time,dateTimeFormatter);
|
||||
}
|
||||
|
||||
public static LocalDateTime localDateTimeFormat(String time){
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME);
|
||||
return LocalDateTime.parse(time,dateTimeFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于获取对象中,前缀一样,后缀为2~50的属性值
|
||||
* @param object 待操作对象
|
||||
* @param methodPrefix 方法前缀
|
||||
* @param number 方法后缀
|
||||
* @return 对象属性值
|
||||
*/
|
||||
public static Float getValueByMethod(Object object, String methodPrefix, Integer number) {
|
||||
try {
|
||||
Method method = object.getClass().getMethod(methodPrefix + number);
|
||||
return (Float) method.invoke(object);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(CommonResponseEnum.REFLECT_METHOD_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getStartTimeEndTime(String beginDate, String endDate) throws Exception {
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(sdf.parse(beginDate));
|
||||
List<String> startTimeEndTime = null;
|
||||
for (long d = cal.getTimeInMillis(); d <= sdf.parse(endDate).getTime(); d = getDplaus(cal)) {
|
||||
startTimeEndTime.add(sdf.format(d));
|
||||
}
|
||||
return startTimeEndTime;
|
||||
}
|
||||
|
||||
public static long getDplaus(Calendar c) {
|
||||
c.set(Calendar.DAY_OF_MONTH, c.get(Calendar.DAY_OF_MONTH) + 1);
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
public static String comFlag(Integer comFlag) {
|
||||
switch (comFlag) {
|
||||
case 0:
|
||||
return "中断";
|
||||
case 1:
|
||||
return "正常";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String runFlag(Integer runFlag) {
|
||||
switch (runFlag) {
|
||||
case 0:
|
||||
return "投运";
|
||||
case 1:
|
||||
return "热备用";
|
||||
case 2:
|
||||
return "停运";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String ptType(Integer ptType) {
|
||||
switch (ptType) {
|
||||
case 0:
|
||||
return "星型接线";
|
||||
case 1:
|
||||
return "三角型接线";
|
||||
case 2:
|
||||
return "开口三角型接线";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.njcn.common.pojo.annotation.OperateInfo;
|
||||
import com.njcn.common.pojo.constant.LogInfo;
|
||||
import com.njcn.common.pojo.constant.OperateType;
|
||||
import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月10日 13:32
|
||||
*/
|
||||
@Slf4j
|
||||
public class ReflectCommonUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 根据异常获取系统内controller中的方法
|
||||
* @param exception 运行时异常
|
||||
*/
|
||||
public static Method getMethod(Exception exception) {
|
||||
List<String> stackInfo = ExceptionUtil.getFirstControllerAndMethodName(exception);
|
||||
Method method = null;
|
||||
if (!CollectionUtil.isEmpty(stackInfo)) {
|
||||
String controllerName = stackInfo.get(0);
|
||||
String methodName = stackInfo.get(1);
|
||||
try {
|
||||
method =ReflectUtil.getMethodByName(Class.forName(controllerName), methodName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("根据controller名以及方法名反射获取方法体异常,controller为:{},方法为:{},异常为:{}", controllerName, methodName, e.getMessage());
|
||||
}
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从异常堆栈信息里找出controller上@ApiOperation内容
|
||||
*
|
||||
* @param exception 异常
|
||||
*/
|
||||
public static String getMethodDescribeByException(Exception exception) {
|
||||
List<String> stackInfo = ExceptionUtil.getFirstControllerAndMethodName(exception);
|
||||
String operate = LogInfo.UNKNOWN_OPERATE;
|
||||
if (!CollectionUtil.isEmpty(stackInfo)) {
|
||||
String controllerName = stackInfo.get(0);
|
||||
String methodName = stackInfo.get(1);
|
||||
try {
|
||||
operate = ReflectCommonUtil.getMethodDescribeByClassAndMethodName(Class.forName(controllerName), methodName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("根据controller名以及方法名获取操作注解内容异常,controller为:{},方法为:{},异常为:{}", controllerName, methodName, e.getMessage());
|
||||
}
|
||||
}
|
||||
return operate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取controller上方法@ApiOperation注解的值,作为当前方法的简短描述
|
||||
*/
|
||||
public static String getMethodDescribeByClassAndMethodName(Class<?> clazz, String methodName) {
|
||||
Method method = ReflectUtil.getMethodByName(clazz, methodName);
|
||||
return getMethodDescribeByMethod(method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取方法上@ApiOperation注解的值,作为当前方法的简短描述
|
||||
*/
|
||||
public static String getMethodDescribeByMethod(Method method) {
|
||||
String operate = LogInfo.UNKNOWN_OPERATE;
|
||||
if (Objects.nonNull(method) && method.isAnnotationPresent(ApiOperation.class)) {
|
||||
operate = method.getAnnotation(ApiOperation.class).value();
|
||||
}
|
||||
return operate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据controller上的方法@OperateInfo注解的内容,返回当前[业务类型]以及[严重度]
|
||||
*/
|
||||
public static LogEnum getOperateInfoByMethod(Method method) {
|
||||
LogEnum logEnum = LogEnum.BUSINESS_COMMON;
|
||||
if(Objects.nonNull(method) && method.isAnnotationPresent(OperateInfo.class)){
|
||||
logEnum = method.getAnnotation(OperateInfo.class).info();
|
||||
}
|
||||
return logEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据controller上的方法@OperateInfo注解的内容,返回当前操作类型
|
||||
*/
|
||||
public static String getOperateTypeByMethod(Method method) {
|
||||
String operateType = OperateType.QUERY;
|
||||
if(Objects.nonNull(method) && method.isAnnotationPresent(OperateInfo.class)){
|
||||
operateType = method.getAnnotation(OperateInfo.class).operateType();
|
||||
}
|
||||
return operateType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.njcn.common.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @createTime 2021年05月20日 14:13
|
||||
*/
|
||||
@Slf4j
|
||||
public class XssCleanRuleUtils {
|
||||
|
||||
private XssCleanRuleUtils() {
|
||||
}
|
||||
|
||||
private static final Pattern[] PATTERNS = {
|
||||
// Avoid anything in a <script> type of expression
|
||||
Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
|
||||
// Avoid anything in a src='...' type of expression
|
||||
Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
// Remove any lonesome </script> tag
|
||||
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
|
||||
// Avoid anything in a <iframe> type of expression
|
||||
Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE),
|
||||
// Remove any lonesome <script ...> tag
|
||||
Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
// Remove any lonesome <img ...> tag
|
||||
Pattern.compile("<img(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
// Avoid eval(...) expressions
|
||||
Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
// Avoid expression(...) expressions
|
||||
Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
// Avoid javascript:... expressions
|
||||
Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
|
||||
// Avoid vbscript:... expressions
|
||||
Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
|
||||
// Avoid onload= expressions
|
||||
Pattern.compile("on(load|error|mouseover|submit|reset|focus|click)(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
|
||||
};
|
||||
|
||||
public static String stripXSS(String value) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return value;
|
||||
}
|
||||
for (Pattern scriptPattern : PATTERNS) {
|
||||
value = scriptPattern.matcher(value).replaceAll("");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.math.BigInteger;
|
||||
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
* @version 1.0.0
|
||||
* @date 2021年06月09日 10:10
|
||||
*/
|
||||
@Slf4j
|
||||
public class DesUtils{
|
||||
|
||||
private static final String KEY = "njcnpqsqpncjnggg";
|
||||
|
||||
private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
|
||||
|
||||
/**
|
||||
* aes解密
|
||||
* @param encrypt 内容
|
||||
*/
|
||||
public static String aesDecrypt(String encrypt) {
|
||||
try {
|
||||
return aesDecrypt(encrypt, KEY);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// System.out.println(aesDecrypt("+xoDu2WfBdl75A4cFdQF1A=="));
|
||||
System.out.println(aesEncrypt("lfan"));
|
||||
}
|
||||
|
||||
/**
|
||||
* aes加密
|
||||
*/
|
||||
public static String aesEncrypt(String content) {
|
||||
try {
|
||||
return aesEncrypt(content, KEY);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将byte[]转为各种进制的字符串
|
||||
* @param bytes byte[]
|
||||
* @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
public static String binary(byte[] bytes, int radix){
|
||||
return new BigInteger(1, bytes).toString(radix);
|
||||
}
|
||||
|
||||
/**
|
||||
* base 64 encode
|
||||
* @param bytes 待编码的byte[]
|
||||
* @return 编码后的base 64 code
|
||||
*/
|
||||
public static String base64Encode(byte[] bytes){
|
||||
return Base64.encodeBase64String(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* base 64 decode
|
||||
* @param base64Code 待解码的base 64 code
|
||||
* @return 解码后的byte[]
|
||||
* @throws Exception .
|
||||
*/
|
||||
public static byte[] base64Decode(String base64Code) throws Exception{
|
||||
return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AES加密
|
||||
* @param content 待加密的内容
|
||||
* @param encryptKey 加密密钥
|
||||
* @return 加密后的byte[]
|
||||
* @throws Exception .
|
||||
*/
|
||||
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
|
||||
KeyGenerator kgen = KeyGenerator.getInstance("AES");
|
||||
kgen.init(128);
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
|
||||
|
||||
return cipher.doFinal(content.getBytes(CharsetUtil.CHARSET_UTF_8));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AES加密为base 64 code
|
||||
* @param content 待加密的内容
|
||||
* @param encryptKey 加密密钥
|
||||
* @return 加密后的base 64 code
|
||||
* @throws Exception .
|
||||
*/
|
||||
public static String aesEncrypt(String content, String encryptKey) throws Exception {
|
||||
return base64Encode(aesEncryptToBytes(content, encryptKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* AES解密
|
||||
* @param encryptBytes 待解密的byte[]
|
||||
* @param decryptKey 解密密钥
|
||||
* @return 解密后的String
|
||||
* @throws Exception .
|
||||
*/
|
||||
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
|
||||
KeyGenerator kgen = KeyGenerator.getInstance("AES");
|
||||
kgen.init(128);
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
|
||||
byte[] decryptBytes = cipher.doFinal(encryptBytes);
|
||||
return new String(decryptBytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将base 64 code AES解密
|
||||
* @param encryptStr 待解密的base 64 code
|
||||
* @param decryptKey 解密密钥
|
||||
* @return 解密后的string
|
||||
* @throws Exception .
|
||||
*/
|
||||
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
|
||||
return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||
import org.bouncycastle.crypto.engines.SM2Engine;
|
||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
@Slf4j
|
||||
public class Sm2 {
|
||||
|
||||
|
||||
/**
|
||||
* SM2解密密碼
|
||||
*
|
||||
* @param privateKey SM2私有秘钥
|
||||
* @param encryptedData 需要解密字符串
|
||||
*/
|
||||
public static String decrypt(String privateKey, String encryptedData) {
|
||||
byte[] encryptedDataByte = Hex.decode(encryptedData);
|
||||
BigInteger privateKeyD = new BigInteger(privateKey, 16);
|
||||
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, getSm2EcDomain());
|
||||
//用私钥解密
|
||||
SM2Engine sm2Engine = new SM2Engine();
|
||||
sm2Engine.init(false, privateKeyParameters);
|
||||
//processBlock得到Base64格式,记得解码
|
||||
byte[] arrayOfBytes = new byte[encryptedDataByte.length];
|
||||
try {
|
||||
arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(encryptedDataByte, 0, encryptedDataByte.length));
|
||||
} catch (InvalidCipherTextException e) {
|
||||
log.error("SM2解密byte转换出错,异常为:" + e.toString());
|
||||
}
|
||||
//得到明文
|
||||
return new String(arrayOfBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SM2秘钥队证书
|
||||
*/
|
||||
public static ECDomainParameters getSm2EcDomain() {
|
||||
ECDomainParameters domainParameters ;
|
||||
//生成密钥对
|
||||
X9ECParameters sm2EcParameters = GMNamedCurves.getByName("sm2p256v1");
|
||||
domainParameters = new ECDomainParameters(sm2EcParameters.getCurve(), sm2EcParameters.getG(), sm2EcParameters.getN());
|
||||
//返回证书
|
||||
return domainParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SM2秘钥对
|
||||
*/
|
||||
public static Map<String, String> getSm2CipHer() throws NoSuchAlgorithmException {
|
||||
//秘钥队
|
||||
Map<String, String> resultMap = new HashMap<>();
|
||||
//生成密钥对
|
||||
ECDomainParameters domainParameters = getSm2EcDomain();
|
||||
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
|
||||
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
|
||||
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
|
||||
|
||||
//私钥,16进制格式,自己保存,格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853
|
||||
BigInteger privateKey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
|
||||
//公钥,16进制格式,发给前端,格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
|
||||
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
|
||||
|
||||
resultMap.put("privateKey", privateKey.toString(16));
|
||||
resultMap.put("publicKey", Hex.toHexString(ecPoint.getEncoded(false)));
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SM2密码有效性,传输完整性验证
|
||||
*/
|
||||
public static String getPasswordSM2Verify(String privateKey, String strPwd) {
|
||||
String strResultPwd = null;
|
||||
try {
|
||||
String password = Sm2.decrypt(privateKey, strPwd);
|
||||
//数据完整性判断
|
||||
String passwordIntegrity = Sm3.getPasswordIntegrity(password);
|
||||
//数据完整性未破坏
|
||||
if (passwordIntegrity != null && passwordIntegrity.length() != 0) {
|
||||
strResultPwd = passwordIntegrity;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
strResultPwd = null;
|
||||
log.error("解析密码有效性出错,异常为:" + e.toString());
|
||||
}
|
||||
return strResultPwd;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
public class Sm3
|
||||
{
|
||||
public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
|
||||
0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
|
||||
(byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
|
||||
(byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
|
||||
(byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
|
||||
0x4e };
|
||||
|
||||
public static int[] Tj = new int[64];
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Tj[i] = 0x79cc4519;
|
||||
}
|
||||
|
||||
for (int i = 16; i < 64; i++)
|
||||
{
|
||||
Tj[i] = 0x7a879d8a;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CF(byte[] V, byte[] B)
|
||||
{
|
||||
int[] v, b;
|
||||
v = convert(V);
|
||||
b = convert(B);
|
||||
return convert(CF(v, b));
|
||||
}
|
||||
|
||||
private static int[] convert(byte[] arr)
|
||||
{
|
||||
int[] out = new int[arr.length / 4];
|
||||
byte[] tmp = new byte[4];
|
||||
for (int i = 0; i < arr.length; i += 4)
|
||||
{
|
||||
System.arraycopy(arr, i, tmp, 0, 4);
|
||||
out[i / 4] = bigEndianByteToInt(tmp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static byte[] convert(int[] arr)
|
||||
{
|
||||
byte[] out = new byte[arr.length * 4];
|
||||
byte[] tmp = null;
|
||||
for (int i = 0; i < arr.length; i++)
|
||||
{
|
||||
tmp = bigEndianIntToByte(arr[i]);
|
||||
System.arraycopy(tmp, 0, out, i * 4, 4);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public static int[] CF(int[] V, int[] B)
|
||||
{
|
||||
int a, b, c, d, e, f, g, h;
|
||||
int ss1, ss2, tt1, tt2;
|
||||
a = V[0];
|
||||
b = V[1];
|
||||
c = V[2];
|
||||
d = V[3];
|
||||
e = V[4];
|
||||
f = V[5];
|
||||
g = V[6];
|
||||
h = V[7];
|
||||
|
||||
int[][] arr = expand(B);
|
||||
int[] w = arr[0];
|
||||
int[] w1 = arr[1];
|
||||
|
||||
for (int j = 0; j < 64; j++)
|
||||
{
|
||||
ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));
|
||||
ss1 = bitCycleLeft(ss1, 7);
|
||||
ss2 = ss1 ^ bitCycleLeft(a, 12);
|
||||
tt1 = FFj(a, b, c, j) + d + ss2 + w1[j];
|
||||
tt2 = GGj(e, f, g, j) + h + ss1 + w[j];
|
||||
d = c;
|
||||
c = bitCycleLeft(b, 9);
|
||||
b = a;
|
||||
a = tt1;
|
||||
h = g;
|
||||
g = bitCycleLeft(f, 19);
|
||||
f = e;
|
||||
e = P0(tt2);
|
||||
}
|
||||
int[] out = new int[8];
|
||||
out[0] = a ^ V[0];
|
||||
out[1] = b ^ V[1];
|
||||
out[2] = c ^ V[2];
|
||||
out[3] = d ^ V[3];
|
||||
out[4] = e ^ V[4];
|
||||
out[5] = f ^ V[5];
|
||||
out[6] = g ^ V[6];
|
||||
out[7] = h ^ V[7];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static int[][] expand(int[] B)
|
||||
{
|
||||
int W[] = new int[68];
|
||||
int W1[] = new int[64];
|
||||
for (int i = 0; i < B.length; i++)
|
||||
{
|
||||
W[i] = B[i];
|
||||
}
|
||||
|
||||
for (int i = 16; i < 68; i++)
|
||||
{
|
||||
W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15))
|
||||
^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
W1[i] = W[i] ^ W[i + 4];
|
||||
}
|
||||
|
||||
int arr[][] = new int[][] { W, W1 };
|
||||
return arr;
|
||||
}
|
||||
|
||||
private static byte[] bigEndianIntToByte(int num)
|
||||
{
|
||||
return back(util.intToBytes(num));
|
||||
}
|
||||
|
||||
private static int bigEndianByteToInt(byte[] bytes)
|
||||
{
|
||||
return util.byteToInt(back(bytes));
|
||||
}
|
||||
|
||||
private static int FFj(int X, int Y, int Z, int j)
|
||||
{
|
||||
if (j >= 0 && j <= 15)
|
||||
{
|
||||
return FF1j(X, Y, Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FF2j(X, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
private static int GGj(int X, int Y, int Z, int j)
|
||||
{
|
||||
if (j >= 0 && j <= 15)
|
||||
{
|
||||
return GG1j(X, Y, Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GG2j(X, Y, Z);
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑位运算函数
|
||||
private static int FF1j(int X, int Y, int Z)
|
||||
{
|
||||
int tmp = X ^ Y ^ Z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int FF2j(int X, int Y, int Z)
|
||||
{
|
||||
int tmp = ((X & Y) | (X & Z) | (Y & Z));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int GG1j(int X, int Y, int Z)
|
||||
{
|
||||
int tmp = X ^ Y ^ Z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int GG2j(int X, int Y, int Z)
|
||||
{
|
||||
int tmp = (X & Y) | (~X & Z);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static int P0(int X)
|
||||
{
|
||||
int y = rotateLeft(X, 9);
|
||||
y = bitCycleLeft(X, 9);
|
||||
int z = rotateLeft(X, 17);
|
||||
z = bitCycleLeft(X, 17);
|
||||
int t = X ^ y ^ z;
|
||||
return t;
|
||||
}
|
||||
|
||||
private static int P1(int X)
|
||||
{
|
||||
int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对最后一个分组字节数据padding
|
||||
*
|
||||
*/
|
||||
public static byte[] padding(byte[] in, int bLen)
|
||||
{
|
||||
int k = 448 - (8 * in.length + 1) % 512;
|
||||
if (k < 0)
|
||||
{
|
||||
k = 960 - (8 * in.length + 1) % 512;
|
||||
}
|
||||
k += 1;
|
||||
byte[] padd = new byte[k / 8];
|
||||
padd[0] = (byte) 0x80;
|
||||
long n = in.length * 8 + bLen * 512;
|
||||
byte[] out = new byte[in.length + k / 8 + 64 / 8];
|
||||
int pos = 0;
|
||||
System.arraycopy(in, 0, out, 0, in.length);
|
||||
pos += in.length;
|
||||
System.arraycopy(padd, 0, out, pos, padd.length);
|
||||
pos += padd.length;
|
||||
byte[] tmp = back(util.longToBytes(n));
|
||||
System.arraycopy(tmp, 0, out, pos, tmp.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组逆序
|
||||
*
|
||||
*/
|
||||
private static byte[] back(byte[] in)
|
||||
{
|
||||
byte[] out = new byte[in.length];
|
||||
for (int i = 0; i < out.length; i++)
|
||||
{
|
||||
out[i] = in[out.length - i - 1];
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public static int rotateLeft(int x, int n)
|
||||
{
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
private static int bitCycleLeft(int n, int bitLen)
|
||||
{
|
||||
bitLen %= 32;
|
||||
byte[] tmp = bigEndianIntToByte(n);
|
||||
int byteLen = bitLen / 8;
|
||||
int len = bitLen % 8;
|
||||
if (byteLen > 0)
|
||||
{
|
||||
tmp = byteCycleLeft(tmp, byteLen);
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
tmp = bitSmall8CycleLeft(tmp, len);
|
||||
}
|
||||
|
||||
return bigEndianByteToInt(tmp);
|
||||
}
|
||||
|
||||
private static byte[] bitSmall8CycleLeft(byte[] in, int len)
|
||||
{
|
||||
byte[] tmp = new byte[in.length];
|
||||
int t1, t2, t3;
|
||||
for (int i = 0; i < tmp.length; i++)
|
||||
{
|
||||
t1 = (byte) ((in[i] & 0x000000ff) << len);
|
||||
t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));
|
||||
t3 = (byte) (t1 | t2);
|
||||
tmp[i] = (byte) t3;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static byte[] byteCycleLeft(byte[] in, int byteLen)
|
||||
{
|
||||
byte[] tmp = new byte[in.length];
|
||||
System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);
|
||||
System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据完整性
|
||||
*
|
||||
* @param strPwd 加密面
|
||||
*/
|
||||
public static String getPasswordIntegrity(String strPwd) {
|
||||
String strResultPwd = null;
|
||||
//分割解密后的密码
|
||||
String[] tmpPwd = strPwd.split("\\|");
|
||||
if (tmpPwd.length == 2) {
|
||||
byte[] md = new byte[32];
|
||||
byte[] msg1 = tmpPwd[1].getBytes();
|
||||
Sm3Digest sm3 = new Sm3Digest();
|
||||
sm3.update(msg1, 0, msg1.length);
|
||||
sm3.doFinal(md, 0);
|
||||
//前台Sm3加密后的密码是否跟后台密码密码一致
|
||||
String tmpStrPwd = new String(Hex.encode(md));
|
||||
if (tmpPwd[0].equals(tmpStrPwd)) {
|
||||
//假如一致则密码未给破坏
|
||||
strResultPwd = tmpPwd[1];
|
||||
}
|
||||
}
|
||||
return strResultPwd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
public class Sm3Digest
|
||||
{
|
||||
/** SM3值的长度 */
|
||||
private static final int BYTE_LENGTH = 32;
|
||||
|
||||
/** SM3分组长度 */
|
||||
private static final int BLOCK_LENGTH = 64;
|
||||
|
||||
/** 缓冲区长度 */
|
||||
private static final int BUFFER_LENGTH = BLOCK_LENGTH;
|
||||
|
||||
/** 缓冲区 */
|
||||
private byte[] xBuf = new byte[BUFFER_LENGTH];
|
||||
|
||||
/** 缓冲区偏移量 */
|
||||
private int xBufOff;
|
||||
|
||||
/** 初始向量 */
|
||||
private byte[] V = Sm3.iv.clone();
|
||||
|
||||
private int cntBlock = 0;
|
||||
|
||||
public Sm3Digest() {
|
||||
}
|
||||
|
||||
public Sm3Digest(Sm3Digest t)
|
||||
{
|
||||
System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
|
||||
this.xBufOff = t.xBufOff;
|
||||
System.arraycopy(t.V, 0, this.V, 0, t.V.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* SM3结果输出
|
||||
*
|
||||
* @param out 保存SM3结构的缓冲区
|
||||
* @param outOff 缓冲区偏移量
|
||||
*/
|
||||
public int doFinal(byte[] out, int outOff)
|
||||
{
|
||||
byte[] tmp = doFinal();
|
||||
System.arraycopy(tmp, 0, out, 0, tmp.length);
|
||||
return BYTE_LENGTH;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
xBufOff = 0;
|
||||
cntBlock = 0;
|
||||
V = Sm3.iv.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 明文输入
|
||||
*
|
||||
* @param in
|
||||
* 明文输入缓冲区
|
||||
* @param inOff
|
||||
* 缓冲区偏移量
|
||||
* @param len
|
||||
* 明文长度
|
||||
*/
|
||||
public void update(byte[] in, int inOff, int len)
|
||||
{
|
||||
int partLen = BUFFER_LENGTH - xBufOff;
|
||||
int inputLen = len;
|
||||
int dPos = inOff;
|
||||
if (partLen < inputLen)
|
||||
{
|
||||
System.arraycopy(in, dPos, xBuf, xBufOff, partLen);
|
||||
inputLen -= partLen;
|
||||
dPos += partLen;
|
||||
doUpdate();
|
||||
while (inputLen > BUFFER_LENGTH)
|
||||
{
|
||||
System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH);
|
||||
inputLen -= BUFFER_LENGTH;
|
||||
dPos += BUFFER_LENGTH;
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);
|
||||
xBufOff += inputLen;
|
||||
}
|
||||
|
||||
private void doUpdate()
|
||||
{
|
||||
byte[] B = new byte[BLOCK_LENGTH];
|
||||
for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH)
|
||||
{
|
||||
System.arraycopy(xBuf, i, B, 0, B.length);
|
||||
doHash(B);
|
||||
}
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
private void doHash(byte[] B)
|
||||
{
|
||||
byte[] tmp = Sm3.CF(V, B);
|
||||
System.arraycopy(tmp, 0, V, 0, V.length);
|
||||
cntBlock++;
|
||||
}
|
||||
|
||||
private byte[] doFinal()
|
||||
{
|
||||
byte[] B = new byte[BLOCK_LENGTH];
|
||||
byte[] buffer = new byte[xBufOff];
|
||||
System.arraycopy(xBuf, 0, buffer, 0, buffer.length);
|
||||
byte[] tmp = Sm3.padding(buffer, cntBlock);
|
||||
for (int i = 0; i < tmp.length; i += BLOCK_LENGTH)
|
||||
{
|
||||
System.arraycopy(tmp, i, B, 0, B.length);
|
||||
doHash(B);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
public void update(byte in)
|
||||
{
|
||||
byte[] buffer = new byte[] { in };
|
||||
update(buffer, 0, 1);
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return BYTE_LENGTH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class Sm4
|
||||
{
|
||||
public static final int SM4_ENCRYPT = 1;
|
||||
|
||||
public static final int SM4_DECRYPT = 0;
|
||||
|
||||
private long GET_ULONG_BE(byte[] b, int i)
|
||||
{
|
||||
long n = (long)(b[i] & 0xff) << 24 | (long)((b[i + 1] & 0xff) << 16) | (long)((b[i + 2] & 0xff) << 8) | (long)(b[i + 3] & 0xff) & 0xffffffffL;
|
||||
return n;
|
||||
}
|
||||
|
||||
private void PUT_ULONG_BE(long n, byte[] b, int i)
|
||||
{
|
||||
b[i] = (byte)(int)(0xFF & n >> 24);
|
||||
b[i + 1] = (byte)(int)(0xFF & n >> 16);
|
||||
b[i + 2] = (byte)(int)(0xFF & n >> 8);
|
||||
b[i + 3] = (byte)(int)(0xFF & n);
|
||||
}
|
||||
|
||||
private long SHL(long x, int n)
|
||||
{
|
||||
return (x & 0xFFFFFFFF) << n;
|
||||
}
|
||||
|
||||
private long ROTL(long x, int n)
|
||||
{
|
||||
return SHL(x, n) | x >> (32 - n);
|
||||
}
|
||||
|
||||
private void SWAP(long[] sk, int i)
|
||||
{
|
||||
long t = sk[i];
|
||||
sk[i] = sk[(31 - i)];
|
||||
sk[(31 - i)] = t;
|
||||
}
|
||||
|
||||
public static final byte[] SboxTable = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
|
||||
(byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
|
||||
0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
|
||||
(byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
|
||||
(byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
|
||||
(byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
|
||||
(byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
|
||||
(byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
|
||||
(byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
|
||||
(byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
|
||||
0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
|
||||
(byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
|
||||
0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
|
||||
0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
|
||||
(byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
|
||||
(byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
|
||||
(byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
|
||||
(byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
|
||||
0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
|
||||
(byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
|
||||
(byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
|
||||
(byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
|
||||
(byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
|
||||
(byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
|
||||
0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
|
||||
(byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
|
||||
0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||
(byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
|
||||
(byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
|
||||
0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
|
||||
(byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
|
||||
0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
|
||||
(byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
|
||||
0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
|
||||
(byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
|
||||
(byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
|
||||
(byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
|
||||
0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
|
||||
(byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 };
|
||||
|
||||
public static final int[] FK = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };
|
||||
|
||||
public static final int[] CK = { 0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
|
||||
0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
|
||||
0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
|
||||
0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
|
||||
0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
|
||||
0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
|
||||
0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
|
||||
0x10171e25,0x2c333a41,0x484f565d,0x646b7279 };
|
||||
|
||||
private byte sm4Sbox(byte inch)
|
||||
{
|
||||
int i = inch & 0xFF;
|
||||
byte retVal = SboxTable[i];
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private long sm4Lt(long ka)
|
||||
{
|
||||
long bb = 0L;
|
||||
long c = 0L;
|
||||
byte[] a = new byte[4];
|
||||
byte[] b = new byte[4];
|
||||
PUT_ULONG_BE(ka, a, 0);
|
||||
b[0] = sm4Sbox(a[0]);
|
||||
b[1] = sm4Sbox(a[1]);
|
||||
b[2] = sm4Sbox(a[2]);
|
||||
b[3] = sm4Sbox(a[3]);
|
||||
bb = GET_ULONG_BE(b, 0);
|
||||
c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
|
||||
return c;
|
||||
}
|
||||
|
||||
private long sm4F(long x0, long x1, long x2, long x3, long rk)
|
||||
{
|
||||
return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
|
||||
}
|
||||
|
||||
private long sm4CalciRK(long ka)
|
||||
{
|
||||
long bb = 0L;
|
||||
long rk = 0L;
|
||||
byte[] a = new byte[4];
|
||||
byte[] b = new byte[4];
|
||||
PUT_ULONG_BE(ka, a, 0);
|
||||
b[0] = sm4Sbox(a[0]);
|
||||
b[1] = sm4Sbox(a[1]);
|
||||
b[2] = sm4Sbox(a[2]);
|
||||
b[3] = sm4Sbox(a[3]);
|
||||
bb = GET_ULONG_BE(b, 0);
|
||||
rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
|
||||
return rk;
|
||||
}
|
||||
|
||||
private void sm4_setkey(long[] SK, byte[] key)
|
||||
{
|
||||
long[] MK = new long[4];
|
||||
long[] k = new long[36];
|
||||
int i = 0;
|
||||
MK[0] = GET_ULONG_BE(key, 0);
|
||||
MK[1] = GET_ULONG_BE(key, 4);
|
||||
MK[2] = GET_ULONG_BE(key, 8);
|
||||
MK[3] = GET_ULONG_BE(key, 12);
|
||||
k[0] = MK[0] ^ (long) FK[0];
|
||||
k[1] = MK[1] ^ (long) FK[1];
|
||||
k[2] = MK[2] ^ (long) FK[2];
|
||||
k[3] = MK[3] ^ (long) FK[3];
|
||||
for (; i < 32; i++)
|
||||
{
|
||||
k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i]));
|
||||
SK[i] = k[(i + 4)];
|
||||
}
|
||||
}
|
||||
|
||||
private void sm4_one_round(long[] sk, byte[] input, byte[] output)
|
||||
{
|
||||
int i = 0;
|
||||
long[] ulbuf = new long[36];
|
||||
ulbuf[0] = GET_ULONG_BE(input, 0);
|
||||
ulbuf[1] = GET_ULONG_BE(input, 4);
|
||||
ulbuf[2] = GET_ULONG_BE(input, 8);
|
||||
ulbuf[3] = GET_ULONG_BE(input, 12);
|
||||
while (i < 32)
|
||||
{
|
||||
ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
|
||||
i++;
|
||||
}
|
||||
PUT_ULONG_BE(ulbuf[35], output, 0);
|
||||
PUT_ULONG_BE(ulbuf[34], output, 4);
|
||||
PUT_ULONG_BE(ulbuf[33], output, 8);
|
||||
PUT_ULONG_BE(ulbuf[32], output, 12);
|
||||
}
|
||||
|
||||
private byte[] padding(byte[] input, int mode)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] ret = (byte[]) null;
|
||||
if (mode == SM4_ENCRYPT)
|
||||
{
|
||||
int p = 16 - input.length % 16;
|
||||
ret = new byte[input.length + p];
|
||||
System.arraycopy(input, 0, ret, 0, input.length);
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
//ret[input.length + i] = (byte) p;
|
||||
ret[input.length + i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int p = input[input.length - 1];
|
||||
ret = new byte[input.length - p];
|
||||
System.arraycopy(input, 0, ret, 0, input.length - p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void sm4_setkey_enc(Sm4Context ctx, byte[] key) throws Exception
|
||||
{
|
||||
if (ctx == null)
|
||||
{
|
||||
throw new Exception("ctx is null!");
|
||||
}
|
||||
|
||||
if (key == null || key.length != 16)
|
||||
{
|
||||
throw new Exception("key error!");
|
||||
}
|
||||
|
||||
ctx.mode = SM4_ENCRYPT;
|
||||
sm4_setkey(ctx.sk, key);
|
||||
}
|
||||
|
||||
public void sm4_setkey_dec(Sm4Context ctx, byte[] key) throws Exception
|
||||
{
|
||||
if (ctx == null)
|
||||
{
|
||||
throw new Exception("ctx is null!");
|
||||
}
|
||||
|
||||
if (key == null || key.length != 16)
|
||||
{
|
||||
throw new Exception("key error!");
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
ctx.mode = SM4_DECRYPT;
|
||||
sm4_setkey(ctx.sk, key);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
SWAP(ctx.sk, i);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] sm4_crypt_ecb(Sm4Context ctx, byte[] input) throws Exception
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
throw new Exception("input is null!");
|
||||
}
|
||||
String str1=util.getHexString(input);
|
||||
if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT))
|
||||
{
|
||||
input = padding(input, SM4_ENCRYPT);
|
||||
}
|
||||
String str2=util.getHexString(input);
|
||||
int length = input.length;
|
||||
ByteArrayInputStream bins = new ByteArrayInputStream(input);
|
||||
ByteArrayOutputStream bous = new ByteArrayOutputStream();
|
||||
for(; length > 0; length -= 16)
|
||||
{
|
||||
byte[] in = new byte[16];
|
||||
byte[] out = new byte[16];
|
||||
bins.read(in);
|
||||
sm4_one_round(ctx.sk, in, out);
|
||||
bous.write(out);
|
||||
}
|
||||
|
||||
byte[] output = bous.toByteArray();
|
||||
if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
|
||||
{
|
||||
output = padding(output, SM4_DECRYPT);
|
||||
}
|
||||
bins.close();
|
||||
bous.close();
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] sm4_crypt_cbc(Sm4Context ctx, byte[] iv, byte[] input) throws Exception
|
||||
{
|
||||
if (iv == null || iv.length != 16)
|
||||
{
|
||||
throw new Exception("iv error!");
|
||||
}
|
||||
|
||||
if (input == null)
|
||||
{
|
||||
throw new Exception("input is null!");
|
||||
}
|
||||
|
||||
if (ctx.isPadding && ctx.mode == SM4_ENCRYPT)
|
||||
{
|
||||
input = padding(input, SM4_ENCRYPT);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int length = input.length;
|
||||
ByteArrayInputStream bins = new ByteArrayInputStream(input);
|
||||
ByteArrayOutputStream bous = new ByteArrayOutputStream();
|
||||
if (ctx.mode == SM4_ENCRYPT)
|
||||
{
|
||||
for(; length > 0; length -= 16)
|
||||
{
|
||||
byte[] in = new byte[16];
|
||||
byte[] out = new byte[16];
|
||||
byte[] out1 = new byte[16];
|
||||
|
||||
bins.read(in);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
out[i] = ((byte) (in[i] ^ iv[i]));
|
||||
}
|
||||
sm4_one_round(ctx.sk, out, out1);
|
||||
System.arraycopy(out1, 0, iv, 0, 16);
|
||||
bous.write(out1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] temp = new byte[16];
|
||||
for(; length > 0; length -= 16)
|
||||
{
|
||||
byte[] in = new byte[16];
|
||||
byte[] out = new byte[16];
|
||||
byte[] out1 = new byte[16];
|
||||
|
||||
bins.read(in);
|
||||
System.arraycopy(in, 0, temp, 0, 16);
|
||||
sm4_one_round(ctx.sk, in, out);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
out1[i] = ((byte) (out[i] ^ iv[i]));
|
||||
}
|
||||
System.arraycopy(temp, 0, iv, 0, 16);
|
||||
bous.write(out1);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] output = bous.toByteArray();
|
||||
if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
|
||||
{
|
||||
output = padding(output, SM4_DECRYPT);
|
||||
}
|
||||
bins.close();
|
||||
bous.close();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
public class Sm4Context
|
||||
{
|
||||
public int mode;
|
||||
|
||||
public long[] sk;
|
||||
|
||||
public boolean isPadding;
|
||||
|
||||
public Sm4Context()
|
||||
{
|
||||
this.mode = 1;
|
||||
this.isPadding = true;
|
||||
this.sk = new long[32];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
import sun.misc.BASE64Decoder;
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
public class Sm4Utils
|
||||
{
|
||||
private String secretKey = "";
|
||||
|
||||
private String iv = "";
|
||||
|
||||
private final boolean HEX_STRING = false;
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getIv() {
|
||||
return iv;
|
||||
}
|
||||
|
||||
public void setIv(String iv) {
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public Sm4Utils(String secretKey)
|
||||
{
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String encryptData_ECB(String plainText)
|
||||
{
|
||||
try
|
||||
{
|
||||
Sm4Context ctx = new Sm4Context();
|
||||
ctx.isPadding = true;
|
||||
ctx.mode = Sm4.SM4_ENCRYPT;
|
||||
|
||||
byte[] keyBytes;
|
||||
if (HEX_STRING)
|
||||
{
|
||||
keyBytes = util.hexStringToBytes(secretKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyBytes = secretKey.getBytes();
|
||||
}
|
||||
|
||||
Sm4 sm4 = new Sm4();
|
||||
sm4.sm4_setkey_enc(ctx, keyBytes);
|
||||
byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("GBK"));
|
||||
String cipherText = new BASE64Encoder().encode(encrypted);
|
||||
if (cipherText != null && cipherText.trim().length() > 0)
|
||||
{
|
||||
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
|
||||
Matcher m = p.matcher(cipherText);
|
||||
cipherText = m.replaceAll("");
|
||||
}
|
||||
return cipherText;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String decryptData_ECB(String cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
Sm4Context ctx = new Sm4Context();
|
||||
ctx.isPadding = true;
|
||||
ctx.mode = Sm4.SM4_DECRYPT;
|
||||
|
||||
byte[] keyBytes;
|
||||
if (HEX_STRING)
|
||||
{
|
||||
keyBytes = util.hexStringToBytes(secretKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyBytes = secretKey.getBytes();
|
||||
}
|
||||
|
||||
Sm4 sm4 = new Sm4();
|
||||
sm4.sm4_setkey_dec(ctx, keyBytes);
|
||||
byte[] decrypted = sm4.sm4_crypt_ecb(ctx, new BASE64Decoder().decodeBuffer(cipherText));
|
||||
return new String(decrypted, "GBK");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String encryptData_CBC(String plainText)
|
||||
{
|
||||
try
|
||||
{
|
||||
Sm4Context ctx = new Sm4Context();
|
||||
ctx.isPadding = true;
|
||||
ctx.mode = Sm4.SM4_ENCRYPT;
|
||||
|
||||
byte[] keyBytes;
|
||||
byte[] ivBytes;
|
||||
if (HEX_STRING)
|
||||
{
|
||||
keyBytes = util.hexStringToBytes(secretKey);
|
||||
ivBytes = util.hexStringToBytes(iv);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyBytes = secretKey.getBytes();
|
||||
ivBytes = iv.getBytes();
|
||||
}
|
||||
|
||||
Sm4 sm4 = new Sm4();
|
||||
sm4.sm4_setkey_enc(ctx, keyBytes);
|
||||
byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes("GBK"));
|
||||
String cipherText = new BASE64Encoder().encode(encrypted);
|
||||
if (cipherText != null && cipherText.trim().length() > 0)
|
||||
{
|
||||
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
|
||||
Matcher m = p.matcher(cipherText);
|
||||
cipherText = m.replaceAll("");
|
||||
}
|
||||
return cipherText;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String decryptData_CBC(String cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
Sm4Context ctx = new Sm4Context();
|
||||
ctx.isPadding = true;
|
||||
ctx.mode = Sm4.SM4_DECRYPT;
|
||||
|
||||
byte[] keyBytes;
|
||||
byte[] ivBytes;
|
||||
if (HEX_STRING)
|
||||
{
|
||||
keyBytes = util.hexStringToBytes(secretKey);
|
||||
ivBytes = util.hexStringToBytes(iv);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyBytes = secretKey.getBytes();
|
||||
ivBytes = iv.getBytes();
|
||||
}
|
||||
|
||||
Sm4 sm4 = new Sm4();
|
||||
sm4.sm4_setkey_dec(ctx, keyBytes);
|
||||
byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, new BASE64Decoder().decodeBuffer(cipherText));
|
||||
return new String(decrypted, "GBK");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
String plainText ="@#001njcnpqs";
|
||||
//11HDESaAhiHHugDz
|
||||
String secretKey = "11HDESaAhiHHug2z";
|
||||
Sm4Utils sm4 = new Sm4Utils(secretKey);
|
||||
|
||||
String cipherText = sm4.encryptData_ECB(plainText);
|
||||
String cipherText1 = sm4.decryptData_ECB(cipherText);
|
||||
cipherText = cipherText + "11HDESaAhiHHug2z";
|
||||
sm4.setSecretKey("11HDESaAhiHHug2z");
|
||||
cipherText = sm4.encryptData_ECB(cipherText);
|
||||
plainText = sm4.decryptData_ECB(cipherText);
|
||||
sm4.setIv("UISwD9fW6cFh9SNS");
|
||||
cipherText = sm4.encryptData_CBC(plainText);
|
||||
|
||||
plainText = sm4.decryptData_CBC(cipherText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,674 @@
|
||||
package com.njcn.common.utils.sm;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author yexibao
|
||||
*/
|
||||
public class util {
|
||||
|
||||
/**
|
||||
* 整形转换成网络传输的字节流(字节数组)型数据
|
||||
*
|
||||
* @param num 一个整型数据
|
||||
* @return 4个字节的自己数组
|
||||
*/
|
||||
public static byte[] intToBytes(int num)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte) (0xff & (num >> 0));
|
||||
bytes[1] = (byte) (0xff & (num >> 8));
|
||||
bytes[2] = (byte) (0xff & (num >> 16));
|
||||
bytes[3] = (byte) (0xff & (num >> 24));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 四个字节的字节数据转换成一个整形数据
|
||||
*
|
||||
* @param bytes 4个字节的字节数组
|
||||
* @return 一个整型数据
|
||||
*/
|
||||
public static int byteToInt(byte[] bytes)
|
||||
{
|
||||
int num = 0;
|
||||
int temp;
|
||||
temp = (0x000000ff & (bytes[0])) << 0;
|
||||
num = num | temp;
|
||||
temp = (0x000000ff & (bytes[1])) << 8;
|
||||
num = num | temp;
|
||||
temp = (0x000000ff & (bytes[2])) << 16;
|
||||
num = num | temp;
|
||||
temp = (0x000000ff & (bytes[3])) << 24;
|
||||
num = num | temp;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* 长整形转换成网络传输的字节流(字节数组)型数据
|
||||
*
|
||||
* @param num 一个长整型数据
|
||||
* @return 4个字节的自己数组
|
||||
*/
|
||||
public static byte[] longToBytes(long num)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
bytes[i] = (byte) (0xff & (num >> (i * 8)));
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 大数字转换字节流(字节数组)型数据
|
||||
*
|
||||
*/
|
||||
public static byte[] byteConvert32Bytes(BigInteger n)
|
||||
{
|
||||
byte tmpd[] = (byte[])null;
|
||||
if(n == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(n.toByteArray().length == 33)
|
||||
{
|
||||
tmpd = new byte[32];
|
||||
System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
|
||||
}
|
||||
else if(n.toByteArray().length == 32)
|
||||
{
|
||||
tmpd = n.toByteArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpd = new byte[32];
|
||||
for(int i = 0; i < 32 - n.toByteArray().length; i++)
|
||||
{
|
||||
tmpd[i] = 0;
|
||||
}
|
||||
System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
|
||||
}
|
||||
return tmpd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 换字节流(字节数组)型数据转大数字
|
||||
*
|
||||
* @param b
|
||||
* @return
|
||||
*/
|
||||
public static BigInteger byteConvertInteger(byte[] b)
|
||||
{
|
||||
if (b[0] < 0)
|
||||
{
|
||||
byte[] temp = new byte[b.length + 1];
|
||||
temp[0] = 0;
|
||||
System.arraycopy(b, 0, temp, 1, b.length);
|
||||
return new BigInteger(temp);
|
||||
}
|
||||
return new BigInteger(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字节数组获得值(十六进制数字)
|
||||
*
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
public static String getHexString(byte[] bytes)
|
||||
{
|
||||
return getHexString(bytes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字节数组获得值(十六进制数字)
|
||||
*
|
||||
* @param bytes
|
||||
* @param upperCase
|
||||
* @return
|
||||
*/
|
||||
public static String getHexString(byte[] bytes, boolean upperCase)
|
||||
{
|
||||
String ret = "";
|
||||
for (int i = 0; i < bytes.length; i++)
|
||||
{
|
||||
ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1);
|
||||
}
|
||||
return upperCase ? ret.toUpperCase() : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印十六进制字符串
|
||||
*
|
||||
* @param bytes
|
||||
*/
|
||||
public static void printHexString(byte[] bytes)
|
||||
{
|
||||
for (int i = 0; i < bytes.length; i++)
|
||||
{
|
||||
String hex = Integer.toHexString(bytes[i] & 0xFF);
|
||||
if (hex.length() == 1)
|
||||
{
|
||||
hex = '0' + hex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string to byte[]
|
||||
*
|
||||
* @param hexString
|
||||
* the hex string
|
||||
* @return byte[]
|
||||
*/
|
||||
public static byte[] hexStringToBytes(String hexString)
|
||||
{
|
||||
if (hexString == null || hexString.equals(""))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] d = new byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int pos = i * 2;
|
||||
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert char to byte
|
||||
*
|
||||
* @param c
|
||||
* char
|
||||
* @return byte
|
||||
*/
|
||||
public static byte charToByte(char c)
|
||||
{
|
||||
return (byte) "0123456789ABCDEF".indexOf(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于建立十六进制字符的输出的小写字符数组
|
||||
*/
|
||||
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
/**
|
||||
* 用于建立十六进制字符的输出的大写字符数组
|
||||
*/
|
||||
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符数组
|
||||
*
|
||||
* @param data byte[]
|
||||
* @return 十六进制char[]
|
||||
*/
|
||||
public static char[] encodeHex(byte[] data) {
|
||||
return encodeHex(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符数组
|
||||
*
|
||||
* @param data byte[]
|
||||
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
|
||||
* @return 十六进制char[]
|
||||
*/
|
||||
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
|
||||
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符数组
|
||||
*
|
||||
* @param data byte[]
|
||||
* @param toDigits 用于控制输出的char[]
|
||||
* @return 十六进制char[]
|
||||
*/
|
||||
protected static char[] encodeHex(byte[] data, char[] toDigits) {
|
||||
int l = data.length;
|
||||
char[] out = new char[l << 1];
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
|
||||
out[j++] = toDigits[0x0F & data[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符串
|
||||
*
|
||||
* @param data byte[]
|
||||
* @return 十六进制String
|
||||
*/
|
||||
public static String encodeHexString(byte[] data) {
|
||||
return encodeHexString(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符串
|
||||
*
|
||||
* @param data byte[]
|
||||
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
|
||||
* @return 十六进制String
|
||||
*/
|
||||
public static String encodeHexString(byte[] data, boolean toLowerCase) {
|
||||
return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符串
|
||||
*
|
||||
* @param data byte[]
|
||||
* @param toDigits 用于控制输出的char[]
|
||||
* @return 十六进制String
|
||||
*/
|
||||
protected static String encodeHexString(byte[] data, char[] toDigits) {
|
||||
return new String(encodeHex(data, toDigits));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将十六进制字符数组转换为字节数组
|
||||
*
|
||||
* @param data 十六进制char[]
|
||||
* @return byte[]
|
||||
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
|
||||
*/
|
||||
public static byte[] decodeHex(char[] data) {
|
||||
int len = data.length;
|
||||
|
||||
if ((len & 0x01) != 0) {
|
||||
throw new RuntimeException("Odd number of characters.");
|
||||
}
|
||||
|
||||
byte[] out = new byte[len >> 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; j < len; i++) {
|
||||
int f = toDigit(data[j], j) << 4;
|
||||
j++;
|
||||
f = f | toDigit(data[j], j);
|
||||
j++;
|
||||
out[i] = (byte) (f & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将十六进制字符转换成一个整数
|
||||
*
|
||||
* @param ch 十六进制char
|
||||
* @param index 十六进制字符在字符数组中的位置
|
||||
* @return 一个整数
|
||||
* @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
|
||||
*/
|
||||
protected static int toDigit(char ch, int index) {
|
||||
int digit = Character.digit(ch, 16);
|
||||
if (digit == -1) {
|
||||
throw new RuntimeException("Illegal hexadecimal character " + ch
|
||||
+ " at index " + index);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字字符串转ASCII码字符串
|
||||
*
|
||||
* @param content
|
||||
* 字符串
|
||||
* @return ASCII字符串
|
||||
*/
|
||||
public static String StringToAsciiString(String content) {
|
||||
String result = "";
|
||||
int max = content.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = content.charAt(i);
|
||||
String b = Integer.toHexString(c);
|
||||
result = result + b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 十六进制转字符串
|
||||
*
|
||||
* @param hexString
|
||||
* 十六进制字符串
|
||||
* @param encodeType
|
||||
* 编码类型4:Unicode,2:普通编码
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String hexStringToString(String hexString, int encodeType) {
|
||||
String result = "";
|
||||
int max = hexString.length() / encodeType;
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = (char) hexStringToAlgorism(hexString
|
||||
.substring(i * encodeType, (i + 1) * encodeType));
|
||||
result += c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 十六进制字符串装十进制
|
||||
*
|
||||
* @param hex
|
||||
* 十六进制字符串
|
||||
* @return 十进制数值
|
||||
*/
|
||||
public static int hexStringToAlgorism(String hex) {
|
||||
hex = hex.toUpperCase();
|
||||
int max = hex.length();
|
||||
int result = 0;
|
||||
for (int i = max; i > 0; i--) {
|
||||
char c = hex.charAt(i - 1);
|
||||
int algorism = 0;
|
||||
if (c >= '0' && c <= '9') {
|
||||
algorism = c - '0';
|
||||
} else {
|
||||
algorism = c - 55;
|
||||
}
|
||||
result += Math.pow(16, max - i) * algorism;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 十六转二进制
|
||||
*
|
||||
* @param hex
|
||||
* 十六进制字符串
|
||||
* @return 二进制字符串
|
||||
*/
|
||||
public static String hexStringToBinary(String hex) {
|
||||
hex = hex.toUpperCase();
|
||||
String result = "";
|
||||
int max = hex.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
char c = hex.charAt(i);
|
||||
switch (c) {
|
||||
case '0':
|
||||
result += "0000";
|
||||
break;
|
||||
case '1':
|
||||
result += "0001";
|
||||
break;
|
||||
case '2':
|
||||
result += "0010";
|
||||
break;
|
||||
case '3':
|
||||
result += "0011";
|
||||
break;
|
||||
case '4':
|
||||
result += "0100";
|
||||
break;
|
||||
case '5':
|
||||
result += "0101";
|
||||
break;
|
||||
case '6':
|
||||
result += "0110";
|
||||
break;
|
||||
case '7':
|
||||
result += "0111";
|
||||
break;
|
||||
case '8':
|
||||
result += "1000";
|
||||
break;
|
||||
case '9':
|
||||
result += "1001";
|
||||
break;
|
||||
case 'A':
|
||||
result += "1010";
|
||||
break;
|
||||
case 'B':
|
||||
result += "1011";
|
||||
break;
|
||||
case 'C':
|
||||
result += "1100";
|
||||
break;
|
||||
case 'D':
|
||||
result += "1101";
|
||||
break;
|
||||
case 'E':
|
||||
result += "1110";
|
||||
break;
|
||||
case 'F':
|
||||
result += "1111";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ASCII码字符串转数字字符串
|
||||
*
|
||||
* @param content
|
||||
* ASCII字符串
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String AsciiStringToString(String content) {
|
||||
String result = "";
|
||||
int length = content.length() / 2;
|
||||
for (int i = 0; i < length; i++) {
|
||||
String c = content.substring(i * 2, i * 2 + 2);
|
||||
int a = hexStringToAlgorism(c);
|
||||
char b = (char) a;
|
||||
String d = String.valueOf(b);
|
||||
result += d;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将十进制转换为指定长度的十六进制字符串
|
||||
*
|
||||
* @param algorism
|
||||
* int 十进制数字
|
||||
* @param maxLength
|
||||
* int 转换后的十六进制字符串长度
|
||||
* @return String 转换后的十六进制字符串
|
||||
*/
|
||||
public static String algorismToHexString(int algorism, int maxLength) {
|
||||
String result = "";
|
||||
result = Integer.toHexString(algorism);
|
||||
|
||||
if (result.length() % 2 == 1) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return patchHexString(result.toUpperCase(), maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转为普通字符串(ASCII对应的字符)
|
||||
*
|
||||
* @param bytearray
|
||||
* byte[]
|
||||
* @return String
|
||||
*/
|
||||
public static String byteToString(byte[] bytearray) {
|
||||
String result = "";
|
||||
char temp;
|
||||
|
||||
int length = bytearray.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
temp = (char) bytearray[i];
|
||||
result += temp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 二进制字符串转十进制
|
||||
*
|
||||
* @param binary
|
||||
* 二进制字符串
|
||||
* @return 十进制数值
|
||||
*/
|
||||
public static int binaryToAlgorism(String binary) {
|
||||
int max = binary.length();
|
||||
int result = 0;
|
||||
for (int i = max; i > 0; i--) {
|
||||
char c = binary.charAt(i - 1);
|
||||
int algorism = c - '0';
|
||||
result += Math.pow(2, max - i) * algorism;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 十进制转换为十六进制字符串
|
||||
*
|
||||
* @param algorism
|
||||
* int 十进制的数字
|
||||
* @return String 对应的十六进制字符串
|
||||
*/
|
||||
public static String algorismToHEXString(int algorism) {
|
||||
String result = "";
|
||||
result = Integer.toHexString(algorism);
|
||||
|
||||
if (result.length() % 2 == 1) {
|
||||
result = "0" + result;
|
||||
|
||||
}
|
||||
result = result.toUpperCase();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* HEX字符串前补0,主要用于长度位数不足。
|
||||
*
|
||||
* @param str
|
||||
* String 需要补充长度的十六进制字符串
|
||||
* @param maxLength
|
||||
* int 补充后十六进制字符串的长度
|
||||
* @return 补充结果
|
||||
*/
|
||||
static public String patchHexString(String str, int maxLength) {
|
||||
String temp = "";
|
||||
for (int i = 0; i < maxLength - str.length(); i++) {
|
||||
temp = "0" + temp;
|
||||
}
|
||||
str = (temp + str).substring(0, maxLength);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个字符串转换为int
|
||||
*
|
||||
* @param s
|
||||
* String 要转换的字符串
|
||||
* @param defaultInt
|
||||
* int 如果出现异常,默认返回的数字
|
||||
* @param radix
|
||||
* int 要转换的字符串是什么进制的,如16 8 10.
|
||||
* @return int 转换后的数字
|
||||
*/
|
||||
public static int parseToInt(String s, int defaultInt, int radix) {
|
||||
int i = 0;
|
||||
try {
|
||||
i = Integer.parseInt(s, radix);
|
||||
} catch (NumberFormatException ex) {
|
||||
i = defaultInt;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个十进制形式的数字字符串转换为int
|
||||
*
|
||||
* @param s
|
||||
* String 要转换的字符串
|
||||
* @param defaultInt
|
||||
* int 如果出现异常,默认返回的数字
|
||||
* @return int 转换后的数字
|
||||
*/
|
||||
public static int parseToInt(String s, int defaultInt) {
|
||||
int i = 0;
|
||||
try {
|
||||
i = Integer.parseInt(s);
|
||||
} catch (NumberFormatException ex) {
|
||||
i = defaultInt;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* 十六进制串转化为byte数组
|
||||
*
|
||||
* @return the array of byte
|
||||
*/
|
||||
public static byte[] hexToByte(String hex)
|
||||
throws IllegalArgumentException {
|
||||
if (hex.length() % 2 != 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
char[] arr = hex.toCharArray();
|
||||
byte[] b = new byte[hex.length() / 2];
|
||||
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
|
||||
String swap = "" + arr[i++] + arr[i];
|
||||
int byteint = Integer.parseInt(swap, 16) & 0xFF;
|
||||
b[j] = new Integer(byteint).byteValue();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数组转换为十六进制字符串
|
||||
*
|
||||
* @param b
|
||||
* byte[] 需要转换的字节数组
|
||||
* @return String 十六进制字符串
|
||||
*/
|
||||
public static String byteToHex(byte b[]) {
|
||||
if (b == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Argument b ( byte array ) is null! ");
|
||||
}
|
||||
String hs = "";
|
||||
String stmp = "";
|
||||
for (int n = 0; n < b.length; n++) {
|
||||
stmp = Integer.toHexString(b[n] & 0xff);
|
||||
if (stmp.length() == 1) {
|
||||
hs = hs + "0" + stmp;
|
||||
} else {
|
||||
hs = hs + stmp;
|
||||
}
|
||||
}
|
||||
return hs.toUpperCase();
|
||||
}
|
||||
|
||||
public static byte[] subByte(byte[] input, int startIndex, int length) {
|
||||
byte[] bt = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
bt[i] = input[i + startIndex];
|
||||
}
|
||||
return bt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 二进制字符串转换为byte数组,每个字节以","隔开
|
||||
* **/
|
||||
public static byte[] conver2HexToByte(String hex2Str) {
|
||||
byte [] b = new byte[hex2Str.length()/8];
|
||||
for (int i = 0; i < b.length ; i++) {
|
||||
b[i] = Long.valueOf(hex2Str.substring(i*8, (i+1)*8), 2).byteValue();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
package com.njcn.common.utils.wave;
|
||||
|
||||
public class BitConverter {
|
||||
|
||||
/**
|
||||
* byte数组转换为无符号short整数
|
||||
* @param bytes byte数组
|
||||
* @param off 开始位置
|
||||
* @return short整数
|
||||
*/
|
||||
public static short byte2ToUnsignedShort(byte[] bytes, int off) {
|
||||
int low = bytes[off]& 0xFF;
|
||||
int high = bytes[off + 1]& 0xFF;
|
||||
return (short)(((high & 0x00FF) << 8) | (0x00FF & low));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节转换为浮点
|
||||
*
|
||||
* @param b 字节(至少4个字节)
|
||||
* @param index 开始位置
|
||||
* @return
|
||||
*/
|
||||
public static float byte4float(byte[] b, int index) {
|
||||
/* b=new byte[4];
|
||||
b[0]=-16;
|
||||
b[1]=-1;
|
||||
b[2]=117;
|
||||
b[3]=66;*/
|
||||
|
||||
int l;
|
||||
l = b[index + 0];
|
||||
l &= 0xff;
|
||||
l |= ((long) b[index + 1] << 8);
|
||||
l &= 0xffff;
|
||||
l |= ((long) b[index + 2] << 16);
|
||||
l &= 0xffffff;
|
||||
l |= ((long) b[index + 3] << 24);
|
||||
return Float.intBitsToFloat(l);
|
||||
}
|
||||
/**
|
||||
* byte数组转换为int32整数
|
||||
* @param bytes byte数组
|
||||
* @param off 开始位置
|
||||
* @return int整数
|
||||
*/
|
||||
public static int byte4ToInt(byte[] bytes, int off) {
|
||||
int b0 = bytes[off] & 0xFF;
|
||||
int b1 = bytes[off + 1] & 0xFF;
|
||||
int b2 = bytes[off + 2] & 0xFF;
|
||||
int b3 = bytes[off + 3] & 0xFF;
|
||||
return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换为int16整数
|
||||
* @param bytes byte数组
|
||||
* @param off 开始位置
|
||||
* @return int整数
|
||||
*/
|
||||
public static int byte2ToInt(byte[] bytes, int off) {
|
||||
int b0 = bytes[off] & 0xFF;
|
||||
int b1 = bytes[off + 1] & 0xFF;
|
||||
return (b1 << 8) | b0;
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换为int16整数
|
||||
* @param bytes byte数组
|
||||
* @param off 开始位置
|
||||
* @return int整数
|
||||
*/
|
||||
public static long byte4ToLong(byte[] bytes, int off) {
|
||||
long b0 = bytes[off] & 0xFF;
|
||||
long b1 = bytes[off + 1] & 0xFF;
|
||||
long b2 = bytes[off + 2] & 0xFF;
|
||||
long b3 = bytes[off + 3] & 0xFF;
|
||||
|
||||
return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
|
||||
}
|
||||
}
|
||||
59
pqs-common/common-db/pom.xml
Normal file
59
pqs-common/common-db/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-db</artifactId>
|
||||
<name>聚合数据库的公共信息</name>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!--数据库相关********satrt-->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<!-- 排除默认的 HikariCP 数据源 -->
|
||||
<exclusion>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!--druid连接池-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!--mysql驱动-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--mybatis增强工具-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!--数据库相关********end-->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.njcn.db.bo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月13日 10:18
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.njcn.db.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.njcn.db.handler.AutoFillValueHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月14日 16:43
|
||||
*/
|
||||
@Configuration
|
||||
public class MybatisConfig {
|
||||
|
||||
/**
|
||||
* 分页插件
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 自定义公共字段自动填充
|
||||
*/
|
||||
@Bean
|
||||
public AutoFillValueHandler autoFillValueHandler() {
|
||||
return new AutoFillValueHandler();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.db.constant;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月20日 16:08
|
||||
*/
|
||||
public interface DbConstant {
|
||||
|
||||
/**
|
||||
* 正序标识
|
||||
*/
|
||||
String ASC = "asc";
|
||||
|
||||
/**
|
||||
* 倒序标识
|
||||
*/
|
||||
String DESC = "desc";
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.db.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.njcn.common.pojo.constant.LogInfo;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 数据自动填充处理器
|
||||
*
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月14日 16:36
|
||||
*/
|
||||
|
||||
public class AutoFillValueHandler implements MetaObjectHandler {
|
||||
|
||||
private static final String CREATE_USER = "createBy";
|
||||
|
||||
private static final String CREATE_TIME = "createTime";
|
||||
|
||||
private static final String UPDATE_USER = "updateBy";
|
||||
|
||||
private static final String UPDATE_TIME = "updateTime";
|
||||
|
||||
|
||||
/**
|
||||
* 执行元数据需要插入的值添加
|
||||
*/
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, CREATE_TIME, LocalDateTime::now, LocalDateTime.class);
|
||||
this.strictInsertFill(metaObject, CREATE_USER, RequestUtil::getUserIndex, String.class);
|
||||
this.strictInsertFill(metaObject, UPDATE_TIME, LocalDateTime::now, LocalDateTime.class);
|
||||
this.strictInsertFill(metaObject, UPDATE_USER, RequestUtil::getUserIndex, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行元数据需要更新的数据更新
|
||||
*/
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, UPDATE_USER, RequestUtil::getUserIndex, String.class);
|
||||
this.strictUpdateFill(metaObject, UPDATE_TIME, LocalDateTime::now, LocalDateTime.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.njcn.db.config.MybatisConfig
|
||||
|
||||
|
||||
46
pqs-common/common-echarts/pom.xml
Normal file
46
pqs-common/common-echarts/pom.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-echarts</artifactId>
|
||||
<name>echart绘图服务</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-microservice</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.abel533</groupId>
|
||||
<artifactId>ECharts</artifactId>
|
||||
</dependency>
|
||||
<!-- echarts绘图所需,可以将包含function的对象转为json -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.njcn.echarts;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.github.abel533.echarts.code.Tool;
|
||||
import com.github.abel533.echarts.code.Trigger;
|
||||
import com.github.abel533.echarts.json.GsonOption;
|
||||
import com.github.abel533.echarts.series.Line;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月02日 18:59
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestUtil {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
JSONObject s = testEchart();
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
ResponseEntity<HttpResult> forEntity = restTemplate.getForEntity("http://192.168.1.14:8910?opt={1}", HttpResult.class,s.toString());
|
||||
|
||||
System.out.println(forEntity.getBody().getData());
|
||||
|
||||
System.out.println(1);
|
||||
|
||||
}
|
||||
|
||||
public static JSONObject testEchart() {
|
||||
String[] types = {"ECS", "实例", "CPU", "MEM"};
|
||||
int[][] datas = {
|
||||
{120, 132, 101, 134, 90, 230, 210},
|
||||
{220, 182, 191, 234, 290, 330, 310},
|
||||
{150, 232, 201, 154, 190, 330, 410},
|
||||
{150, 232, 201, 154, 190, 330, 410}
|
||||
};
|
||||
String title = "资源增长情况";
|
||||
GsonOption option = new GsonOption();
|
||||
option.title().text(title).x("left");// 大标题、位置
|
||||
// 提示工具
|
||||
option.tooltip().trigger(Trigger.axis);// 在轴上触发提示数据
|
||||
// 工具栏
|
||||
option.toolbox().show(true).feature(Tool.saveAsImage);// 显示,保存为图片
|
||||
option.legend(types);// 图例
|
||||
com.github.abel533.echarts.axis.CategoryAxis category = new com.github.abel533.echarts.axis.CategoryAxis();// 轴分类
|
||||
category.data("2019-03-09", "2019-03-02", "2019-03-16");
|
||||
category.boundaryGap(false);// 起始和结束两端空白策略
|
||||
//循环数据
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
Line line = new Line();// 三条线,三个对象
|
||||
String type = types[i];
|
||||
line.name(type).stack("总量");
|
||||
for (int j = 0; j < datas[i].length; j++) {
|
||||
line.data(datas[i][j]);
|
||||
}
|
||||
option.series(line);
|
||||
}
|
||||
if (true) {// 横轴为类别、纵轴为值
|
||||
option.xAxis(category);// x轴
|
||||
// y轴
|
||||
com.github.abel533.echarts.axis.ValueAxis ecsY = new com.github.abel533.echarts.axis.ValueAxis();
|
||||
ecsY.name("ECS 台").position("left").axisLine().lineStyle().color("#1E90FF");
|
||||
option.yAxis(ecsY);
|
||||
} else {// 横轴为值、纵轴为类别
|
||||
option.xAxis(new com.github.abel533.echarts.axis.ValueAxis());// x轴
|
||||
option.yAxis(category);// y轴
|
||||
}
|
||||
|
||||
String optionStr = option.toString().replace(" ", "");
|
||||
System.out.println(optionStr);
|
||||
JSONObject jsonObject = new JSONObject(optionStr);
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
44
pqs-common/common-influxdb/pom.xml
Normal file
44
pqs-common/common-influxdb/pom.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>common-influxDB</artifactId>
|
||||
<name>influxDB公共服务信息</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.influxdb</groupId>
|
||||
<artifactId>influxdb-java</artifactId>
|
||||
<version>${influxdb-java.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>event-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.influxdb.config;
|
||||
|
||||
import com.njcn.influxdb.utils.InfluxDbUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 类的介绍:
|
||||
*
|
||||
* @author xuyang
|
||||
* @version 1.0.0
|
||||
* @createTime 2021/12/10 10:48
|
||||
*/
|
||||
@Configuration
|
||||
public class InfluxDbConfig {
|
||||
|
||||
@Value("${spring.influx.url:''}")
|
||||
private String influxDBUrl;
|
||||
|
||||
@Value("${spring.influx.user:''}")
|
||||
private String userName;
|
||||
|
||||
@Value("${spring.influx.password:''}")
|
||||
private String password;
|
||||
|
||||
@Value("${spring.influx.database:''}")
|
||||
private String database;
|
||||
|
||||
@Bean
|
||||
public InfluxDbUtils influxDbUtils() {
|
||||
return new InfluxDbUtils(userName, password, influxDBUrl, database, "autogen");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
package com.njcn.influxdb.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.influxdb.InfluxDB;
|
||||
import org.influxdb.InfluxDB.ConsistencyLevel;
|
||||
import org.influxdb.InfluxDBFactory;
|
||||
import org.influxdb.dto.*;
|
||||
import org.influxdb.dto.Point.Builder;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 类的介绍:
|
||||
*
|
||||
* @author xuyang
|
||||
* @version 1.0.0
|
||||
* @createTime 2021/11/16 10:20
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
public class InfluxDbUtils {
|
||||
|
||||
/**用户名*/
|
||||
private String username;
|
||||
/**密码*/
|
||||
private String password;
|
||||
/**链接地址*/
|
||||
private String openurl;
|
||||
/**数据库*/
|
||||
private String dbName;
|
||||
/**保留策略*/
|
||||
private String retentionPolicy;
|
||||
|
||||
private InfluxDB influxDB;
|
||||
|
||||
public InfluxDbUtils(String username, String password, String url, String dbName, String retentionPolicy) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.openurl = url;
|
||||
this.dbName = dbName;
|
||||
this.retentionPolicy = retentionPolicy == null || retentionPolicy.equals("") ? "autogen" : retentionPolicy;
|
||||
influxDbBuild();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 连接时序数据库 ,若不存在则创建
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public InfluxDB influxDbBuild() {
|
||||
if (influxDB == null) {
|
||||
influxDB = InfluxDBFactory.connect(openurl, username, password);
|
||||
}
|
||||
try {
|
||||
// if (!influxDB.databaseExists(database)) {
|
||||
// influxDB.createDatabase(database);
|
||||
// }
|
||||
} catch (Exception e) {
|
||||
// 该数据库可能设置动态代理,不支持创建数据库
|
||||
// e.printStackTrace();
|
||||
} finally {
|
||||
influxDB.setRetentionPolicy(retentionPolicy);
|
||||
}
|
||||
influxDB.setLogLevel(InfluxDB.LogLevel.NONE);
|
||||
return influxDB;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建数据库
|
||||
*
|
||||
* @param dbName
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void createDB(String dbName) {
|
||||
influxDB.createDatabase(dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据库
|
||||
*
|
||||
* @param dbName
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void deleteDB(String dbName) {
|
||||
influxDB.deleteDatabase(dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试连接是否正常
|
||||
*
|
||||
* @return true 正常
|
||||
*/
|
||||
public boolean ping() {
|
||||
boolean isConnected = false;
|
||||
Pong pong;
|
||||
try {
|
||||
pong = influxDB.ping();
|
||||
if (pong != null) {
|
||||
isConnected = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义保留策略
|
||||
*
|
||||
* @param policyName 策略名
|
||||
* @param days 保存天数
|
||||
* @param replication 保存副本数量
|
||||
* @param isDefault 是否设为默认保留策略
|
||||
*/
|
||||
public void createRetentionPolicy(String dataBaseName, String policyName, int days, int replication,
|
||||
Boolean isDefault) {
|
||||
String sql = String.format("CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %sd REPLICATION %s ", policyName,
|
||||
dataBaseName, days, replication);
|
||||
if (isDefault) {
|
||||
sql = sql + " DEFAULT";
|
||||
}
|
||||
query(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认的保留策略
|
||||
*
|
||||
* 策略名:hour,保存天数:30天,保存副本数量:1,设为默认保留策略
|
||||
*/
|
||||
public void createDefaultRetentionPolicy() {
|
||||
String command = String
|
||||
.format("CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %s REPLICATION %s DEFAULT", "hour", dbName,
|
||||
"30d", 1);
|
||||
this.query(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*
|
||||
* @param command 查询语句
|
||||
* @return
|
||||
*/
|
||||
public QueryResult query(String command) {
|
||||
return influxDB.query(new Query(command, dbName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入
|
||||
*
|
||||
* @param measurement 表
|
||||
* @param tags 标签
|
||||
* @param fields 字段
|
||||
*/
|
||||
public void insert(String measurement, Map<String, String> tags, Map<String, Object> fields, long time,
|
||||
TimeUnit timeUnit) {
|
||||
Builder builder = Point.measurement(measurement);
|
||||
builder.tag(tags);
|
||||
builder.fields(fields);
|
||||
if (0 != time) {
|
||||
time = time + 28800000;
|
||||
builder.time(time, timeUnit);
|
||||
}
|
||||
influxDB.write(dbName, retentionPolicy, builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量写入测点
|
||||
*
|
||||
* @param batchPoints
|
||||
*/
|
||||
public void batchInsert(BatchPoints batchPoints, TimeUnit timeUnit) {
|
||||
influxDB.write(batchPoints);
|
||||
// influxDB.enableGzip();
|
||||
// influxDB.enableBatch(2000,100,timeUnit);
|
||||
// influxDB.disableGzip();
|
||||
// influxDB.disableBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量写入数据
|
||||
*
|
||||
* @param database 数据库
|
||||
* @param retentionPolicy 保存策略
|
||||
* @param consistency 一致性
|
||||
* @param records 要保存的数据(调用BatchPoints.lineProtocol()可得到一条record)
|
||||
*/
|
||||
public void batchInsert(final String database, final String retentionPolicy, final ConsistencyLevel consistency,TimeUnit timeUnit, final List<String> records) {
|
||||
influxDB.write(database, retentionPolicy, consistency, records);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量写入数据
|
||||
*
|
||||
* @param database 数据库
|
||||
* @param retentionPolicy 保存策略
|
||||
* @param consistency 一致性
|
||||
* @param records 要保存的数据(调用BatchPoints.lineProtocol()可得到一条record)
|
||||
*/
|
||||
public void batchInsert(final String database, final String retentionPolicy, final ConsistencyLevel consistency, final List<String> records) {
|
||||
influxDB.write(database, retentionPolicy, consistency, records);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param command 删除语句
|
||||
* @return 返回错误信息
|
||||
*/
|
||||
public String deleteMeasurementData(String command) {
|
||||
QueryResult result = influxDB.query(new Query(command, dbName));
|
||||
return result.getError();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
*/
|
||||
public void close() {
|
||||
influxDB.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建Point
|
||||
*
|
||||
* @param measurement
|
||||
* @param time
|
||||
* @param fields
|
||||
* @return
|
||||
*/
|
||||
public Point pointBuilder(String measurement, long time, TimeUnit timeUnit, Map<String, String> tags,
|
||||
Map<String, Object> fields) {
|
||||
Point point = Point.measurement(measurement).time(time, timeUnit).tag(tags).fields(fields).build();
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//单条查询语句封装
|
||||
/**
|
||||
* 查询结果封装到map
|
||||
* @param commond 单条sql语句
|
||||
* @return 查询结果
|
||||
*/
|
||||
public List<Map<String, Object>> getResult(String commond){
|
||||
List<Map<String, Object>> retList = new ArrayList<>();
|
||||
QueryResult queryResult = influxDB.query(new Query(commond,dbName));
|
||||
List<QueryResult.Result> results = queryResult.getResults();
|
||||
if (results==null||results.isEmpty()){
|
||||
return retList;
|
||||
}
|
||||
QueryResult.Result result = results.get(0);
|
||||
List<QueryResult.Series> seriess = result.getSeries();
|
||||
if (seriess==null||seriess.isEmpty()){
|
||||
return retList;
|
||||
}
|
||||
QueryResult.Series series = seriess.get(0);
|
||||
List<String> columns = series.getColumns();
|
||||
List<List<Object>> values = series.getValues();
|
||||
for (List<Object> columnValue :values){
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
for (int i=0;i<columnValue.size();i++){
|
||||
if(columns.get(i).equals("time")){
|
||||
long aa = Instant.parse(columnValue.get(i).toString()).minusMillis(TimeUnit.HOURS.toMillis(8)).getEpochSecond();
|
||||
map.put(columns.get(i), aa);
|
||||
}else {
|
||||
map.put(columns.get(i),columnValue.get(i));
|
||||
}
|
||||
}
|
||||
retList.add(map);
|
||||
}
|
||||
return retList;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResult(String commond, String type){
|
||||
|
||||
List<Map<String, Object>> retList = new ArrayList<>();
|
||||
QueryResult queryResult = influxDB.query(new Query(commond,dbName));
|
||||
List<QueryResult.Result> results = queryResult.getResults();
|
||||
if (results==null||results.isEmpty()){
|
||||
return retList;
|
||||
}
|
||||
QueryResult.Result result = results.get(0);
|
||||
List<QueryResult.Series> seriess = result.getSeries();
|
||||
if (seriess==null||seriess.isEmpty()){
|
||||
return retList;
|
||||
}
|
||||
QueryResult.Series series = seriess.get(0);
|
||||
List<String> columns = series.getColumns();
|
||||
List<List<Object>> values = series.getValues();
|
||||
for (List<Object> columnValue :values){
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
for (int i=0;i<columnValue.size();i++){
|
||||
if(columns.get(i).equals("time")){
|
||||
Instant aa = Instant.parse(columnValue.get(i).toString()).minusMillis(TimeUnit.HOURS.toMillis(8));
|
||||
LocalDateTime localDateTime =LocalDateTime.ofInstant(aa,ZoneId.systemDefault());
|
||||
String time = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
map.put(columns.get(i), time);
|
||||
}else {
|
||||
map.put(columns.get(i),columnValue.get(i));
|
||||
}
|
||||
}
|
||||
retList.add(map);
|
||||
}
|
||||
return retList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
204
pqs-common/common-influxdb/src/test/java/test.java
Normal file
204
pqs-common/common-influxdb/src/test/java/test.java
Normal file
@@ -0,0 +1,204 @@
|
||||
import com.njcn.influxdb.utils.InfluxDbUtils;
|
||||
import org.influxdb.InfluxDB.ConsistencyLevel;
|
||||
import org.influxdb.dto.BatchPoints;
|
||||
import org.influxdb.dto.Point;
|
||||
import org.influxdb.dto.QueryResult;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 类的介绍:
|
||||
*
|
||||
* @author xuyang
|
||||
* @version 1.0.0
|
||||
* @createTime 2021/11/16 11:07
|
||||
*/
|
||||
|
||||
public class test {
|
||||
|
||||
//查询
|
||||
public static QueryResult select(InfluxDbUtils influxDBUtil) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
QueryResult result = influxDBUtil.query("select * from data_V where phasic_type='A'");
|
||||
long endTime = System.currentTimeMillis();
|
||||
System.out.println(endTime - startTime);
|
||||
return result;
|
||||
}
|
||||
|
||||
//处理结果集
|
||||
public static void chanelResult(QueryResult result) {
|
||||
QueryResult.Result result1 = result.getResults().get(0);
|
||||
if (result1.getSeries() != null) {
|
||||
List<List<Object>> valueList = result1.getSeries().stream().map(QueryResult.Series::getValues).collect(Collectors.toList()).get(0);
|
||||
if (valueList != null && valueList.size() > 0) {
|
||||
for (List<Object> value : valueList) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
// 数据库中字段1取值
|
||||
String field1 = value.get(0) == null ? null : value.get(0).toString();
|
||||
System.out.println(field1);
|
||||
// 数据库中字段2取值
|
||||
String field2 = value.get(1) == null ? null : value.get(1).toString();
|
||||
System.out.println(field2);
|
||||
// TODO 用取出的字段做你自己的业务逻辑……
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
InfluxDbUtils influxDBUtil = new InfluxDbUtils("root", "123456789", "http://192.168.1.16:8086", "pqsbase", "");
|
||||
insert(influxDBUtil);
|
||||
}
|
||||
//单条数据插入
|
||||
public static void insert(InfluxDbUtils influxDBUtil) {
|
||||
Map<String, String> tags = new HashMap<>();
|
||||
tags.put("lineid", "1e3b8531483b2a8cbee6747f1f641cf9");
|
||||
Map<String, Object> fields = new HashMap<>();
|
||||
fields.put("phasic_type","T");
|
||||
fields.put("value_type","MAX");
|
||||
fields.put("Freq_Dev", 48.6 );
|
||||
fields.put("Voltage_Dev", 8.3 );
|
||||
fields.put("UBalance", 7.6 );
|
||||
fields.put("Flicker", 4.6 );
|
||||
fields.put("UAberrance", 6.5 );
|
||||
fields.put("I_Neg", 5.6 );
|
||||
fields.put("UHarm_2", 6.8 );
|
||||
fields.put("UHarm_3", 5.5 );
|
||||
fields.put("UHarm_4", 5.4 );
|
||||
fields.put("UHarm_5", 7.8 );
|
||||
fields.put("UHarm_6", 6.2 );
|
||||
fields.put("UHarm_7", 2.5 );
|
||||
fields.put("UHarm_8", 8.3 );
|
||||
fields.put("UHarm_9", 6.2 );
|
||||
fields.put("UHarm_10", 12.8 );
|
||||
fields.put("UHarm_11", 2.8 );
|
||||
fields.put("UHarm_12", 8.4 );
|
||||
fields.put("UHarm_13", 5.6 );
|
||||
fields.put("UHarm_14", 5.2 );
|
||||
fields.put("UHarm_15", 9.5 );
|
||||
fields.put("UHarm_16", 8.3 );
|
||||
fields.put("UHarm_17", 7.8 );
|
||||
fields.put("UHarm_18", 6.2 );
|
||||
fields.put("UHarm_19", 2.5);
|
||||
fields.put("UHarm_20", 4.5 );
|
||||
fields.put("UHarm_21", 4.5 );
|
||||
fields.put("UHarm_22", 6.5 );
|
||||
fields.put("UHarm_23", 5.9 );
|
||||
fields.put("UHarm_24", 9.2 );
|
||||
fields.put("UHarm_25", 5.8 );
|
||||
fields.put("IHarm_2", 12.8 );
|
||||
fields.put("IHarm_3", 5.4 );
|
||||
fields.put("IHarm_4", 6.2 );
|
||||
fields.put("IHarm_5", 3.2 );
|
||||
fields.put("IHarm_6", 5.2 );
|
||||
fields.put("IHarm_7", 5.2 );
|
||||
fields.put("IHarm_8", 5.5 );
|
||||
fields.put("IHarm_9", 4.8 );
|
||||
fields.put("IHarm_10", 8.2 );
|
||||
fields.put("IHarm_11", 2.5 );
|
||||
fields.put("IHarm_12", 8.6 );
|
||||
fields.put("IHarm_13", 5.8 );
|
||||
fields.put("IHarm_14", 3.5 );
|
||||
fields.put("IHarm_15", 2.4 );
|
||||
fields.put("IHarm_16", 5.2 );
|
||||
fields.put("IHarm_17", 2.5 );
|
||||
fields.put("IHarm_18", 9.2 );
|
||||
fields.put("IHarm_19", 8.5);
|
||||
fields.put("IHarm_20", 8.5 );
|
||||
fields.put("IHarm_21", 6.2 );
|
||||
fields.put("IHarm_22", 5.2 );
|
||||
fields.put("IHarm_23", 8.5 );
|
||||
fields.put("IHarm_24", 5.2 );
|
||||
fields.put("IHarm_25", 8.4 );
|
||||
fields.put("InUHARM_1", 8.2 );
|
||||
fields.put("InUHARM_2", 5.2 );
|
||||
fields.put("InUHARM_3", 6.2 );
|
||||
fields.put("InUHARM_4", 4.2 );
|
||||
fields.put("InUHARM_5", 2.3 );
|
||||
fields.put("InUHARM_6", 6.2 );
|
||||
fields.put("InUHARM_7", 5.2 );
|
||||
fields.put("InUHARM_8", 10.2 );
|
||||
fields.put("InUHARM_9", 2.3 );
|
||||
fields.put("InUHARM_10", 4.2 );
|
||||
fields.put("InUHARM_11", 3.5 );
|
||||
fields.put("InUHARM_12", 3.6 );
|
||||
fields.put("InUHARM_13", 2.3 );
|
||||
fields.put("InUHARM_14", 7.2 );
|
||||
fields.put("InUHARM_15", 5.6 );
|
||||
fields.put("InUHARM_16", 5.6 );
|
||||
influxDBUtil.insert("PQS_AbnormalData", tags, fields, System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
//循环写入数据库
|
||||
public static void batchInsertOne(InfluxDbUtils influxDBUtil) {
|
||||
Map<String, String> tags1 = new HashMap<>();
|
||||
tags1.put("LineID", "8");
|
||||
tags1.put("Phasic_Type", "A");
|
||||
Map<String, Object> fields1 = new HashMap<>();
|
||||
fields1.put("RMS", 2);
|
||||
fields1.put("RMS_AB", 2);
|
||||
fields1.put("RMS_BC", 2);
|
||||
fields1.put("RMS_CA", 2);
|
||||
Map<String, String> tags2 = new HashMap<>();
|
||||
tags2.put("LineID", "9");
|
||||
tags2.put("Phasic_Type", "A");
|
||||
Map<String, Object> fields2 = new HashMap<>();
|
||||
fields2.put("RMS", 4);
|
||||
fields2.put("RMS_AB", 4);
|
||||
fields2.put("RMS_BC", 4);
|
||||
fields2.put("RMS_CA", 4);
|
||||
// 一条记录值
|
||||
Point point1 = influxDBUtil.pointBuilder("test", System.currentTimeMillis(), TimeUnit.MILLISECONDS, tags1, fields1);
|
||||
Point point2 = influxDBUtil.pointBuilder("test", System.currentTimeMillis(), TimeUnit.MILLISECONDS, tags2, fields2);
|
||||
// 将两条记录添加到batchPoints中
|
||||
BatchPoints batchPoints1 = BatchPoints.database("test").tag("LineID", "8").tag("Phasic_Type", "A").retentionPolicy("")
|
||||
.consistency(ConsistencyLevel.ALL).build();
|
||||
BatchPoints batchPoints2 = BatchPoints.database("test").tag("LineID", "9").tag("Phasic_Type", "A").retentionPolicy("")
|
||||
.consistency(ConsistencyLevel.ALL).build();
|
||||
batchPoints1.point(point1);
|
||||
batchPoints2.point(point2);
|
||||
// 将两条数据批量插入到数据库中
|
||||
influxDBUtil.batchInsert(batchPoints1, TimeUnit.MILLISECONDS);
|
||||
influxDBUtil.batchInsert(batchPoints2, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
//批量插入数据
|
||||
public static void batchInsert(InfluxDbUtils influxDBUtil) {
|
||||
Map<String, String> tags1 = new HashMap<>();
|
||||
tags1.put("LineID", "4");
|
||||
tags1.put("Phasic_Type", "A");
|
||||
Map<String, Object> fields1 = new HashMap<>();
|
||||
fields1.put("RMS", 4.1111);
|
||||
fields1.put("RMS_AB", 4.1111);
|
||||
fields1.put("RMS_BC", 4.1111);
|
||||
fields1.put("RMS_CA", 4.1111);
|
||||
Map<String, String> tags2 = new HashMap<>();
|
||||
tags2.put("LineID", "5");
|
||||
tags2.put("Phasic_Type", "A");
|
||||
Map<String, Object> fields2 = new HashMap<>();
|
||||
fields2.put("RMS", 5.1111);
|
||||
fields2.put("RMS_AB", 5.1111);
|
||||
fields2.put("RMS_BC", 5.1111);
|
||||
fields2.put("RMS_CA", 5.1111);
|
||||
// 一条记录值。(注意:生产环境不要用System.currentTimeMillis(),因为数据量大会产生重复时间戳,导致数据丢失,要用数据自己的时间戳,这里只做演示)
|
||||
Point point1 = influxDBUtil.pointBuilder("Data_v", System.currentTimeMillis(), TimeUnit.MILLISECONDS, tags1, fields1);
|
||||
Point point2 = influxDBUtil.pointBuilder("Data_v", System.currentTimeMillis(), TimeUnit.MILLISECONDS, tags2, fields2);
|
||||
// BatchPoints batchPoints1 = BatchPoints.database("Data_v").tag("LineID", "4").tag("Phasic_Type","A").retentionPolicy("").consistency(ConsistencyLevel.ALL).precision(TimeUnit.MILLISECONDS).build();
|
||||
BatchPoints batchPoints1 = BatchPoints.database("test").tag("LineID", "4").tag("Phasic_Type", "A").retentionPolicy("").consistency(ConsistencyLevel.ALL).build();
|
||||
batchPoints1.point(point1);
|
||||
BatchPoints batchPoints2 = BatchPoints.database("test").tag("LineID", "5").tag("Phasic_Type", "A").retentionPolicy("").consistency(ConsistencyLevel.ALL).build();
|
||||
// 将两条记录添加到batchPoints中
|
||||
batchPoints2.point(point2);
|
||||
// 将不同的batchPoints序列化后,一次性写入数据库,提高写入速度
|
||||
List<String> records = new ArrayList<String>();
|
||||
records.add(batchPoints1.lineProtocol());
|
||||
records.add(batchPoints2.lineProtocol());
|
||||
// 将两条数据批量插入到数据库中
|
||||
influxDBUtil.batchInsert("test", "", ConsistencyLevel.ALL, TimeUnit.MILLISECONDS, records);
|
||||
}
|
||||
|
||||
}
|
||||
58
pqs-common/common-microservice/pom.xml
Normal file
58
pqs-common/common-microservice/pom.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-microservice</artifactId>
|
||||
<name>聚合spring cloud等微服务组件的公共信息</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!--springcloud alibaba nacos的服务发现-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<!--springcloud alibaba nacos的配置服务器-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
<!--服务调用-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
</dependency>
|
||||
<!--服务治理,熔断、降级等-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
36
pqs-common/common-poi/pom.xml
Normal file
36
pqs-common/common-poi/pom.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>common-poi</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.afterturn</groupId>
|
||||
<artifactId>easypoi-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.njcn.poi.excel;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.njcn.web.utils.HttpServletUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年04月01日 10:48
|
||||
*/
|
||||
@Slf4j
|
||||
public class ExcelUtil {
|
||||
|
||||
/**
|
||||
* 指定名称、数据下载报表
|
||||
*
|
||||
* @param fileName 文件名
|
||||
*/
|
||||
public static void exportExcel(String fileName, Class<?> pojoClass, Collection<?> dataSet) {
|
||||
HttpServletResponse response = HttpServletUtil.getResponse();
|
||||
try (ServletOutputStream outputStream = response.getOutputStream()) {
|
||||
fileName = URLEncoder.encode(fileName, CharsetUtil.UTF_8);
|
||||
response.reset();
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.setContentType("application/octet-stream;charset=UTF-8");
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), pojoClass, dataSet);
|
||||
workbook.write(outputStream);
|
||||
} catch (IOException e) {
|
||||
log.error(">>> 导出数据异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param excel 目标excel
|
||||
* @param statisticsType 统计类型
|
||||
* @param statisticsName 统计名称
|
||||
* @param pojoClass 目标class
|
||||
* @param dataSet 数据集合
|
||||
*/
|
||||
public static void exportExcelWithTargetFile(File excel, String statisticsType, String statisticsName, Class<?> pojoClass, Collection<?> dataSet) {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(excel)) {
|
||||
if (!excel.getParentFile().exists()) {
|
||||
excel.getParentFile().mkdirs();
|
||||
}
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(statisticsType, statisticsName), pojoClass, dataSet);
|
||||
workbook.write(outputStream);
|
||||
} catch (IOException e) {
|
||||
log.error(">>> 导出数据异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param excel 目标excel
|
||||
* @param pojoClass 目标class
|
||||
* @param dataSet 数据集合
|
||||
*/
|
||||
public static void exportExcelWithTargetFile(File excel, Class<?> pojoClass, Collection<?> dataSet) {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(excel)) {
|
||||
if (!excel.getParentFile().exists()) {
|
||||
excel.getParentFile().mkdirs();
|
||||
}
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), pojoClass, dataSet);
|
||||
workbook.write(outputStream);
|
||||
} catch (IOException e) {
|
||||
log.error(">>> 导出数据异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.poi.pojo.bo;
|
||||
|
||||
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||
import com.njcn.poi.pojo.constant.DeviceInfoConstant;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月31日 16:28
|
||||
*/
|
||||
@Data
|
||||
public class BaseLineExcelBody implements Serializable {
|
||||
|
||||
@Excel(name = "统计名称", width = 20, mergeVertical = true)
|
||||
private String statisticsName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.UNIT_NAME, width = 25, mergeVertical = true)
|
||||
private String gdName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.DEPARTMENT_NAME, width = 25, mergeVertical = true)
|
||||
private String subName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.DEPARTMENT_NAME_SCALE, width = 20)
|
||||
private String subScale;
|
||||
|
||||
@Excel(name = "终端名称", width = 15, mergeVertical = true)
|
||||
private String deviceName;
|
||||
|
||||
@Excel(name = "网络参数", width = 15, mergeVertical = true)
|
||||
private String networkParam;
|
||||
|
||||
@Excel(name = "通讯状态", replace = {"中断_0", "正常_1"}, width = 15)
|
||||
private String comState;
|
||||
|
||||
@Excel(name = "终端厂家", width = 15)
|
||||
private String factoryName;
|
||||
|
||||
@Excel(name = "最新更新数据时间", width = 18)
|
||||
private String time;
|
||||
|
||||
@Excel(name = "母线电压等级", width = 15, mergeVertical = true)
|
||||
private String subvScale;
|
||||
|
||||
@Excel(name = "监测点名称", width = 20)
|
||||
private String lineName;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.njcn.poi.pojo.bo;
|
||||
|
||||
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||
import com.njcn.poi.pojo.constant.DeviceInfoConstant;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年04月01日 15:07
|
||||
*/
|
||||
@Data
|
||||
public class BaseLineProExcelBody implements Serializable {
|
||||
|
||||
@Excel(name = "统计名称", width = 20, mergeVertical = true)
|
||||
private String statisticsName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.PROJECT_NAME, width = 25, mergeVertical = true)
|
||||
private String provincialName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.UNIT_NAME, width = 25, mergeVertical = true)
|
||||
private String gdName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.DEPARTMENT_NAME, width = 25, mergeVertical = true)
|
||||
private String subName;
|
||||
|
||||
@Excel(name = DeviceInfoConstant.DEPARTMENT_NAME_SCALE, width = 20)
|
||||
private String subScale;
|
||||
|
||||
@Excel(name = "终端名称", width = 15, mergeVertical = true)
|
||||
private String deviceName;
|
||||
|
||||
@Excel(name = "网络参数", width = 15, mergeVertical = true)
|
||||
private String networkParam;
|
||||
|
||||
@Excel(name = "通讯状态", replace = {"中断_0", "正常_1"}, width = 15)
|
||||
private String comState;
|
||||
|
||||
@Excel(name = "终端厂家", width = 15)
|
||||
private String factoryName;
|
||||
|
||||
@Excel(name = "最新更新数据时间", width = 18)
|
||||
private String time;
|
||||
|
||||
@Excel(name = "母线电压等级", width = 15, mergeVertical = true)
|
||||
private String subvScale;
|
||||
|
||||
@Excel(name = "监测点名称", width = 25)
|
||||
private String lineName;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.njcn.poi.pojo.constant;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年03月31日 18:39
|
||||
*/
|
||||
public interface DeviceInfoConstant {
|
||||
|
||||
/**
|
||||
* 【工程名称】-【单位】-【部门】
|
||||
* 在数据中心、电网省公司为:【省级】-【供电公司】-【变电站】
|
||||
*
|
||||
* 企业用户:【企业】-【区域】-【单位】
|
||||
**/
|
||||
String PROJECT_NAME="省级";
|
||||
String UNIT_NAME = "供电公司";
|
||||
String DEPARTMENT_NAME = "变电站";
|
||||
String DEPARTMENT_NAME_SCALE = "变电站电压等级";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.njcn.poi.util;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年04月01日 20:10
|
||||
*/
|
||||
public class PoiUtil {
|
||||
|
||||
/**
|
||||
* 根据数值返回适当文字描述
|
||||
* 比如:3.14159 - 暂无数据
|
||||
*/
|
||||
public static String dealData(Double value) {
|
||||
return value == 3.14159 ? "暂无数据" : value + "%";
|
||||
}
|
||||
|
||||
/**
|
||||
* excel包装数字返回的
|
||||
*/
|
||||
public static String dealPOIData(Double value) {
|
||||
|
||||
return " : (" + dealData(value) + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* 注意:此方法下载完文件后,会删除当前文件
|
||||
*
|
||||
* @param filePath 文件绝对路径
|
||||
* @param response 响应
|
||||
*/
|
||||
public static void exportFileByAbsolutePath(String filePath, HttpServletResponse response) {
|
||||
File file = new File(filePath);
|
||||
String fileName = file.getName();
|
||||
try (ServletOutputStream outputStream = response.getOutputStream(); FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileName = URLEncoder.encode(fileName, CharsetUtil.UTF_8);
|
||||
response.reset();
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.setContentType("application/octet-stream;charset=" + CharsetUtil.UTF_8);
|
||||
int len = 0;
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((len = fileInputStream.read(bytes)) != -1) {
|
||||
outputStream.write(bytes, 0, len);
|
||||
outputStream.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new BusinessException(CommonResponseEnum.EXPORT_FILE_ERROR);
|
||||
}
|
||||
FileUtil.del(file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按工作蒲导出文件
|
||||
*
|
||||
* @param workbook 工作蒲
|
||||
* @param fileName 文件名
|
||||
* @param response 响应
|
||||
*/
|
||||
public static void exportFileByWorkbook(Workbook workbook, String fileName, HttpServletResponse response) {
|
||||
response.reset();
|
||||
try (ServletOutputStream outputStream = response.getOutputStream()) {
|
||||
fileName = URLEncoder.encode(fileName, CharsetUtil.UTF_8);
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.setContentType("application/octet-stream;charset=" + CharsetUtil.UTF_8);
|
||||
workbook.write(outputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new BusinessException(CommonResponseEnum.EXPORT_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
43
pqs-common/common-redis/pom.xml
Normal file
43
pqs-common/common-redis/pom.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-redis</artifactId>
|
||||
<name>redis公共服务信息</name>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!--redis集成,客户端为lettuce-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging</groupId>
|
||||
<artifactId>logging-parent</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!--redis客户端Lettuce需要commons-pool2创建连接池-->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.njcn.redis.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月08日 17:53
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
|
||||
/**
|
||||
* 修改RedisTemplate序列化由JdkSerializationRedisSerializer二进制调整为:JSON格式
|
||||
*/
|
||||
@Bean("redisTemplate")
|
||||
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
|
||||
// 为了开发方便,一般直接使用<String,object>
|
||||
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
|
||||
// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// 指定要序列化的域(field,get,set),访问修饰符(public,private,protected)
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
// key采用string的序列化方式
|
||||
redisTemplate.setKeySerializer(stringRedisSerializer);
|
||||
// value序列化方式采用jackson
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
// hash的key采用string的序列化方式
|
||||
redisTemplate.setHashKeySerializer(stringRedisSerializer);
|
||||
// hash的value序列化方式采用jackson
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.redis.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2022年04月02日 14:28
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class RedisListenerConfig {
|
||||
|
||||
|
||||
@Bean
|
||||
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.redis.pojo.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @createTime 2021年05月11日 17:37
|
||||
*/
|
||||
@Getter
|
||||
public enum RedisKeyEnum {
|
||||
|
||||
/**
|
||||
* 角色与资源的对应关系缓存,每次启动用户服务、角色与资源的关系发生变动时,进行清理并重新缓存
|
||||
*/
|
||||
ROLE_FUNCTION_KEY("ROLES_FUNCTIONS",-1L),
|
||||
PUBLIC_FUNCTIONS_KEY("PUBLIC_FUNCTIONS",-1L),
|
||||
|
||||
/**
|
||||
* 终端信息查询缓存的公共key前缀
|
||||
*/
|
||||
DEVICE_INFO_KEY("DEVICE_INFO_PUBLIC:",-1L);
|
||||
|
||||
private final String key;
|
||||
|
||||
/**
|
||||
* redis存储的时间,单位:分钟
|
||||
*/
|
||||
private final Long time;
|
||||
|
||||
RedisKeyEnum(String key, Long time){
|
||||
this.key=key;
|
||||
this.time=time;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
package com.njcn.redis.utils;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年04月30日 09:38
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RedisUtil {
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 指定key的失效时间
|
||||
* 秒级别的过期时间
|
||||
*/
|
||||
public void expire(String key, long time) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据key获取过期时间
|
||||
*/
|
||||
public long getExpire(String key) {
|
||||
Long expireTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
return Objects.isNull(expireTime) ? 0 : expireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断key是否存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
Boolean hasKeyFlag = redisTemplate.hasKey(key);
|
||||
if (Objects.isNull(hasKeyFlag)) {
|
||||
return false;
|
||||
}
|
||||
return hasKeyFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某个Key
|
||||
*/
|
||||
public void delete(String key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除keys
|
||||
*/
|
||||
public void deleteKeys(String... keys) {
|
||||
redisTemplate.delete(Arrays.asList(keys));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取key对应的字符数据
|
||||
*/
|
||||
public String getStringByKey(String key) {
|
||||
return (String) redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取key对应对象数据
|
||||
*/
|
||||
public Object getObjectByKey(String key) {
|
||||
return redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
public void saveByKey(String key, Object value) {
|
||||
redisTemplate.boundValueOps(key).set(value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据,指定生命周期(秒)
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param expireTime 生命时间
|
||||
*/
|
||||
public void saveByKeyWithExpire(String key, Object value, Long expireTime) {
|
||||
if (expireTime <= 0) {
|
||||
saveByKey(key, value);
|
||||
} else {
|
||||
redisTemplate.boundValueOps(key).set(value, expireTime, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序的递增和递减
|
||||
*
|
||||
* @param value 增减根据数值的正负来判断
|
||||
*/
|
||||
public void increment(String key, Long value) {
|
||||
redisTemplate.boundValueOps(key).increment(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加一个Map集合
|
||||
*/
|
||||
public void saveMapValue(String key, Map<String, ?> map, long expireTime) {
|
||||
redisTemplate.boundHashOps(key).putAll(map);
|
||||
if (expireTime > 0) {
|
||||
expire(key, expireTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取map中所有的keys
|
||||
*/
|
||||
public Set<?> getMapKeys(String key) {
|
||||
return redisTemplate.boundHashOps(key).keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取map中所有的values
|
||||
*/
|
||||
public List<?> getMapValues(String key) {
|
||||
return redisTemplate.boundHashOps(key).values();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据map中某个key获取对应的value
|
||||
*/
|
||||
public Object getMapValueByMapKey(String redisKey, String mapKey) {
|
||||
return redisTemplate.boundHashOps(redisKey).get(mapKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据map中的某个key删除对应的value
|
||||
*/
|
||||
public void deleteMapValueByMapKey(String redisKey, String mapKey) {
|
||||
redisTemplate.boundHashOps(redisKey).delete(mapKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断map中是否有指定的key
|
||||
*/
|
||||
public boolean hasMapKey(String redisKey, String mapKey) {
|
||||
Boolean hasKey = redisTemplate.boundHashOps(redisKey).hasKey(mapKey);
|
||||
if (Objects.isNull(hasKey)) {
|
||||
return false;
|
||||
}
|
||||
return hasKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 右存放List
|
||||
*/
|
||||
public void saveRightListByKey(String key, List<?> values, long expireTime) {
|
||||
redisTemplate.boundListOps(key).rightPushAll(values);
|
||||
if (expireTime > 0) {
|
||||
expire(key, expireTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 左存放List
|
||||
*/
|
||||
public void saveLeftListByKey(String key, List<?> values, long expireTime) {
|
||||
redisTemplate.boundListOps(key).leftPushAll(values);
|
||||
if (expireTime > 0) {
|
||||
expire(key, expireTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取List某范围的值
|
||||
*
|
||||
* @param start 起始索引
|
||||
* @param end 截止索引
|
||||
*/
|
||||
public List<?> getListRangeValues(String key, long start, long end) {
|
||||
long size = getListSize(key);
|
||||
if ((start < 0 && end < 0) || (start > end)) {
|
||||
start = 0;
|
||||
end = size;
|
||||
} else if (end > size) {
|
||||
end = size;
|
||||
} else if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
return redisTemplate.boundListOps(key).range(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取List所有数据
|
||||
*/
|
||||
public List<?> getListAllValues(String key) {
|
||||
long size = getListSize(key);
|
||||
return redisTemplate.boundListOps(key).range(0, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定索引获取指定value
|
||||
*/
|
||||
public Object getListValueByIndex(String key, int index) {
|
||||
return redisTemplate.boundListOps(key).index(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list长度
|
||||
*/
|
||||
public Long getListSize(String key) {
|
||||
return Objects.isNull(redisTemplate.boundListOps(key).size()) ? 0 : redisTemplate.boundListOps(key).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引修改某个值
|
||||
*/
|
||||
public void updateListValueByIndex(String key, int index, Object newObj) {
|
||||
redisTemplate.boundListOps(key).set(index, newObj);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.njcn.redis.config.RedisConfig,\
|
||||
com.njcn.redis.utils.RedisUtil
|
||||
|
||||
|
||||
26
pqs-common/common-swagger/pom.xml
Normal file
26
pqs-common/common-swagger/pom.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pqs-common</artifactId>
|
||||
<groupId>com.njcn</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-swagger</artifactId>
|
||||
<name>swagger通用配置</name>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.njcn.swagger.config;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import springfox.documentation.RequestHandler;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.OAuthBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.service.*;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @createTime 2021年03月23日 19:51
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2WebMvc
|
||||
public class Knife4jSwaggerConfig {
|
||||
|
||||
// 定义分隔符
|
||||
private static final String SPLITOR = ";";
|
||||
|
||||
@Value("${microservice.name}")
|
||||
private String microserviceName;
|
||||
|
||||
@Value("${microservice.version}")
|
||||
private String microserviceVersion;
|
||||
|
||||
@Value("${microservice.gateway.url}")
|
||||
private String gatewayUrl;
|
||||
|
||||
/**
|
||||
* swagger通用配置
|
||||
*/
|
||||
@Bean(value = "defaultApi")
|
||||
@Order(value = 1)
|
||||
public Docket defaultApi() {
|
||||
List<String> controllerPath = Stream.of(
|
||||
"com.njcn.user.controller",
|
||||
"com.njcn.device.controller",
|
||||
"com.njcn.auth.controller",
|
||||
"com.njcn.system.controller",
|
||||
"com.njcn.harmonic.controller",
|
||||
"com.njcn.event.controller",
|
||||
"com.njcn.energy.controller")
|
||||
.collect(Collectors.toList());
|
||||
List<GrantType> grantTypes = new ArrayList<>();
|
||||
String passwordTokenUrl = "http://" + gatewayUrl + "/pqs-auth/oauth/token";
|
||||
ResourceOwnerPasswordCredentialsGrant resourceOwnerPasswordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(passwordTokenUrl);
|
||||
grantTypes.add(resourceOwnerPasswordCredentialsGrant);
|
||||
OAuth oAuth = new OAuthBuilder().name("oauth2").grantTypes(grantTypes).build();
|
||||
//schemas
|
||||
List<SecurityScheme> securitySchemes = Lists.newArrayList(oAuth);
|
||||
//securyContext
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(apiInfo())
|
||||
.enable(true)
|
||||
.select()
|
||||
// 指定添加swagger注解的方法
|
||||
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
//这里指定Controller扫描包路径
|
||||
.apis(basePackage(String.join(SPLITOR, controllerPath)))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.securityContexts(securityContexts())
|
||||
.securitySchemes(securitySchemes)
|
||||
.apiInfo(apiInfo());
|
||||
}
|
||||
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder().title(microserviceName).description(microserviceName)
|
||||
.version(microserviceVersion)
|
||||
.contact(contact())
|
||||
.build();
|
||||
}
|
||||
|
||||
private Contact contact() {
|
||||
return new Contact("灿能系统组", "", "13914774158@163.com");
|
||||
}
|
||||
|
||||
|
||||
private List<SecurityContext> securityContexts() {
|
||||
List<SecurityContext> securityContexts = new ArrayList<>();
|
||||
securityContexts.add(
|
||||
SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.ant("/**"))
|
||||
.build());
|
||||
return securityContexts;
|
||||
}
|
||||
|
||||
List<SecurityReference> defaultAuth() {
|
||||
//scope方位
|
||||
List<AuthorizationScope> scopes = new ArrayList<>();
|
||||
scopes.add(new AuthorizationScope("read", "read resources"));
|
||||
scopes.add(new AuthorizationScope("write", "write resources"));
|
||||
scopes.add(new AuthorizationScope("reads", "read all resources"));
|
||||
scopes.add(new AuthorizationScope("writes", "write all resources"));
|
||||
SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{}));
|
||||
List<SecurityReference> securityReferences = new ArrayList<>();
|
||||
securityReferences.add(securityReference);
|
||||
return securityReferences;
|
||||
}
|
||||
|
||||
public static Predicate<RequestHandler> basePackage(final String basePackage) {
|
||||
return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
|
||||
}
|
||||
|
||||
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
|
||||
return input -> {
|
||||
// 循环判断匹配
|
||||
for (String strPackage : basePackage.split(SPLITOR)) {
|
||||
boolean isMatch = input.getPackage().getName().startsWith(strPackage);
|
||||
if (isMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
|
||||
return Optional.fromNullable(input.declaringClass());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.njcn.swagger.config.Knife4jSwaggerConfig
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user