thewindminer 代码提交
This commit is contained in:
425
pom.xml
Normal file
425
pom.xml
Normal file
@@ -0,0 +1,425 @@
|
||||
<?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.wind</groupId>
|
||||
<artifactId>windminer</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>追风矿机工单系统</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<!-- bootstrap 启动器 -->
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.6.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot 监控客户端 -->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.cloud</groupId>-->
|
||||
<!-- <artifactId>spring-cloud-starter-gateway</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- FastDFS 分布式文件系统 -->
|
||||
<dependency>
|
||||
<groupId>com.github.tobato</groupId>
|
||||
<artifactId>fastdfs-client</artifactId>
|
||||
<version>${tobato.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Mybatis-plus 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jsqlparser</artifactId>
|
||||
<groupId>com.github.jsqlparser</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<groupId>org.mybatis</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<groupId>org.mybatis</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>${swagger.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>${swagger.core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 文件上传工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>${commons.fileupload.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Collection 增强Java集合框架 -->
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>${commons-collections.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON 解析器和生成器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 线程传递值 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
<version>${transmittable-thread-local.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-maven-plugin</artifactId>
|
||||
<version>${lombok-maven-plugin.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Lang3 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.26</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Boot Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>5.3.19</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<groupId>org.springframework</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.7</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<name>windminer</name>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<jxy.verson>3.5.0</jxy.verson>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<spring-boot.version>2.6.7</spring-boot.version>
|
||||
<spring-cloud.version>2021.0.1</spring-cloud.version>
|
||||
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
|
||||
<alibaba.nacos.version>2.0.4</alibaba.nacos.version>
|
||||
<spring-boot-admin.version>2.6.6</spring-boot-admin.version>
|
||||
<spring-boot.mybatis>2.2.2</spring-boot.mybatis>
|
||||
<swagger.fox.version>3.0.0</swagger.fox.version>
|
||||
<swagger.core.version>1.6.2</swagger.core.version>
|
||||
|
||||
<tobato.version>1.27.2</tobato.version>
|
||||
<mybatis-plus.version>3.3.0</mybatis-plus.version>
|
||||
<kaptcha.version>2.3.2</kaptcha.version>
|
||||
<pagehelper.boot.version>1.4.1</pagehelper.boot.version>
|
||||
<commons.io.version>2.11.0</commons.io.version>
|
||||
<commons.fileupload.version>1.4</commons.fileupload.version>
|
||||
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<fastjson.version>1.2.80</fastjson.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<commons-collections.version>3.2.2</commons-collections.version>
|
||||
<transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
|
||||
<lombok-maven-plugin.version>1.18.6.0</lombok-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
<dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- SpringCloud 微服务 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba 微服务 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>${spring-cloud-alibaba.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot 监控客户端 -->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- FastDFS 分布式文件系统 -->
|
||||
<dependency>
|
||||
<groupId>com.github.tobato</groupId>
|
||||
<artifactId>fastdfs-client</artifactId>
|
||||
<version>${tobato.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Mybatis-plus 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-models</artifactId>
|
||||
<version>${swagger.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>${swagger.core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>${kaptcha.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 文件上传工具类 -->
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>${commons.fileupload.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Collection 增强Java集合框架 -->
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>${commons-collections.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON 解析器和生成器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 线程传递值 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
<version>${transmittable-thread-local.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-maven-plugin</artifactId>
|
||||
<version>${lombok-maven-plugin.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<finalName>windminer</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
27
src/main/java/com/jxy/windminer/WindminerApplication.java
Normal file
27
src/main/java/com/jxy/windminer/WindminerApplication.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.jxy.windminer;
|
||||
|
||||
import com.jxy.windminer.common.security.annotation.EnableCustomConfig;
|
||||
import com.jxy.windminer.common.security.config.ApplicationConfig;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2023/9/12 15:00
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableAsync
|
||||
// 自动加载类
|
||||
@Import({ ApplicationConfig.class})
|
||||
@MapperScan("com.jxy.windminer.mapper")
|
||||
public class WindminerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WindminerApplication.class,args);
|
||||
System.out.println("windminer微服务启动成功");
|
||||
}
|
||||
}
|
||||
163
src/main/java/com/jxy/windminer/annotation/Excel.java
Normal file
163
src/main/java/com/jxy/windminer/annotation/Excel.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package com.jxy.windminer.annotation;
|
||||
|
||||
import com.jxy.windminer.common.utils.poi.ExcelHandlerAdapter;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 自定义导出Excel数据注解
|
||||
*
|
||||
* @author
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Excel
|
||||
{
|
||||
/**
|
||||
* 导出时在excel中排序
|
||||
*/
|
||||
public int sort() default Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* 导出到Excel中的名字.
|
||||
*/
|
||||
public String name() default "";
|
||||
|
||||
/**
|
||||
* 日期格式, 如: yyyy-MM-dd
|
||||
*/
|
||||
public String dateFormat() default "";
|
||||
|
||||
/**
|
||||
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
|
||||
*/
|
||||
public String readConverterExp() default "";
|
||||
|
||||
/**
|
||||
* 分隔符,读取字符串组内容
|
||||
*/
|
||||
public String separator() default ",";
|
||||
|
||||
/**
|
||||
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
|
||||
*/
|
||||
public int scale() default -1;
|
||||
|
||||
/**
|
||||
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
|
||||
*/
|
||||
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的高度 单位为字符
|
||||
*/
|
||||
public double height() default 14;
|
||||
|
||||
/**
|
||||
* 导出时在excel中每个列的宽 单位为字符
|
||||
*/
|
||||
public double width() default 16;
|
||||
|
||||
/**
|
||||
* 文字后缀,如% 90 变成90%
|
||||
*/
|
||||
public String suffix() default "";
|
||||
|
||||
/**
|
||||
* 当值为空时,字段的默认值
|
||||
*/
|
||||
public String defaultValue() default "";
|
||||
|
||||
/**
|
||||
* 提示信息
|
||||
*/
|
||||
public String prompt() default "";
|
||||
|
||||
/**
|
||||
* 设置只能选择不能输入的列内容.
|
||||
*/
|
||||
public String[] combo() default {};
|
||||
|
||||
/**
|
||||
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
|
||||
*/
|
||||
public boolean isExport() default true;
|
||||
|
||||
/**
|
||||
* 另一个类中的属性名称,支持多级获取,以小数点隔开
|
||||
*/
|
||||
public String targetAttr() default "";
|
||||
|
||||
/**
|
||||
* 是否自动统计数据,在最后追加一行统计数据总和
|
||||
*/
|
||||
public boolean isStatistics() default false;
|
||||
|
||||
/**
|
||||
* 导出类型(0数字 1字符串)
|
||||
*/
|
||||
public ColumnType cellType() default ColumnType.STRING;
|
||||
|
||||
/**
|
||||
* 导出字体颜色
|
||||
*/
|
||||
public IndexedColors color() default IndexedColors.BLACK;
|
||||
|
||||
/**
|
||||
* 导出字段对齐方式
|
||||
*/
|
||||
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器
|
||||
*/
|
||||
public Class<?> handler() default ExcelHandlerAdapter.class;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器参数
|
||||
*/
|
||||
public String[] args() default {};
|
||||
|
||||
/**
|
||||
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
|
||||
*/
|
||||
Type type() default Type.ALL;
|
||||
|
||||
public enum Type
|
||||
{
|
||||
ALL(0), EXPORT(1), IMPORT(2);
|
||||
private final int value;
|
||||
|
||||
Type(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ColumnType
|
||||
{
|
||||
NUMERIC(0), STRING(1), IMAGE(2);
|
||||
private final int value;
|
||||
|
||||
ColumnType(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/main/java/com/jxy/windminer/annotation/Excels.java
Normal file
18
src/main/java/com/jxy/windminer/annotation/Excels.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.jxy.windminer.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Excel注解集
|
||||
*
|
||||
* @author 杜懿
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Excels
|
||||
{
|
||||
Excel[] value();
|
||||
}
|
||||
21
src/main/java/com/jxy/windminer/annotation/ParamName.java
Normal file
21
src/main/java/com/jxy/windminer/annotation/ParamName.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.jxy.windminer.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/7/8 18:24
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value={ElementType.FIELD})
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface ParamName {
|
||||
/**
|
||||
* 参数名称
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
30
src/main/java/com/jxy/windminer/annotation/RateLimiter.java
Normal file
30
src/main/java/com/jxy/windminer/annotation/RateLimiter.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.jxy.windminer.annotation;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.constant.CacheConstants;
|
||||
import com.jxy.windminer.common.enums.LimitType;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/30 17:28
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimiter
|
||||
{
|
||||
// 限流key
|
||||
public String key() default CacheConstants.RATE_LIMIT_KEY;
|
||||
|
||||
// 限流时间,单位秒
|
||||
public int time() default 30;
|
||||
|
||||
// 限流次数
|
||||
public int count() default 30;
|
||||
|
||||
// 限流类型
|
||||
public LimitType limitType() default LimitType.DEFAULT;
|
||||
}
|
||||
44
src/main/java/com/jxy/windminer/common/RedisTransKey.java
Normal file
44
src/main/java/com/jxy/windminer/common/RedisTransKey.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.jxy.windminer.common;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/18 15:35
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class RedisTransKey {
|
||||
|
||||
|
||||
public static final String RedisNameSpace="user";
|
||||
public static final String RedisTokenName="token";
|
||||
public static final String RedisLoginName="login";
|
||||
public static final String RedisEmailCodeName="emailCode";
|
||||
public static final String RedisAddCreditEmailCodeName="addCreditEmailCode";
|
||||
public static final String RedisResetPwdCodeName="restPwdCode";
|
||||
|
||||
public static String setEmailKey(String key){
|
||||
return RedisNameSpace+":"+RedisEmailCodeName+":"+key;
|
||||
}
|
||||
public static String setRootKey(String key){
|
||||
return RedisNameSpace+":"+key+":";
|
||||
}
|
||||
public static String setTokenKey(String key){
|
||||
return RedisNameSpace+':'+RedisTokenName+":"+key;
|
||||
}
|
||||
public static String setLoginKey(String key){
|
||||
return RedisNameSpace+':'+RedisLoginName+":"+key;
|
||||
}
|
||||
public static String setResetPwdKey(String key){
|
||||
return RedisNameSpace+":"+RedisResetPwdCodeName+":"+key;
|
||||
}
|
||||
public static String setAddCreditEmailKey(String key){
|
||||
return RedisNameSpace+":"+RedisAddCreditEmailCodeName+":"+key;
|
||||
}
|
||||
|
||||
public static String getEmailKey(String key){return setEmailKey(key);}
|
||||
public static String getRootKey(String key){return setRootKey(key);}
|
||||
public static String getTokenKey(String key){return setTokenKey(key);}
|
||||
public static String getLoginKey(String key){return setLoginKey(key);}
|
||||
public static String getResetPwdKey(String key){return setResetPwdKey(key);}
|
||||
public static String getAddCreditEmailKey(String key){return setAddCreditEmailKey(key);}
|
||||
|
||||
}
|
||||
78
src/main/java/com/jxy/windminer/common/Result/R.java
Normal file
78
src/main/java/com/jxy/windminer/common/Result/R.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.jxy.windminer.common.Result;
|
||||
|
||||
import com.jxy.windminer.common.constant.Constants;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description 响应信息主体
|
||||
* @Date 2022/5/10 9:18
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public class R<T> implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 3276842119125241681L;
|
||||
|
||||
/** 成功 */
|
||||
public static final int SUCCESS = Constants.SUCCESS;
|
||||
|
||||
/** 失败 */
|
||||
public static final int FAIL = Constants.FAIL;
|
||||
|
||||
private int code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private T data;
|
||||
|
||||
public static <T> R<T> success()
|
||||
{
|
||||
return restResult(null, SUCCESS, null);
|
||||
}
|
||||
|
||||
public static <T> R<T> success(T data)
|
||||
{
|
||||
return restResult(data, SUCCESS, null);
|
||||
}
|
||||
|
||||
public static <T> R<T> success(T data, String msg)
|
||||
{
|
||||
return restResult(data, SUCCESS, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail()
|
||||
{
|
||||
return restResult(null, FAIL, null);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(String msg)
|
||||
{
|
||||
return restResult(null, FAIL, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(T data)
|
||||
{
|
||||
return restResult(data, FAIL, null);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(T data, String msg)
|
||||
{
|
||||
return restResult(data, FAIL, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> fail(int code, String msg)
|
||||
{
|
||||
return restResult(null, code, msg);
|
||||
}
|
||||
|
||||
private static <T> R<T> restResult(T data, int code, String msg)
|
||||
{
|
||||
R<T> apiResult = new R<>();
|
||||
apiResult.setCode(code);
|
||||
apiResult.setData(data);
|
||||
apiResult.setMsg(msg);
|
||||
return apiResult;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description 缓存的key
|
||||
* @Date 2022/5/10 17:22
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class CacheConstants
|
||||
{
|
||||
/**
|
||||
* 缓存有效期,默认720(分钟)
|
||||
*/
|
||||
public final static long EXPIRATION = 720 * 2 *30;
|
||||
|
||||
/**
|
||||
* 缓存刷新时间,默认120(分钟)* 12
|
||||
*/
|
||||
public final static long REFRESH_TIME = 120 * 12;
|
||||
|
||||
/**
|
||||
* 权限缓存前缀
|
||||
*/
|
||||
public final static String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 防重提交 redis key
|
||||
*/
|
||||
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
public static final String RATE_LIMIT_KEY = "rate_limit:";
|
||||
}
|
||||
136
src/main/java/com/jxy/windminer/common/constant/Constants.java
Normal file
136
src/main/java/com/jxy/windminer/common/constant/Constants.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description 常量信息
|
||||
* @Date 2022/5/9 18:13
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
public static final String UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* GBK 字符集
|
||||
*/
|
||||
public static final String GBK = "GBK";
|
||||
|
||||
/**
|
||||
* RMI 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_RMI = "rmi:";
|
||||
|
||||
/**
|
||||
* LDAP 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAP = "ldap:";
|
||||
|
||||
/**
|
||||
* LDAPS 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAPS = "ldaps:";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
public static final String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
public static final String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 成功标记
|
||||
*/
|
||||
public static final Integer SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* 失败标记
|
||||
*/
|
||||
public static final Integer FAIL = 500;
|
||||
|
||||
/**
|
||||
* 登录成功状态
|
||||
*/
|
||||
public static final String LOGIN_SUCCESS_STATUS = "0";
|
||||
|
||||
/**
|
||||
* 登录失败状态
|
||||
*/
|
||||
public static final String LOGIN_FAIL_STATUS = "1";
|
||||
|
||||
/**
|
||||
* 登录成功
|
||||
*/
|
||||
public static final String LOGIN_SUCCESS = "Success";
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
public static final String LOGOUT = "Logout";
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public static final String REGISTER = "Register";
|
||||
|
||||
/**
|
||||
* 登录失败
|
||||
*/
|
||||
public static final String LOGIN_FAIL = "Error";
|
||||
|
||||
/**
|
||||
* 当前记录起始索引
|
||||
*/
|
||||
public static final String PAGE_NUM = "pageNum";
|
||||
|
||||
/**
|
||||
* 每页显示记录数
|
||||
*/
|
||||
public static final String PAGE_SIZE = "pageSize";
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
public static final String ORDER_BY_COLUMN = "orderByColumn";
|
||||
|
||||
/**
|
||||
* 排序的方向 "desc" 或者 "asc".
|
||||
*/
|
||||
public static final String IS_ASC = "isAsc";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 验证码有效期(分钟)
|
||||
*/
|
||||
public static final long CAPTCHA_EXPIRATION = 2;
|
||||
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
public static final String SYS_CONFIG_KEY = "sys_config:";
|
||||
|
||||
/**
|
||||
* 资源映射路径 前缀
|
||||
*/
|
||||
public static final String RESOURCE_PREFIX = "/profile";
|
||||
|
||||
/**
|
||||
* 维修订单key前缀
|
||||
*/
|
||||
public static final String TICKET_ORDER_PREFIX = "tk_order_";
|
||||
|
||||
/**
|
||||
* 商城订单key前缀
|
||||
*/
|
||||
public static final String WORDPRESS_ORDER_PREFIX = "wc_order_";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description 返回状态码
|
||||
* @Date 2022/5/10 11:35
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class HttpStatus
|
||||
{
|
||||
/**
|
||||
* 操作成功
|
||||
*/
|
||||
public static final int SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* 对象创建成功
|
||||
*/
|
||||
public static final int CREATED = 201;
|
||||
|
||||
/**
|
||||
* 请求已经被接受
|
||||
*/
|
||||
public static final int ACCEPTED = 202;
|
||||
|
||||
/**
|
||||
* 操作已经执行成功,但是没有返回数据
|
||||
*/
|
||||
public static final int NO_CONTENT = 204;
|
||||
|
||||
/**
|
||||
* 资源已被移除
|
||||
*/
|
||||
public static final int MOVED_PERM = 301;
|
||||
|
||||
/**
|
||||
* 重定向
|
||||
*/
|
||||
public static final int SEE_OTHER = 303;
|
||||
|
||||
/**
|
||||
* 资源没有被修改
|
||||
*/
|
||||
public static final int NOT_MODIFIED = 304;
|
||||
|
||||
/**
|
||||
* 参数列表错误(缺少,格式不匹配)
|
||||
*/
|
||||
public static final int BAD_REQUEST = 400;
|
||||
|
||||
/**
|
||||
* 未授权
|
||||
*/
|
||||
public static final int UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* 登陆过期
|
||||
*/
|
||||
public static final int LOGINEXPIRES = 421;
|
||||
|
||||
/**
|
||||
* 登陆过期
|
||||
*/
|
||||
public static final int TOKENEXPIRES = 422;
|
||||
|
||||
/**
|
||||
* 访问受限,授权过期
|
||||
*/
|
||||
public static final int FORBIDDEN = 403;
|
||||
|
||||
/**
|
||||
* 资源,服务未找到
|
||||
*/
|
||||
public static final int NOT_FOUND = 404;
|
||||
|
||||
/**
|
||||
* 不允许的http方法
|
||||
*/
|
||||
public static final int BAD_METHOD = 405;
|
||||
|
||||
/**
|
||||
* 资源冲突,或者资源被锁
|
||||
*/
|
||||
public static final int CONFLICT = 409;
|
||||
|
||||
/**
|
||||
* 不支持的数据,媒体类型
|
||||
*/
|
||||
public static final int UNSUPPORTED_TYPE = 415;
|
||||
|
||||
/**
|
||||
* 系统内部错误
|
||||
*/
|
||||
public static final int ERROR = 500;
|
||||
|
||||
/**
|
||||
* 接口未实现
|
||||
*/
|
||||
public static final int NOT_IMPLEMENTED = 501;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description Order相关常量
|
||||
* @Date 2022/5/10 16:12
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class OrderConstants {
|
||||
|
||||
|
||||
/**
|
||||
* REDIS前缀
|
||||
*/
|
||||
public static final String TOKEN_PRE = "userLoginToken::";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description 权限相关通用常量
|
||||
* @Date 2022/5/10 16:19
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class SecurityConstants {
|
||||
|
||||
/**
|
||||
* 用户ID字段
|
||||
*/
|
||||
public static final String DETAILS_USER_ID = "user_id";
|
||||
|
||||
/**
|
||||
* 用户名字段
|
||||
*/
|
||||
public static final String DETAILS_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* 用户名字段
|
||||
*/
|
||||
public static final String DETAILS_EMAIL = "email";
|
||||
/**
|
||||
* 授权信息字段
|
||||
*/
|
||||
public static final String AUTHORIZATION_HEADER = "authorization";
|
||||
|
||||
/**
|
||||
* 请求来源
|
||||
*/
|
||||
public static final String FROM_SOURCE = "from-source";
|
||||
|
||||
/**
|
||||
* 内部请求
|
||||
*/
|
||||
public static final String INNER = "inner";
|
||||
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
public static final String USER_KEY = "user_key";
|
||||
|
||||
/**
|
||||
* 登录用户
|
||||
*/
|
||||
public static final String LOGIN_USER = "login_user";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description Token的Key常量
|
||||
* @Date 2022/5/10 16:12
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class TokenConstants {
|
||||
|
||||
/**
|
||||
* 令牌自定义标识
|
||||
*/
|
||||
public static final String AUTHENTICATION = "Authorization";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 令牌秘钥
|
||||
*/
|
||||
//TODO 根据情况更改密钥
|
||||
public final static String SECRET = "aatbbhcceddweeiffnggdhhmiiijjnkkellrmm";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.jxy.windminer.common.constant;
|
||||
|
||||
/**
|
||||
* @Description 用户相关常量
|
||||
* @Date 2022/5/10 17:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class UserConstants
|
||||
{
|
||||
/**
|
||||
* 平台内系统用户的唯一标志
|
||||
*/
|
||||
public static final String SYS_USER = "SYS_USER";
|
||||
|
||||
/** 正常状态 */
|
||||
public static final String NORMAL = "0";
|
||||
|
||||
/** 异常状态 */
|
||||
public static final String EXCEPTION = "1";
|
||||
|
||||
/** 用户封禁状态 */
|
||||
public static final String USER_DISABLE = "1";
|
||||
|
||||
/** 角色封禁状态 */
|
||||
public static final String ROLE_DISABLE = "1";
|
||||
|
||||
/** 部门正常状态 */
|
||||
public static final String DEPT_NORMAL = "0";
|
||||
|
||||
/** 部门停用状态 */
|
||||
public static final String DEPT_DISABLE = "1";
|
||||
|
||||
/** 字典正常状态 */
|
||||
public static final String DICT_NORMAL = "0";
|
||||
|
||||
/** 是否为系统默认(是) */
|
||||
public static final String YES = "Y";
|
||||
|
||||
/** 是否菜单外链(是) */
|
||||
public static final String YES_FRAME = "0";
|
||||
|
||||
/** 是否菜单外链(否) */
|
||||
public static final String NO_FRAME = "1";
|
||||
|
||||
/** 菜单类型(目录) */
|
||||
public static final String TYPE_DIR = "M";
|
||||
|
||||
/** 菜单类型(菜单) */
|
||||
public static final String TYPE_MENU = "C";
|
||||
|
||||
/** 菜单类型(按钮) */
|
||||
public static final String TYPE_BUTTON = "F";
|
||||
|
||||
/** Layout组件标识 */
|
||||
public final static String LAYOUT = "Layout";
|
||||
|
||||
/** ParentView组件标识 */
|
||||
public final static String PARENT_VIEW = "ParentView";
|
||||
|
||||
/** InnerLink组件标识 */
|
||||
public final static String INNER_LINK = "InnerLink";
|
||||
|
||||
/** 校验返回结果码 */
|
||||
public final static String UNIQUE = "0";
|
||||
|
||||
public final static String NOT_UNIQUE = "1";
|
||||
|
||||
/**
|
||||
* 用户名长度限制
|
||||
*/
|
||||
public static final int USERNAME_MIN_LENGTH = 3;
|
||||
|
||||
public static final int USERNAME_MAX_LENGTH = 16;
|
||||
|
||||
/**
|
||||
* 密码长度限制
|
||||
*/
|
||||
public static final int PASSWORD_MIN_LENGTH = 6;
|
||||
|
||||
public static final int PASSWORD_MAX_LENGTH = 32;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.jxy.windminer.common.context;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.jxy.windminer.common.constant.SecurityConstants;
|
||||
import com.jxy.windminer.common.text.Convert;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @Description 获取当前线程变量中的 用户id、用户名称、Token等信息
|
||||
* @Date 2022/5/10 11:32
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class SecurityContextHolder
|
||||
{
|
||||
private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();
|
||||
|
||||
public static void set(String key, Object value)
|
||||
{
|
||||
Map<String, Object> map = getLocalMap();
|
||||
map.put(key, value == null ? StringUtils.EMPTY : value);
|
||||
}
|
||||
|
||||
public static String get(String key)
|
||||
{
|
||||
Map<String, Object> map = getLocalMap();
|
||||
return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY));
|
||||
}
|
||||
|
||||
public static <T> T get(String key, Class<T> clazz)
|
||||
{
|
||||
Map<String, Object> map = getLocalMap();
|
||||
return StringUtils.cast(map.getOrDefault(key, null));
|
||||
}
|
||||
|
||||
public static Map<String, Object> getLocalMap()
|
||||
{
|
||||
Map<String, Object> map = THREAD_LOCAL.get();
|
||||
if (map == null)
|
||||
{
|
||||
map = new ConcurrentHashMap<String, Object>();
|
||||
THREAD_LOCAL.set(map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static void setLocalMap(Map<String, Object> threadLocalMap)
|
||||
{
|
||||
THREAD_LOCAL.set(threadLocalMap);
|
||||
}
|
||||
|
||||
public static Long getUserId()
|
||||
{
|
||||
return Convert.toLong(get(SecurityConstants.DETAILS_USER_ID), 0L);
|
||||
}
|
||||
|
||||
public static void setUserId(String account)
|
||||
{
|
||||
set(SecurityConstants.DETAILS_USER_ID, account);
|
||||
}
|
||||
|
||||
public static String getUserName()
|
||||
{
|
||||
return get(SecurityConstants.DETAILS_USERNAME);
|
||||
}
|
||||
|
||||
public static void setUserName(String username)
|
||||
{
|
||||
set(SecurityConstants.DETAILS_USERNAME, username);
|
||||
}
|
||||
|
||||
public static String getEmail()
|
||||
{
|
||||
return get(SecurityConstants.DETAILS_EMAIL);
|
||||
}
|
||||
|
||||
public static void setEmail(String email)
|
||||
{
|
||||
set(SecurityConstants.DETAILS_EMAIL, email);
|
||||
}
|
||||
|
||||
public static String getUserKey()
|
||||
{
|
||||
return get(SecurityConstants.USER_KEY);
|
||||
}
|
||||
|
||||
public static void setUserKey(String userKey)
|
||||
{
|
||||
set(SecurityConstants.USER_KEY, userKey);
|
||||
}
|
||||
|
||||
public static void remove()
|
||||
{
|
||||
THREAD_LOCAL.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jxy.windminer.common.datascope.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @Description 数据权限过滤注解
|
||||
* @Date 2022/5/16 15:13
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataScope {
|
||||
|
||||
/**
|
||||
* 部门表的别名
|
||||
*/
|
||||
public String deptAlias() default "";
|
||||
|
||||
/**
|
||||
* 用户表的别名
|
||||
*/
|
||||
public String userAlias() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.jxy.windminer.common.datascope.aspect;
|
||||
|
||||
import com.jxy.windminer.common.datascope.annotation.DataScope;
|
||||
import com.jxy.windminer.common.security.utils.SecurityUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.common.web.entity.BaseEntity;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import com.jxy.windminer.entity.system.SysRole;
|
||||
import com.jxy.windminer.entity.system.SysUser;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 数据过滤处理
|
||||
* @Date 2022/5/16 15:23
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class DataScopeAspect {
|
||||
|
||||
/** 全部数据权限 */
|
||||
public static final String DATA_SCOPE_ALL = "1";
|
||||
|
||||
/** 自定数据权限 */
|
||||
public static final String DATA_SCOPE_CUSTOM = "2";
|
||||
|
||||
/** 部门数据权限 */
|
||||
public static final String DATA_SCOPE_DEPT = "3";
|
||||
|
||||
/** 部门及以下数据权限 */
|
||||
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
|
||||
|
||||
/** 仅本人数据权限 */
|
||||
public static final String DATA_SCOPE_SELF = "5";
|
||||
|
||||
/** 数据权限过滤关键字 */
|
||||
public static final String DATA_SCOPE = "dataScope";
|
||||
|
||||
@Before("@annotation(controllerDataScope)")
|
||||
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
|
||||
{
|
||||
clearDataScope(point);
|
||||
handleDataScope(point, controllerDataScope);
|
||||
}
|
||||
|
||||
protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
|
||||
{
|
||||
// 获取当前的用户
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (StringUtils.isNotNull(loginUser))
|
||||
{
|
||||
SysUser currentUser = loginUser.getSysUser();
|
||||
// 超级管理员,无需过滤
|
||||
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
|
||||
{
|
||||
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
|
||||
controllerDataScope.userAlias());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据范围过滤
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
* @param user 用户
|
||||
* @param deptAlias 部门别名
|
||||
* @param userAlias 用户别名
|
||||
*/
|
||||
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
|
||||
{
|
||||
StringBuilder sqlString = new StringBuilder();
|
||||
|
||||
for (SysRole role : user.getRoles())
|
||||
{
|
||||
String dataScope = role.getDataScope();
|
||||
if (DATA_SCOPE_ALL.equals(dataScope))
|
||||
{
|
||||
sqlString = new StringBuilder();
|
||||
break;
|
||||
}
|
||||
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
|
||||
{
|
||||
sqlString.append(StringUtils.format(
|
||||
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
|
||||
role.getRoleId()));
|
||||
}
|
||||
else if (DATA_SCOPE_DEPT.equals(dataScope))
|
||||
{
|
||||
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
|
||||
}
|
||||
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
|
||||
{
|
||||
sqlString.append(StringUtils.format(
|
||||
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
|
||||
deptAlias, user.getDeptId(), user.getDeptId()));
|
||||
}
|
||||
else if (DATA_SCOPE_SELF.equals(dataScope))
|
||||
{
|
||||
if (StringUtils.isNotBlank(userAlias))
|
||||
{
|
||||
sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 数据权限为仅本人且没有userAlias别名不查询任何数据
|
||||
sqlString.append(" OR 1=0 ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(sqlString.toString()))
|
||||
{
|
||||
Object params = joinPoint.getArgs()[0];
|
||||
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
|
||||
{
|
||||
BaseEntity baseEntity = (BaseEntity) params;
|
||||
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 先清空params.dataScope参数防止注入
|
||||
*/
|
||||
private void clearDataScope(final JoinPoint joinPoint)
|
||||
{
|
||||
Object params = joinPoint.getArgs()[0];
|
||||
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
|
||||
{
|
||||
BaseEntity baseEntity = (BaseEntity) params;
|
||||
baseEntity.getParams().put(DATA_SCOPE, "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
37
src/main/java/com/jxy/windminer/common/enums/HttpMethod.java
Normal file
37
src/main/java/com/jxy/windminer/common/enums/HttpMethod.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package com.jxy.windminer.common.enums;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2024/5/30 11:18
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public enum HttpMethod {
|
||||
|
||||
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
|
||||
|
||||
private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
|
||||
|
||||
static
|
||||
{
|
||||
for (HttpMethod httpMethod : values())
|
||||
{
|
||||
mappings.put(httpMethod.name(), httpMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HttpMethod resolve(@Nullable String method)
|
||||
{
|
||||
return (method != null ? mappings.get(method) : null);
|
||||
}
|
||||
|
||||
public boolean matches(String method)
|
||||
{
|
||||
return (this == resolve(method));
|
||||
}
|
||||
}
|
||||
14
src/main/java/com/jxy/windminer/common/enums/LimitType.java
Normal file
14
src/main/java/com/jxy/windminer/common/enums/LimitType.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.jxy.windminer.common.enums;
|
||||
|
||||
public enum LimitType {
|
||||
|
||||
/**
|
||||
* 默认策略全局限流
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* 根据请求者IP进行限流
|
||||
*/
|
||||
IP
|
||||
}
|
||||
34
src/main/java/com/jxy/windminer/common/enums/UserRole.java
Normal file
34
src/main/java/com/jxy/windminer/common/enums/UserRole.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.jxy.windminer.common.enums;
|
||||
|
||||
public enum UserRole {
|
||||
ADMIN(1, "admin", "管理员"),
|
||||
REGISTERED(2, "registered", "注册用户"),
|
||||
ADVANCE(3, "advance", "付费用户"),
|
||||
VIP(4, "vip", "vip"),
|
||||
SUPPORT(5, "support", "支持人员"),
|
||||
VERIFIER(6, "verifier", "审核人员"),
|
||||
ACCOUNTTING(7, "accounting", "财务");
|
||||
|
||||
private final int roleId;
|
||||
private final String role;
|
||||
private final String des;
|
||||
|
||||
UserRole(int roleId, String role, String des)
|
||||
{
|
||||
this.roleId = roleId;
|
||||
this.role = role;
|
||||
this.des = des;
|
||||
}
|
||||
|
||||
public int getRoleId()
|
||||
{
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public String getRole()
|
||||
{
|
||||
return role;
|
||||
}
|
||||
|
||||
public String getDes(){return des;}
|
||||
}
|
||||
31
src/main/java/com/jxy/windminer/common/enums/UserStatus.java
Normal file
31
src/main/java/com/jxy/windminer/common/enums/UserStatus.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.jxy.windminer.common.enums;
|
||||
|
||||
/**
|
||||
* @Description 用户状态
|
||||
* @Date 2022/5/12 14:52
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public enum UserStatus {
|
||||
|
||||
OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
|
||||
|
||||
private final String code;
|
||||
private final String info;
|
||||
|
||||
UserStatus(String code, String info)
|
||||
{
|
||||
this.code = code;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getInfo()
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
/**
|
||||
* @Description 验证码错误异常类
|
||||
* @Date 2022/5/17 10:51
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class CaptchaException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CaptchaException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
/**
|
||||
* @Description 全局异常
|
||||
* @Date 2022/5/16 14:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class GlobalException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 错误明细,内部调试错误
|
||||
*
|
||||
*/
|
||||
private String detailMessage;
|
||||
|
||||
/**
|
||||
* 空构造方法,避免反序列化问题
|
||||
*/
|
||||
public GlobalException()
|
||||
{
|
||||
}
|
||||
|
||||
public GlobalException(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getDetailMessage()
|
||||
{
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
public GlobalException setDetailMessage(String detailMessage)
|
||||
{
|
||||
this.detailMessage = detailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public GlobalException setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
/**
|
||||
* @Description 内部认证异常
|
||||
* @Date 2022/5/13 18:23
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class InnerAuthException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InnerAuthException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
/**
|
||||
* @Description 权限异常
|
||||
* @Date 2022/5/16 11:31
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class PreAuthorizeException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PreAuthorizeException()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 业务异常
|
||||
* @Date 2022/5/10 16:32
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public final class ServiceException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 错误明细,内部调试错误
|
||||
*
|
||||
*/
|
||||
private String detailMessage;
|
||||
|
||||
/**
|
||||
* 空构造方法,避免反序列化问题
|
||||
*/
|
||||
public ServiceException()
|
||||
{
|
||||
}
|
||||
|
||||
public ServiceException(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ServiceException(String message, Integer code)
|
||||
{
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getDetailMessage()
|
||||
{
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public Integer getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public ServiceException setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServiceException setDetailMessage(String detailMessage)
|
||||
{
|
||||
this.detailMessage = detailMessage;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jxy.windminer.common.exception;
|
||||
|
||||
/**
|
||||
* @Description 工具类异常
|
||||
* @Date 2022/5/10 11:32
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class UtilException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 8247642119125314183L;
|
||||
|
||||
public UtilException(Throwable e)
|
||||
{
|
||||
super(e.getMessage(), e);
|
||||
}
|
||||
|
||||
public UtilException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UtilException(String message, Throwable throwable)
|
||||
{
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
/**
|
||||
* @Description 登录过期异常
|
||||
* @Date 2022/5/13 9:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class LoginExpiresException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public LoginExpiresException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
/**
|
||||
* @Description 没有通过的登陆认证异常
|
||||
* @Date 2022/5/13 9:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class NotLoginException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotLoginException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description 未能通过的权限认证异常
|
||||
* @Date 2022/5/13 9:45
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class NotPermissionException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotPermissionException(String permission)
|
||||
{
|
||||
super(permission);
|
||||
}
|
||||
|
||||
public NotPermissionException(String[] permissions)
|
||||
{
|
||||
super(StringUtils.join(permissions, ","));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description 未能通过的角色认证异常
|
||||
* @Date 2022/5/13 9:48
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class NotRoleException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotRoleException(String role)
|
||||
{
|
||||
super(role);
|
||||
}
|
||||
|
||||
public NotRoleException(String[] roles)
|
||||
{
|
||||
super(StringUtils.join(roles, ","));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
/**
|
||||
* @Description Token过期异常
|
||||
* @Date 2022/5/13 9:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class TokenExpiresException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public TokenExpiresException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception.auth;
|
||||
|
||||
/**
|
||||
* @Description 未授权异常
|
||||
* @Date 2022/5/13 9:39
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class UnAuthorizedException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UnAuthorizedException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.jxy.windminer.common.exception.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 基础异常
|
||||
* @Date 2022/5/16 11:42
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public class BaseException extends RuntimeException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 所属模块
|
||||
*/
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 错误码对应的参数
|
||||
*/
|
||||
private Object[] args;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String defaultMessage;
|
||||
|
||||
public BaseException(String module, String code, Object[] args, String defaultMessage)
|
||||
{
|
||||
this.module = module;
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
this.defaultMessage = defaultMessage;
|
||||
}
|
||||
|
||||
public BaseException(String module, String code, Object[] args)
|
||||
{
|
||||
this(module, code, args, null);
|
||||
}
|
||||
|
||||
public BaseException(String module, String defaultMessage)
|
||||
{
|
||||
this(module, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public BaseException(String code, Object[] args)
|
||||
{
|
||||
this(null, code, args, null);
|
||||
}
|
||||
|
||||
|
||||
public BaseException(String defaultMessage)
|
||||
{
|
||||
this(null, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public String getModule()
|
||||
{
|
||||
return module;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Object[] getArgs()
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getDefaultMessage()
|
||||
{
|
||||
return defaultMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.jxy.windminer.common.exception.file;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* 文件信息异常类
|
||||
*
|
||||
* @author jxy
|
||||
*/
|
||||
public class FileException extends BaseException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileException(String code, Object[] args)
|
||||
{
|
||||
super("file", code, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jxy.windminer.common.exception.file;
|
||||
|
||||
/**
|
||||
* 文件名称超长限制异常类
|
||||
*
|
||||
* @author jxy
|
||||
*/
|
||||
public class FileNameLengthLimitExceededException extends FileException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileNameLengthLimitExceededException(int defaultFileNameLength)
|
||||
{
|
||||
super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jxy.windminer.common.exception.file;
|
||||
|
||||
/**
|
||||
* 文件名大小限制异常类
|
||||
*
|
||||
* @author jxy
|
||||
*/
|
||||
public class FileSizeLimitExceededException extends FileException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FileSizeLimitExceededException(long defaultMaxSize)
|
||||
{
|
||||
super("文件名超长", new Object[] { defaultMaxSize });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jxy.windminer.common.exception.file;
|
||||
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 文件上传 误异常类
|
||||
*
|
||||
* @author jxy
|
||||
*/
|
||||
public class InvalidExtensionException extends FileUploadException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String[] allowedExtension;
|
||||
private String extension;
|
||||
private String filename;
|
||||
|
||||
public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
|
||||
{
|
||||
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
|
||||
this.allowedExtension = allowedExtension;
|
||||
this.extension = extension;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String[] getAllowedExtension()
|
||||
{
|
||||
return allowedExtension;
|
||||
}
|
||||
|
||||
public String getExtension()
|
||||
{
|
||||
return extension;
|
||||
}
|
||||
|
||||
public String getFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
public static class InvalidImageExtensionException extends InvalidExtensionException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
|
||||
{
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidFlashExtensionException extends InvalidExtensionException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
|
||||
{
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidMediaExtensionException extends InvalidExtensionException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
|
||||
{
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidVideoExtensionException extends InvalidExtensionException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
|
||||
{
|
||||
super(allowedExtension, extension, filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jxy.windminer.common.exception.user;
|
||||
|
||||
/**
|
||||
* @Description 验证码失效异常类
|
||||
* @Date 2022/5/18 17:51
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class CaptchaExpireException extends UserException{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CaptchaExpireException()
|
||||
{
|
||||
super("user.jcaptcha.expire", null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.jxy.windminer.common.exception.user;
|
||||
|
||||
import com.jxy.windminer.common.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* @Description 用户信息异常类
|
||||
* @Date 2022/5/16 14:05
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class UserException extends BaseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UserException(String code, Object[] args) {
|
||||
|
||||
super("user",code, args,null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.jxy.windminer.common.redis.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* @Description redis使用FastJson序列化
|
||||
* @Date 2022/5/12 10:01
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private Class<T> clazz;
|
||||
|
||||
static
|
||||
{
|
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
}
|
||||
|
||||
public FastJson2JsonRedisSerializer(Class<T> clazz)
|
||||
{
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) throws SerializationException
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) throws SerializationException
|
||||
{
|
||||
if (bytes == null || bytes.length <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, DEFAULT_CHARSET);
|
||||
|
||||
return JSON.parseObject(str, clazz);
|
||||
}
|
||||
|
||||
public void setObjectMapper(ObjectMapper objectMapper)
|
||||
{
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
protected JavaType getJavaType(Class<?> clazz)
|
||||
{
|
||||
return TypeFactory.defaultInstance().constructType(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.jxy.windminer.common.redis.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* @Description redis配置
|
||||
* @Date 2022/5/12 09:58
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
||||
{
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
|
||||
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||
serializer.setObjectMapper(mapper);
|
||||
|
||||
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(serializer);
|
||||
|
||||
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(serializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultRedisScript<Long> limitScript()
|
||||
{
|
||||
// 泛型是返回值的类型
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
||||
// 设置脚本
|
||||
redisScript.setScriptText(limitScriptText());
|
||||
// 设置返回值类型
|
||||
redisScript.setResultType(Long.class);
|
||||
return redisScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private String limitScriptText()
|
||||
{
|
||||
return "local key = KEYS[1]\n" +
|
||||
"local count = tonumber(ARGV[1])\n" +
|
||||
"local time = tonumber(ARGV[2])\n" +
|
||||
"local current = redis.call('get', key);\n" +
|
||||
"if current and tonumber(current) > count then\n" +
|
||||
" return tonumber(current);\n" +
|
||||
"end\n" +
|
||||
"current = redis.call('incr', key)\n" +
|
||||
"if tonumber(current) == 1 then\n" +
|
||||
" redis.call('expire', key, time)\n" +
|
||||
"end\n" +
|
||||
"return tonumber(current);";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package com.jxy.windminer.common.redis.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Description redis 相关
|
||||
* @Date 2022/5/12 9:22
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||
@Component
|
||||
public class RedisService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout)
|
||||
{
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout, final TimeUnit unit)
|
||||
{
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @return 有效时间
|
||||
*/
|
||||
public long getExpire(final String key)
|
||||
{
|
||||
return redisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @return 有效时间
|
||||
*/
|
||||
public long getExpire(final String key,TimeUnit timetype)
|
||||
{
|
||||
return redisTemplate.getExpire(key,timetype);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断 key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public Boolean hasKey(String key)
|
||||
{
|
||||
return redisTemplate.hasKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key)
|
||||
{
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public boolean deleteObject(final String key)
|
||||
{
|
||||
return redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
public long deleteObject(final Collection collection)
|
||||
{
|
||||
return redisTemplate.delete(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
public <T> long setCacheList(final String key, final List<T> dataList)
|
||||
{
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key)
|
||||
{
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
|
||||
{
|
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||
Iterator<T> it = dataSet.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
setOperation.add(it.next());
|
||||
}
|
||||
return setOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> getCacheSet(final String key)
|
||||
{
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
|
||||
{
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key)
|
||||
{
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
|
||||
{
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
public <T> T getCacheMapValue(final String key, final String hKey)
|
||||
{
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
|
||||
{
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern)
|
||||
{
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jxy.windminer.common.security.annotation;
|
||||
|
||||
import com.jxy.windminer.common.security.config.ApplicationConfig;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
// 表示通过aop框架暴露该代理对象,AopContext能够访问
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
// 指定要扫描的Mapper类的包的路径
|
||||
// 开启线程异步执行
|
||||
@EnableAsync
|
||||
// 自动加载类
|
||||
@Import({ ApplicationConfig.class})
|
||||
public @interface EnableCustomConfig
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jxy.windminer.common.security.annotation;
|
||||
|
||||
/**
|
||||
* @Description 权限注解验证模式设定
|
||||
* @Date 2022/5/16 9:33
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public enum Logical
|
||||
{
|
||||
/**
|
||||
* 必须具有所有的元素
|
||||
*/
|
||||
AND,
|
||||
|
||||
/**
|
||||
* 只需具有其中一个元素
|
||||
*/
|
||||
OR
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.jxy.windminer.common.security.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @Description 登录认证:登录成功后才能进入该方法
|
||||
* @Date 2022/5/13 19:11
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresLogin {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.jxy.windminer.common.security.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @Description 角色认证:必须拥有该方法所需角色标识才能进入方法
|
||||
* @Date 2022/5/16 9:35
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresRoles {
|
||||
|
||||
/**
|
||||
* 需要校验的角色标识
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* 验证逻辑:AND | OR,默认AND
|
||||
*/
|
||||
Logical logical() default Logical.AND;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.jxy.windminer.common.security.aspect;
|
||||
|
||||
import com.jxy.windminer.common.security.annotation.RequiresLogin;
|
||||
import com.jxy.windminer.common.security.annotation.RequiresRoles;
|
||||
import com.jxy.windminer.common.security.auth.AuthUtil;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @Description 基于 Spring Aop 的注解鉴权
|
||||
* @Date 2022/5/13 18:47
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class PreAuthAspect {
|
||||
|
||||
/**
|
||||
* 构建
|
||||
*/
|
||||
public PreAuthAspect(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义AOP签名 (切入所有使用鉴权注解的方法)
|
||||
*/
|
||||
public static final String POINTCUT_SIGN = " @annotation(com.jxy.windminer.common.security.annotation.RequiresLogin) || "
|
||||
+ "@annotation(com.jxy.windminer.common.security.annotation.RequiresRoles)";
|
||||
|
||||
/**
|
||||
* 声明AOP签名
|
||||
*/
|
||||
@Pointcut(POINTCUT_SIGN)
|
||||
public void pointcut()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 环绕切入
|
||||
*
|
||||
* @param joinPoint 切面对象
|
||||
* @return 底层方法执行后的返回值
|
||||
* @throws Throwable 底层方法抛出的异常
|
||||
*/
|
||||
@Around("pointcut()")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
|
||||
// 注解鉴权
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
checkMethodAnnotation(signature.getMethod());
|
||||
try
|
||||
{
|
||||
// 执行原有逻辑
|
||||
Object obj = joinPoint.proceed();
|
||||
return obj;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解检查
|
||||
*/
|
||||
public void checkMethodAnnotation(Method method)
|
||||
{
|
||||
//校验 @RequiresLogin 注解
|
||||
RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class);
|
||||
if(requiresLogin != null){
|
||||
AuthUtil.checkLogin();
|
||||
}
|
||||
|
||||
//校验 @RequiresRoles 注解
|
||||
RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
|
||||
if(requiresRoles != null){
|
||||
AuthUtil.checkRole(requiresRoles);
|
||||
}
|
||||
|
||||
////校验 @RequiresPermissions 注解
|
||||
//RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
|
||||
//if(requiresPermissions != null){
|
||||
// AuthUtil.checkPermission(requiresPermissions);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.jxy.windminer.common.security.aspect;
|
||||
|
||||
import com.jxy.windminer.annotation.RateLimiter;
|
||||
import com.jxy.windminer.common.enums.LimitType;
|
||||
import com.jxy.windminer.common.exception.ServiceException;
|
||||
import com.jxy.windminer.common.utils.ServletUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.common.utils.ip.IpUtils;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description 限流处理
|
||||
* @Date 2022/11/30 17:38
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class RateLimiterAspect {
|
||||
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
||||
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
|
||||
private RedisScript<Long> limitScript;
|
||||
|
||||
@Autowired
|
||||
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
|
||||
{
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setLimitScript(RedisScript<Long> limitScript)
|
||||
{
|
||||
this.limitScript = limitScript;
|
||||
}
|
||||
|
||||
@Before("@annotation(rateLimiter)")
|
||||
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
|
||||
{
|
||||
int time = rateLimiter.time();
|
||||
int count = rateLimiter.count();
|
||||
|
||||
String combineKey = getCombineKey(rateLimiter, point);
|
||||
List<Object> keys = Collections.singletonList(combineKey);
|
||||
try
|
||||
{
|
||||
Long number = redisTemplate.execute(limitScript, keys, count, time);
|
||||
if (StringUtils.isNull(number) || number.intValue() > count)
|
||||
{
|
||||
throw new ServiceException("访问过于频繁,请稍候再试");
|
||||
}
|
||||
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
|
||||
}
|
||||
catch (ServiceException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("服务器限流异常,请稍候再试");
|
||||
}
|
||||
}
|
||||
|
||||
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
|
||||
{
|
||||
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
|
||||
if (rateLimiter.limitType() == LimitType.IP)
|
||||
{
|
||||
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
|
||||
}
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Class<?> targetClass = method.getDeclaringClass();
|
||||
stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
package com.jxy.windminer.common.security.auth;
|
||||
|
||||
//import com.jxy.common.security.annotation.RequiresPermissions;
|
||||
import com.jxy.windminer.common.exception.auth.NotLoginException;
|
||||
import com.jxy.windminer.common.exception.auth.NotPermissionException;
|
||||
import com.jxy.windminer.common.exception.auth.NotRoleException;
|
||||
import com.jxy.windminer.common.security.annotation.Logical;
|
||||
import com.jxy.windminer.common.security.annotation.RequiresLogin;
|
||||
import com.jxy.windminer.common.security.annotation.RequiresRoles;
|
||||
import com.jxy.windminer.common.security.service.TokenService;
|
||||
import com.jxy.windminer.common.security.utils.SecurityUtils;
|
||||
import com.jxy.windminer.common.utils.SpringUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Description 权限验证的逻辑实现类
|
||||
* @Date 2022/5/13 14:04
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class AuthLogic {
|
||||
|
||||
/** 所有权限标识 */
|
||||
private static final String ALL_PERMISSION = "*:*:*";
|
||||
|
||||
/** 管理员角色权限标识 */
|
||||
private static final String SUPER_ADMIN = "admin";
|
||||
|
||||
private TokenService tokenService = SpringUtils.getBean(TokenService.class);
|
||||
|
||||
/**
|
||||
* 会话注销
|
||||
*/
|
||||
public void logout()
|
||||
{
|
||||
String token = SecurityUtils.getToken();
|
||||
if (token == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
logoutByToken(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话注销,根据指定Token
|
||||
*/
|
||||
public void logoutByToken(String token)
|
||||
{
|
||||
tokenService.delLoginUser(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验用户是否已经登录,如未登录,则抛出异常
|
||||
*/
|
||||
public void checkLogin(){getLoginUser();}
|
||||
|
||||
/**
|
||||
* 获取当前用户缓存信息, 如果未登录,则抛出异常
|
||||
*
|
||||
* @return 用户缓存信息
|
||||
*/
|
||||
public LoginUser getLoginUser()
|
||||
{
|
||||
String token = SecurityUtils.getToken();
|
||||
if (token == null)
|
||||
{
|
||||
throw new NotLoginException("未提供token");
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser == null)
|
||||
{
|
||||
throw new NotLoginException("无效的token");
|
||||
}
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户缓存信息, 如果未登录,则抛出异常
|
||||
*
|
||||
* @param token 前端传递的认证信息
|
||||
* @return 用户缓存信息
|
||||
*/
|
||||
public LoginUser getLoginUser(String token)
|
||||
{
|
||||
return tokenService.getLoginUser(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证当前用户有效期, 如果相差不足120分钟,自动刷新缓存
|
||||
*
|
||||
* @param loginUser 当前用户信息
|
||||
*/
|
||||
public void verifyLoginUserExpire(LoginUser loginUser)
|
||||
{
|
||||
tokenService.verifyToken(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解(@RequiresLogin)鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(RequiresLogin at)
|
||||
{
|
||||
this.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解(@RequiresRoles)鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(RequiresRoles at)
|
||||
{
|
||||
String[] roleArray = at.value();
|
||||
if (at.logical() == Logical.AND)
|
||||
{
|
||||
this.checkRoleAnd(roleArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解(@RequiresPermissions)鉴权
|
||||
*
|
||||
* @param at 注解对象
|
||||
*/
|
||||
//public void checkByAnnotation(RequiresPermissions at)
|
||||
//{
|
||||
// String[] permissionArray = at.value();
|
||||
// if (at.logical() == Logical.AND)
|
||||
// {
|
||||
// this.checkPermissionAnd(permissionArray);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.checkPermissionOr(permissionArray);
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 获取当前账号的角色列表
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
public Set<String> getRoleList()
|
||||
{
|
||||
try
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser.getRoles();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前账号的权限列表
|
||||
*
|
||||
* @return 权限列表
|
||||
*/
|
||||
//public Set<String> getPermissionList()
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// LoginUser loginUser = getLoginUser();
|
||||
// return loginUser.getPermissions();
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// return new HashSet<>();
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 判断用户是否拥有某个角色
|
||||
*
|
||||
* @param role 角色标识
|
||||
* @return 用户是否具备某角色
|
||||
*/
|
||||
public boolean hasRole(String role)
|
||||
{
|
||||
return hasRole(getRoleList(), role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否拥有某个角色, 如果验证未通过,则抛出异常: NotRoleException
|
||||
*
|
||||
* @param role 角色标识
|
||||
*/
|
||||
public void checkRole(String role)
|
||||
{
|
||||
if (!hasRole(role))
|
||||
{
|
||||
throw new NotRoleException(role);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解(@RequiresRoles)鉴权
|
||||
*
|
||||
* @param requiresRoles 注解对象
|
||||
*/
|
||||
public void checkRole(RequiresRoles requiresRoles)
|
||||
{
|
||||
if (requiresRoles.logical() == Logical.AND)
|
||||
{
|
||||
checkRoleAnd(requiresRoles.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
checkRoleOr(requiresRoles.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否含有指定角色,必须全部拥有
|
||||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleAnd(String... roles)
|
||||
{
|
||||
Set<String> roleList = getRoleList();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (!hasRole(roleList, role))
|
||||
{
|
||||
throw new NotRoleException(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户是否含有指定角色,只需包含其中一个
|
||||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleOr(String... roles)
|
||||
{
|
||||
Set<String> roleList = getRoleList();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (hasRole(roleList, role))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (roles.length > 0)
|
||||
{
|
||||
throw new NotRoleException(roles);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证用户是否具备某权限
|
||||
*
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
//public boolean hasPermission(String permission)
|
||||
//{
|
||||
// return hasPermission(getPermissionList(), permission);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException
|
||||
*
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
//public void checkPermission(String permission)
|
||||
//{
|
||||
// if (!hasPermission(getPermissionList(), permission))
|
||||
// {
|
||||
// throw new NotPermissionException(permission);
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 根据注解(@RequiresPermissions)鉴权, 如果验证未通过,则抛出异常: NotPermissionException
|
||||
*
|
||||
* @param requiresPermissions 注解对象
|
||||
*/
|
||||
//public void checkPermission(RequiresPermissions requiresPermissions)
|
||||
//{
|
||||
// if (requiresPermissions.logical() == Logical.AND)
|
||||
// {
|
||||
// checkPermissionAnd(requiresPermissions.value());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// checkPermissionOr(requiresPermissions.value());
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 验证用户是否含有指定权限,必须全部拥有
|
||||
*
|
||||
* @param permissions 权限列表
|
||||
*/
|
||||
//public void checkPermissionAnd(String... permissions)
|
||||
//{
|
||||
// Set<String> permissionList = getPermissionList();
|
||||
// for (String permission : permissions)
|
||||
// {
|
||||
// if (!hasPermission(permissionList, permission))
|
||||
// {
|
||||
// throw new NotPermissionException(permission);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 验证用户是否含有指定权限,只需包含其中一个
|
||||
*
|
||||
* @param permissions 权限码数组
|
||||
*/
|
||||
//public void checkPermissionOr(String... permissions)
|
||||
//{
|
||||
// Set<String> permissionList = getPermissionList();
|
||||
// for (String permission : permissions)
|
||||
// {
|
||||
// if (hasPermission(permissionList, permission))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// if (permissions.length > 0)
|
||||
// {
|
||||
// throw new NotPermissionException(permissions);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否包含权限
|
||||
*
|
||||
* @param authorities 权限列表
|
||||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public boolean hasPermission(Collection<String> authorities, String permission)
|
||||
{
|
||||
return authorities.stream().filter(StringUtils::hasText)
|
||||
.anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含角色
|
||||
*
|
||||
* @param roles 角色列表
|
||||
* @param role 角色
|
||||
* @return 用户是否具备某角色权限
|
||||
*/
|
||||
public boolean hasRole(Collection<String> roles, String role)
|
||||
{
|
||||
return roles.stream().filter(StringUtils::hasText)
|
||||
.anyMatch(x -> SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.jxy.windminer.common.security.auth;
|
||||
|
||||
import com.jxy.windminer.common.security.annotation.RequiresRoles;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
/**
|
||||
* @Description 权限验证工具类
|
||||
* @Date 2022/5/13 16:17
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class AuthUtil {
|
||||
|
||||
/**
|
||||
* 底层的AuthLogic对象
|
||||
*/
|
||||
public static AuthLogic authLogic = new AuthLogic();
|
||||
|
||||
/**
|
||||
* 检查当前用户是否登陆
|
||||
*/
|
||||
public static void checkLogin(){
|
||||
authLogic.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登陆用户信息
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public static LoginUser getLoginUser(String token){return authLogic.getLoginUser(token);}
|
||||
|
||||
/**
|
||||
* 验证当前用户有效期
|
||||
* @param loginUser
|
||||
*/
|
||||
public static void verifyLoginUserExpire(LoginUser loginUser){
|
||||
authLogic.verifyLoginUserExpire(loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
*判断当前用户是否有指定的角色标识
|
||||
* @param role 角色标识
|
||||
* @return 返回布尔值
|
||||
*/
|
||||
public static boolean hasRole(String role){return authLogic.hasRole(role);}
|
||||
|
||||
/**
|
||||
*当前账号是否含有指定角色标识,如果验证未通过,则抛出异常: NotRoleException
|
||||
* @param role
|
||||
*/
|
||||
public static void checkRole(String role){authLogic.checkRole(role);}
|
||||
|
||||
/**
|
||||
* 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotRoleException
|
||||
*
|
||||
* @param requiresRoles 角色权限注解
|
||||
*/
|
||||
public static void checkRole(RequiresRoles requiresRoles)
|
||||
{
|
||||
authLogic.checkRole(requiresRoles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
|
||||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public static void checkRoleAnd(String... roles)
|
||||
{
|
||||
authLogic.checkRoleAnd(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
|
||||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public static void checkRoleOr(String... roles)
|
||||
{
|
||||
authLogic.checkRoleOr(roles);
|
||||
}
|
||||
|
||||
|
||||
///**
|
||||
// * 判断当前账号是否含有指定权限
|
||||
// *
|
||||
// * @param permission 权限码
|
||||
// * @return 是否含有指定权限
|
||||
// */
|
||||
//public static boolean hasPermission(String permission)
|
||||
//{
|
||||
// return authLogic.hasPermission(permission);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
|
||||
*
|
||||
* @param permission 权限码
|
||||
*/
|
||||
//public static void checkPermission(String permission)
|
||||
//{
|
||||
// authLogic.checkPermission(permission);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotPermissionException
|
||||
*
|
||||
* @param requiresPermissions 权限注解
|
||||
*/
|
||||
//public static void checkPermission(RequiresPermissions requiresPermissions)
|
||||
//{
|
||||
// authLogic. checkPermission(requiresPermissions);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 [指定多个,必须全部验证通过]
|
||||
*
|
||||
* @param permissions 权限码数组
|
||||
*/
|
||||
//public static void checkPermissionAnd(String... permissions)
|
||||
//{
|
||||
// authLogic.checkPermissionAnd(permissions);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
|
||||
*
|
||||
* @param permissions 权限码数组
|
||||
*/
|
||||
//public static void checkPermissionOr(String... permissions)
|
||||
//{
|
||||
// authLogic.checkPermissionOr(permissions);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 会话注销
|
||||
*/
|
||||
public static void logout(){authLogic.logout();}
|
||||
|
||||
/**
|
||||
* 根据token注销会话
|
||||
* @param token
|
||||
*/
|
||||
public static void logoutByToken(String token){authLogic.logoutByToken(token);}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jxy.windminer.common.security.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @Description 系统配置
|
||||
* @Date 2022/5/13 10:59
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class ApplicationConfig {
|
||||
|
||||
/**
|
||||
* 时区配置
|
||||
*/
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
|
||||
{
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.jxy.windminer.common.security.config;
|
||||
|
||||
import com.jxy.windminer.common.security.interceptor.HeaderInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @Description 拦截器配置
|
||||
* @Date 2023/5/13 17:56
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Configuration
|
||||
@Component
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
/** 不需要拦截的地址 */
|
||||
public static final String[] excludeUrls = {"/**/login","/**/emailcode","/logout",
|
||||
"/**/refresh","/**/hello",
|
||||
"/**/resetPwdcode","/**/resetPwd",
|
||||
"/**/register","/**/getFaults",
|
||||
"/**/downloadFile","/**/getTools",
|
||||
"/order/endOrder","/order/test","/order/getPayAddress","/order/payment","/order/getPayment","/order/ifConfirm",
|
||||
"/**/wpUserLogin","/**/importTemplate"};
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(getHeaderInterceptor())
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(excludeUrls)
|
||||
.order(-10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")//项目中的所有接口都支持跨域
|
||||
.allowedOriginPatterns("*")//所有地址都可以访问,也可以配置具体地址
|
||||
.allowCredentials(true)
|
||||
.allowedMethods("*")//"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"
|
||||
.maxAge(3600);// 跨域允许时间
|
||||
}
|
||||
/**
|
||||
* 自定义请求头拦截器
|
||||
*/
|
||||
@Bean
|
||||
public HeaderInterceptor getHeaderInterceptor(){return new HeaderInterceptor();}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.jxy.windminer.common.security.handler;
|
||||
|
||||
import com.jxy.windminer.common.constant.HttpStatus;
|
||||
import com.jxy.windminer.common.exception.InnerAuthException;
|
||||
import com.jxy.windminer.common.exception.ServiceException;
|
||||
import com.jxy.windminer.common.exception.auth.*;
|
||||
import com.jxy.windminer.common.exception.file.FileNameLengthLimitExceededException;
|
||||
import com.jxy.windminer.common.security.utils.SecurityUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.common.web.Result.AjaxResult;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.multipart.MultipartException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @Description 全局异常处理器
|
||||
* @Date 2022/5/13 11:36
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
/**
|
||||
* 权限码异常
|
||||
*/
|
||||
@ExceptionHandler(NotPermissionException.class)
|
||||
public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权");
|
||||
}
|
||||
|
||||
/**
|
||||
* 令牌为空异常
|
||||
*/
|
||||
@ExceptionHandler(UnAuthorizedException.class)
|
||||
public AjaxResult handleUnAuthorizedException(UnAuthorizedException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',token令牌异常'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.UNAUTHORIZED, e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 令牌过期异常
|
||||
*/
|
||||
@ExceptionHandler(TokenExpiresException.class)
|
||||
public AjaxResult handleTokenExpiresException(TokenExpiresException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',token令牌异常'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.TOKENEXPIRES, e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录过期异常
|
||||
*/
|
||||
@ExceptionHandler(LoginExpiresException.class)
|
||||
public AjaxResult handleLoginExpiresException(LoginExpiresException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',token令牌异常'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.LOGINEXPIRES, e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色权限异常
|
||||
*/
|
||||
@ExceptionHandler(NotRoleException.class)
|
||||
public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
System.out.println(loginUser.getRoles());
|
||||
log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.FORBIDDEN, "权限不足,请自行升级或联系管理员授权");
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方式不支持
|
||||
*/
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
|
||||
HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
Integer code = e.getCode();
|
||||
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截文件异常异常
|
||||
*/
|
||||
@ExceptionHandler(MultipartException.class)
|
||||
public AjaxResult handleMultException(MultipartException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生文件异常.", requestURI, e);
|
||||
return AjaxResult.error("文件过大,单个文件最大2M");
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截文件名超长异常
|
||||
*/
|
||||
@ExceptionHandler(FileNameLengthLimitExceededException.class)
|
||||
public AjaxResult handleFileNameLengthException(FileNameLengthLimitExceededException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生文件异常.", requestURI, e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public AjaxResult handleException(Exception e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生系统异常.", requestURI, e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public AjaxResult handleBindException(BindException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||
return AjaxResult.error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getBindingResult().getFieldError().getDefaultMessage();
|
||||
return AjaxResult.error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部认证异常
|
||||
*/
|
||||
@ExceptionHandler(InnerAuthException.class)
|
||||
public AjaxResult handleInnerAuthException(InnerAuthException e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sql查询验证异常
|
||||
*/
|
||||
@ExceptionHandler(SQLException.class)
|
||||
public AjaxResult handleSQLException(SQLException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生sql执行异常.", requestURI, e);
|
||||
return AjaxResult.error("请求地址'{}',发生sql执行异常.");
|
||||
}
|
||||
|
||||
@ExceptionHandler(BadSqlGrammarException.class)
|
||||
public AjaxResult handleBadSqlGrammarException(BadSqlGrammarException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生SQL异常.", requestURI, e);
|
||||
return AjaxResult.error(HttpStatus.ERROR, "数据库异常!");
|
||||
}
|
||||
//todo 根据业务需求增加异常
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.jxy.windminer.common.security.interceptor;
|
||||
|
||||
import com.jxy.windminer.common.constant.CacheConstants;
|
||||
import com.jxy.windminer.common.constant.HttpStatus;
|
||||
import com.jxy.windminer.common.constant.SecurityConstants;
|
||||
import com.jxy.windminer.common.constant.TokenConstants;
|
||||
import com.jxy.windminer.common.context.SecurityContextHolder;
|
||||
import com.jxy.windminer.common.exception.auth.LoginExpiresException;
|
||||
import com.jxy.windminer.common.exception.auth.TokenExpiresException;
|
||||
import com.jxy.windminer.common.exception.auth.UnAuthorizedException;
|
||||
import com.jxy.windminer.common.redis.service.RedisService;
|
||||
import com.jxy.windminer.common.security.auth.AuthUtil;
|
||||
import com.jxy.windminer.common.security.utils.SecurityUtils;
|
||||
import com.jxy.windminer.common.utils.JwtUtils;
|
||||
import com.jxy.windminer.common.utils.ServletUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @Description 自定义请求头拦截器,将请求头数据封装到线程变量中方便后续获取使用
|
||||
* 同时获取当前用户有效时间并刷新有效期
|
||||
* @Date 2022/5/13 17:29
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class HeaderInterceptor implements AsyncHandlerInterceptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HeaderInterceptor.class);
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
System.out.println(handler);
|
||||
System.out.println(handler.toString());
|
||||
|
||||
if(!(handler instanceof HandlerMethod)){
|
||||
|
||||
System.out.println("直接放行了!");
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
//解析token
|
||||
String token = SecurityUtils.getToken();
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
|
||||
{
|
||||
System.out.println("裁剪了token");
|
||||
token = token.replaceFirst(TokenConstants.PREFIX, "");
|
||||
}
|
||||
if (StringUtils.isEmpty(token))
|
||||
{
|
||||
throw new UnAuthorizedException("令牌不能为空");
|
||||
}
|
||||
Claims claims = null;
|
||||
try {
|
||||
claims = JwtUtils.parseToken(token);
|
||||
}catch (Exception e){
|
||||
throw new UnAuthorizedException("令牌解析失败!");
|
||||
}
|
||||
|
||||
if (claims == null)
|
||||
{
|
||||
throw new TokenExpiresException("令牌已过期或验证不正确!");
|
||||
}
|
||||
String userkey = JwtUtils.getUserKey(claims);
|
||||
boolean islogin = redisService.hasKey(getTokenKey(userkey));
|
||||
if (!islogin)
|
||||
{
|
||||
throw new LoginExpiresException("登录状态已过期!");
|
||||
}
|
||||
String userid = JwtUtils.getUserId(claims);
|
||||
String username = JwtUtils.getUserName(claims);
|
||||
if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))
|
||||
{
|
||||
throw new UnAuthorizedException("令牌验证失败!");
|
||||
|
||||
}
|
||||
if(StringUtils.isNotEmpty(token)){
|
||||
SecurityContextHolder.setUserId(JwtUtils.getUserId(token));
|
||||
SecurityContextHolder.setUserName(JwtUtils.getUserName(token));
|
||||
SecurityContextHolder.setUserKey(JwtUtils.getUserKey(token));
|
||||
SecurityContextHolder.setEmail(JwtUtils.getEmail(token));
|
||||
LoginUser loginUser = AuthUtil.getLoginUser(token);
|
||||
if(StringUtils.isNotNull(loginUser)){
|
||||
|
||||
//验证当前用户有效时间
|
||||
AuthUtil.verifyLoginUserExpire(loginUser);
|
||||
SecurityContextHolder.set(SecurityConstants.LOGIN_USER,loginUser);
|
||||
}
|
||||
|
||||
}else {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
|
||||
SecurityContextHolder.remove();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取缓存key
|
||||
*/
|
||||
private String getTokenKey(String token)
|
||||
{
|
||||
return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.jxy.windminer.common.security.service;
|
||||
|
||||
|
||||
|
||||
import com.jxy.windminer.common.constant.CacheConstants;
|
||||
import com.jxy.windminer.common.constant.OrderConstants;
|
||||
import com.jxy.windminer.common.constant.SecurityConstants;
|
||||
import com.jxy.windminer.common.redis.service.RedisService;
|
||||
import com.jxy.windminer.common.security.utils.SecurityUtils;
|
||||
import com.jxy.windminer.common.utils.JwtUtils;
|
||||
import com.jxy.windminer.common.utils.ServletUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.common.utils.ip.IpUtils;
|
||||
import com.jxy.windminer.common.utils.uuid.IdUtils;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Description token验证处理
|
||||
* @Date 2022/5/13 10:06
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Component
|
||||
public class TokenService {
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
/** 秒 */
|
||||
protected static final long MILLIS_SECOND = 1000;
|
||||
|
||||
/** 分 */
|
||||
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
|
||||
|
||||
/** 过期时间/缓存有效期 一个月*/
|
||||
private final static long expireTime = CacheConstants.EXPIRATION ;
|
||||
|
||||
/** 权限缓存前缀 */
|
||||
private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;
|
||||
|
||||
/** 缓存刷新时间 */
|
||||
private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;
|
||||
|
||||
/**
|
||||
* 创建令牌
|
||||
*/
|
||||
public Map<String, Object> createToken(LoginUser loginUser)
|
||||
{
|
||||
String token = IdUtils.fastUUID();
|
||||
Long userId = loginUser.getSysUser().getUserId();
|
||||
String userName = loginUser.getSysUser().getUserName();
|
||||
String email = loginUser.getSysUser().getEmail();
|
||||
loginUser.setToken(token);
|
||||
loginUser.setUserid(userId);
|
||||
loginUser.setUsername(userName);
|
||||
loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
|
||||
refreshToken(loginUser);
|
||||
|
||||
// Jwt存储信息
|
||||
Map<String, Object> claimsMap = new HashMap<String, Object>();
|
||||
claimsMap.put(SecurityConstants.USER_KEY, token);
|
||||
claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
|
||||
claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);
|
||||
claimsMap.put(SecurityConstants.DETAILS_EMAIL,email);
|
||||
|
||||
|
||||
// 接口返回信息
|
||||
Map<String, Object> rspMap = new HashMap<String, Object>();
|
||||
String accessToken = JwtUtils.createToken(claimsMap);
|
||||
//将token存入redis 以便于通过用户邮箱拿到token
|
||||
if(redisService.hasKey(OrderConstants.TOKEN_PRE +email)){
|
||||
redisService.deleteObject(OrderConstants.TOKEN_PRE+email);
|
||||
}
|
||||
redisService.setCacheObject(OrderConstants.TOKEN_PRE+email,accessToken,expireTime,TimeUnit.MINUTES);
|
||||
|
||||
rspMap.put("access_token", accessToken);
|
||||
rspMap.put("expires_in", expireTime);
|
||||
rspMap.put("userName", loginUser.getUsername());
|
||||
return rspMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户身份信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
public LoginUser getLoginUser()
|
||||
{
|
||||
return getLoginUser(ServletUtils.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户身份信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
public LoginUser getLoginUser(HttpServletRequest request)
|
||||
{
|
||||
// 获取请求携带的令牌
|
||||
String token = SecurityUtils.getToken(request);
|
||||
return getLoginUser(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户身份信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
public LoginUser getLoginUser(String token)
|
||||
{
|
||||
LoginUser user = null;
|
||||
try
|
||||
{
|
||||
if (StringUtils.isNotEmpty(token))
|
||||
{
|
||||
String userkey = JwtUtils.getUserKey(token);
|
||||
user = redisService.getCacheObject(getTokenKey(userkey));
|
||||
return user;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户身份信息
|
||||
*/
|
||||
public void setLoginUser(LoginUser loginUser)
|
||||
{
|
||||
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
|
||||
{
|
||||
refreshToken(loginUser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户缓存信息
|
||||
*/
|
||||
public void delLoginUser(String token)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(token))
|
||||
{
|
||||
String userkey = JwtUtils.getUserKey(token);
|
||||
//System.out.println("用户登出,从redis删除key:"+userkey);
|
||||
redisService.deleteObject(getTokenKey(userkey));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证令牌有效期,相差不足120分钟,自动刷新缓存
|
||||
*
|
||||
* @param loginUser
|
||||
*/
|
||||
public void verifyToken(LoginUser loginUser)
|
||||
{
|
||||
long expireTime = loginUser.getExpireTime();
|
||||
long currentTime = System.currentTimeMillis();
|
||||
//可以考虑直接刷新缓存 而不是小于才刷新缓存
|
||||
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
|
||||
{
|
||||
refreshToken(loginUser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新令牌有效期
|
||||
*
|
||||
* @param loginUser 登录信息
|
||||
*/
|
||||
public void refreshToken(LoginUser loginUser)
|
||||
{
|
||||
loginUser.setLoginTime(System.currentTimeMillis());
|
||||
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
|
||||
// 根据uuid将loginUser缓存
|
||||
String userKey = getTokenKey(loginUser.getToken());
|
||||
redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private String getTokenKey(String token)
|
||||
{
|
||||
return ACCESS_TOKEN + token;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.jxy.windminer.common.security.utils;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.constant.SecurityConstants;
|
||||
import com.jxy.windminer.common.constant.TokenConstants;
|
||||
import com.jxy.windminer.common.context.SecurityContextHolder;
|
||||
import com.jxy.windminer.common.utils.ServletUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import com.jxy.windminer.entity.auth.LoginUser;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @Description 权限获取工具类
|
||||
* @Date 2022/5/11 16:58
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户ID
|
||||
*/
|
||||
public static Long getUserId()
|
||||
{
|
||||
return SecurityContextHolder.getUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户名称
|
||||
*/
|
||||
public static String getUsername()
|
||||
{
|
||||
return SecurityContextHolder.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户key
|
||||
*/
|
||||
public static String getUserKey()
|
||||
{
|
||||
return SecurityContextHolder.getUserKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户邮箱
|
||||
*/
|
||||
public static String getEmail()
|
||||
{
|
||||
return SecurityContextHolder.getEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户信息
|
||||
*/
|
||||
public static LoginUser getLoginUser()
|
||||
{
|
||||
return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
public static String getToken()
|
||||
{
|
||||
return getToken(ServletUtils.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据request获取请求token
|
||||
*/
|
||||
public static String getToken(HttpServletRequest request)
|
||||
{
|
||||
// 从header获取token标识
|
||||
String token = request.getHeader(TokenConstants.AUTHENTICATION);
|
||||
return replaceTokenPrefix(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪token前缀
|
||||
*/
|
||||
public static String replaceTokenPrefix(String token)
|
||||
{
|
||||
// 如果前端设置了令牌前缀,则裁剪掉前缀
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
|
||||
{
|
||||
token = token.replaceFirst(TokenConstants.PREFIX, "");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin(Long userId)
|
||||
{
|
||||
return userId != null && 1L == userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
}
|
||||
88
src/main/java/com/jxy/windminer/common/text/CharsetKit.java
Normal file
88
src/main/java/com/jxy/windminer/common/text/CharsetKit.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package com.jxy.windminer.common.text;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @Description 字符集工具
|
||||
* @Date 2022/5/9 9:01
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class CharsetKit
|
||||
{
|
||||
/** ISO-8859-1 */
|
||||
public static final String ISO_8859_1 = "ISO-8859-1";
|
||||
/** UTF-8 */
|
||||
public static final String UTF_8 = "UTF-8";
|
||||
/** GBK */
|
||||
public static final String GBK = "GBK";
|
||||
|
||||
/** ISO-8859-1 */
|
||||
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
|
||||
/** UTF-8 */
|
||||
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
|
||||
/** GBK */
|
||||
public static final Charset CHARSET_GBK = Charset.forName(GBK);
|
||||
|
||||
/**
|
||||
* 转换为Charset对象
|
||||
*
|
||||
* @param charset 字符集,为空则返回默认字符集
|
||||
* @return Charset
|
||||
*/
|
||||
public static Charset charset(String charset)
|
||||
{
|
||||
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换字符串的字符集编码
|
||||
*
|
||||
* @param source 字符串
|
||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
||||
* @param destCharset 目标字符集,默认UTF-8
|
||||
* @return 转换后的字符集
|
||||
*/
|
||||
public static String convert(String source, String srcCharset, String destCharset)
|
||||
{
|
||||
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换字符串的字符集编码
|
||||
*
|
||||
* @param source 字符串
|
||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
||||
* @param destCharset 目标字符集,默认UTF-8
|
||||
* @return 转换后的字符集
|
||||
*/
|
||||
public static String convert(String source, Charset srcCharset, Charset destCharset)
|
||||
{
|
||||
if (null == srcCharset)
|
||||
{
|
||||
srcCharset = StandardCharsets.ISO_8859_1;
|
||||
}
|
||||
|
||||
if (null == destCharset)
|
||||
{
|
||||
destCharset = StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
return new String(source.getBytes(srcCharset), destCharset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 系统字符集编码
|
||||
*/
|
||||
public static String systemCharset()
|
||||
{
|
||||
return Charset.defaultCharset().name();
|
||||
}
|
||||
}
|
||||
916
src/main/java/com/jxy/windminer/common/text/Convert.java
Normal file
916
src/main/java/com/jxy/windminer/common/text/Convert.java
Normal file
@@ -0,0 +1,916 @@
|
||||
package com.jxy.windminer.common.text;
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Description 类型转换器
|
||||
* @Date 2022/5/9 9:13
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class Convert
|
||||
{
|
||||
/**
|
||||
* 转换为字符串<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static String toStr(Object value, String defaultValue)
|
||||
{
|
||||
if (null == value)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof String)
|
||||
{
|
||||
return (String) value;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为字符串<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static String toStr(Object value)
|
||||
{
|
||||
return toStr(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为字符<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Character toChar(Object value, Character defaultValue)
|
||||
{
|
||||
if (null == value)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Character)
|
||||
{
|
||||
return (Character) value;
|
||||
}
|
||||
|
||||
final String valueStr = toStr(value, null);
|
||||
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为字符<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Character toChar(Object value)
|
||||
{
|
||||
return toChar(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为byte<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Byte toByte(Object value, Byte defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Byte)
|
||||
{
|
||||
return (Byte) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).byteValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Byte.parseByte(valueStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为byte<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Byte toByte(Object value)
|
||||
{
|
||||
return toByte(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Short<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Short toShort(Object value, Short defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Short)
|
||||
{
|
||||
return (Short) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).shortValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Short.parseShort(valueStr.trim());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Short<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Short toShort(Object value)
|
||||
{
|
||||
return toShort(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Number<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Number toNumber(Object value, Number defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return (Number) value;
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return NumberFormat.getInstance().parse(valueStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Number<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Number toNumber(Object value)
|
||||
{
|
||||
return toNumber(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为int<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Integer toInt(Object value, Integer defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Integer)
|
||||
{
|
||||
return (Integer) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(valueStr.trim());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为int<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Integer toInt(Object value)
|
||||
{
|
||||
return toInt(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Integer数组<br>
|
||||
*
|
||||
* @param str 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Integer[] toIntArray(String str)
|
||||
{
|
||||
return toIntArray(",", str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Long数组<br>
|
||||
*
|
||||
* @param str 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Long[] toLongArray(String str)
|
||||
{
|
||||
return toLongArray(",", str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Integer数组<br>
|
||||
*
|
||||
* @param split 分隔符
|
||||
* @param split 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Integer[] toIntArray(String split, String str)
|
||||
{
|
||||
if (StringUtils.isEmpty(str))
|
||||
{
|
||||
return new Integer[] {};
|
||||
}
|
||||
String[] arr = str.split(split);
|
||||
final Integer[] ints = new Integer[arr.length];
|
||||
for (int i = 0; i < arr.length; i++)
|
||||
{
|
||||
final Integer v = toInt(arr[i], 0);
|
||||
ints[i] = v;
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Long数组<br>
|
||||
*
|
||||
* @param split 分隔符
|
||||
* @param str 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Long[] toLongArray(String split, String str)
|
||||
{
|
||||
if (StringUtils.isEmpty(str))
|
||||
{
|
||||
return new Long[] {};
|
||||
}
|
||||
String[] arr = str.split(split);
|
||||
final Long[] longs = new Long[arr.length];
|
||||
for (int i = 0; i < arr.length; i++)
|
||||
{
|
||||
final Long v = toLong(arr[i], null);
|
||||
longs[i] = v;
|
||||
}
|
||||
return longs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为String数组<br>
|
||||
*
|
||||
* @param str 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static String[] toStrArray(String str)
|
||||
{
|
||||
return toStrArray(",", str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为String数组<br>
|
||||
*
|
||||
* @param split 分隔符
|
||||
* @param split 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static String[] toStrArray(String split, String str)
|
||||
{
|
||||
return str.split(split);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为long<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Long toLong(Object value, Long defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Long)
|
||||
{
|
||||
return (Long) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
// 支持科学计数法
|
||||
return new BigDecimal(valueStr.trim()).longValue();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为long<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Long toLong(Object value)
|
||||
{
|
||||
return toLong(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为double<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Double toDouble(Object value, Double defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Double)
|
||||
{
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).doubleValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
// 支持科学计数法
|
||||
return new BigDecimal(valueStr.trim()).doubleValue();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为double<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Double toDouble(Object value)
|
||||
{
|
||||
return toDouble(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Float<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Float toFloat(Object value, Float defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Float)
|
||||
{
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Number)
|
||||
{
|
||||
return ((Number) value).floatValue();
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Float.parseFloat(valueStr.trim());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Float<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Float toFloat(Object value)
|
||||
{
|
||||
return toFloat(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为boolean<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Boolean toBool(Object value, Boolean defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof Boolean)
|
||||
{
|
||||
return (Boolean) value;
|
||||
}
|
||||
String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
valueStr = valueStr.trim().toLowerCase();
|
||||
switch (valueStr)
|
||||
{
|
||||
case "true":
|
||||
return true;
|
||||
case "false":
|
||||
return false;
|
||||
case "yes":
|
||||
return true;
|
||||
case "ok":
|
||||
return true;
|
||||
case "no":
|
||||
return false;
|
||||
case "1":
|
||||
return true;
|
||||
case "0":
|
||||
return false;
|
||||
default:
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为boolean<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static Boolean toBool(Object value)
|
||||
{
|
||||
return toBool(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为BigInteger<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof BigInteger)
|
||||
{
|
||||
return (BigInteger) value;
|
||||
}
|
||||
if (value instanceof Long)
|
||||
{
|
||||
return BigInteger.valueOf((Long) value);
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return new BigInteger(valueStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为BigInteger<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static BigInteger toBigInteger(Object value)
|
||||
{
|
||||
return toBigInteger(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为BigDecimal<br>
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @param defaultValue 转换错误时的默认值
|
||||
* @return 结果
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (value instanceof BigDecimal)
|
||||
{
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
if (value instanceof Long)
|
||||
{
|
||||
return new BigDecimal((Long) value);
|
||||
}
|
||||
if (value instanceof Double)
|
||||
{
|
||||
return new BigDecimal((Double) value);
|
||||
}
|
||||
if (value instanceof Integer)
|
||||
{
|
||||
return new BigDecimal((Integer) value);
|
||||
}
|
||||
final String valueStr = toStr(value, null);
|
||||
if (StringUtils.isEmpty(valueStr))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
try
|
||||
{
|
||||
return new BigDecimal(valueStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为BigDecimal<br>
|
||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
||||
* 转换失败不会报错
|
||||
*
|
||||
* @param value 被转换的值
|
||||
* @return 结果
|
||||
*/
|
||||
public static BigDecimal toBigDecimal(Object value)
|
||||
{
|
||||
return toBigDecimal(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转为字符串<br>
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String utf8Str(Object obj)
|
||||
{
|
||||
return str(obj, CharsetKit.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转为字符串<br>
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param charsetName 字符集
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String str(Object obj, String charsetName)
|
||||
{
|
||||
return str(obj, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转为字符串<br>
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param charset 字符集
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String str(Object obj, Charset charset)
|
||||
{
|
||||
if (null == obj)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj instanceof String)
|
||||
{
|
||||
return (String) obj;
|
||||
}
|
||||
else if (obj instanceof byte[] || obj instanceof Byte[])
|
||||
{
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
return str((byte[]) obj, charset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] bytes = (Byte[]) obj;
|
||||
int length = bytes.length;
|
||||
byte[] dest = new byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
dest[i] = bytes[i];
|
||||
}
|
||||
return str(dest, charset);
|
||||
}
|
||||
}
|
||||
else if (obj instanceof ByteBuffer)
|
||||
{
|
||||
return str((ByteBuffer) obj, charset);
|
||||
}
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将byte数组转为字符串
|
||||
*
|
||||
* @param bytes byte数组
|
||||
* @param charset 字符集
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String str(byte[] bytes, String charset)
|
||||
{
|
||||
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码字节码
|
||||
*
|
||||
* @param data 字符串
|
||||
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String str(byte[] data, Charset charset)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null == charset)
|
||||
{
|
||||
return new String(data);
|
||||
}
|
||||
return new String(data, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将编码的byteBuffer数据转换为字符串
|
||||
*
|
||||
* @param data 数据
|
||||
* @param charset 字符集,如果为空使用当前系统字符集
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String str(ByteBuffer data, String charset)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return str(data, Charset.forName(charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将编码的byteBuffer数据转换为字符串
|
||||
*
|
||||
* @param data 数据
|
||||
* @param charset 字符集,如果为空使用当前系统字符集
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String str(ByteBuffer data, Charset charset)
|
||||
{
|
||||
if (null == charset)
|
||||
{
|
||||
charset = Charset.defaultCharset();
|
||||
}
|
||||
return charset.decode(data).toString();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- 全角半角转换
|
||||
/**
|
||||
* 半角转全角
|
||||
*
|
||||
* @param input String.
|
||||
* @return 全角字符串.
|
||||
*/
|
||||
public static String toSBC(String input)
|
||||
{
|
||||
return toSBC(input, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 半角转全角
|
||||
*
|
||||
* @param input String
|
||||
* @param notConvertSet 不替换的字符集合
|
||||
* @return 全角字符串.
|
||||
*/
|
||||
public static String toSBC(String input, Set<Character> notConvertSet)
|
||||
{
|
||||
char c[] = input.toCharArray();
|
||||
for (int i = 0; i < c.length; i++)
|
||||
{
|
||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
||||
{
|
||||
// 跳过不替换的字符
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c[i] == ' ')
|
||||
{
|
||||
c[i] = '\u3000';
|
||||
}
|
||||
else if (c[i] < '\177')
|
||||
{
|
||||
c[i] = (char) (c[i] + 65248);
|
||||
|
||||
}
|
||||
}
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 全角转半角
|
||||
*
|
||||
* @param input String.
|
||||
* @return 半角字符串
|
||||
*/
|
||||
public static String toDBC(String input)
|
||||
{
|
||||
return toDBC(input, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换全角为半角
|
||||
*
|
||||
* @param text 文本
|
||||
* @param notConvertSet 不替换的字符集合
|
||||
* @return 替换后的字符
|
||||
*/
|
||||
public static String toDBC(String text, Set<Character> notConvertSet)
|
||||
{
|
||||
char c[] = text.toCharArray();
|
||||
for (int i = 0; i < c.length; i++)
|
||||
{
|
||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
||||
{
|
||||
// 跳过不替换的字符
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c[i] == '\u3000')
|
||||
{
|
||||
c[i] = ' ';
|
||||
}
|
||||
else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
|
||||
{
|
||||
c[i] = (char) (c[i] - 65248);
|
||||
}
|
||||
}
|
||||
String returnString = new String(c);
|
||||
|
||||
return returnString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
|
||||
*
|
||||
* @param n 数字
|
||||
* @return 中文大写数字
|
||||
*/
|
||||
public static String digitUppercase(double n)
|
||||
{
|
||||
String[] fraction = { "角", "分" };
|
||||
String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
|
||||
String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
|
||||
|
||||
String head = n < 0 ? "负" : "";
|
||||
n = Math.abs(n);
|
||||
|
||||
String s = "";
|
||||
for (int i = 0; i < fraction.length; i++)
|
||||
{
|
||||
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
|
||||
}
|
||||
if (s.length() < 1)
|
||||
{
|
||||
s = "整";
|
||||
}
|
||||
int integerPart = (int) Math.floor(n);
|
||||
|
||||
for (int i = 0; i < unit[0].length && integerPart > 0; i++)
|
||||
{
|
||||
String p = "";
|
||||
for (int j = 0; j < unit[1].length && n > 0; j++)
|
||||
{
|
||||
p = digit[integerPart % 10] + unit[1][j] + p;
|
||||
integerPart = integerPart / 10;
|
||||
}
|
||||
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
|
||||
}
|
||||
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.jxy.windminer.common.text;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description 字符串格式化
|
||||
* @Date 2022/5/9 9:52
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class StrFormatter
|
||||
{
|
||||
public static final String EMPTY_JSON = "{}";
|
||||
public static final char C_BACKSLASH = '\\';
|
||||
public static final char C_DELIM_START = '{';
|
||||
public static final char C_DELIM_END = '}';
|
||||
|
||||
/**
|
||||
* 格式化字符串<br>
|
||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
||||
* 例:<br>
|
||||
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
|
||||
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
|
||||
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
|
||||
*
|
||||
* @param strPattern 字符串模板
|
||||
* @param argArray 参数列表
|
||||
* @return 结果
|
||||
*/
|
||||
public static String format(final String strPattern, final Object... argArray)
|
||||
{
|
||||
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
|
||||
{
|
||||
return strPattern;
|
||||
}
|
||||
final int strPatternLength = strPattern.length();
|
||||
|
||||
// 初始化定义好的长度以获得更好的性能
|
||||
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
|
||||
|
||||
int handledPosition = 0;
|
||||
int delimIndex;// 占位符所在位置
|
||||
for (int argIndex = 0; argIndex < argArray.length; argIndex++)
|
||||
{
|
||||
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
|
||||
if (delimIndex == -1)
|
||||
{
|
||||
if (handledPosition == 0)
|
||||
{
|
||||
return strPattern;
|
||||
}
|
||||
else
|
||||
{ // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
|
||||
sbuf.append(strPattern, handledPosition, strPatternLength);
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
|
||||
{
|
||||
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
|
||||
{
|
||||
// 转义符之前还有一个转义符,占位符依旧有效
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 占位符被转义
|
||||
argIndex--;
|
||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
||||
sbuf.append(C_DELIM_START);
|
||||
handledPosition = delimIndex + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正常占位符
|
||||
sbuf.append(strPattern, handledPosition, delimIndex);
|
||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
||||
handledPosition = delimIndex + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 加入最后一个占位符后所有的字符
|
||||
sbuf.append(strPattern, handledPosition, strPattern.length());
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
||||
43
src/main/java/com/jxy/windminer/common/utils/CodeUtils.java
Normal file
43
src/main/java/com/jxy/windminer/common/utils/CodeUtils.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/18 14:26
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class CodeUtils {
|
||||
//public static void main(String[] args) {
|
||||
// String s = creatCode(4);
|
||||
// //System.out.println("随机验证码为:" + s);
|
||||
//}
|
||||
|
||||
//定义一个方法返回一个随机验证码
|
||||
public static String creatCode(int n) {
|
||||
|
||||
String code = "";
|
||||
Random r = new Random();
|
||||
//2.在方法内部使用for循环生成指定位数的随机字符,并连接起来
|
||||
for (int i = 0; i <= n; i++) {
|
||||
//生成一个随机字符:大写 ,小写 ,数字(0 1 2)
|
||||
int type = r.nextInt(3);
|
||||
switch (type) {
|
||||
case 0:
|
||||
char ch = (char) (r.nextInt(26) + 65);
|
||||
code += ch;
|
||||
break;
|
||||
case 1:
|
||||
char ch1 = (char) (r.nextInt(26) + 97);
|
||||
code += ch1;
|
||||
break;
|
||||
case 2:
|
||||
code += r.nextInt(10);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
||||
310
src/main/java/com/jxy/windminer/common/utils/DateUtils.java
Normal file
310
src/main/java/com/jxy/windminer/common/utils/DateUtils.java
Normal file
@@ -0,0 +1,310 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @Description 时间工具类
|
||||
* @Date 2022/5/9 18:21
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
||||
{
|
||||
public static String YYYY = "yyyy";
|
||||
|
||||
public static String YYYY_MM = "yyyy-MM";
|
||||
|
||||
public static String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
|
||||
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
||||
|
||||
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static String[] parsePatterns = {
|
||||
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
||||
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
||||
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
|
||||
|
||||
/**
|
||||
* 获取当前Date型日期
|
||||
*
|
||||
* @return Date() 当前日期
|
||||
*/
|
||||
public static Date getNowDate()
|
||||
{
|
||||
return new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期, 默认格式为yyyy-MM-dd
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public static String getDate()
|
||||
{
|
||||
return dateTimeNow(YYYY_MM_DD);
|
||||
}
|
||||
|
||||
public static final String getTime()
|
||||
{
|
||||
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
|
||||
}
|
||||
|
||||
public static final String dateTimeNow()
|
||||
{
|
||||
return dateTimeNow(YYYYMMDDHHMMSS);
|
||||
}
|
||||
|
||||
public static final String dateTimeNow(final String format)
|
||||
{
|
||||
return parseDateToStr(format, new Date());
|
||||
}
|
||||
|
||||
public static final String dateTime(final Date date)
|
||||
{
|
||||
return parseDateToStr(YYYY_MM_DD, date);
|
||||
}
|
||||
|
||||
public static final String parseDateToStr(final String format, final Date date)
|
||||
{
|
||||
return new SimpleDateFormat(format).format(date);
|
||||
}
|
||||
|
||||
public static final Date dateTime(final String format, final String ts)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat(format).parse(ts);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期路径 即年/月/日 如2018/08/08
|
||||
*/
|
||||
public static final String datePath()
|
||||
{
|
||||
Date now = new Date();
|
||||
return DateFormatUtils.format(now, "yyyy/MM/dd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期路径 即年/月/日 如20180808
|
||||
*/
|
||||
public static final String dateTime()
|
||||
{
|
||||
Date now = new Date();
|
||||
return DateFormatUtils.format(now, "yyyyMMdd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期型字符串转化为日期 格式
|
||||
*/
|
||||
public static Date parseDate(Object str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return parseDate(str.toString(), parsePatterns);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期型字符串转化为日期 格式
|
||||
*/
|
||||
public static Date parseCNDate(Object str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
Date date = parseDate(str.toString(), parsePatterns);
|
||||
return UTCToCNDate(date);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器启动时间
|
||||
*/
|
||||
public static Date getServerStartDate()
|
||||
{
|
||||
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
|
||||
return new Date(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个时间差
|
||||
*/
|
||||
public static String getDatePoor(Date endDate, Date nowDate)
|
||||
{
|
||||
long nd = 1000 * 24 * 60 * 60;
|
||||
long nh = 1000 * 60 * 60;
|
||||
long nm = 1000 * 60;
|
||||
// long ns = 1000;
|
||||
// 获得两个时间的毫秒时间差异
|
||||
long diff = endDate.getTime() - nowDate.getTime();
|
||||
// 计算差多少天
|
||||
long day = diff / nd;
|
||||
// 计算差多少小时
|
||||
long hour = diff % nd / nh;
|
||||
// 计算差多少分钟
|
||||
long min = diff % nd % nh / nm;
|
||||
// 计算差多少秒//输出结果
|
||||
// long sec = diff % nd % nh % nm / ns;
|
||||
return day + "天" + hour + "小时" + min + "分钟";
|
||||
}
|
||||
/**
|
||||
* 计算两个时间差 天数
|
||||
*/
|
||||
public static Long getDateDiff(Date endDate, Date nowDate)
|
||||
{
|
||||
long nd = 1000 * 24 * 60 * 60;
|
||||
long nh = 1000 * 60 * 60;
|
||||
long nm = 1000 * 60;
|
||||
// long ns = 1000;
|
||||
// 获得两个时间的毫秒时间差异
|
||||
long diff = endDate.getTime() - nowDate.getTime();
|
||||
// 计算差多少天
|
||||
long day = diff / nd;
|
||||
return day;
|
||||
}
|
||||
|
||||
public static Long getDateDiffSecond(Date endDate, Date nowDate)
|
||||
{
|
||||
long nd = 1000 * 24 * 60 * 60;
|
||||
long nh = 1000 * 60 * 60;
|
||||
long nm = 1000 * 60;
|
||||
long ns = 1000;
|
||||
// 获得两个时间的毫秒时间差异
|
||||
long diff = endDate.getTime() - nowDate.getTime();
|
||||
// 计算差多少秒
|
||||
long sec = diff % nd % nh % nm / ns;
|
||||
return sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个时间差 按月
|
||||
*/
|
||||
public static int getMonthDiff(Date d1, Date d2) {
|
||||
Calendar c1 = Calendar.getInstance();
|
||||
Calendar c2 = Calendar.getInstance();
|
||||
c1.setTime(d1);
|
||||
c2.setTime(d2);
|
||||
int year1 = c1.get(Calendar.YEAR);
|
||||
int year2 = c2.get(Calendar.YEAR);
|
||||
int month1 = c1.get(Calendar.MONTH);
|
||||
int month2 = c2.get(Calendar.MONTH);
|
||||
int day1 = c1.get(Calendar.DAY_OF_MONTH);
|
||||
int day2 = c2.get(Calendar.DAY_OF_MONTH);
|
||||
// 获取年的差值
|
||||
int yearInterval = year1 - year2;
|
||||
// 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
|
||||
if (month1 < month2 || month1 == month2 && day1 < day2) {
|
||||
yearInterval--;
|
||||
}
|
||||
// 获取月数差值
|
||||
int monthInterval = (month1 + 12) - month2;
|
||||
if (day1 < day2) {
|
||||
monthInterval--;
|
||||
}
|
||||
monthInterval %= 12;
|
||||
int monthsDiff = Math.abs(yearInterval * 12 + monthInterval);
|
||||
return monthsDiff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 增加 LocalDateTime ==> Date
|
||||
*/
|
||||
public static Date toDate(LocalDateTime temporalAccessor)
|
||||
{
|
||||
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
|
||||
return Date.from(zdt.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加 LocalDate ==> Date
|
||||
*/
|
||||
public static Date toDate(LocalDate temporalAccessor)
|
||||
{
|
||||
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
|
||||
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
|
||||
return Date.from(zdt.toInstant());
|
||||
}
|
||||
|
||||
public static LocalDate toLocalDate(Date date)
|
||||
{
|
||||
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
return localDate;
|
||||
}
|
||||
|
||||
public static LocalDateTime toLocalDateTime(Date date)
|
||||
{
|
||||
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
return localDateTime;
|
||||
}
|
||||
|
||||
public static boolean isSameDay(final Date d1,final Date d2){
|
||||
String s1 = dateTime(d1);
|
||||
String s2 = dateTime(d2);
|
||||
|
||||
if (s1 == null || s2 == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s1.equals(s2)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSameDate(final Date d1,final Date d2){
|
||||
|
||||
String s1 = parseDateToStr(YYYY_MM_DD_HH_MM_SS,d1);
|
||||
String s2 = parseDateToStr(YYYY_MM_DD_HH_MM_SS,d2);
|
||||
|
||||
if (s1 == null || s2 == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s1.equals(s2)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Date UTCToCNDate(Date date)
|
||||
{
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
// 设置时区为北京
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
|
||||
String format = simpleDateFormat.format(date);
|
||||
|
||||
return DateUtils.parseDate(format);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @Description 错误信息处理类
|
||||
* @Date 2022/5/10 14:06
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class ExceptionUtil
|
||||
{
|
||||
/**
|
||||
* 获取exception的详细错误信息。
|
||||
*/
|
||||
public static String getExceptionMessage(Throwable e)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw, true));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static String getRootErrorMessage(Exception e)
|
||||
{
|
||||
Throwable root = ExceptionUtils.getRootCause(e);
|
||||
root = (root == null ? e : root);
|
||||
if (root == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
String msg = root.getMessage();
|
||||
if (msg == null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
return StringUtils.defaultString(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import com.jxy.windminer.common.exception.file.FileNameLengthLimitExceededException;
|
||||
import com.jxy.windminer.common.exception.file.FileSizeLimitExceededException;
|
||||
import com.jxy.windminer.common.exception.file.InvalidExtensionException;
|
||||
import com.jxy.windminer.common.utils.file.MimeTypeUtils;
|
||||
import com.jxy.windminer.common.utils.uuid.Seq;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 文件上传工具类
|
||||
*
|
||||
* @author jxy
|
||||
*/
|
||||
public class FileUploadUtils
|
||||
{
|
||||
/**
|
||||
* 默认大小 200M
|
||||
*/
|
||||
public static final long DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 默认的文件名最大长度 100
|
||||
*/
|
||||
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* 系统工具大小 200M
|
||||
*/
|
||||
public static final long TOOLS_MAX_SIZE = 200 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 系统工具的文件名最大长度 100
|
||||
*/
|
||||
public static final int TOOLS_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* 根据文件路径上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
* @throws IOException
|
||||
*/
|
||||
public static final String upload(String baseDir, MultipartFile file) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @param allowedExtension 上传文件类型
|
||||
* @return 返回上传成功的文件名
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws FileNameLengthLimitExceededException 文件名太长
|
||||
* @throws IOException 比如读写文件出错时
|
||||
* @throws InvalidExtensionException 文件校验异常
|
||||
*/
|
||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
|
||||
InvalidExtensionException
|
||||
{
|
||||
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
|
||||
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
|
||||
{
|
||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
|
||||
}
|
||||
|
||||
assertAllowed(file, allowedExtension);
|
||||
|
||||
String fileName = extractFilename(file);
|
||||
|
||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||
file.transferTo(Paths.get(absPath));
|
||||
return getPathFileName(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统工具文件上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @param allowedExtension 上传文件类型
|
||||
* @return 返回上传成功的文件名
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws FileNameLengthLimitExceededException 文件名太长
|
||||
* @throws IOException 比如读写文件出错时
|
||||
* @throws InvalidExtensionException 文件校验异常
|
||||
*/
|
||||
public static final String toolsUpload(String baseDir, MultipartFile file, String fileName, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
|
||||
InvalidExtensionException
|
||||
{
|
||||
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
|
||||
if (fileNamelength > FileUploadUtils.TOOLS_NAME_LENGTH)
|
||||
{
|
||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.TOOLS_NAME_LENGTH);
|
||||
}
|
||||
System.out.println("toolsAssertAllowed调用");
|
||||
toolsAssertAllowed(file, allowedExtension);
|
||||
System.out.println("toolsAssertAllowed调用结束");
|
||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||
System.out.println("absPath|"+absPath);
|
||||
file.transferTo(Paths.get(absPath));
|
||||
return getPathFileName(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码文件名
|
||||
*/
|
||||
public static final String extractFilename(MultipartFile file)
|
||||
{
|
||||
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
|
||||
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
|
||||
}
|
||||
|
||||
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
|
||||
{
|
||||
File desc = new File(uploadDir + File.separator + fileName);
|
||||
|
||||
if (!desc.exists())
|
||||
{
|
||||
if (!desc.getParentFile().exists())
|
||||
{
|
||||
desc.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
|
||||
}
|
||||
|
||||
private static final String getPathFileName(String fileName) throws IOException
|
||||
{
|
||||
String pathFileName = "/" + fileName;
|
||||
return pathFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小校验
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws InvalidExtensionException 文件校验异常
|
||||
*/
|
||||
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, InvalidExtensionException
|
||||
{
|
||||
long size = file.getSize();
|
||||
if (size > DEFAULT_MAX_SIZE)
|
||||
{
|
||||
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
String extension = getExtension(file);
|
||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
|
||||
{
|
||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidExtensionException(allowedExtension, extension, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小校验
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
||||
* @throws InvalidExtensionException 文件校验异常
|
||||
*/
|
||||
public static final void toolsAssertAllowed(MultipartFile file, String[] allowedExtension)
|
||||
throws FileSizeLimitExceededException, InvalidExtensionException
|
||||
{
|
||||
long size = file.getSize();
|
||||
if (size > TOOLS_MAX_SIZE)
|
||||
{
|
||||
throw new FileSizeLimitExceededException(TOOLS_MAX_SIZE / 1024 / 1024);
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
String extension = getExtension(file);
|
||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
|
||||
{
|
||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
|
||||
{
|
||||
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
|
||||
fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidExtensionException(allowedExtension, extension, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MIME类型是否是允许的MIME类型
|
||||
*
|
||||
* @param extension 上传文件类型
|
||||
* @param allowedExtension 允许上传文件类型
|
||||
* @return true/false
|
||||
*/
|
||||
public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
|
||||
{
|
||||
for (String str : allowedExtension)
|
||||
{
|
||||
if (str.equalsIgnoreCase(extension))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的后缀
|
||||
*
|
||||
* @param file 表单文件
|
||||
* @return 后缀名
|
||||
*/
|
||||
public static final String getExtension(MultipartFile file)
|
||||
{
|
||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
if (StringUtils.isEmpty(extension))
|
||||
{
|
||||
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
||||
146
src/main/java/com/jxy/windminer/common/utils/JwtUtils.java
Normal file
146
src/main/java/com/jxy/windminer/common/utils/JwtUtils.java
Normal file
@@ -0,0 +1,146 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import com.jxy.windminer.common.constant.SecurityConstants;
|
||||
import com.jxy.windminer.common.constant.TokenConstants;
|
||||
import com.jxy.windminer.common.text.Convert;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description Jwt工具类
|
||||
* @Date 2022/5/10 16:38
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class JwtUtils
|
||||
{
|
||||
public static String secret = TokenConstants.SECRET;
|
||||
|
||||
/**
|
||||
* 从数据声明生成令牌
|
||||
*
|
||||
* @param claims 数据声明
|
||||
* @return 令牌
|
||||
*/
|
||||
public static String createToken(Map<String, Object> claims)
|
||||
{
|
||||
String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从令牌中获取数据声明
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 数据声明
|
||||
*/
|
||||
public static Claims parseToken(String token)
|
||||
{
|
||||
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户标识
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserKey(String token)
|
||||
{
|
||||
Claims claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户标识
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserKey(Claims claims)
|
||||
{
|
||||
return getValue(claims, SecurityConstants.USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户ID
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserId(String token)
|
||||
{
|
||||
Claims claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户邮箱
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getEmail(String token)
|
||||
{
|
||||
Claims claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.DETAILS_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户标识
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getEmail(Claims claims)
|
||||
{
|
||||
return getValue(claims, SecurityConstants.DETAILS_EMAIL);
|
||||
}
|
||||
/**
|
||||
* 根据身份信息获取用户ID
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserId(Claims claims)
|
||||
{
|
||||
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户名
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUserName(String token)
|
||||
{
|
||||
Claims claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份信息获取用户名
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUserName(Claims claims)
|
||||
{
|
||||
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份信息获取键值
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public static String getValue(Claims claims, String key)
|
||||
{
|
||||
return Convert.toStr(claims.get(key), "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import com.jxy.windminer.common.utils.DateUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/18 14:26
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class MysqlBackUpUtils {
|
||||
private static Lock lock = new ReentrantLock();
|
||||
|
||||
@Value("${spring.datasource.username}")
|
||||
private static String username;
|
||||
|
||||
@Value("${spring.datasource.password}")
|
||||
private static String pwd;
|
||||
|
||||
@Value("${my.env}")
|
||||
private static String env;
|
||||
|
||||
|
||||
//根据交易链 币种 地址 验证支付信息
|
||||
static public void addrBackUp(){
|
||||
//验证功能脚本地址
|
||||
String command="mysqldump -h127.0.0.1 -u "+username+" -p"+pwd+" -P3306 miner > /home/ubuntu/backup/addr_backup/mysql" + DateUtils.dateTimeNow()+".sql" ;
|
||||
//if("test".equals(env)){
|
||||
// command="mysqldump -h127.0.0.1 -u "+username+" -p"+pwd+" -P3306 test_miner > /home/ubuntu/testBK/addr_backup/mysql" +DateUtils.dateTimeNow()+".sql" ;
|
||||
//}
|
||||
try {
|
||||
lock.lock();
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
process.waitFor();
|
||||
System.out.println("Database backup completed.");
|
||||
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("地址数据库数据备份异常");
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static public void userBackUp(){
|
||||
//验证功能脚本地址
|
||||
String command="mysqldump -h127.0.0.1 -u "+username+" -p"+pwd+" -P3306 miner > /home/ubuntu/backup/user_backup/mysql" +DateUtils.dateTimeNow()+".sql" ;
|
||||
//if("test".equals(env)){
|
||||
// command="mysqldump -h127.0.0.1 -u "+username+" -p"+pwd+" -P3306 test_miner > /home/ubuntu/testBK/user_backup/mysql" +DateUtils.dateTimeNow()+".sql" ;
|
||||
//}
|
||||
try {
|
||||
lock.lock();
|
||||
System.out.println("用户备份执行指令:|"+command+"|");
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
process.waitFor();
|
||||
System.out.println("Database backup completed.");
|
||||
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("用户数据库数据备份异常");
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/main/java/com/jxy/windminer/common/utils/PageUtils.java
Normal file
36
src/main/java/com/jxy/windminer/common/utils/PageUtils.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.jxy.windminer.common.utils.sql.SqlUtil;
|
||||
import com.jxy.windminer.common.web.page.Page;
|
||||
import com.jxy.windminer.common.web.page.TableSupport;
|
||||
|
||||
/**
|
||||
* @Description 分页工具类
|
||||
* @Date 2022/5/10 14:37
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class PageUtils extends PageHelper
|
||||
{
|
||||
/**
|
||||
* 设置请求分页数据
|
||||
*/
|
||||
public static void startPage()
|
||||
{
|
||||
Page page = TableSupport.buildPageRequest();
|
||||
Integer pageNum = page.getPageNum();
|
||||
Integer pageSize = page.getPageSize();
|
||||
String orderBy = SqlUtil.escapeOrderBySql(page.getOrderBy());
|
||||
Boolean reasonable = page.getReasonable();
|
||||
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理分页的线程变量
|
||||
*/
|
||||
public static void clearPage()
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
|
||||
110
src/main/java/com/jxy/windminer/common/utils/PwdUtils.java
Normal file
110
src/main/java/com/jxy/windminer/common/utils/PwdUtils.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2023/10/25 16:55
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class PwdUtils {
|
||||
|
||||
// 特殊字符
|
||||
private static final String SPECIAL_CHARS = "!@#$%&*_=";
|
||||
// 去掉I、L、O、Q易混淆字符
|
||||
private static final String UPPER_WORD_CHARS = "ABCDEFGHJKMNPRSTUVWXYZ";
|
||||
// 去掉i、l、o、q易混淆字符
|
||||
private static final String LOWER_WORD_CHARS = "abcdefghjkmnprstuvwxyz";
|
||||
// 去掉1、0易混淆字符
|
||||
private static final String NUMBER_CHARS = "23456789";
|
||||
|
||||
|
||||
/**
|
||||
* 生成固定长度的复杂密码
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
public static String randomPassword(int length){
|
||||
return randomPassword(length,true,true,true,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param length 生成密码的长度 建议至少6位
|
||||
* @param isLowerWord 是否包含小写字母
|
||||
* @param isUpperWord 是否包含大写字母
|
||||
* @param isSpecialChar 是否包含特殊字符
|
||||
* @param isNum 是否包含数字
|
||||
* @return String 随机密码
|
||||
* @description: 生成随机密码的工具方法
|
||||
*/
|
||||
public static String randomPassword(int length, Boolean isLowerWord, Boolean isUpperWord, Boolean isSpecialChar, Boolean isNum) {
|
||||
Random rnd = new Random();
|
||||
// 先取必填项1个
|
||||
Map<Integer, String> map = new HashMap<>();
|
||||
if (isLowerWord) {
|
||||
map.put(1, LOWER_WORD_CHARS);
|
||||
}
|
||||
if (isUpperWord) {
|
||||
map.put(2, UPPER_WORD_CHARS);
|
||||
}
|
||||
if (isSpecialChar) {
|
||||
map.put(3, SPECIAL_CHARS);
|
||||
}
|
||||
if (isNum) {
|
||||
map.put(4, NUMBER_CHARS);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<Integer, String> entry : map.entrySet()) {
|
||||
String value = entry.getValue();
|
||||
sb.append(value.charAt(rnd.nextInt(value.length())));
|
||||
}
|
||||
char[] chars = new char[length - sb.length()];
|
||||
for (int i = 0; i < length - sb.length(); i++) {
|
||||
chars[i] = nextChar(rnd, isLowerWord, isUpperWord, isSpecialChar, isNum);
|
||||
}
|
||||
StringBuilder resultSb = sb.append(new String(chars));
|
||||
// 对结果数据乱序处理(前面固定放到前几个了,故需乱序)
|
||||
String[] split = resultSb.toString().split("");
|
||||
List<String> strings = Arrays.asList(split);
|
||||
Collections.shuffle(strings);
|
||||
StringBuilder stringBuilder = new StringBuilder(strings.size());
|
||||
strings.forEach(stringBuilder::append);
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
private static char nextChar(Random rnd, Boolean isLowerWord, Boolean isUpperWord, Boolean isSpecialChar, Boolean isNum) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
if (isLowerWord) {
|
||||
list.add(1);
|
||||
}
|
||||
if (isUpperWord) {
|
||||
list.add(2);
|
||||
}
|
||||
if (isSpecialChar) {
|
||||
list.add(3);
|
||||
}
|
||||
if (isNum) {
|
||||
list.add(4);
|
||||
}
|
||||
if (list.size() == 0) {
|
||||
// 默认数字密码
|
||||
list.add(4);
|
||||
}
|
||||
|
||||
// 随机list索引
|
||||
int index = rnd.nextInt(list.size());
|
||||
Integer integer = list.get(index);
|
||||
switch (integer) {
|
||||
case 1:
|
||||
return LOWER_WORD_CHARS.charAt(rnd.nextInt(LOWER_WORD_CHARS.length()));
|
||||
case 2:
|
||||
return UPPER_WORD_CHARS.charAt(rnd.nextInt(UPPER_WORD_CHARS.length()));
|
||||
case 3:
|
||||
return SPECIAL_CHARS.charAt(rnd.nextInt(SPECIAL_CHARS.length()));
|
||||
default:
|
||||
return NUMBER_CHARS.charAt(rnd.nextInt(NUMBER_CHARS.length()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
306
src/main/java/com/jxy/windminer/common/utils/ServletUtils.java
Normal file
306
src/main/java/com/jxy/windminer/common/utils/ServletUtils.java
Normal file
@@ -0,0 +1,306 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jxy.windminer.common.Result.R;
|
||||
import com.jxy.windminer.common.constant.Constants;
|
||||
import com.jxy.windminer.common.text.Convert;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import reactor.core.publisher.Mono;
|
||||
//import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description 客户端工具类
|
||||
* @Date 2022/5/10 14:45
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class ServletUtils
|
||||
{
|
||||
/**
|
||||
* 获取String参数
|
||||
*/
|
||||
public static String getParameter(String name)
|
||||
{
|
||||
System.out.println(getRequest().toString());
|
||||
return getRequest().getParameter(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取String参数
|
||||
*/
|
||||
public static String getParameter(String name, String defaultValue)
|
||||
{
|
||||
return Convert.toStr(getRequest().getParameter(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Integer参数
|
||||
*/
|
||||
public static Integer getParameterToInt(String name)
|
||||
{
|
||||
return Convert.toInt(getRequest().getParameter(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Integer参数
|
||||
*/
|
||||
public static Integer getParameterToInt(String name, Integer defaultValue)
|
||||
{
|
||||
return Convert.toInt(getRequest().getParameter(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean参数
|
||||
*/
|
||||
public static Boolean getParameterToBool(String name)
|
||||
{
|
||||
return Convert.toBool(getRequest().getParameter(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean参数
|
||||
*/
|
||||
public static Boolean getParameterToBool(String name, Boolean defaultValue)
|
||||
{
|
||||
return Convert.toBool(getRequest().getParameter(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public static HttpServletRequest getRequest()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getRequestAttributes().getRequest();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取response
|
||||
*/
|
||||
public static HttpServletResponse getResponse()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getRequestAttributes().getResponse();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取session
|
||||
*/
|
||||
public static HttpSession getSession()
|
||||
{
|
||||
return getRequest().getSession();
|
||||
}
|
||||
|
||||
public static ServletRequestAttributes getRequestAttributes()
|
||||
{
|
||||
try
|
||||
{
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
return (ServletRequestAttributes) attributes;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getHeader(HttpServletRequest request, String name)
|
||||
{
|
||||
String value = request.getHeader(name);
|
||||
if (StringUtils.isEmpty(value))
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return urlDecode(value);
|
||||
}
|
||||
|
||||
public static Map<String, String> getHeaders(HttpServletRequest request)
|
||||
{
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
Enumeration<String> enumeration = request.getHeaderNames();
|
||||
if (enumeration != null)
|
||||
{
|
||||
while (enumeration.hasMoreElements())
|
||||
{
|
||||
String key = enumeration.nextElement();
|
||||
String value = request.getHeader(key);
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串渲染到客户端
|
||||
*
|
||||
* @param response 渲染对象
|
||||
* @param string 待渲染的字符串
|
||||
*/
|
||||
public static void renderString(HttpServletResponse response, String string)
|
||||
{
|
||||
try
|
||||
{
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.getWriter().print(string);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Ajax异步请求
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
public static boolean isAjaxRequest(HttpServletRequest request)
|
||||
{
|
||||
String accept = request.getHeader("accept");
|
||||
if (accept != null && accept.contains("application/json"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
String xRequestedWith = request.getHeader("X-Requested-With");
|
||||
if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
String uri = request.getRequestURI();
|
||||
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
String ajax = request.getParameter("__ajax");
|
||||
return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容编码
|
||||
*
|
||||
* @param str 内容
|
||||
* @return 编码后的内容
|
||||
*/
|
||||
public static String urlEncode(String str)
|
||||
{
|
||||
try
|
||||
{
|
||||
return URLEncoder.encode(str, Constants.UTF8);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容解码
|
||||
*
|
||||
* @param str 内容
|
||||
* @return 解码后的内容
|
||||
*/
|
||||
public static String urlDecode(String str)
|
||||
{
|
||||
try
|
||||
{
|
||||
return URLDecoder.decode(str, Constants.UTF8);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value)
|
||||
{
|
||||
return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code)
|
||||
{
|
||||
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param status http状态码
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, int code)
|
||||
{
|
||||
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param contentType content-type
|
||||
* @param status http状态码
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code)
|
||||
{
|
||||
response.setStatusCode(status);
|
||||
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
|
||||
R<?> result = R.fail(code, value.toString());
|
||||
DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(result).getBytes());
|
||||
return response.writeWith(Mono.just(dataBuffer));
|
||||
}
|
||||
}
|
||||
114
src/main/java/com/jxy/windminer/common/utils/SpringUtils.java
Normal file
114
src/main/java/com/jxy/windminer/common/utils/SpringUtils.java
Normal file
@@ -0,0 +1,114 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description Spring工具类
|
||||
* 方便在非spring管理环境中获取bean
|
||||
* @Date 2022/5/9 17:27
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Component
|
||||
public final class SpringUtils implements BeanFactoryPostProcessor
|
||||
{
|
||||
/** Spring应用Context环境 */
|
||||
private static ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
|
||||
{
|
||||
SpringUtils.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象
|
||||
*
|
||||
* @param name
|
||||
* @return Object
|
||||
* @throws BeansException
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String name) throws BeansException
|
||||
{
|
||||
return (T) beanFactory.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型为requiredType的对象
|
||||
*
|
||||
* @param clz
|
||||
* @return
|
||||
* @throws BeansException
|
||||
*
|
||||
*/
|
||||
public static <T> T getBean(Class<T> clz) throws BeansException
|
||||
{
|
||||
T result = (T) beanFactory.getBean(clz);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*判断BeanFactory中是否包含有所给名字的bean
|
||||
* @param name
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean containsBean(String name)
|
||||
{
|
||||
return beanFactory.containsBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
|
||||
*
|
||||
* @param name
|
||||
* @return boolean
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*
|
||||
*/
|
||||
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
|
||||
{
|
||||
return beanFactory.isSingleton(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return Class 注册对象的类型
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*
|
||||
*/
|
||||
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
|
||||
{
|
||||
return beanFactory.getType(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @throws NoSuchBeanDefinitionException
|
||||
*
|
||||
*/
|
||||
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
|
||||
{
|
||||
return beanFactory.getAliases(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取aop代理对象
|
||||
*
|
||||
* @param invoker
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAopProxy(T invoker)
|
||||
{
|
||||
return (T) AopContext.currentProxy();
|
||||
}
|
||||
}
|
||||
548
src/main/java/com/jxy/windminer/common/utils/StringUtils.java
Normal file
548
src/main/java/com/jxy/windminer/common/utils/StringUtils.java
Normal file
@@ -0,0 +1,548 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import com.jxy.windminer.common.constant.Constants;
|
||||
import com.jxy.windminer.common.text.StrFormatter;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description 字符串工具类
|
||||
* @Date 2022/5/9 14:41
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||
{
|
||||
/** 空字符串 */
|
||||
private static final String NULLSTR = "";
|
||||
|
||||
public static final int INDEX_NOT_FOUND = -1;
|
||||
|
||||
/** 下划线 */
|
||||
private static final char SEPARATOR = '_';
|
||||
|
||||
/**
|
||||
* 获取参数不为空值
|
||||
*
|
||||
* @param value defaultValue 要判断的value
|
||||
* @return value 返回值
|
||||
*/
|
||||
public static <T> T nvl(T value, T defaultValue)
|
||||
{
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个Collection是否为空, 包含List,Set,Queue
|
||||
*
|
||||
* @param coll 要判断的Collection
|
||||
* @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isEmpty(Collection<?> coll)
|
||||
{
|
||||
return isNull(coll) || coll.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个Collection是否非空,包含List,Set,Queue
|
||||
*
|
||||
* @param coll 要判断的Collection
|
||||
* @return true:非空 false:空
|
||||
*/
|
||||
public static boolean isNotEmpty(Collection<?> coll)
|
||||
{
|
||||
return !isEmpty(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个对象数组是否为空
|
||||
*
|
||||
* @param objects 要判断的对象数组
|
||||
** @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isEmpty(Object[] objects)
|
||||
{
|
||||
return isNull(objects) || (objects.length == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个对象数组是否非空
|
||||
*
|
||||
* @param objects 要判断的对象数组
|
||||
* @return true:非空 false:空
|
||||
*/
|
||||
public static boolean isNotEmpty(Object[] objects)
|
||||
{
|
||||
return !isEmpty(objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个Map是否为空
|
||||
*
|
||||
* @param map 要判断的Map
|
||||
* @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isEmpty(Map<?, ?> map)
|
||||
{
|
||||
return isNull(map) || map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个Map是否为空
|
||||
*
|
||||
* @param map 要判断的Map
|
||||
* @return true:非空 false:空
|
||||
*/
|
||||
public static boolean isNotEmpty(Map<?, ?> map)
|
||||
{
|
||||
return !isEmpty(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个字符串是否为空串
|
||||
*
|
||||
* @param str String
|
||||
* @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isEmpty(String str)
|
||||
{
|
||||
return isNull(str) || NULLSTR.equals(str.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个字符串是否为非空串
|
||||
*
|
||||
* @param str String
|
||||
* @return true:非空串 false:空串
|
||||
*/
|
||||
public static boolean isNotEmpty(String str)
|
||||
{
|
||||
return !isEmpty(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个对象是否为空
|
||||
*
|
||||
* @param object Object
|
||||
* @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isNull(Object object)
|
||||
{
|
||||
return object == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个对象是否非空
|
||||
*
|
||||
* @param object Object
|
||||
* @return true:非空 false:空
|
||||
*/
|
||||
public static boolean isNotNull(Object object)
|
||||
{
|
||||
return !isNull(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个对象是否是数组类型(Java基本型别的数组)
|
||||
*
|
||||
* @param object 对象
|
||||
* @return true:是数组 false:不是数组
|
||||
*/
|
||||
public static boolean isArray(Object object)
|
||||
{
|
||||
return isNotNull(object) && object.getClass().isArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 去空格
|
||||
*/
|
||||
public static String trim(String str)
|
||||
{
|
||||
return (str == null ? "" : str.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param start 开始
|
||||
* @return 结果
|
||||
*/
|
||||
public static String substring(final String str, int start)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return NULLSTR;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
{
|
||||
start = str.length() + start;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
if (start > str.length())
|
||||
{
|
||||
return NULLSTR;
|
||||
}
|
||||
|
||||
return str.substring(start);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param start 开始
|
||||
* @param end 结束
|
||||
* @return 结果
|
||||
*/
|
||||
public static String substring(final String str, int start, int end)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return NULLSTR;
|
||||
}
|
||||
|
||||
if (end < 0)
|
||||
{
|
||||
end = str.length() + end;
|
||||
}
|
||||
if (start < 0)
|
||||
{
|
||||
start = str.length() + start;
|
||||
}
|
||||
|
||||
if (end > str.length())
|
||||
{
|
||||
end = str.length();
|
||||
}
|
||||
|
||||
if (start > end)
|
||||
{
|
||||
return NULLSTR;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
if (end < 0)
|
||||
{
|
||||
end = 0;
|
||||
}
|
||||
|
||||
return str.substring(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为空,并且不是空白字符
|
||||
*
|
||||
* @param str 要判断的value
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean hasText(String str)
|
||||
{
|
||||
return (str != null && !str.isEmpty() && containsText(str));
|
||||
}
|
||||
|
||||
private static boolean containsText(CharSequence str)
|
||||
{
|
||||
int strLen = str.length();
|
||||
for (int i = 0; i < strLen; i++)
|
||||
{
|
||||
if (!Character.isWhitespace(str.charAt(i)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文本, {} 表示占位符<br>
|
||||
*
|
||||
* @param template 文本模板,被替换的部分用 {} 表示
|
||||
* @param params 参数值
|
||||
* @return 格式化后的文本
|
||||
*/
|
||||
public static String format(String template, Object... params)
|
||||
{
|
||||
if (isEmpty(params) || isEmpty(template))
|
||||
{
|
||||
return template;
|
||||
}
|
||||
return StrFormatter.format(template, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为http(s)://开头
|
||||
*
|
||||
* @param link 链接
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isHttp(String link)
|
||||
{
|
||||
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线命名
|
||||
*/
|
||||
public static String toUnderScoreCase(String str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 前置字符是否大写
|
||||
boolean preCharIsUpperCase = true;
|
||||
// 当前字符是否大写
|
||||
boolean curreCharIsUpperCase = true;
|
||||
// 下一字符是否大写
|
||||
boolean nexteCharIsUpperCase = true;
|
||||
for (int i = 0; i < str.length(); i++)
|
||||
{
|
||||
char c = str.charAt(i);
|
||||
if (i > 0)
|
||||
{
|
||||
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
preCharIsUpperCase = false;
|
||||
}
|
||||
|
||||
curreCharIsUpperCase = Character.isUpperCase(c);
|
||||
|
||||
if (i < (str.length() - 1))
|
||||
{
|
||||
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
|
||||
}
|
||||
|
||||
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
|
||||
{
|
||||
sb.append(SEPARATOR);
|
||||
}
|
||||
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
|
||||
{
|
||||
sb.append(SEPARATOR);
|
||||
}
|
||||
sb.append(Character.toLowerCase(c));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含字符串
|
||||
*
|
||||
* @param str 验证字符串
|
||||
* @param strs 字符串组
|
||||
* @return 包含返回true
|
||||
*/
|
||||
public static boolean inStringIgnoreCase(String str, String... strs)
|
||||
{
|
||||
if (str != null && strs != null)
|
||||
{
|
||||
for (String s : strs)
|
||||
{
|
||||
if (str.equalsIgnoreCase(trim(s)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
|
||||
*
|
||||
* @param name 转换前的下划线大写方式命名的字符串
|
||||
* @return 转换后的驼峰式命名的字符串
|
||||
*/
|
||||
public static String convertToCamelCase(String name)
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
// 快速检查
|
||||
if (name == null || name.isEmpty())
|
||||
{
|
||||
// 没必要转换
|
||||
return "";
|
||||
}
|
||||
else if (!name.contains("_"))
|
||||
{
|
||||
// 不含下划线,仅将首字母大写
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
// 用下划线将原始字符串分割
|
||||
String[] camels = name.split("_");
|
||||
for (String camel : camels)
|
||||
{
|
||||
// 跳过原始字符串中开头、结尾的下换线或双重下划线
|
||||
if (camel.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 首字母大写
|
||||
result.append(camel.substring(0, 1).toUpperCase());
|
||||
result.append(camel.substring(1).toLowerCase());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰式命名法 例如:user_name->userName
|
||||
*/
|
||||
public static String toCamelCase(String s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
s = s.toLowerCase();
|
||||
StringBuilder sb = new StringBuilder(s.length());
|
||||
boolean upperCase = false;
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (c == SEPARATOR)
|
||||
{
|
||||
upperCase = true;
|
||||
}
|
||||
else if (upperCase)
|
||||
{
|
||||
sb.append(Character.toUpperCase(c));
|
||||
upperCase = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
|
||||
*
|
||||
* @param str 指定字符串
|
||||
* @param strs 需要检查的字符串数组
|
||||
* @return 是否匹配
|
||||
*/
|
||||
public static boolean matches(String str, List<String> strs)
|
||||
{
|
||||
if (isEmpty(str) || isEmpty(strs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (String pattern : strs)
|
||||
{
|
||||
if (isMatch(pattern, str))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否与规则配置:
|
||||
* ? 表示单个字符;
|
||||
* * 表示一层路径内的任意字符串,不可跨层级;
|
||||
* ** 表示任意层路径;
|
||||
*
|
||||
* @param pattern 匹配规则
|
||||
* @param url 需要匹配的url
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String url)
|
||||
{
|
||||
AntPathMatcher matcher = new AntPathMatcher();
|
||||
return matcher.match(pattern, url);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T cast(Object obj)
|
||||
{
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
|
||||
*
|
||||
* @param num 数字对象
|
||||
* @param size 字符串指定长度
|
||||
* @return 返回数字的字符串格式,该字符串为指定长度。
|
||||
*/
|
||||
public static final String padl(final Number num, final int size)
|
||||
{
|
||||
return padl(num.toString(), size, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
|
||||
*
|
||||
* @param s 原始字符串
|
||||
* @param size 字符串指定长度
|
||||
* @param c 用于补齐的字符
|
||||
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
|
||||
*/
|
||||
public static final String padl(final String s, final int size, final char c)
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder(size);
|
||||
if (s != null)
|
||||
{
|
||||
final int len = s.length();
|
||||
if (s.length() <= size)
|
||||
{
|
||||
for (int i = size - len; i > 0; i--)
|
||||
{
|
||||
sb.append(c);
|
||||
}
|
||||
sb.append(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
return s.substring(len - size, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = size; i > 0; i--)
|
||||
{
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
public static String substringAfter(final String str, final String separator) {
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
if (separator == null) {
|
||||
return NULLSTR;
|
||||
}
|
||||
final int pos = str.indexOf(separator);
|
||||
if (pos == INDEX_NOT_FOUND) {
|
||||
return NULLSTR;
|
||||
}
|
||||
return str.substring(pos + separator.length());
|
||||
}
|
||||
|
||||
public static String clean(String str){
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
|
||||
return str.replaceAll("\\r\\n|\\n|\\\\n| |\\s","");
|
||||
}
|
||||
}
|
||||
112
src/main/java/com/jxy/windminer/common/utils/WalletUils.java
Normal file
112
src/main/java/com/jxy/windminer/common/utils/WalletUils.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/18 14:26
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class WalletUils {
|
||||
private static Lock lock = new ReentrantLock();
|
||||
//根据交易链 币种 地址 验证支付信息
|
||||
static public String createAddress(String chain){
|
||||
//验证功能脚本地址
|
||||
String path="/home/ubuntu/script/wallet/main.js";
|
||||
long t1 = System.currentTimeMillis();
|
||||
|
||||
//String chain = "ETH";
|
||||
//
|
||||
//String num = Convert.toStr(10);
|
||||
String param ="";
|
||||
switch (chain.toUpperCase()){
|
||||
case "ETH": param = "ETH";break;
|
||||
case "TRX": param = "TRON";break;
|
||||
case "TRON": param = "TRON";break;
|
||||
case "POLYGON": param = "ETH";break;
|
||||
case "OPTIMISM": param = "ETH";break;
|
||||
case "ARBITRUM": param = "ETH";break;
|
||||
}
|
||||
if(StringUtils.isBlank(param)){
|
||||
return "";
|
||||
}
|
||||
|
||||
BufferedReader reader = null;
|
||||
BufferedReader errorReader = null;
|
||||
try {
|
||||
lock.lock();
|
||||
String num ="200";
|
||||
ProcessBuilder processBuilder = new ProcessBuilder("node",path,param,num);
|
||||
|
||||
Process process = processBuilder.start();
|
||||
|
||||
//获取进程输出流输入参数
|
||||
//BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
||||
//writer.write("ETH 10");
|
||||
//
|
||||
//writer.newLine();
|
||||
//writer.flush();
|
||||
|
||||
//获取进程输入流读取返回值
|
||||
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
while ((line = reader.readLine()) != null){
|
||||
output.append(line).append("\n");
|
||||
}
|
||||
|
||||
System.out.println("输出内容:|"+output.toString()+"|");
|
||||
|
||||
//获取进程错误流流读取返回值
|
||||
errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
|
||||
String errorLine;
|
||||
|
||||
StringBuilder errorOutput = new StringBuilder();
|
||||
|
||||
while ((errorLine = errorReader.readLine()) != null){
|
||||
errorOutput.append(errorLine).append("\n");
|
||||
}
|
||||
|
||||
reader.close();
|
||||
errorReader.close();
|
||||
|
||||
System.out.println("错误信息:|"+errorOutput.toString()+"|");
|
||||
|
||||
if(StringUtils.isNotBlank(output) && StringUtils.isBlank(errorOutput)){
|
||||
return output.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
catch (Exception e){
|
||||
return "";
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
if (errorReader != null) {
|
||||
errorReader.close();
|
||||
}
|
||||
long t2 = System.currentTimeMillis();
|
||||
if(t2-t1 < 200){
|
||||
// 资源1s最多请求5次 所以每个资源耗时需要200ms
|
||||
//当走到最后整个程序耗时没到200则强制休眠 休眠时间为200减去执行程序已消耗的时间 即200-(t2-t1)
|
||||
long time = 200-(t2-t1);
|
||||
Thread.sleep(time);
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.jxy.windminer.common.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/18 14:26
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class WalletVerifyUtils {
|
||||
private static Lock lock = new ReentrantLock();
|
||||
//根据交易链 币种 地址 验证支付信息
|
||||
static public String verifyAddress(String chain,String coin,String address){
|
||||
//验证功能脚本地址
|
||||
String path="/home/ubuntu/script/wallet-verify/main.js";
|
||||
long t1 = System.currentTimeMillis();
|
||||
|
||||
//String chain = "ETH";
|
||||
//
|
||||
//String num = Convert.toStr(10);
|
||||
String param ="";
|
||||
switch (chain.toUpperCase()){
|
||||
case "ETH": param = "ERC20_analysis_by_receive_address";break;
|
||||
case "TRX": param = "TRC20_analysis_by_receive_address";break;
|
||||
case "TRON": param = "TRC20_analysis_by_receive_address";break;
|
||||
case "POLYGON": param = "Polygon_analysis_by_receive_address";break;
|
||||
case "OPTIMISM": param = "OP_analysis_by_receive_address";break;
|
||||
case "ARBITRUM": param = "Arbitrum_analysis_by_receive_address";break;
|
||||
}
|
||||
if(StringUtils.isBlank(param)){
|
||||
return "";
|
||||
}
|
||||
|
||||
BufferedReader reader = null;
|
||||
BufferedReader errorReader = null;
|
||||
try {
|
||||
lock.lock();
|
||||
ProcessBuilder processBuilder = new ProcessBuilder("node",path,param,coin,address);
|
||||
|
||||
Process process = processBuilder.start();
|
||||
|
||||
//获取进程输出流输入参数
|
||||
//BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
||||
//writer.write("ETH 10");
|
||||
//
|
||||
//writer.newLine();
|
||||
//writer.flush();
|
||||
|
||||
//获取进程输入流读取返回值
|
||||
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
while ((line = reader.readLine()) != null){
|
||||
output.append(line).append("\n");
|
||||
}
|
||||
|
||||
System.out.println("输出内容:|"+output.toString()+"|");
|
||||
|
||||
//获取进程错误流流读取返回值
|
||||
errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
|
||||
String errorLine;
|
||||
|
||||
StringBuilder errorOutput = new StringBuilder();
|
||||
|
||||
while ((errorLine = errorReader.readLine()) != null){
|
||||
errorOutput.append(errorLine).append("\n");
|
||||
}
|
||||
|
||||
reader.close();
|
||||
errorReader.close();
|
||||
|
||||
System.out.println("错误信息:|"+errorOutput.toString()+"|");
|
||||
|
||||
if(StringUtils.isNotBlank(output) && StringUtils.isBlank(errorOutput)){
|
||||
return output.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
catch (Exception e){
|
||||
return "";
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
if (errorReader != null) {
|
||||
errorReader.close();
|
||||
}
|
||||
long t2 = System.currentTimeMillis();
|
||||
if(t2-t1 < 200){
|
||||
// 资源1s最多请求5次 所以每个资源耗时需要200ms
|
||||
//当走到最后整个程序耗时没到200则强制休眠 休眠时间为200减去执行程序已消耗的时间 即200-(t2-t1)
|
||||
long time = 200-(t2-t1);
|
||||
Thread.sleep(time);
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
112
src/main/java/com/jxy/windminer/common/utils/bean/BeanUtils.java
Normal file
112
src/main/java/com/jxy/windminer/common/utils/bean/BeanUtils.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.jxy.windminer.common.utils.bean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @Description Bean工具类
|
||||
* @Date 2022/5/9 10:16
|
||||
* @Author 杜懿
|
||||
*/
|
||||
|
||||
public class BeanUtils extends org.springframework.beans.BeanUtils
|
||||
{
|
||||
/** Bean方法名中属性名开始的下标 */
|
||||
private static final int BEAN_METHOD_PROP_INDEX = 3;
|
||||
|
||||
/** * 匹配getter方法的正则表达式 */
|
||||
private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
|
||||
|
||||
/** * 匹配setter方法的正则表达式 */
|
||||
private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
|
||||
|
||||
/**
|
||||
* Bean属性复制工具方法。
|
||||
*
|
||||
* @param dest 目标对象
|
||||
* @param src 源对象
|
||||
*/
|
||||
public static void copyBeanProp(Object dest, Object src)
|
||||
{
|
||||
try
|
||||
{
|
||||
copyProperties(src, dest);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的setter方法。
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 对象的setter方法列表
|
||||
*/
|
||||
public static List<Method> getSetterMethods(Object obj)
|
||||
{
|
||||
// setter方法列表
|
||||
List<Method> setterMethods = new ArrayList<Method>();
|
||||
|
||||
// 获取所有方法
|
||||
Method[] methods = obj.getClass().getMethods();
|
||||
|
||||
// 查找setter方法
|
||||
|
||||
for (Method method : methods)
|
||||
{
|
||||
Matcher m = SET_PATTERN.matcher(method.getName());
|
||||
if (m.matches() && (method.getParameterTypes().length == 1))
|
||||
{
|
||||
setterMethods.add(method);
|
||||
}
|
||||
}
|
||||
// 返回setter方法列表
|
||||
return setterMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的getter方法。
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 对象的getter方法列表
|
||||
*/
|
||||
|
||||
public static List<Method> getGetterMethods(Object obj)
|
||||
{
|
||||
// getter方法列表
|
||||
List<Method> getterMethods = new ArrayList<Method>();
|
||||
// 获取所有方法
|
||||
Method[] methods = obj.getClass().getMethods();
|
||||
// 查找getter方法
|
||||
for (Method method : methods)
|
||||
{
|
||||
Matcher m = GET_PATTERN.matcher(method.getName());
|
||||
if (m.matches() && (method.getParameterTypes().length == 0))
|
||||
{
|
||||
getterMethods.add(method);
|
||||
}
|
||||
}
|
||||
// 返回getter方法列表
|
||||
return getterMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查Bean方法名中的属性名是否相等。<br>
|
||||
* 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
|
||||
*
|
||||
* @param m1 方法名1
|
||||
* @param m2 方法名2
|
||||
* @return 属性名一样返回true,否则返回false
|
||||
*/
|
||||
|
||||
public static boolean isMethodPropEquals(String m1, String m2)
|
||||
{
|
||||
return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.jxy.windminer.common.utils.bean;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Validator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Description bean对象属性验证
|
||||
* @Date 2022/5/9 10:43
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class BeanValidators {
|
||||
|
||||
public static void validateWithException(Validator validator, Object object, Class<?>... groups)
|
||||
throws ConstraintViolationException
|
||||
{
|
||||
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
|
||||
if (!constraintViolations.isEmpty())
|
||||
{
|
||||
throw new ConstraintViolationException(constraintViolations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.jxy.windminer.common.utils.file;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @Description 文件类型工具类
|
||||
* @Date 2022/5/9 10:49
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class FileTypeUtils {
|
||||
/**
|
||||
* 根据文件获取文件类型
|
||||
* <p>
|
||||
* 例如: aa.txt, 返回: txt
|
||||
*
|
||||
* @param file 文件名
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public static String getFileType(File file)
|
||||
{
|
||||
if (null == file)
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return getFileType(file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
* <p>
|
||||
* 例如: aa.txt, 返回: txt
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public static String getFileType(String fileName)
|
||||
{
|
||||
int separatorIndex = fileName.lastIndexOf(".");
|
||||
if (separatorIndex < 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return fileName.substring(separatorIndex + 1).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
*
|
||||
* @param photoByte 文件字节码
|
||||
* @return 后缀(不含".")
|
||||
*/
|
||||
public static String getFileExtendName(byte[] photoByte)
|
||||
{
|
||||
String strFileExtendName = "JPG";
|
||||
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
|
||||
&& ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
|
||||
{
|
||||
strFileExtendName = "GIF";
|
||||
}
|
||||
else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
|
||||
{
|
||||
strFileExtendName = "JPG";
|
||||
}
|
||||
else if ((photoByte[0] == 66) && (photoByte[1] == 77))
|
||||
{
|
||||
strFileExtendName = "BMP";
|
||||
}
|
||||
else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
|
||||
{
|
||||
strFileExtendName = "PNG";
|
||||
}
|
||||
return strFileExtendName;
|
||||
}
|
||||
|
||||
}
|
||||
257
src/main/java/com/jxy/windminer/common/utils/file/FileUtils.java
Normal file
257
src/main/java/com/jxy/windminer/common/utils/file/FileUtils.java
Normal file
@@ -0,0 +1,257 @@
|
||||
package com.jxy.windminer.common.utils.file;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @Description 文件处理工具类
|
||||
* @Date 2022/5/9 11:31
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class FileUtils {
|
||||
|
||||
/** 字符常量:斜杠 {@code '/'} */
|
||||
public static final char SLASH = '/';
|
||||
|
||||
/** 字符常量:反斜杠 {@code '\\'} */
|
||||
public static final char BACKSLASH = '\\';
|
||||
|
||||
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
||||
|
||||
/**
|
||||
* 输出指定文件的byte数组
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param os 输出流
|
||||
* @return
|
||||
*/
|
||||
public static void writeBytes(String filePath, OutputStream os) throws IOException
|
||||
{
|
||||
FileInputStream fis = null;
|
||||
try
|
||||
{
|
||||
File file = new File(filePath);
|
||||
if (!file.exists())
|
||||
{
|
||||
throw new FileNotFoundException(filePath);
|
||||
}
|
||||
fis = new FileInputStream(file);
|
||||
byte[] b = new byte[1024];
|
||||
int length;
|
||||
while ((length = fis.read(b)) > 0)
|
||||
{
|
||||
os.write(b, 0, length);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (os != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
os.close();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (fis != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fis.close();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param filePath 文件
|
||||
* @return
|
||||
*/
|
||||
public static boolean deleteFile(String filePath)
|
||||
{
|
||||
boolean flag = false;
|
||||
File file = new File(filePath);
|
||||
// 路径为文件且不为空则进行删除
|
||||
if (file.isFile() && file.exists())
|
||||
{
|
||||
file.delete();
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件名称验证
|
||||
*
|
||||
* @param filename 文件名称
|
||||
* @return true 正常 false 非法
|
||||
*/
|
||||
public static boolean isValidFilename(String filename)
|
||||
{
|
||||
return filename.matches(FILENAME_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否可下载
|
||||
*
|
||||
* @param resource 需要下载的文件
|
||||
* @return true 正常 false 非法
|
||||
*/
|
||||
public static boolean checkAllowDownload(String resource)
|
||||
{
|
||||
// 禁止目录上跳级别
|
||||
if (StringUtils.contains(resource, ".."))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查允许下载的文件规则
|
||||
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 不在允许下载的文件规则
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件名重新编码
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param fileName 文件名
|
||||
* @return 编码后的文件名
|
||||
*/
|
||||
public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
|
||||
{
|
||||
final String agent = request.getHeader("USER-AGENT");
|
||||
String filename = fileName;
|
||||
if (agent.contains("MSIE"))
|
||||
{
|
||||
// IE浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
filename = filename.replace("+", " ");
|
||||
}
|
||||
else if (agent.contains("Firefox"))
|
||||
{
|
||||
// 火狐浏览器
|
||||
filename = new String(fileName.getBytes(), "ISO8859-1");
|
||||
}
|
||||
else if (agent.contains("Chrome"))
|
||||
{
|
||||
// google浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其它浏览器
|
||||
filename = URLEncoder.encode(filename, "utf-8");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
*
|
||||
* @param filePath 文件
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getName(String filePath)
|
||||
{
|
||||
if (null == filePath)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int len = filePath.length();
|
||||
if (0 == len)
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
if (isFileSeparator(filePath.charAt(len - 1)))
|
||||
{
|
||||
// 以分隔符结尾的去掉结尾分隔符
|
||||
len--;
|
||||
}
|
||||
|
||||
int begin = 0;
|
||||
char c;
|
||||
for (int i = len - 1; i > -1; i--)
|
||||
{
|
||||
c = filePath.charAt(i);
|
||||
if (isFileSeparator(c))
|
||||
{
|
||||
// 查找最后一个路径分隔符(/或者\)
|
||||
begin = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return filePath.substring(begin, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为Windows或者Linux(Unix)文件分隔符<br>
|
||||
* Windows平台下分隔符为\,Linux(Unix)为/
|
||||
*
|
||||
* @param c 字符
|
||||
* @return 是否为Windows或者Linux(Unix)文件分隔符
|
||||
*/
|
||||
public static boolean isFileSeparator(char c)
|
||||
{
|
||||
return SLASH == c || BACKSLASH == c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件名重新编码
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param realFileName 真实文件名
|
||||
* @return
|
||||
*/
|
||||
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
|
||||
{
|
||||
String percentEncodedFileName = percentEncode(realFileName);
|
||||
|
||||
StringBuilder contentDispositionValue = new StringBuilder();
|
||||
contentDispositionValue.append("attachment; filename=")
|
||||
.append(percentEncodedFileName)
|
||||
.append(";")
|
||||
.append("filename*=")
|
||||
.append("utf-8''")
|
||||
.append(percentEncodedFileName);
|
||||
|
||||
response.setHeader("Content-disposition", contentDispositionValue.toString());
|
||||
response.setHeader("download-filename", percentEncodedFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 百分号编码工具方法
|
||||
*
|
||||
* @param s 需要百分号编码的字符串
|
||||
* @return 百分号编码后的字符串
|
||||
*/
|
||||
public static String percentEncode(String s) throws UnsupportedEncodingException
|
||||
{
|
||||
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
|
||||
return encode.replaceAll("\\+", "%20");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.jxy.windminer.common.utils.file;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @Description 图片处理工具类
|
||||
* @Date 2022/5/9 14:03
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class ImageUtils
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
|
||||
|
||||
public static byte[] getImage(String imagePath)
|
||||
{
|
||||
InputStream is = getFile(imagePath);
|
||||
try
|
||||
{
|
||||
return IOUtils.toByteArray(is);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("图片加载异常 {}", e);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream getFile(String imagePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] result = readFile(imagePath);
|
||||
result = Arrays.copyOf(result, result.length);
|
||||
return new ByteArrayInputStream(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("获取图片异常 {}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件为字节数据
|
||||
*
|
||||
* @param url 地址
|
||||
* @return 字节数据
|
||||
*/
|
||||
public static byte[] readFile(String url)
|
||||
{
|
||||
InputStream in = null;
|
||||
try
|
||||
{
|
||||
// 网络地址
|
||||
URL urlObj = new URL(url);
|
||||
URLConnection urlConnection = urlObj.openConnection();
|
||||
urlConnection.setConnectTimeout(30 * 1000);
|
||||
urlConnection.setReadTimeout(60 * 1000);
|
||||
urlConnection.setDoInput(true);
|
||||
in = urlConnection.getInputStream();
|
||||
return IOUtils.toByteArray(in);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("访问文件异常 {}", e);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.jxy.windminer.common.utils.file;
|
||||
|
||||
/**
|
||||
* @Description 媒体类型工具类
|
||||
* @Date 2022/5/9 14:31
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class MimeTypeUtils
|
||||
{
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String IMAGE_JPG = "image/jpg";
|
||||
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String IMAGE_BMP = "image/bmp";
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
|
||||
|
||||
public static final String[] FLASH_EXTENSION = { "swf", "flv" };
|
||||
|
||||
public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3","aif", "aiff", "wav", "wma", "wmv", "mid", "avi", "mpg",
|
||||
"asf", "rm", "rmvb" };
|
||||
|
||||
public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
|
||||
|
||||
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
|
||||
// 图片
|
||||
"bmp", "gif", "jpg", "jpeg", "png",
|
||||
// word excel powerpoint
|
||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
||||
// 压缩文件
|
||||
"rar", "zip", "gz", "bz2", "7z",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb",
|
||||
// pdf
|
||||
"pdf" };
|
||||
|
||||
public static final String[] DEFAULT_WINDMINER_EXTENSION = {
|
||||
// 图片
|
||||
"jpg", "jpeg", "png",
|
||||
//音频
|
||||
"mp3","aif", "aiff", "wav", "wma",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb"};
|
||||
|
||||
public static String getExtension(String prefix)
|
||||
{
|
||||
switch (prefix)
|
||||
{
|
||||
case IMAGE_PNG:
|
||||
return "png";
|
||||
case IMAGE_JPG:
|
||||
return "jpg";
|
||||
case IMAGE_JPEG:
|
||||
return "jpeg";
|
||||
case IMAGE_BMP:
|
||||
return "bmp";
|
||||
case IMAGE_GIF:
|
||||
return "gif";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.jxy.windminer.common.utils.html;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 转义和反转义工具类
|
||||
*
|
||||
* @author 杜懿
|
||||
*/
|
||||
public class EscapeUtil
|
||||
{
|
||||
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
||||
|
||||
private static final char[][] TEXT = new char[64][];
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
TEXT[i] = new char[] { (char) i };
|
||||
}
|
||||
|
||||
// special HTML characters
|
||||
TEXT['\''] = "'".toCharArray(); // 单引号
|
||||
TEXT['"'] = """.toCharArray(); // 双引号
|
||||
TEXT['&'] = "&".toCharArray(); // &符
|
||||
TEXT['<'] = "<".toCharArray(); // 小于号
|
||||
TEXT['>'] = ">".toCharArray(); // 大于号
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义文本中的HTML字符为安全的字符
|
||||
*
|
||||
* @param text 被转义的文本
|
||||
* @return 转义后的文本
|
||||
*/
|
||||
public static String escape(String text)
|
||||
{
|
||||
return encode(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原被转义的HTML特殊字符
|
||||
*
|
||||
* @param content 包含转义符的HTML内容
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
public static String unescape(String content)
|
||||
{
|
||||
return decode(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有HTML标签,但是不删除标签内的内容
|
||||
*
|
||||
* @param content 文本
|
||||
* @return 清除标签后的文本
|
||||
*/
|
||||
public static String clean(String content)
|
||||
{
|
||||
return new HTMLFilter().filter(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape编码
|
||||
*
|
||||
* @param text 被编码的文本
|
||||
* @return 编码后的字符
|
||||
*/
|
||||
private static String encode(String text)
|
||||
{
|
||||
if (StringUtils.isEmpty(text))
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
final StringBuilder tmp = new StringBuilder(text.length() * 6);
|
||||
char c;
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
c = text.charAt(i);
|
||||
if (c < 256)
|
||||
{
|
||||
tmp.append("%");
|
||||
if (c < 16)
|
||||
{
|
||||
tmp.append("0");
|
||||
}
|
||||
tmp.append(Integer.toString(c, 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.append("%u");
|
||||
if (c <= 0xfff)
|
||||
{
|
||||
// issue#I49JU8@Gitee
|
||||
tmp.append("0");
|
||||
}
|
||||
tmp.append(Integer.toString(c, 16));
|
||||
}
|
||||
}
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape解码
|
||||
*
|
||||
* @param content 被转义的内容
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String decode(String content)
|
||||
{
|
||||
if (StringUtils.isEmpty(content))
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
StringBuilder tmp = new StringBuilder(content.length());
|
||||
int lastPos = 0, pos = 0;
|
||||
char ch;
|
||||
while (lastPos < content.length())
|
||||
{
|
||||
pos = content.indexOf("%", lastPos);
|
||||
if (pos == lastPos)
|
||||
{
|
||||
if (content.charAt(pos + 1) == 'u')
|
||||
{
|
||||
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
|
||||
tmp.append(ch);
|
||||
lastPos = pos + 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
|
||||
tmp.append(ch);
|
||||
lastPos = pos + 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos == -1)
|
||||
{
|
||||
tmp.append(content.substring(lastPos));
|
||||
lastPos = content.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.append(content.substring(lastPos, pos));
|
||||
lastPos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
//public static void main(String[] args)
|
||||
//{
|
||||
// //String html = "<script>alert(1);</script>";
|
||||
//
|
||||
//
|
||||
// String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
|
||||
// // String html = "<123";
|
||||
// // String html = "123>";
|
||||
//
|
||||
// String escape = EscapeUtil.escape(html);
|
||||
// System.out.println("clean: " + EscapeUtil.clean(html));
|
||||
// System.out.println("escape: " + escape);
|
||||
// System.out.println("unescape: " + EscapeUtil.unescape(escape));
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,566 @@
|
||||
package com.jxy.windminer.common.utils.html;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* HTML过滤器,用于去除XSS漏洞隐患。
|
||||
*
|
||||
* @author 杜懿
|
||||
*/
|
||||
public final class HTMLFilter
|
||||
{
|
||||
/**
|
||||
* regex flag union representing /si modifiers in php
|
||||
**/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("\"");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* set of allowed html elements, along with allowed attributes for each element
|
||||
**/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/**
|
||||
* counts of open tags for each (allowable) html element
|
||||
**/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
* set of disallowed html elements
|
||||
**/
|
||||
private final String[] vDisallowed;
|
||||
/**
|
||||
* attributes which should be checked for valid protocols
|
||||
**/
|
||||
private final String[] vProtocolAtts;
|
||||
/**
|
||||
* allowed protocols
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
* entities allowed within html markup
|
||||
**/
|
||||
private final String[] vAllowedEntities;
|
||||
/**
|
||||
* flag determining whether comments are allowed in input String.
|
||||
*/
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
|
||||
* becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public HTMLFilter()
|
||||
{
|
||||
vAllowed = new HashMap<>();
|
||||
|
||||
final ArrayList<String> a_atts = new ArrayList<>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
|
||||
final ArrayList<String> img_atts = new ArrayList<>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
|
||||
final ArrayList<String> no_atts = new ArrayList<>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
|
||||
vSelfClosingTags = new String[] { "img" };
|
||||
vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
|
||||
vDisallowed = new String[] {};
|
||||
vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
|
||||
vProtocolAtts = new String[] { "src", "href" };
|
||||
vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
|
||||
vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public HTMLFilter(final Map<String, Object> conf)
|
||||
{
|
||||
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
vTagCounts.clear();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal)
|
||||
{
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
|
||||
public static String htmlSpecialChars(final String s)
|
||||
{
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input)
|
||||
{
|
||||
reset();
|
||||
String s = input;
|
||||
|
||||
s = escapeComments(s);
|
||||
|
||||
s = balanceHTML(s);
|
||||
|
||||
s = checkTags(s);
|
||||
|
||||
s = processRemoveBlanks(s);
|
||||
|
||||
// s = validateEntities(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isAlwaysMakeTags()
|
||||
{
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
|
||||
public boolean isStripComments()
|
||||
{
|
||||
return stripComment;
|
||||
}
|
||||
|
||||
private String escapeComments(final String s)
|
||||
{
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find())
|
||||
{
|
||||
final String match = m.group(1); // (.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String balanceHTML(String s)
|
||||
{
|
||||
if (alwaysMakeTags)
|
||||
{
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
// 不追加结束标签
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String checkTags(String s)
|
||||
{
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find())
|
||||
{
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
final StringBuilder sBuilder = new StringBuilder(buf.toString());
|
||||
for (String key : vTagCounts.keySet())
|
||||
{
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++)
|
||||
{
|
||||
sBuilder.append("</").append(key).append(">");
|
||||
}
|
||||
}
|
||||
s = sBuilder.toString();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String processRemoveBlanks(final String s)
|
||||
{
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks)
|
||||
{
|
||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
|
||||
{
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
|
||||
{
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
|
||||
{
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
|
||||
private String processTag(final String s)
|
||||
{
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name))
|
||||
{
|
||||
if (false == inArray(name, vSelfClosingTags))
|
||||
{
|
||||
if (vTagCounts.containsKey(name))
|
||||
{
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
|
||||
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name))
|
||||
{
|
||||
final StringBuilder params = new StringBuilder();
|
||||
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<>();
|
||||
final List<String> paramValues = new ArrayList<>();
|
||||
while (m2.find())
|
||||
{
|
||||
paramNames.add(m2.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); // (.*?)
|
||||
}
|
||||
while (m3.find())
|
||||
{
|
||||
paramNames.add(m3.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); // ([^\"\\s']+)
|
||||
}
|
||||
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++)
|
||||
{
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
|
||||
// debug( "paramName='" + paramName + "'" );
|
||||
// debug( "paramValue='" + paramValue + "'" );
|
||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
||||
|
||||
if (allowedAttribute(name, paramName))
|
||||
{
|
||||
if (inArray(paramName, vProtocolAtts))
|
||||
{
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (inArray(name, vSelfClosingTags))
|
||||
{
|
||||
ending = " /";
|
||||
}
|
||||
|
||||
if (inArray(name, vNeedClosingTags))
|
||||
{
|
||||
ending = "";
|
||||
}
|
||||
|
||||
if (ending == null || ending.length() < 1)
|
||||
{
|
||||
if (vTagCounts.containsKey(name))
|
||||
{
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find())
|
||||
{
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String processParamProtocol(String s)
|
||||
{
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols))
|
||||
{
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1);
|
||||
if (s.startsWith("#//"))
|
||||
{
|
||||
s = "#" + s.substring(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String decodeEntities(String s)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
private String validateEntities(final String s)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String one = m.group(1); // ([^&;]*)
|
||||
final String two = m.group(2); // (?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
|
||||
private String encodeQuotes(final String s)
|
||||
{
|
||||
if (encodeQuotes)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String one = m.group(1); // (>|^)
|
||||
final String two = m.group(2); // ([^<]+?)
|
||||
final String three = m.group(3); // (<|$)
|
||||
// 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(final String preamble, final String term)
|
||||
{
|
||||
|
||||
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble;
|
||||
}
|
||||
|
||||
private boolean isValidEntity(final String entity)
|
||||
{
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
|
||||
private static boolean inArray(final String s, final String[] array)
|
||||
{
|
||||
for (String item : array)
|
||||
{
|
||||
if (item != null && item.equals(s))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowed(final String name)
|
||||
{
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
|
||||
private boolean allowedAttribute(final String name, final String paramName)
|
||||
{
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
||||
267
src/main/java/com/jxy/windminer/common/utils/ip/IpUtils.java
Normal file
267
src/main/java/com/jxy/windminer/common/utils/ip/IpUtils.java
Normal file
@@ -0,0 +1,267 @@
|
||||
package com.jxy.windminer.common.utils.ip;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* @Description 获取ip
|
||||
* @Date 2022/5/9 16:51
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class IpUtils
|
||||
{
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return IP地址
|
||||
*/
|
||||
public static String getIpAddr(HttpServletRequest request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return "unknown";
|
||||
}
|
||||
String ip = request.getHeader("x-forwarded-for");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
||||
{
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
||||
{
|
||||
ip = request.getHeader("X-Forwarded-For");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
||||
{
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
||||
{
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
}
|
||||
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
||||
{
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为内部IP地址
|
||||
*
|
||||
* @param ip IP地址
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean internalIp(String ip)
|
||||
{
|
||||
byte[] addr = textToNumericFormatV4(ip);
|
||||
return internalIp(addr) || "127.0.0.1".equals(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为内部IP地址
|
||||
*
|
||||
* @param addr byte地址
|
||||
* @return 结果
|
||||
*/
|
||||
private static boolean internalIp(byte[] addr)
|
||||
{
|
||||
if (StringUtils.isNull(addr) || addr.length < 2)
|
||||
|
||||
{
|
||||
return true;
|
||||
}
|
||||
final byte b0 = addr[0];
|
||||
final byte b1 = addr[1];
|
||||
// 10.x.x.x/8
|
||||
final byte SECTION_1 = 0x0A;
|
||||
// 172.16.x.x/12
|
||||
final byte SECTION_2 = (byte) 0xAC;
|
||||
final byte SECTION_3 = (byte) 0x10;
|
||||
final byte SECTION_4 = (byte) 0x1F;
|
||||
// 192.168.x.x/16
|
||||
final byte SECTION_5 = (byte) 0xC0;
|
||||
final byte SECTION_6 = (byte) 0xA8;
|
||||
switch (b0)
|
||||
{
|
||||
case SECTION_1:
|
||||
return true;
|
||||
case SECTION_2:
|
||||
if (b1 >= SECTION_3 && b1 <= SECTION_4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case SECTION_5:
|
||||
switch (b1)
|
||||
{
|
||||
case SECTION_6:
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址转换成字节
|
||||
*
|
||||
* @param text IPv4地址
|
||||
* @return byte 字节
|
||||
*/
|
||||
public static byte[] textToNumericFormatV4(String text)
|
||||
{
|
||||
if (text.length() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[4];
|
||||
String[] elements = text.split("\\.", -1);
|
||||
try
|
||||
{
|
||||
long l;
|
||||
int i;
|
||||
switch (elements.length)
|
||||
{
|
||||
case 1:
|
||||
l = Long.parseLong(elements[0]);
|
||||
if ((l < 0L) || (l > 4294967295L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
|
||||
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
|
||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 2:
|
||||
l = Integer.parseInt(elements[0]);
|
||||
if ((l < 0L) || (l > 255L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[0] = (byte) (int) (l & 0xFF);
|
||||
l = Integer.parseInt(elements[1]);
|
||||
if ((l < 0L) || (l > 16777215L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
|
||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 3:
|
||||
for (i = 0; i < 2; ++i)
|
||||
{
|
||||
l = Integer.parseInt(elements[i]);
|
||||
if ((l < 0L) || (l > 255L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[i] = (byte) (int) (l & 0xFF);
|
||||
}
|
||||
l = Integer.parseInt(elements[2]);
|
||||
if ((l < 0L) || (l > 65535L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 4:
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
l = Integer.parseInt(elements[i]);
|
||||
if ((l < 0L) || (l > 255L))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bytes[i] = (byte) (int) (l & 0xFF);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP地址
|
||||
*
|
||||
* @return 本地IP地址
|
||||
*/
|
||||
public static String getHostIp()
|
||||
{
|
||||
try
|
||||
{
|
||||
return InetAddress.getLocalHost().getHostAddress();
|
||||
}
|
||||
catch (UnknownHostException e)
|
||||
{
|
||||
}
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机名
|
||||
*
|
||||
* @return 本地主机名
|
||||
*/
|
||||
public static String getHostName()
|
||||
{
|
||||
try
|
||||
{
|
||||
return InetAddress.getLocalHost().getHostName();
|
||||
}
|
||||
catch (UnknownHostException e)
|
||||
{
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
/**
|
||||
* 从多级反向代理中获得第一个非unknown IP地址
|
||||
*
|
||||
* @param ip 获得的IP地址
|
||||
* @return 第一个非unknown IP地址
|
||||
*/
|
||||
public static String getMultistageReverseProxyIp(String ip)
|
||||
{
|
||||
// 多级反向代理检测
|
||||
if (ip != null && ip.indexOf(",") > 0)
|
||||
{
|
||||
final String[] ips = ip.trim().split(",");
|
||||
for (String subIp : ips)
|
||||
{
|
||||
if (false == isUnknown(subIp))
|
||||
{
|
||||
ip = subIp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测给定字符串是否为未知,多用于检测HTTP请求相关
|
||||
*
|
||||
* @param checkString 被检测的字符串
|
||||
* @return 是否未知
|
||||
*/
|
||||
public static boolean isUnknown(String checkString)
|
||||
{
|
||||
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jxy.windminer.common.utils.poi;
|
||||
|
||||
/**
|
||||
* Excel数据格式处理适配器
|
||||
*
|
||||
* @author 杜懿
|
||||
*/
|
||||
public interface ExcelHandlerAdapter
|
||||
{
|
||||
/**
|
||||
* 格式化
|
||||
*
|
||||
* @param value 单元格数据值
|
||||
* @param args excel注解args参数组
|
||||
*
|
||||
* @return 处理后的值
|
||||
*/
|
||||
Object format(Object value, String[] args);
|
||||
}
|
||||
1168
src/main/java/com/jxy/windminer/common/utils/poi/ExcelUtil.java
Normal file
1168
src/main/java/com/jxy/windminer/common/utils/poi/ExcelUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,406 @@
|
||||
package com.jxy.windminer.common.utils.reflect;
|
||||
|
||||
import com.jxy.windminer.common.text.Convert;
|
||||
import com.jxy.windminer.common.utils.DateUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
||||
*
|
||||
* @author 杜懿
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ReflectUtils
|
||||
{
|
||||
private static final String SETTER_PREFIX = "set";
|
||||
|
||||
private static final String GETTER_PREFIX = "get";
|
||||
|
||||
private static final String CGLIB_CLASS_SEPARATOR = "$$";
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
|
||||
|
||||
/**
|
||||
* 调用Getter方法.
|
||||
* 支持多级,如:对象名.对象名.方法
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E invokeGetter(Object obj, String propertyName)
|
||||
{
|
||||
Object object = obj;
|
||||
for (String name : StringUtils.split(propertyName, "."))
|
||||
{
|
||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
|
||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
||||
}
|
||||
return (E) object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用Setter方法, 仅匹配方法名。
|
||||
* 支持多级,如:对象名.对象名.方法
|
||||
*/
|
||||
public static <E> void invokeSetter(Object obj, String propertyName, E value)
|
||||
{
|
||||
Object object = obj;
|
||||
String[] names = StringUtils.split(propertyName, ".");
|
||||
for (int i = 0; i < names.length; i++)
|
||||
{
|
||||
if (i < names.length - 1)
|
||||
{
|
||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
|
||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
||||
}
|
||||
else
|
||||
{
|
||||
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
|
||||
invokeMethodByName(object, setterMethodName, new Object[] { value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E getFieldValue(final Object obj, final String fieldName)
|
||||
{
|
||||
Field field = getAccessibleField(obj, fieldName);
|
||||
if (field == null)
|
||||
{
|
||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
||||
return null;
|
||||
}
|
||||
E result = null;
|
||||
try
|
||||
{
|
||||
result = (E) field.get(obj);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
logger.error("不可能抛出的异常{}", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
|
||||
*/
|
||||
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
|
||||
{
|
||||
Field field = getAccessibleField(obj, fieldName);
|
||||
if (field == null)
|
||||
{
|
||||
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
field.set(obj, value);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
logger.error("不可能抛出的异常: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用对象方法, 无视private/protected修饰符.
|
||||
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
|
||||
* 同时匹配方法名+参数类型,
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
|
||||
final Object[] args)
|
||||
{
|
||||
if (obj == null || methodName == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
|
||||
if (method == null)
|
||||
{
|
||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return (E) method.invoke(obj, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用对象方法, 无视private/protected修饰符,
|
||||
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
|
||||
* 只匹配函数名,如果有多个同名函数调用第一个。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
|
||||
{
|
||||
Method method = getAccessibleMethodByName(obj, methodName, args.length);
|
||||
if (method == null)
|
||||
{
|
||||
// 如果为空不报错,直接返回空。
|
||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
// 类型转换(将参数数据类型转换为目标方法参数类型)
|
||||
Class<?>[] cs = method.getParameterTypes();
|
||||
for (int i = 0; i < cs.length; i++)
|
||||
{
|
||||
if (args[i] != null && !args[i].getClass().equals(cs[i]))
|
||||
{
|
||||
if (cs[i] == String.class)
|
||||
{
|
||||
args[i] = Convert.toStr(args[i]);
|
||||
if (StringUtils.endsWith((String) args[i], ".0"))
|
||||
{
|
||||
args[i] = StringUtils.substringBefore((String) args[i], ".0");
|
||||
}
|
||||
}
|
||||
else if (cs[i] == Integer.class)
|
||||
{
|
||||
args[i] = Convert.toInt(args[i]);
|
||||
}
|
||||
else if (cs[i] == Long.class)
|
||||
{
|
||||
args[i] = Convert.toLong(args[i]);
|
||||
}
|
||||
else if (cs[i] == Double.class)
|
||||
{
|
||||
args[i] = Convert.toDouble(args[i]);
|
||||
}
|
||||
else if (cs[i] == Float.class)
|
||||
{
|
||||
args[i] = Convert.toFloat(args[i]);
|
||||
}
|
||||
else if (cs[i] == Date.class)
|
||||
{
|
||||
if (args[i] instanceof String)
|
||||
{
|
||||
args[i] = DateUtils.parseDate(args[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
args[i] = DateUtil.getJavaDate((Double) args[i]);
|
||||
}
|
||||
}
|
||||
else if (cs[i] == boolean.class || cs[i] == Boolean.class)
|
||||
{
|
||||
args[i] = Convert.toBool(args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (E) method.invoke(obj, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
|
||||
* 如向上转型到Object仍无法找到, 返回null.
|
||||
*/
|
||||
public static Field getAccessibleField(final Object obj, final String fieldName)
|
||||
{
|
||||
// 为空不报错。直接返回 null
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Validate.notBlank(fieldName, "fieldName can't be blank");
|
||||
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
|
||||
{
|
||||
try
|
||||
{
|
||||
Field field = superClass.getDeclaredField(fieldName);
|
||||
makeAccessible(field);
|
||||
return field;
|
||||
}
|
||||
catch (NoSuchFieldException e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
||||
* 如向上转型到Object仍无法找到, 返回null.
|
||||
* 匹配函数名+参数类型。
|
||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
||||
*/
|
||||
public static Method getAccessibleMethod(final Object obj, final String methodName,
|
||||
final Class<?>... parameterTypes)
|
||||
{
|
||||
// 为空不报错。直接返回 null
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Validate.notBlank(methodName, "methodName can't be blank");
|
||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
|
||||
makeAccessible(method);
|
||||
return method;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
||||
* 如向上转型到Object仍无法找到, 返回null.
|
||||
* 只匹配函数名。
|
||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
||||
*/
|
||||
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
|
||||
{
|
||||
// 为空不报错。直接返回 null
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Validate.notBlank(methodName, "methodName can't be blank");
|
||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
||||
{
|
||||
Method[] methods = searchType.getDeclaredMethods();
|
||||
for (Method method : methods)
|
||||
{
|
||||
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
|
||||
{
|
||||
makeAccessible(method);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
||||
*/
|
||||
public static void makeAccessible(Method method)
|
||||
{
|
||||
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|
||||
&& !method.isAccessible())
|
||||
{
|
||||
method.setAccessible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
||||
*/
|
||||
public static void makeAccessible(Field field)
|
||||
{
|
||||
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|
||||
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
|
||||
{
|
||||
field.setAccessible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
|
||||
* 如无法找到, 返回Object.class.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<T> getClassGenricType(final Class clazz)
|
||||
{
|
||||
return getClassGenricType(clazz, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
|
||||
* 如无法找到, 返回Object.class.
|
||||
*/
|
||||
public static Class getClassGenricType(final Class clazz, final int index)
|
||||
{
|
||||
Type genType = clazz.getGenericSuperclass();
|
||||
|
||||
if (!(genType instanceof ParameterizedType))
|
||||
{
|
||||
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
|
||||
|
||||
if (index >= params.length || index < 0)
|
||||
{
|
||||
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
|
||||
+ params.length);
|
||||
return Object.class;
|
||||
}
|
||||
if (!(params[index] instanceof Class))
|
||||
{
|
||||
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
return (Class) params[index];
|
||||
}
|
||||
|
||||
public static Class<?> getUserClass(Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
throw new RuntimeException("Instance must not be null");
|
||||
}
|
||||
Class clazz = instance.getClass();
|
||||
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
|
||||
{
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass != null && !Object.class.equals(superClass))
|
||||
{
|
||||
return superClass;
|
||||
}
|
||||
}
|
||||
return clazz;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将反射时的checked exception转换为unchecked exception.
|
||||
*/
|
||||
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
|
||||
{
|
||||
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|
||||
|| e instanceof NoSuchMethodException)
|
||||
{
|
||||
return new IllegalArgumentException(msg, e);
|
||||
}
|
||||
else if (e instanceof InvocationTargetException)
|
||||
{
|
||||
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
|
||||
}
|
||||
return new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
292
src/main/java/com/jxy/windminer/common/utils/sign/Base64.java
Normal file
292
src/main/java/com/jxy/windminer/common/utils/sign/Base64.java
Normal file
@@ -0,0 +1,292 @@
|
||||
package com.jxy.windminer.common.utils.sign;
|
||||
|
||||
/**
|
||||
* @Description Base64工具类
|
||||
* @Date 2022/5/17 15:19
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public final class Base64 {
|
||||
|
||||
static private final int BASELENGTH = 256;
|
||||
static private final int LOOKUPLENGTH = 64;
|
||||
static private final int TWENTYFOURBITGROUP = 24;
|
||||
static private final int EIGHTBIT = 8;
|
||||
static private final int SIXTEENBIT = 16;
|
||||
static private final int FOURBYTE = 4;
|
||||
static private final int SIGN = -128;
|
||||
static private final char PAD = '=';
|
||||
static final private byte[] base64Alphabet = new byte[BASELENGTH];
|
||||
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < BASELENGTH; ++i)
|
||||
{
|
||||
base64Alphabet[i] = -1;
|
||||
}
|
||||
for (int i = 'Z'; i >= 'A'; i--)
|
||||
{
|
||||
base64Alphabet[i] = (byte) (i - 'A');
|
||||
}
|
||||
for (int i = 'z'; i >= 'a'; i--)
|
||||
{
|
||||
base64Alphabet[i] = (byte) (i - 'a' + 26);
|
||||
}
|
||||
|
||||
for (int i = '9'; i >= '0'; i--)
|
||||
{
|
||||
base64Alphabet[i] = (byte) (i - '0' + 52);
|
||||
}
|
||||
|
||||
base64Alphabet['+'] = 62;
|
||||
base64Alphabet['/'] = 63;
|
||||
|
||||
for (int i = 0; i <= 25; i++)
|
||||
{
|
||||
lookUpBase64Alphabet[i] = (char) ('A' + i);
|
||||
}
|
||||
|
||||
for (int i = 26, j = 0; i <= 51; i++, j++)
|
||||
{
|
||||
lookUpBase64Alphabet[i] = (char) ('a' + j);
|
||||
}
|
||||
|
||||
for (int i = 52, j = 0; i <= 61; i++, j++)
|
||||
{
|
||||
lookUpBase64Alphabet[i] = (char) ('0' + j);
|
||||
}
|
||||
lookUpBase64Alphabet[62] = (char) '+';
|
||||
lookUpBase64Alphabet[63] = (char) '/';
|
||||
}
|
||||
|
||||
private static boolean isWhiteSpace(char octect)
|
||||
{
|
||||
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
|
||||
}
|
||||
|
||||
private static boolean isPad(char octect)
|
||||
{
|
||||
return (octect == PAD);
|
||||
}
|
||||
|
||||
private static boolean isData(char octect)
|
||||
{
|
||||
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes hex octects into Base64
|
||||
*
|
||||
* @param binaryData Array containing binaryData
|
||||
* @return Encoded Base64 array
|
||||
*/
|
||||
public static String encode(byte[] binaryData)
|
||||
{
|
||||
if (binaryData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int lengthDataBits = binaryData.length * EIGHTBIT;
|
||||
if (lengthDataBits == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
|
||||
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
|
||||
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
|
||||
char encodedData[] = null;
|
||||
|
||||
encodedData = new char[numberQuartet * 4];
|
||||
|
||||
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
|
||||
|
||||
int encodedIndex = 0;
|
||||
int dataIndex = 0;
|
||||
|
||||
for (int i = 0; i < numberTriplets; i++)
|
||||
{
|
||||
b1 = binaryData[dataIndex++];
|
||||
b2 = binaryData[dataIndex++];
|
||||
b3 = binaryData[dataIndex++];
|
||||
|
||||
l = (byte) (b2 & 0x0f);
|
||||
k = (byte) (b1 & 0x03);
|
||||
|
||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
||||
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
|
||||
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
|
||||
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
|
||||
}
|
||||
|
||||
// form integral number of 6-bit groups
|
||||
if (fewerThan24bits == EIGHTBIT)
|
||||
{
|
||||
b1 = binaryData[dataIndex];
|
||||
k = (byte) (b1 & 0x03);
|
||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
}
|
||||
else if (fewerThan24bits == SIXTEENBIT)
|
||||
{
|
||||
b1 = binaryData[dataIndex];
|
||||
b2 = binaryData[dataIndex + 1];
|
||||
l = (byte) (b2 & 0x0f);
|
||||
k = (byte) (b1 & 0x03);
|
||||
|
||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
||||
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
|
||||
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
}
|
||||
return new String(encodedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes Base64 data into octects
|
||||
*
|
||||
* @param encoded string containing Base64 data
|
||||
* @return Array containind decoded data.
|
||||
*/
|
||||
public static byte[] decode(String encoded)
|
||||
{
|
||||
if (encoded == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
char[] base64Data = encoded.toCharArray();
|
||||
// remove white spaces
|
||||
int len = removeWhiteSpace(base64Data);
|
||||
|
||||
if (len % FOURBYTE != 0)
|
||||
{
|
||||
return null;// should be divisible by four
|
||||
}
|
||||
|
||||
int numberQuadruple = (len / FOURBYTE);
|
||||
|
||||
if (numberQuadruple == 0)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
byte decodedData[] = null;
|
||||
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
|
||||
char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
|
||||
|
||||
int i = 0;
|
||||
int encodedIndex = 0;
|
||||
int dataIndex = 0;
|
||||
decodedData = new byte[(numberQuadruple) * 3];
|
||||
|
||||
for (; i < numberQuadruple - 1; i++)
|
||||
{
|
||||
|
||||
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
|
||||
|| !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
|
||||
{
|
||||
return null;
|
||||
} // if found "no data" just return null
|
||||
|
||||
b1 = base64Alphabet[d1];
|
||||
b2 = base64Alphabet[d2];
|
||||
b3 = base64Alphabet[d3];
|
||||
b4 = base64Alphabet[d4];
|
||||
|
||||
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
||||
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
||||
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
|
||||
}
|
||||
|
||||
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])))
|
||||
{
|
||||
return null;// if found "no data" just return null
|
||||
}
|
||||
|
||||
b1 = base64Alphabet[d1];
|
||||
b2 = base64Alphabet[d2];
|
||||
|
||||
d3 = base64Data[dataIndex++];
|
||||
d4 = base64Data[dataIndex++];
|
||||
if (!isData((d3)) || !isData((d4)))
|
||||
{// Check if they are PAD characters
|
||||
if (isPad(d3) && isPad(d4))
|
||||
{
|
||||
if ((b2 & 0xf) != 0)// last 4 bits should be zero
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] tmp = new byte[i * 3 + 1];
|
||||
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
|
||||
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
|
||||
return tmp;
|
||||
}
|
||||
else if (!isPad(d3) && isPad(d4))
|
||||
{
|
||||
b3 = base64Alphabet[d3];
|
||||
if ((b3 & 0x3) != 0)// last 2 bits should be zero
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] tmp = new byte[i * 3 + 2];
|
||||
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
|
||||
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
||||
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
||||
return tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // No PAD e.g 3cQl
|
||||
b3 = base64Alphabet[d3];
|
||||
b4 = base64Alphabet[d4];
|
||||
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
||||
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
||||
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
|
||||
|
||||
}
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove WhiteSpace from MIME containing encoded Base64 data.
|
||||
*
|
||||
* @param data the byte array of base64 data (with WS)
|
||||
* @return the new length
|
||||
*/
|
||||
private static int removeWhiteSpace(char[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// count characters that's not whitespace
|
||||
int newSize = 0;
|
||||
int len = data.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!isWhiteSpace(data[i]))
|
||||
{
|
||||
data[newSize++] = data[i];
|
||||
}
|
||||
}
|
||||
return newSize;
|
||||
}
|
||||
|
||||
}
|
||||
173
src/main/java/com/jxy/windminer/common/utils/sign/RsaUtils.java
Normal file
173
src/main/java/com/jxy/windminer/common/utils/sign/RsaUtils.java
Normal file
@@ -0,0 +1,173 @@
|
||||
package com.jxy.windminer.common.utils.sign;
|
||||
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* @Description TODO
|
||||
* @Date 2022/11/25 17:35
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class RsaUtils {
|
||||
|
||||
// Rsa 私钥
|
||||
public static String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTla3smq/59AVL\n" +
|
||||
"g0PayphcAyefuJlgJOHF7nN9eOpnbtDdsgLQ0giAoByujHcp7mZv6EngPmlgVudF\n" +
|
||||
"1pELpfXrhAMwszE13aOBWtJXAlsQgloE14sjNxLpnOjNUQyAiq44F+6vC3yKXTvR\n" +
|
||||
"4VzOgEuIVed8uWZOnHR9J6bilMEshE+4zR9BAB4PjX0+7+nTrsS5gEw7LX1zql/R\n" +
|
||||
"BCdRVt09mMO9lvxYtde2kqEBZP/2joKMmSJ5OaSOyU/jv1+T8iZFduYAvCgHJWlj\n" +
|
||||
"6Rfo1NfqAETLney+LtquULUgr4+n2df9FtSQtGhcfaF7p2B3kX/xAJXh4cwnoJ4u\n" +
|
||||
"5Q5FXHYVAgMBAAECggEAMEj8Q/6ZIkWZ3725Ankxg+4EYOLTvaktDOp52Kx7cddM\n" +
|
||||
"OwugsN79qbzgTsUnfJ43KlqsYUxc5+ttI/bvauUY1gJuZ/K8zDokUiTT059qAL5+\n" +
|
||||
"pJQ74HF1E3MHfbN9UuhTEeIESlYoubrFKARyFX4Zvqc8CK6WtmHmA5nE7/hajTnK\n" +
|
||||
"aToKPLP8KXa/U8W8paKUhUV1aoEBtqxOLQs1rg8PREGCUmUyTRzzxblm/SVd6YYB\n" +
|
||||
"vCKcbZgKQwt7lrKrUVcVc+VDrJ6UWU+XNMABWT+NwUvrTayQehot5lxfZxfPk0IG\n" +
|
||||
"h9OhOtclOQ8FfRh2UeLmkAG4PTadr+r7Lrbcm9NokQKBgQDtKbNcvJIuXKqecVxA\n" +
|
||||
"+QiINx/PPp44wFhZk9iIHh02MVRNtgxEIMpUleyIHlEGMmTKcchO56GRXiFfqNu5\n" +
|
||||
"8DduoU4tbKztl1YtYctMRWvYDvcNcveEhm/+J01e/Zyej4ElLjTZeg+rOSREhkMr\n" +
|
||||
"EKDSA6AoltjpcCThYxG+Rtr0SwKBgQDkY+PRDc5BWw+icKXu6DgajUw+i3pzVRMW\n" +
|
||||
"lF/Q4sNi7zlTP+YcnuhqgHu0ILFUgTQAgbdqVKZjG3g9bI7Ziaus10H+LXTizNue\n" +
|
||||
"QNibe/UZ29Q2SsDeATMwDGrUQ2d0FuGaVWJoY4auNWuZr+6XaEnih2x5FniktdQk\n" +
|
||||
"+YbYinQDHwKBgFBCs4un2YTNIYS7cnAel0+Z8C7vzxX/qiaujTILlvE3IoOmH2KT\n" +
|
||||
"AkY78q9iKyOAvHFyrkpdw2TxyTOZbrrvW6MZ/d4LkD5b3/M9zFJEkCmvbtZjWPbF\n" +
|
||||
"lHMbk+iYxX83q4oMqCANWe4lSWvTUDnrx7ErPvFdk4z0wdZw85lEW2cfAoGBAICn\n" +
|
||||
"3I/JTST33QjOmErKucALVKXvAF2z0PrpPkh3VUWIKSzCVChPQ/GqywSfXgWSeu7G\n" +
|
||||
"I8JcSRaPRN6lJptYuEK3R8+dX7jbWeP994cu/tVARn0HAzqMRn+MnylPhxmYQiIk\n" +
|
||||
"czkGx7mfEiwTNT5JW0Wmr+5OQEvYudbSUant5IhVAoGBAM0rAsaQ2ZQEeUCZGuu1\n" +
|
||||
"IfW21gwl13G4mWt2ng1rV8iv8Kn9yu0o7CRGAf4IlUYqOcJtfh8F5liQBcJzd2Bc\n" +
|
||||
"odT7Zo+P4Zqtgg9nKehkd5Z7+zmFNog3Z/lZMj/dJuwO+Q8Ef6qKMYdPQuwrsVBD\n" +
|
||||
"RY91AS8cjE/RsmNeWNJjTkq5";
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param text 待解密的文本
|
||||
* @return 解密后的文本
|
||||
*/
|
||||
public static String decryptByPrivateKey(String text) throws Exception
|
||||
{
|
||||
return decryptByPrivateKey(privateKey, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥解密
|
||||
*
|
||||
* @param publicKeyString 公钥
|
||||
* @param text 待解密的信息
|
||||
* @return 解密后的文本
|
||||
*/
|
||||
public static String decryptByPublicKey(String publicKeyString, String text) throws Exception
|
||||
{
|
||||
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, publicKey);
|
||||
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥加密
|
||||
*
|
||||
* @param privateKeyString 私钥
|
||||
* @param text 待加密的信息
|
||||
* @return 加密后的文本
|
||||
*/
|
||||
public static String encryptByPrivateKey(String privateKeyString, String text) throws Exception
|
||||
{
|
||||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
||||
byte[] result = cipher.doFinal(text.getBytes());
|
||||
return Base64.encodeBase64String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param privateKeyString 私钥
|
||||
* @param text 待解密的文本
|
||||
* @return 解密后的文本
|
||||
*/
|
||||
public static String decryptByPrivateKey(String privateKeyString, String text) throws Exception
|
||||
{
|
||||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥加密
|
||||
*
|
||||
* @param publicKeyString 公钥
|
||||
* @param text 待加密的文本
|
||||
* @return 加密后的文本
|
||||
*/
|
||||
public static String encryptByPublicKey(String publicKeyString, String text) throws Exception
|
||||
{
|
||||
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] result = cipher.doFinal(text.getBytes());
|
||||
return Base64.encodeBase64String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建RSA密钥对
|
||||
*
|
||||
* @return 生成后的公私钥信息
|
||||
*/
|
||||
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException
|
||||
{
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(1024);
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
|
||||
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
|
||||
return new RsaKeyPair(publicKeyString, privateKeyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA密钥对对象
|
||||
*/
|
||||
public static class RsaKeyPair
|
||||
{
|
||||
private final String publicKey;
|
||||
private final String privateKey;
|
||||
|
||||
public RsaKeyPair(String publicKey, String privateKey)
|
||||
{
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getPublicKey()
|
||||
{
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey()
|
||||
{
|
||||
return privateKey;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.jxy.windminer.common.utils.sql;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.exception.UtilException;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* @Description sql操作工具类
|
||||
* @Date 2022/5/10 11:40
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class SqlUtil
|
||||
{
|
||||
/**
|
||||
* 定义常用的 sql关键字
|
||||
*/
|
||||
public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
|
||||
|
||||
/**
|
||||
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
|
||||
*/
|
||||
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
|
||||
|
||||
/**
|
||||
* 检查字符,防止注入绕过
|
||||
*/
|
||||
public static String escapeOrderBySql(String value)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
|
||||
{
|
||||
throw new UtilException("参数不符合规范,不能进行查询");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 order by 语法是否符合规范
|
||||
*/
|
||||
public static boolean isValidOrderBySql(String value)
|
||||
{
|
||||
return value.matches(SQL_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL关键字检查
|
||||
*/
|
||||
public static void filterKeyword(String value)
|
||||
{
|
||||
if (StringUtils.isEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
|
||||
for (String sqlKeyword : sqlKeywords)
|
||||
{
|
||||
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
|
||||
{
|
||||
throw new UtilException("参数存在SQL注入风险");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.jxy.windminer.common.utils.uuid;
|
||||
|
||||
/**
|
||||
* @Description ID生成器
|
||||
* @Date 2022/5/10 11:24
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class IdUtils
|
||||
{
|
||||
/**
|
||||
* 获取随机UUID
|
||||
*
|
||||
* @return 随机UUID
|
||||
*/
|
||||
public static String randomUUID()
|
||||
{
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的UUID,去掉了横线
|
||||
*
|
||||
* @return 简化的UUID,去掉了横线
|
||||
*/
|
||||
public static String simpleUUID()
|
||||
{
|
||||
return UUID.randomUUID().toString(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
|
||||
*
|
||||
* @return 随机UUID
|
||||
*/
|
||||
public static String fastUUID()
|
||||
{
|
||||
return UUID.fastUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
|
||||
*
|
||||
* @return 简化的UUID,去掉了横线
|
||||
*/
|
||||
public static String fastSimpleUUID()
|
||||
{
|
||||
return UUID.fastUUID().toString(true);
|
||||
}
|
||||
}
|
||||
88
src/main/java/com/jxy/windminer/common/utils/uuid/Seq.java
Normal file
88
src/main/java/com/jxy/windminer/common/utils/uuid/Seq.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package com.jxy.windminer.common.utils.uuid;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.utils.DateUtils;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author jxy 序列生成类
|
||||
*/
|
||||
public class Seq
|
||||
{
|
||||
// 通用序列类型
|
||||
public static final String commSeqType = "COMMON";
|
||||
|
||||
// 上传序列类型
|
||||
public static final String uploadSeqType = "UPLOAD";
|
||||
|
||||
// 通用接口序列数
|
||||
private static AtomicInteger commSeq = new AtomicInteger(1);
|
||||
|
||||
// 上传接口序列数
|
||||
private static AtomicInteger uploadSeq = new AtomicInteger(1);
|
||||
|
||||
// 机器标识
|
||||
private static String machineCode = "A";
|
||||
|
||||
/**
|
||||
* 获取通用序列号
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId()
|
||||
{
|
||||
return getId(commSeqType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(String type)
|
||||
{
|
||||
AtomicInteger atomicInt = commSeq;
|
||||
if (uploadSeqType.equals(type))
|
||||
{
|
||||
atomicInt = uploadSeq;
|
||||
}
|
||||
return getId(atomicInt, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
|
||||
*
|
||||
* @param atomicInt 序列数
|
||||
* @param length 数值长度
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(AtomicInteger atomicInt, int length)
|
||||
{
|
||||
String result = DateUtils.dateTimeNow();
|
||||
result += machineCode;
|
||||
result += getSeq(atomicInt, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
private synchronized static String getSeq(AtomicInteger atomicInt, int length)
|
||||
{
|
||||
// 先取值再+1
|
||||
int value = atomicInt.getAndIncrement();
|
||||
|
||||
// 如果更新后值>=10 的 (length)幂次方则重置为1
|
||||
int maxSeq = (int) Math.pow(10, length);
|
||||
if (atomicInt.get() >= maxSeq)
|
||||
{
|
||||
atomicInt.set(1);
|
||||
}
|
||||
// 转字符串,用0左补齐
|
||||
return StringUtils.padl(value, length);
|
||||
}
|
||||
}
|
||||
486
src/main/java/com/jxy/windminer/common/utils/uuid/UUID.java
Normal file
486
src/main/java/com/jxy/windminer/common/utils/uuid/UUID.java
Normal file
@@ -0,0 +1,486 @@
|
||||
package com.jxy.windminer.common.utils.uuid;
|
||||
|
||||
import com.jxy.windminer.common.exception.UtilException;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Description 提供通用唯一识别码(universally unique identifier)(UUID)实现
|
||||
* @Date 2022/5/10 9:26
|
||||
* @Author 杜懿
|
||||
*/
|
||||
|
||||
public final class UUID implements java.io.Serializable, Comparable<UUID>
|
||||
{
|
||||
private static final long serialVersionUID = -1285054133654744140L;
|
||||
|
||||
/**
|
||||
* SecureRandom 的单例
|
||||
*
|
||||
*/
|
||||
private static class Holder
|
||||
{
|
||||
static final SecureRandom numberGenerator = getSecureRandom();
|
||||
}
|
||||
|
||||
/** 此UUID的最高64有效位 */
|
||||
private final long mostSigBits;
|
||||
|
||||
/** 此UUID的最低64有效位 */
|
||||
private final long leastSigBits;
|
||||
|
||||
/**
|
||||
* 私有构造
|
||||
*
|
||||
* @param data 数据
|
||||
*/
|
||||
private UUID(byte[] data)
|
||||
{
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
assert data.length == 16 : "data must be 16 bytes in length";
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
msb = (msb << 8) | (data[i] & 0xff);
|
||||
}
|
||||
for (int i = 8; i < 16; i++)
|
||||
{
|
||||
lsb = (lsb << 8) | (data[i] & 0xff);
|
||||
}
|
||||
this.mostSigBits = msb;
|
||||
this.leastSigBits = lsb;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的数据构造新的 UUID。
|
||||
*
|
||||
* @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
|
||||
* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
|
||||
*/
|
||||
public UUID(long mostSigBits, long leastSigBits)
|
||||
{
|
||||
this.mostSigBits = mostSigBits;
|
||||
this.leastSigBits = leastSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID fastUUID()
|
||||
{
|
||||
return randomUUID(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID randomUUID()
|
||||
{
|
||||
return randomUUID(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
||||
*
|
||||
* @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
|
||||
* @return 随机生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID randomUUID(boolean isSecure)
|
||||
{
|
||||
final Random ng = isSecure ? Holder.numberGenerator : getRandom();
|
||||
|
||||
byte[] randomBytes = new byte[16];
|
||||
ng.nextBytes(randomBytes);
|
||||
randomBytes[6] &= 0x0f; /* clear version */
|
||||
randomBytes[6] |= 0x40; /* set to version 4 */
|
||||
randomBytes[8] &= 0x3f; /* clear variant */
|
||||
randomBytes[8] |= 0x80; /* set to IETF variant */
|
||||
return new UUID(randomBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
|
||||
*
|
||||
* @param name 用于构造 UUID 的字节数组。
|
||||
*
|
||||
* @return 根据指定数组生成的 {@code UUID}
|
||||
*/
|
||||
public static UUID nameUUIDFromBytes(byte[] name)
|
||||
{
|
||||
MessageDigest md;
|
||||
try
|
||||
{
|
||||
md = MessageDigest.getInstance("MD5");
|
||||
}
|
||||
catch (NoSuchAlgorithmException nsae)
|
||||
{
|
||||
throw new InternalError("MD5 not supported");
|
||||
}
|
||||
byte[] md5Bytes = md.digest(name);
|
||||
md5Bytes[6] &= 0x0f; /* clear version */
|
||||
md5Bytes[6] |= 0x30; /* set to version 3 */
|
||||
md5Bytes[8] &= 0x3f; /* clear variant */
|
||||
md5Bytes[8] |= 0x80; /* set to IETF variant */
|
||||
return new UUID(md5Bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
|
||||
*
|
||||
* @param name 指定 {@code UUID} 字符串
|
||||
* @return 具有指定值的 {@code UUID}
|
||||
* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
|
||||
*
|
||||
*/
|
||||
public static UUID fromString(String name)
|
||||
{
|
||||
String[] components = name.split("-");
|
||||
if (components.length != 5)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid UUID string: " + name);
|
||||
}
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
components[i] = "0x" + components[i];
|
||||
}
|
||||
|
||||
long mostSigBits = Long.decode(components[0]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[1]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[2]).longValue();
|
||||
|
||||
long leastSigBits = Long.decode(components[3]).longValue();
|
||||
leastSigBits <<= 48;
|
||||
leastSigBits |= Long.decode(components[4]).longValue();
|
||||
|
||||
return new UUID(mostSigBits, leastSigBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的 128 位值中的最低有效 64 位。
|
||||
*
|
||||
* @return 此 UUID 的 128 位值中的最低有效 64 位。
|
||||
*/
|
||||
public long getLeastSignificantBits()
|
||||
{
|
||||
return leastSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的 128 位值中的最高有效 64 位。
|
||||
*
|
||||
* @return 此 UUID 的 128 位值中最高有效 64 位。
|
||||
*/
|
||||
public long getMostSignificantBits()
|
||||
{
|
||||
return mostSigBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
|
||||
* <p>
|
||||
* 版本号具有以下含意:
|
||||
* <ul>
|
||||
* <li>1 基于时间的 UUID
|
||||
* <li>2 DCE 安全 UUID
|
||||
* <li>3 基于名称的 UUID
|
||||
* <li>4 随机生成的 UUID
|
||||
* </ul>
|
||||
*
|
||||
* @return 此 {@code UUID} 的版本号
|
||||
*/
|
||||
public int version()
|
||||
{
|
||||
// Version is bits masked by 0x000000000000F000 in MS long
|
||||
return (int) ((mostSigBits >> 12) & 0x0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
|
||||
* <p>
|
||||
* 变体号具有以下含意:
|
||||
* <ul>
|
||||
* <li>0 为 NCS 向后兼容保留
|
||||
* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类
|
||||
* <li>6 保留,微软向后兼容
|
||||
* <li>7 保留供以后定义使用
|
||||
* </ul>
|
||||
*
|
||||
* @return 此 {@code UUID} 相关联的变体号
|
||||
*/
|
||||
public int variant()
|
||||
{
|
||||
// This field is composed of a varying number of bits.
|
||||
// 0 - - Reserved for NCS backward compatibility
|
||||
// 1 0 - The IETF aka Leach-Salz variant (used by this class)
|
||||
// 1 1 0 Reserved, Microsoft backward compatibility
|
||||
// 1 1 1 Reserved for future definition.
|
||||
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关联的时间戳值。
|
||||
*
|
||||
* <p>
|
||||
* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
|
||||
* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
|
||||
*
|
||||
* <p>
|
||||
* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
||||
* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
||||
*
|
||||
* @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
|
||||
*/
|
||||
public long timestamp() throws UnsupportedOperationException
|
||||
{
|
||||
checkTimeBase();
|
||||
return (mostSigBits & 0x0FFFL) << 48//
|
||||
| ((mostSigBits >> 16) & 0x0FFFFL) << 32//
|
||||
| mostSigBits >>> 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关联的时钟序列值。
|
||||
*
|
||||
* <p>
|
||||
* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
|
||||
* <p>
|
||||
* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
|
||||
* UnsupportedOperationException。
|
||||
*
|
||||
* @return 此 {@code UUID} 的时钟序列
|
||||
*
|
||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
||||
*/
|
||||
public int clockSequence() throws UnsupportedOperationException
|
||||
{
|
||||
checkTimeBase();
|
||||
return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
|
||||
}
|
||||
|
||||
/**
|
||||
* 与此 UUID 相关的节点值。
|
||||
*
|
||||
* <p>
|
||||
* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
|
||||
* <p>
|
||||
* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
||||
* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
||||
*
|
||||
* @return 此 {@code UUID} 的节点值
|
||||
*
|
||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
||||
*/
|
||||
public long node() throws UnsupportedOperationException
|
||||
{
|
||||
checkTimeBase();
|
||||
return leastSigBits & 0x0000FFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此{@code UUID} 的字符串表现形式。
|
||||
*
|
||||
* <p>
|
||||
* UUID 的字符串表示形式由此 BNF 描述:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
||||
* time_low = 4*<hexOctet>
|
||||
* time_mid = 2*<hexOctet>
|
||||
* time_high_and_version = 2*<hexOctet>
|
||||
* variant_and_sequence = 2*<hexOctet>
|
||||
* node = 6*<hexOctet>
|
||||
* hexOctet = <hexDigit><hexDigit>
|
||||
* hexDigit = [0-9a-fA-F]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @return 此{@code UUID} 的字符串表现形式
|
||||
* @see #toString(boolean)
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return toString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此{@code UUID} 的字符串表现形式。
|
||||
*
|
||||
* <p>
|
||||
* UUID 的字符串表示形式由此 BNF 描述:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
||||
* time_low = 4*<hexOctet>
|
||||
* time_mid = 2*<hexOctet>
|
||||
* time_high_and_version = 2*<hexOctet>
|
||||
* variant_and_sequence = 2*<hexOctet>
|
||||
* node = 6*<hexOctet>
|
||||
* hexOctet = <hexDigit><hexDigit>
|
||||
* hexDigit = [0-9a-fA-F]
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
|
||||
* @return 此{@code UUID} 的字符串表现形式
|
||||
*/
|
||||
public String toString(boolean isSimple)
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
|
||||
// time_low
|
||||
builder.append(digits(mostSigBits >> 32, 8));
|
||||
if (false == isSimple)
|
||||
{
|
||||
builder.append('-');
|
||||
}
|
||||
// time_mid
|
||||
builder.append(digits(mostSigBits >> 16, 4));
|
||||
if (false == isSimple)
|
||||
{
|
||||
builder.append('-');
|
||||
}
|
||||
// time_high_and_version
|
||||
builder.append(digits(mostSigBits, 4));
|
||||
if (false == isSimple)
|
||||
{
|
||||
builder.append('-');
|
||||
}
|
||||
// variant_and_sequence
|
||||
builder.append(digits(leastSigBits >> 48, 4));
|
||||
if (false == isSimple)
|
||||
{
|
||||
builder.append('-');
|
||||
}
|
||||
// node
|
||||
builder.append(digits(leastSigBits, 12));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此 UUID 的哈希码。
|
||||
*
|
||||
* @return UUID 的哈希码值。
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
long hilo = mostSigBits ^ leastSigBits;
|
||||
return ((int) (hilo >> 32)) ^ (int) hilo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将此对象与指定对象比较。
|
||||
* <p>
|
||||
* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
|
||||
*
|
||||
* @param obj 要与之比较的对象
|
||||
*
|
||||
* @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if ((null == obj) || (obj.getClass() != UUID.class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
UUID id = (UUID) obj;
|
||||
return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
|
||||
}
|
||||
|
||||
// Comparison Operations
|
||||
|
||||
/**
|
||||
* 将此 UUID 与指定的 UUID 比较。
|
||||
*
|
||||
* <p>
|
||||
* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
|
||||
*
|
||||
* @param val 与此 UUID 比较的 UUID
|
||||
*
|
||||
* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(UUID val)
|
||||
{
|
||||
// The ordering is intentionally set up so that the UUIDs
|
||||
// can simply be numerically compared as two numbers
|
||||
return (this.mostSigBits < val.mostSigBits ? -1 : //
|
||||
(this.mostSigBits > val.mostSigBits ? 1 : //
|
||||
(this.leastSigBits < val.leastSigBits ? -1 : //
|
||||
(this.leastSigBits > val.leastSigBits ? 1 : //
|
||||
0))));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Private method start
|
||||
/**
|
||||
* 返回指定数字对应的hex值
|
||||
*
|
||||
* @param val 值
|
||||
* @param digits 位
|
||||
* @return 值
|
||||
*/
|
||||
private static String digits(long val, int digits)
|
||||
{
|
||||
long hi = 1L << (digits * 4);
|
||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为time-based版本UUID
|
||||
*/
|
||||
private void checkTimeBase()
|
||||
{
|
||||
if (version() != 1)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not a time-based UUID");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
|
||||
*
|
||||
* @return {@link SecureRandom}
|
||||
*/
|
||||
public static SecureRandom getSecureRandom()
|
||||
{
|
||||
try
|
||||
{
|
||||
return SecureRandom.getInstance("SHA1PRNG");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new UtilException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机数生成器对象<br>
|
||||
*
|
||||
* @return {@link ThreadLocalRandom}
|
||||
*/
|
||||
public static ThreadLocalRandom getRandom()
|
||||
{
|
||||
return ThreadLocalRandom.current();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.jxy.windminer.common.web.Result;
|
||||
|
||||
import com.jxy.windminer.common.constant.HttpStatus;
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @Description 操作消息提醒
|
||||
* @Date 2022/5/10 15:05
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class AjaxResult extends HashMap<String, Object>
|
||||
{
|
||||
private static final long serialVersionUID = 3247645319123122183L;
|
||||
|
||||
/** 状态码 */
|
||||
public static final String CODE_TAG = "code";
|
||||
|
||||
/** 返回内容 */
|
||||
public static final String MSG_TAG = "msg";
|
||||
|
||||
/** 数据对象 */
|
||||
public static final String DATA_TAG = "data";
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
|
||||
*/
|
||||
public AjaxResult()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
*/
|
||||
public AjaxResult(int code, String msg)
|
||||
{
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
*/
|
||||
public AjaxResult(int code, String msg, Object data)
|
||||
{
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
if (StringUtils.isNotNull(data))
|
||||
{
|
||||
super.put(DATA_TAG, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便链式调用
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult put(String key, Object value)
|
||||
{
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success()
|
||||
{
|
||||
return AjaxResult.success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功数据
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(Object data)
|
||||
{
|
||||
return AjaxResult.success("操作成功", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg)
|
||||
{
|
||||
return AjaxResult.success(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg, Object data)
|
||||
{
|
||||
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static AjaxResult error()
|
||||
{
|
||||
return AjaxResult.error("操作失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg)
|
||||
{
|
||||
return AjaxResult.error(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg, Object data)
|
||||
{
|
||||
return new AjaxResult(HttpStatus.ERROR, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(int code, String msg)
|
||||
{
|
||||
return new AjaxResult(code, msg, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jxy.windminer.common.web.Result;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 操作消息提醒
|
||||
* @Date 2022/5/10 15:05
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@ApiModel(description = "响应信息")
|
||||
@Data
|
||||
public class PageResult<T>
|
||||
{
|
||||
//总记录条数
|
||||
@ApiModelProperty(value = "总记录条数")
|
||||
private Long count;
|
||||
|
||||
@ApiModelProperty(value = "总页数")
|
||||
private Long totalPage;
|
||||
|
||||
//返回的数据
|
||||
@ApiModelProperty(value = "返回的数据")
|
||||
private T data;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.jxy.windminer.common.web.controller;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.jxy.windminer.common.constant.HttpStatus;
|
||||
import com.jxy.windminer.common.utils.DateUtils;
|
||||
import com.jxy.windminer.common.utils.PageUtils;
|
||||
import com.jxy.windminer.common.web.Result.AjaxResult;
|
||||
import com.jxy.windminer.common.web.page.TableDataInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description web层数据处理
|
||||
* @Date 2022/5/10 15:52
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class BaseController
|
||||
{
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
|
||||
*/
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder)
|
||||
{
|
||||
// Date 类型转换
|
||||
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
|
||||
{
|
||||
@Override
|
||||
public void setAsText(String text)
|
||||
{
|
||||
setValue(DateUtils.parseDate(text));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求分页数据
|
||||
*/
|
||||
protected void startPage()
|
||||
{
|
||||
PageUtils.startPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理分页的线程变量
|
||||
*/
|
||||
protected void clearPage()
|
||||
{
|
||||
PageUtils.clearPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应请求分页数据
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected TableDataInfo getDataTable(List<?> list)
|
||||
{
|
||||
TableDataInfo rspData = new TableDataInfo();
|
||||
rspData.setCode(HttpStatus.SUCCESS);
|
||||
rspData.setRows(list);
|
||||
rspData.setMsg("查询成功");
|
||||
PageInfo pageInfo = new PageInfo(list);
|
||||
rspData.setTotal(pageInfo.getTotal());
|
||||
rspData.setTotalPage(pageInfo.getPages());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应返回结果
|
||||
*
|
||||
* @param rows 影响行数
|
||||
* @return 操作结果
|
||||
*/
|
||||
protected AjaxResult toAjax(int rows)
|
||||
{
|
||||
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应返回结果
|
||||
*
|
||||
* @param result 结果
|
||||
* @return 操作结果
|
||||
*/
|
||||
protected AjaxResult toAjax(boolean result)
|
||||
{
|
||||
return result ? success() : error();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功
|
||||
*/
|
||||
public AjaxResult success()
|
||||
{
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回失败消息
|
||||
*/
|
||||
public AjaxResult error()
|
||||
{
|
||||
return AjaxResult.error();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*/
|
||||
public AjaxResult success(String message)
|
||||
{
|
||||
return AjaxResult.success(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回失败消息
|
||||
*/
|
||||
public AjaxResult error(String message)
|
||||
{
|
||||
return AjaxResult.error(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.jxy.windminer.common.web.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description Entity基类
|
||||
* @Date 2022/5/10 15:31
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 2417642483861314318L;
|
||||
|
||||
/** 搜索值 */
|
||||
private String searchValue;
|
||||
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/** 请求参数 */
|
||||
private Map<String, Object> params;
|
||||
|
||||
|
||||
public Map<String, Object> getParams()
|
||||
{
|
||||
if (params == null)
|
||||
{
|
||||
params = new HashMap<>();
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
64
src/main/java/com/jxy/windminer/common/web/page/Page.java
Normal file
64
src/main/java/com/jxy/windminer/common/web/page/Page.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package com.jxy.windminer.common.web.page;
|
||||
|
||||
import com.jxy.windminer.common.utils.StringUtils;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 数据分页
|
||||
* @Date 2022/5/10 14:14
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public class Page {
|
||||
|
||||
/** 当前记录起始索引 */
|
||||
private Integer pageNum;
|
||||
|
||||
/** 每页显示记录数 */
|
||||
private Integer pageSize;
|
||||
|
||||
/** 排序列 */
|
||||
private String orderByColumn;
|
||||
|
||||
/** 排序的方向desc或者asc */
|
||||
private String isAsc = "asc";
|
||||
|
||||
/** 分页参数合理化 */
|
||||
private Boolean reasonable = true;
|
||||
|
||||
public String getOrderBy()
|
||||
{
|
||||
if (StringUtils.isEmpty(orderByColumn))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
|
||||
}
|
||||
|
||||
public void setIsAsc(String isAsc)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(isAsc))
|
||||
{
|
||||
// 兼容前端排序类型
|
||||
if ("ascending".equals(isAsc))
|
||||
{
|
||||
isAsc = "asc";
|
||||
}
|
||||
else if ("descending".equals(isAsc))
|
||||
{
|
||||
isAsc = "desc";
|
||||
}
|
||||
this.isAsc = isAsc;
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getReasonable()
|
||||
{
|
||||
if (StringUtils.isNull(reasonable))
|
||||
{
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return reasonable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.jxy.windminer.common.web.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description 表格分页数据对象
|
||||
* @Date 2022/5/10 14:59
|
||||
* @Author 杜懿
|
||||
*/
|
||||
@Data
|
||||
public class TableDataInfo implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 总记录数 */
|
||||
private long total;
|
||||
|
||||
/** 总页数 */
|
||||
private long totalPage;
|
||||
|
||||
/** 列表数据 */
|
||||
private List<?> rows;
|
||||
|
||||
/** 消息状态码 */
|
||||
private int code;
|
||||
|
||||
/** 消息内容 */
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 表格数据对象
|
||||
*/
|
||||
public TableDataInfo()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*
|
||||
* @param list 列表数据
|
||||
* @param total 总记录数
|
||||
*/
|
||||
public TableDataInfo(List<?> list, int total)
|
||||
{
|
||||
this.rows = list;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.jxy.windminer.common.web.page;
|
||||
|
||||
|
||||
import com.jxy.windminer.common.text.Convert;
|
||||
import com.jxy.windminer.common.utils.ServletUtils;
|
||||
|
||||
/**
|
||||
* @Description 表格数据处理
|
||||
* @Date 2022/5/10 14:32
|
||||
* @Author 杜懿
|
||||
*/
|
||||
public class TableSupport
|
||||
{
|
||||
/**
|
||||
* 当前记录起始索引
|
||||
*/
|
||||
public static final String PAGE_NUM = "pageNum";
|
||||
|
||||
/**
|
||||
* 每页显示记录数
|
||||
*/
|
||||
public static final String PAGE_SIZE = "pageSize";
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
public static final String ORDER_BY_COLUMN = "orderByColumn";
|
||||
|
||||
/**
|
||||
* 排序的方向 "desc" 或者 "asc".
|
||||
*/
|
||||
public static final String IS_ASC = "isAsc";
|
||||
|
||||
/**
|
||||
* 分页参数合理化
|
||||
*/
|
||||
public static final String REASONABLE = "reasonable";
|
||||
|
||||
/**
|
||||
* 封装分页对象
|
||||
*/
|
||||
public static Page getPage()
|
||||
{
|
||||
Page page = new Page();
|
||||
page.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
|
||||
page.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 20));
|
||||
page.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
|
||||
page.setIsAsc(ServletUtils.getParameter(IS_ASC));
|
||||
page.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
|
||||
System.out.println(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
public static Page buildPageRequest()
|
||||
{
|
||||
return getPage();
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/jxy/windminer/common/xss/Xss.java
Normal file
27
src/main/java/com/jxy/windminer/common/xss/Xss.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.jxy.windminer.common.xss;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义xss校验注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
|
||||
@Constraint(validatedBy = { XssValidator.class })
|
||||
public @interface Xss {
|
||||
|
||||
String message()
|
||||
|
||||
default "不允许任何脚本运行";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user