first commit

This commit is contained in:
2025-06-21 11:06:35 +08:00
commit 4f3d1693b4
721 changed files with 47462 additions and 0 deletions
+267
View File
@@ -0,0 +1,267 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.1024lab</groupId>
<artifactId>sa-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sa-case-common</artifactId>
<version>1.0.0</version>
<name>sa-case-common</name>
<description>sa-case-common project</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<exclusions>
<exclusion>
<artifactId>error_prone_annotations</artifactId>
<groupId>com.google.errorprone</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
</dependency>
<!-- poi start -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
</dependency>
<!-- poi end -->
<dependency>
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
<artifactId>concurrentlinkedhashmap-lru</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
</dependency>
<!-- sax 读取时候用到的 -->
<!-- <dependency>-->
<!-- <groupId>xerces</groupId>-->
<!-- <artifactId>xercesImpl</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity.tools</groupId>
<artifactId>velocity-tools-generic</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!--XSS 安全过滤-->
<!-- https://gitee.com/596392912/mica/tree/master/mica-xss-->
<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>mica-core</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>mica-xss</artifactId>
<version>2.6.0</version>
</dependency>
<!-- http 相关-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,20 @@
package net.lab1024.sa.common.common.annoation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 不需要登录注解
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NoNeedLogin {
}
@@ -0,0 +1,22 @@
package net.lab1024.sa.common.common.annoation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 校验权限注解
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SaAuth {
String saAuth = "saAuth";
}
@@ -0,0 +1,39 @@
package net.lab1024.sa.common.common.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum AppErrorCode implements ErrorCode {
PARAM_ERROR(40001, "参数错误"),
DATA_NOT_EXIST(40002, "左翻右翻,数据竟然找不到了~"),
ALREADY_EXIST(40003, "数据已存在了呀~"),
REPEAT_SUBMIT(40004, "亲~您操作的太快了,请稍等下再操作~"),
NO_PERMISSION(40005, "对不起,您无法访问此资源哦~"),
DEVELOPING(40006, "系統正在紧急开发中,敬请期待~"),
LOGIN_STATE_INVALID(40007, "您还未登录或登录失效,请重新登录!"),
USER_STATUS_ERROR(40008, "用户状态异常"),
FORM_REPEAT_SUBMIT(40009, "请勿重复提交");
private final int code;
private final String msg;
private final String level;
AppErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
this.level = LEVEL_USER;
}
}
@@ -0,0 +1,52 @@
package net.lab1024.sa.common.common.code;
/**
* 错误码<br>
* 一共分为三种: 1)系统错误、2)用户级别错误、3)未预期到的错误
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public interface ErrorCode {
/**
* 系统等级
*/
String LEVEL_SYSTEM = "system";
/**
* 用户等级
*/
String LEVEL_USER = "user";
/**
* 未预期到的等级
*/
String LEVEL_UNEXPECTED = "unexpected";
/**
* 错误码
*
* @return
*/
int getCode();
/**
* 错误消息
*
* @return
*/
String getMsg();
/**
* 错误等级
*
* @return
*/
String getLevel();
}
@@ -0,0 +1,119 @@
package net.lab1024.sa.common.common.code;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 错误码 注册容器
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/09/27 22:09
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
class ErrorCodeRangeContainer {
/**
* 所有的错误码均大于10000
*/
static final int MIN_START_CODE = 10000;
static final Map<Class<? extends ErrorCode>, ImmutablePair<Integer, Integer>> CODE_RANGE_MAP = new ConcurrentHashMap<>();
/**
* 用于统计数量
*/
static int errorCounter = 0;
/**
* 注册状态码
* 校验是否重复 是否越界
*
* @param clazz
* @param start
* @param end
*/
static void register(Class<? extends ErrorCode> clazz, int start, int end) {
String simpleName = clazz.getSimpleName();
if (!clazz.isEnum()) {
throw new ExceptionInInitializerError(String.format("<<ErrorCodeRangeValidator>> error: %s not Enum class !", simpleName));
}
if (start > end) {
throw new ExceptionInInitializerError(String.format("<<ErrorCodeRangeValidator>> error: %s start must be less than the end !", simpleName));
}
if (start <= MIN_START_CODE) {
throw new ExceptionInInitializerError(String.format("<<ErrorCodeRangeValidator>> error: %s start must be more than %s !", simpleName, MIN_START_CODE));
}
// 校验是否重复注册
boolean containsKey = CODE_RANGE_MAP.containsKey(clazz);
if (containsKey) {
throw new ExceptionInInitializerError(String.format("<<ErrorCodeRangeValidator>> error: Enum %s already exist !", simpleName));
}
// 校验 开始结束值 是否越界
CODE_RANGE_MAP.forEach((k, v) -> {
if (isExistOtherRange(start, end, v)) {
throw new IllegalArgumentException(String.format("<<ErrorCodeRangeValidator>> error: %s[%d,%d] has intersection with class:%s[%d,%d]", simpleName, start, end,
k.getSimpleName(), v.getLeft(), v.getRight()));
}
});
// 循环校验code并存储
List<Integer> codeList = Stream.of(clazz.getEnumConstants()).map(codeEnum -> {
Integer code = codeEnum.getCode();
if (code < start || code > end) {
throw new IllegalArgumentException(String.format("<<ErrorCodeRangeValidator>> error: %s[%d,%d] code %d out of range", simpleName, start, end, code));
}
return code;
}).collect(Collectors.toList());
// 校验code是否重复
List<Integer> distinctCodeList = codeList.stream().distinct().collect(Collectors.toList());
Collection<Integer> subtract = CollectionUtils.subtract(codeList, distinctCodeList);
if (CollectionUtils.isNotEmpty(subtract)) {
throw new IllegalArgumentException(String.format("<<ErrorCodeRangeValidator>> error: %s code %s is repeat!", simpleName, subtract));
}
CODE_RANGE_MAP.put(clazz, ImmutablePair.of(start, end));
// 统计
errorCounter = errorCounter + distinctCodeList.size();
}
/**
* 是否存在于其他范围
*
* @param start
* @param end
* @param range
* @return
*/
private static boolean isExistOtherRange(int start, int end, ImmutablePair<Integer, Integer> range) {
if (start >= range.getLeft() && start <= range.getRight()) {
return true;
}
if (end >= range.getLeft() && end <= range.getRight()) {
return true;
}
return false;
}
/**
* 进行初始化
*/
static int initialize() {
return errorCounter;
}
}
@@ -0,0 +1,44 @@
package net.lab1024.sa.common.common.code;
import static net.lab1024.sa.common.common.code.ErrorCodeRangeContainer.register;
/**
* 注册code状态码 <br>
* ps:为什么要在此处不那么优雅的手动注册?
* 主要是为了能统一、清晰、浏览当前定义的所有状态码
* 方便后续维护
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/09/27 23:09
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class ErrorCodeRegister {
static {
// 系统 错误码
register(SystemErrorCode.class, 10001, 20000);
// 意外 错误码
register(UnexpectedErrorCode.class, 20001, 30000);
// 用户 通用错误码
register(UserErrorCode.class, 30001, 40000);
// app 通用错误码
register(AppErrorCode.class, 40001, 50000);
}
public static int initialize() {
return ErrorCodeRangeContainer.initialize();
}
public static void main(String[] args) {
ErrorCodeRegister.initialize();
}
}
@@ -0,0 +1,36 @@
package net.lab1024.sa.common.common.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 系统错误状态码(此类返回码应该高度重视)
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/10/24 20:09
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Getter
@AllArgsConstructor
public enum SystemErrorCode implements ErrorCode {
SYSTEM_ERROR(10001, "系统似乎出现了点小问题"),
;
private final int code;
private final String msg;
private final String level;
SystemErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
this.level = LEVEL_SYSTEM;
}
}
@@ -0,0 +1,36 @@
package net.lab1024.sa.common.common.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 未预期的错误码(即发生了不可能发生的事情,此类返回码应该高度重视)
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/09/27 22:10:46
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Getter
@AllArgsConstructor
public enum UnexpectedErrorCode implements ErrorCode {
BUSINESS_HANDING(20001, "呃~ 业务繁忙,请稍后重试"),
PAY_ORDER_ID_ERROR(20002, "付款单id发生了异常,请联系技术人员排查"),
;
private final int code;
private final String msg;
private final String level;
UnexpectedErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
this.level = LEVEL_UNEXPECTED;
}
}
@@ -0,0 +1,53 @@
package net.lab1024.sa.common.common.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户级别的错误码(用户引起的错误返回码,可以不用关注)
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/09/21 22:12:27
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Getter
@AllArgsConstructor
public enum UserErrorCode implements ErrorCode {
PARAM_ERROR(30001, "参数错误"),
DATA_NOT_EXIST(30002, "左翻右翻,数据竟然找不到了~"),
ALREADY_EXIST(30003, "数据已存在了呀~"),
REPEAT_SUBMIT(30004, "亲~您操作的太快了,请稍等下再操作~"),
NO_PERMISSION(30005, "对不起,您无法访问此资源哦~"),
DEVELOPING(30006, "系統正在紧急开发中,敬请期待~"),
LOGIN_STATE_INVALID(30007, "您还未登录或登录失效,请重新登录!"),
USER_STATUS_ERROR(30008, "用户状态异常"),
FORM_REPEAT_SUBMIT(30009, "请勿重复提交"),
NO_PERMISSION_EDIT(30010, "该状态不允许修改"),
NO_MODIFY(30011, "该账号无需补充资料"),
PROJECT_CLOSE(30012, "本年度人工肝病例登记项目已结束,谢谢您的关注!"),
ExpertBankVerifyFail(30013, "银行卡认证失败");
private final int code;
private final String msg;
private final String level;
UserErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
this.level = LEVEL_USER;
}
}
@@ -0,0 +1,18 @@
package net.lab1024.sa.common.common.constant;
/**
* 请求消息头常量
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-15 20:46:27
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class RequestHeaderConst {
public static final String TOKEN = "x-access-token";
public static final String USER_AGENT = "user-agent";
}
@@ -0,0 +1,44 @@
package net.lab1024.sa.common.common.constant;
/**
* 字符串常量
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-10-14 23:16:47
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class StringConst {
/**
* 全局通用分隔符
*/
public static final String SEPARATOR = ",";
/**
* 全局通用分隔符 下划线
*/
public static final String UNDERLINE = "_";
/**
* 全局通用 横杠
*/
public static final String HORIZONTAL = "-";
/**
* 全局通用分隔符
*/
public static final Character SEPARATOR_CHAR = ',';
/**
* 全局通用分隔符 斜杠
*/
public static final String SEPARATOR_SLASH = "/";
/**
* 空字符串
*/
public static final String EMPTY = "";
}
@@ -0,0 +1,16 @@
package net.lab1024.sa.common.common.controller;
import net.lab1024.sa.common.constant.UrlPrefixConst;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 支撑类业务路由基类
*
* @Author 1024创新实验室: 胡克
* @Date 2022-04-24 20:43:55
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@RequestMapping(UrlPrefixConst.SUPPORT)
public class SupportBaseController {
}
@@ -0,0 +1,15 @@
package net.lab1024.sa.common.common.domain;
import org.apache.ibatis.plugin.Interceptor;
/**
* 数据范围 插件
*
* @Author 1024创新实验室: 罗伊
* @Date 2021-11-15 17:20:04
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public abstract class DataScopePlugin implements Interceptor {
}
@@ -0,0 +1,58 @@
package net.lab1024.sa.common.common.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 分页基础参数
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020/04/28 16:19
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class PageParam {
@ApiModelProperty(value = "页码(不能为空)", required = true, example = "1")
@NotNull(message = "分页参数不能为空")
private Integer pageNum;
@ApiModelProperty(value = "每页数量(不能为空)", required = true, example = "10")
@NotNull(message = "每页数量不能为空")
@Max(value = 200, message = "每页最大为200")
private Integer pageSize;
@ApiModelProperty("是否查询总条数")
protected Boolean searchCount;
@ApiModelProperty("排序字段集合")
@Size(max = 10, message = "排序字段最多10")
@Valid
private List<SortItem> sortItemList;
/**
* 排序DTO类
*/
@Data
public static class SortItem {
@ApiModelProperty("true正序|false倒序")
@NotNull(message = "排序规则不能为空")
private Boolean isAsc;
@ApiModelProperty(value = "排序字段")
@NotBlank(message = "排序字段不能为空")
@Length(max = 30, message = "排序字段最多30")
private String column;
}
}
@@ -0,0 +1,53 @@
package net.lab1024.sa.common.common.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* 分页返回对象
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020/04/28 16:19
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class PageResult<T> {
/**
* 当前页
*/
@ApiModelProperty(value = "当前页")
private Long pageNum;
/**
* 每页的数量
*/
@ApiModelProperty(value = "每页的数量")
private Long pageSize;
/**
* 总记录数
*/
@ApiModelProperty(value = "总记录数")
private Long total;
/**
* 总页数
*/
@ApiModelProperty(value = "总页数")
private Long pages;
/**
* 结果集
*/
@ApiModelProperty(value = "结果集")
private List<T> list;
@ApiModelProperty("是否为空")
private Boolean emptyFlag;
}
@@ -0,0 +1,26 @@
package net.lab1024.sa.common.common.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 请求url返回对象
*
* @Author 1024创新实验室: 李善逸
* @Date 2021/9/1 20:15
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class RequestUrlVO {
@ApiModelProperty("注释说明")
private String comment;
@ApiModelProperty("controller.method")
private String name;
@ApiModelProperty("url")
private String url;
}
@@ -0,0 +1,49 @@
package net.lab1024.sa.common.common.domain;
import net.lab1024.sa.common.common.enumeration.UserTypeEnum;
/**
* 请求用户
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-12-21 19:55:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public interface RequestUser {
/**
* 请求用户id
*
* @return
*/
Long getUserId();
/**
* 请求用户名称
*
* @return
*/
String getUserName();
/**
* 获取用户类型
*/
UserTypeEnum getUserType();
/**
* 获取请求的IP
*
* @return
*/
String getIp();
/**
* 获取请求 user-agent
*
* @return
*/
String getUserAgent();
}
@@ -0,0 +1,114 @@
package net.lab1024.sa.common.common.domain;
import lombok.Data;
import net.lab1024.sa.common.common.code.ErrorCode;
import net.lab1024.sa.common.common.code.UserErrorCode;
import org.apache.commons.lang3.StringUtils;
/**
* 请求返回对象
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-10-31 21:06:11
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class ResponseDTO<T> {
public static final int OK_CODE = 0;
public static final int APP_OK_CODE = 200;
public static final String OK_MSG = "success";
private Integer code;
private String level;
private String msg;
private Boolean ok;
private T data;
public ResponseDTO(Integer code, String level, boolean ok, String msg, T data) {
this.code = code;
this.level = level;
this.ok = ok;
this.msg = msg;
this.data = data;
}
public ResponseDTO(ErrorCode errorCode, boolean ok, String msg, T data) {
this.code = errorCode.getCode();
this.level = errorCode.getLevel();
this.ok = ok;
if (StringUtils.isNotBlank(msg)) {
this.msg = msg;
} else {
this.msg = errorCode.getMsg();
}
this.data = data;
}
public static <T> ResponseDTO<T> ok() {
return new ResponseDTO<>(OK_CODE, null, true, OK_MSG, null);
}
public static <T> ResponseDTO<T> ok(T data) {
return new ResponseDTO<>(OK_CODE, null, true, OK_MSG, data);
}
public static <T> ResponseDTO<T> okMsg(String msg) {
return new ResponseDTO<>(OK_CODE, null, true, msg, null);
}
public static <T> ResponseDTO<T> app_ok() {
return new ResponseDTO<>(APP_OK_CODE, null, true, OK_MSG, null);
}
public static <T> ResponseDTO<T> app_ok(T data) {
return new ResponseDTO<>(APP_OK_CODE, null, true, OK_MSG, data);
}
public static <T> ResponseDTO<T> app_okMsg(String msg) {
return new ResponseDTO<>(APP_OK_CODE, null, true, msg, null);
}
// -------------------------------------------- 最常用的 用户参数 错误码 --------------------------------------------
public static <T> ResponseDTO<T> userErrorParam() {
return new ResponseDTO<>(UserErrorCode.PARAM_ERROR, false, null, null);
}
public static <T> ResponseDTO<T> userErrorParam(String msg) {
return new ResponseDTO<>(UserErrorCode.PARAM_ERROR, false, msg, null);
}
// -------------------------------------------- 错误码 --------------------------------------------
public static <T> ResponseDTO<T> error(ErrorCode errorCode) {
return new ResponseDTO<>(errorCode, false, null, null);
}
public static <T> ResponseDTO<T> error(ErrorCode errorCode, boolean ok) {
return new ResponseDTO<>(errorCode, ok, null, null);
}
public static ResponseDTO error(ResponseDTO responseDTO) {
return new ResponseDTO<>(responseDTO.getCode(), responseDTO.getLevel(), responseDTO.getOk(), responseDTO.getMsg(), responseDTO.getData());
}
public static <T> ResponseDTO<T> error(ErrorCode errorCode, String msg) {
return new ResponseDTO<>(errorCode, false, msg, null);
}
public static <T> ResponseDTO<T> errorData(ErrorCode errorCode, T data) {
return new ResponseDTO<>(errorCode, false, null, data);
}
}
@@ -0,0 +1,35 @@
package net.lab1024.sa.common.common.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.lab1024.sa.common.common.enumeration.SystemEnvironmentEnum;
/**
* 系统环境
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/8/13 21:06:11
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@AllArgsConstructor
@Getter
public class SystemEnvironment {
/**
* 是否位生产环境
*/
private boolean isProd;
/**
* 项目名称
*/
private String projectName;
/**
* 当前环境
*/
private SystemEnvironmentEnum currentEnvironment;
}
@@ -0,0 +1,21 @@
package net.lab1024.sa.common.common.domain;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 校验数据是否为空的包装类
*
* @Author 1024创新实验室: 胡克
* @Date 2020/10/16 21:06:11
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class ValidateData<T> {
@NotNull(message = "数据不能为空哦")
private T data;
}
@@ -0,0 +1,153 @@
package net.lab1024.sa.common.common.domain;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.*;
/**
* 校验集合是否为空的包装类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-02-03 17:37
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class ValidateList<E> implements List<E> {
@Valid
@NotEmpty(message = "数据长度不能为空哦")
private List<E> list;
public ValidateList() {
this.list = new ArrayList<>();
}
public ValidateList(List<E> list) {
this.list = list;
}
public List<E> getList() {
return list;
}
public void setList(List<E> list) {
this.list = list;
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
return list.set(index, element);
}
@Override
public void add(int index, E element) {
list.add(index, element);
}
@Override
public E remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
}
@@ -0,0 +1,99 @@
package net.lab1024.sa.common.common.enumeration;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONAware;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.CaseFormat;
import lombok.Data;
import java.util.LinkedHashMap;
import java.util.Objects;
/**
* 枚举类接口
*
* @Author 1024创新实验室: 胡克
* @Date 2018-07-17 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public interface BaseEnum {
/**
* 获取枚举类的值
*
* @return
*/
Object getValue();
/**
* 获取枚举类的说明
*
* @return String
*/
String getDesc();
/**
* 比较参数是否与枚举类的value相同
*
* @param value
* @return boolean
*/
default boolean equalsValue(Object value) {
return Objects.equals(getValue(), value);
}
/**
* 比较枚举类是否相同
*
* @param baseEnum
* @return boolean
*/
default boolean equals(BaseEnum baseEnum) {
return Objects.equals(getValue(), baseEnum.getValue()) && Objects.equals(getDesc(), baseEnum.getDesc());
}
/**
* 返回枚举类的说明
*
* @param clazz 枚举类类对象
* @return
*/
static String getInfo(Class<? extends BaseEnum> clazz) {
BaseEnum[] enums = clazz.getEnumConstants();
LinkedHashMap<String, JSONObject> json = new LinkedHashMap<>(enums.length);
for (BaseEnum e : enums) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", new DeletedQuotationAware(e.getValue()));
jsonObject.put("desc", new DeletedQuotationAware(e.getDesc()));
json.put(e.toString(), jsonObject);
}
String enumJson = JSON.toJSONString(json, true);
enumJson = enumJson.replaceAll("\"", "");
enumJson = enumJson.replaceAll("\t", "&nbsp;&nbsp;");
enumJson = enumJson.replaceAll("\n", "<br>");
String prefix = " <br> export const <br> " + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, clazz.getSimpleName() + " = <br> ");
return prefix + "" + enumJson + " <br>";
}
@Data
class DeletedQuotationAware implements JSONAware {
private String value;
public DeletedQuotationAware(Object value) {
if (value instanceof String) {
this.value = "'" + value + "'";
} else {
this.value = value.toString();
}
}
@Override
public String toJSONString() {
return value;
}
}
}
@@ -0,0 +1,37 @@
package net.lab1024.sa.common.common.enumeration;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 性别枚举类
*
* @Author 1024创新实验室: 胡克
* @Date 2019/09/24 16:50
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@AllArgsConstructor
@Getter
public enum GenderEnum implements BaseEnum {
/**
* 0 未知
*/
UNKNOWN(0, "未知"),
/**
* 男 1 奇数为阳
*/
MAN(1, ""),
/**
* 女 2 偶数为阴
*/
WOMAN(2, "");
private final Integer value;
private final String desc;
}
@@ -0,0 +1,50 @@
package net.lab1024.sa.common.common.enumeration;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 系统环境枚举类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-10-15 22:45:04
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@AllArgsConstructor
@Getter
public enum SystemEnvironmentEnum implements BaseEnum {
/**
* dev
*/
DEV(SystemEnvironmentNameConst.DEV, "开发环境"),
/**
* test
*/
TEST(SystemEnvironmentNameConst.TEST, "测试环境"),
/**
* pre
*/
PRE(SystemEnvironmentNameConst.PRE, "预发布环境"),
/**
* prod
*/
PROD(SystemEnvironmentNameConst.PROD, "生产环境");
private final String value;
private final String desc;
public static final class SystemEnvironmentNameConst {
public static final String DEV = "dev";
public static final String TEST = "test";
public static final String PRE = "pre";
public static final String PROD = "prod----ttt";
}
}
@@ -0,0 +1,38 @@
package net.lab1024.sa.common.common.enumeration;
/**
* 用户类型
*
* @Author 1024创新实验室-主任:卓大
* @Date 2022/10/19 21:46:24
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net ),2012-2022
*/
public enum UserTypeEnum implements BaseEnum {
/**
* 管理端 员工用户
*/
ADMIN_EMPLOYEE(1, "员工"),
EXPERT(2, "专家");
private Integer type;
private String desc;
UserTypeEnum(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
@Override
public Integer getValue() {
return type;
}
@Override
public String getDesc() {
return desc;
}
}
@@ -0,0 +1,185 @@
package net.lab1024.sa.common.common.excel;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.entity.params.ExcelForEachParams;
import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler;
import org.apache.poi.ss.usermodel.*;
/**
* excel样式
*
* @Author 1024创新实验室: 罗伊
* @Date 2020/9/25 19:52
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class ExcelStyle implements IExcelExportStyler {
private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");
private static final short FONT_SIZE_TEN = 10;
private static final short FONT_SIZE_ELEVEN = 11;
private static final short FONT_SIZE_TWELVE = 12;
/**
* 大标题样式
*/
private CellStyle headerStyle;
/**
* 每列标题样式
*/
private CellStyle titleStyle;
/**
* 数据行样式
*/
private CellStyle styles;
public ExcelStyle(Workbook workbook) {
this.init(workbook);
}
/**
* 初始化样式
*
* @param workbook
*/
private void init(Workbook workbook) {
this.headerStyle = initHeaderStyle(workbook);
this.titleStyle = initTitleStyle(workbook);
this.styles = initStyles(workbook);
}
/**
* 大标题样式
*
* @param color
* @return
*/
@Override
public CellStyle getHeaderStyle(short color) {
return headerStyle;
}
/**
* 每列标题样式
*
* @param color
* @return
*/
@Override
public CellStyle getTitleStyle(short color) {
return titleStyle;
}
/**
* 数据行样式
*
* @param parity 可以用来表示奇偶行
* @param entity 数据内容
* @return 样式
*/
public CellStyle getStyles(boolean parity, ExcelExportEntity entity) {
return styles;
}
/**
* 获取样式方法
*
* @param dataRow 数据行
* @param obj 对象
* @param data 数据
*/
@Override
public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {
return getStyles(true, entity);
}
/**
* 模板使用的样式设置
*/
@Override
public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {
return null;
}
/**
* 初始化--大标题样式
*
* @param workbook
* @return
*/
private CellStyle initHeaderStyle(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));
return style;
}
/**
* 初始化--每列标题样式
*
* @param workbook
* @return
*/
private CellStyle initTitleStyle(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));
//背景色
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
return style;
}
/**
* 初始化--数据行样式
*
* @param workbook
* @return
*/
private CellStyle initStyles(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_TEN, false));
style.setDataFormat(STRING_FORMAT);
style.setAlignment(HorizontalAlignment.LEFT);
return style;
}
/**
* 基础样式
*
* @return
*/
private CellStyle getBaseCellStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle();
//下边框
style.setBorderBottom(BorderStyle.THIN);
//左边框
style.setBorderLeft(BorderStyle.THIN);
//上边框
style.setBorderTop(BorderStyle.THIN);
//右边框
style.setBorderRight(BorderStyle.THIN);
//水平居中
style.setAlignment(HorizontalAlignment.CENTER);
//上下居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
//设置自动换行
style.setWrapText(true);
return style;
}
/**
* 字体样式
*
* @param size 字体大小
* @param isBold 是否加粗
* @return
*/
private Font getFont(Workbook workbook, short size, boolean isBold) {
Font font = workbook.createFont();
//字体样式
font.setFontName("宋体");
//是否加粗
font.setBold(isBold);
//字体大小
font.setFontHeightInPoints(size);
return font;
}
}
@@ -0,0 +1,38 @@
package net.lab1024.sa.common.common.exception;
import net.lab1024.sa.common.common.code.ErrorCode;
/**
* 业务逻辑异常,全局异常拦截后统一返回ResponseCodeConst.SYSTEM_ERROR
*
* @Author 1024创新实验室: 罗伊
* @Date 2020/8/25 21:57
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class BusinessException extends RuntimeException {
public BusinessException() {
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMsg());
}
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@@ -0,0 +1,148 @@
package net.lab1024.sa.common.common.interceptor;
import com.alibaba.fastjson.JSONObject;
import net.lab1024.sa.common.common.annoation.NoNeedLogin;
import net.lab1024.sa.common.common.code.UserErrorCode;
import net.lab1024.sa.common.common.constant.RequestHeaderConst;
import net.lab1024.sa.common.common.domain.RequestUser;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import net.lab1024.sa.common.common.util.SmartRequestUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.function.Function;
/**
* 抽象拦截器
*
* @Author 1024创新实验室: 罗伊
* @Date 2021-10-09 20:56:14
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public abstract class AbstractInterceptor implements HandlerInterceptor {
@Autowired
private List<String> ignoreUrlList;
/**
* Token获取用户信息
*
* @return
*/
protected abstract Function<String, RequestUser> userFunction();
/**
* 拦截路径
*
* @return
*/
public abstract String[] pathPatterns();
/**
* 忽略的url集合
*
* @return
*/
protected List<String> getIgnoreUrlList() {
return ignoreUrlList;
}
/**
* 拦截服务器端响应处理ajax请求返回结果
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// OPTIONS请求直接return
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpStatus.NO_CONTENT.value());
return false;
}
boolean isHandler = handler instanceof HandlerMethod;
if (!isHandler) {
return true;
}
//放行的Uri前缀
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
String target = uri.replaceFirst(contextPath, "");
if (this.contain(this.getIgnoreUrlList(), target)) {
return true;
}
//不需要登录
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
// 检查是否包含 token
String xRequestToken = request.getParameter(RequestHeaderConst.TOKEN);
String xHeaderToken = request.getHeader(RequestHeaderConst.TOKEN);
String xAccessToken = StringUtils.isNotBlank(xRequestToken) ? xRequestToken : xHeaderToken;
// 包含token 则获取用户信息 并保存
if (StringUtils.isNotBlank(xAccessToken)) {
RequestUser requestUser = userFunction().apply(xAccessToken);
if (requestUser != null) {
SmartRequestUtil.setRequestUser(requestUser);
}
// 有token 无需登录
if (null != noNeedLogin) {
return true;
}
}
// 无token 无需登录
if (null != noNeedLogin) {
return true;
}
if (StringUtils.isBlank(xAccessToken)) {
this.outputResult(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID));
return false;
}
return true;
}
public Boolean contain(List<String> ignores, String uri) {
if (CollectionUtils.isEmpty(ignores)) {
return false;
}
for (String ignoreUrl : ignores) {
if (uri.startsWith(ignoreUrl)) {
return true;
}
}
return false;
}
/**
* 错误输出
*
* @param response
* @param responseDTO
* @throws IOException
*/
private void outputResult(HttpServletResponse response, ResponseDTO responseDTO) throws IOException {
String msg = JSONObject.toJSONString(responseDTO);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(msg);
response.flushBuffer();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
SmartRequestUtil.remove();
}
}
@@ -0,0 +1,52 @@
package net.lab1024.sa.common.common.json.deserializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.module.support.dict.domain.vo.DictValueVO;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 字典反序列化
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-08-12 22:17:53
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
public class DictValueVoDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
List<DictValueVO> list = new ArrayList<>();
ObjectCodec objectCodec = jsonParser.getCodec();
JsonNode listOrObjectNode = objectCodec.readTree(jsonParser);
String deserialize = "";
try {
if (listOrObjectNode.isArray()) {
for (JsonNode node : listOrObjectNode) {
list.add(objectCodec.treeToValue(node, DictValueVO.class));
}
} else {
list.add(objectCodec.treeToValue(listOrObjectNode, DictValueVO.class));
}
deserialize = list.stream().map(DictValueVO::getValueCode).collect(Collectors.joining(","));
} catch (Exception e) {
log.error(e.getMessage(), e);
deserialize = listOrObjectNode.asText();
}
return deserialize;
}
}
@@ -0,0 +1,53 @@
package net.lab1024.sa.common.common.json.deserializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.module.support.file.domain.vo.FileVO;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 文件key反序列化<br>
* 由于前端接收到的是序列化过的字段, 这边入库需要进行反序列化操作比较方便处理
*
* @Author 1024创新实验室: 胡克
* @Date 2022-11-24 17:15:23
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
public class FileKeyVoDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
List<FileVO> list = new ArrayList<>();
ObjectCodec objectCodec = jsonParser.getCodec();
JsonNode listOrObjectNode = objectCodec.readTree(jsonParser);
String deserialize = "";
try {
if (listOrObjectNode.isArray()) {
for (JsonNode node : listOrObjectNode) {
list.add(objectCodec.treeToValue(node, FileVO.class));
}
} else {
list.add(objectCodec.treeToValue(listOrObjectNode, FileVO.class));
}
deserialize = list.stream().map(FileVO::getFileKey).collect(Collectors.joining(","));
} catch (Exception e) {
log.error(e.getMessage(), e);
deserialize = listOrObjectNode.asText();
}
return deserialize;
}
}
@@ -0,0 +1,30 @@
package net.lab1024.sa.common.common.json.deserializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
/**
* Long类型序列化
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-06-02 22:55:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class LongJsonDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String value = jsonParser.getText();
try {
return value == null ? null : Long.parseLong(value);
} catch (NumberFormatException e) {
return null;
}
}
}
@@ -0,0 +1,29 @@
package net.lab1024.sa.common.common.json.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.math.BigDecimal;
/**
* 数字序列化
*
* @Author 1024创新实验室: 罗伊
* @Date 2020/8/20 21:04
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class BigDecimalNullZeroSerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (value == null) {
jsonGenerator.writeNumber(BigDecimal.ZERO);
return;
}
jsonGenerator.writeNumber(value);
}
}
@@ -0,0 +1,52 @@
package net.lab1024.sa.common.common.json.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.google.common.collect.Lists;
import net.lab1024.sa.common.module.support.dict.domain.vo.DictValueVO;
import net.lab1024.sa.common.module.support.dict.service.DictCacheService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* 字典序列化
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-08-12 22:17:53
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class DictValueVoSerializer extends JsonSerializer<String> {
@Autowired
private DictCacheService dictCacheService;
@Override
public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (StringUtils.isEmpty(value)) {
jsonGenerator.writeObject(Lists.newArrayList());
return;
}
String[] valueCodeArray = value.split(",");
List<String> valueCodeList = Arrays.asList(valueCodeArray);
List<DictValueVO> dictValueVOList = Lists.newArrayList();
valueCodeList.forEach(e->{
if(StringUtils.isNotBlank(e)){
DictValueVO dictValueVO = dictCacheService.selectValueByValueCode(value);
if(dictValueVO != null){
dictValueVOList.add(dictValueVO);
}
}
});
jsonGenerator.writeObject(dictValueVOList);
}
}
@@ -0,0 +1,45 @@
//package net.lab1024.sa.common.common.json.serializer;
//
//import com.fasterxml.jackson.core.JsonGenerator;
//import com.fasterxml.jackson.databind.JsonSerializer;
//import com.fasterxml.jackson.databind.SerializerProvider;
//import net.lab1024.sa.common.common.domain.ResponseDTO;
//import net.lab1024.sa.common.module.support.file.service.FileService;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.beans.factory.annotation.Autowired;
//
//import java.io.IOException;
//
///**
// * 文件key进行序列化对象
// *
// * @Author 1024创新实验室: 罗伊
// * @Date 2020/8/15 22:06
// * @Wechat zhuoda1024
// * @Email lab1024@163.com
// * @Copyright 1024创新实验室 https://1024lab.net
// */
//public class FileKeySerializer extends JsonSerializer<String> {
//
// @Autowired
// private FileService fileService;
//
//
// @Override
// public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
// if (StringUtils.isEmpty(value)) {
// jsonGenerator.writeString(value);
// return;
// }
// if (fileService == null) {
// jsonGenerator.writeString(value);
// return;
// }
// ResponseDTO<String> responseDTO = fileService.getFileUrl(value);
// if (responseDTO.getOk()) {
// jsonGenerator.writeString(responseDTO.getData());
// return;
// }
// jsonGenerator.writeString(value);
// }
//}
@@ -0,0 +1,46 @@
//package net.lab1024.sa.common.common.json.serializer;
//
//import com.fasterxml.jackson.core.JsonGenerator;
//import com.fasterxml.jackson.databind.JsonSerializer;
//import com.fasterxml.jackson.databind.SerializerProvider;
//import com.google.common.collect.Lists;
//import net.lab1024.sa.common.module.support.file.domain.vo.FileVO;
//import net.lab1024.sa.common.module.support.file.service.FileService;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.beans.factory.annotation.Autowired;
//
//import java.io.IOException;
//import java.util.Arrays;
//import java.util.List;
//
///**
// * 文件key进行序列化对象
// *
// * @Author 1024创新实验室: 罗伊
// * @Date 2020/8/15 22:06
// * @Wechat zhuoda1024
// * @Email lab1024@163.com
// * @Copyright 1024创新实验室 https://1024lab.net
// */
//public class FileKeyVoSerializer extends JsonSerializer<String> {
//
// @Autowired
// private FileService fileService;
//
//
// @Override
// public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
// if (StringUtils.isEmpty(value)) {
// jsonGenerator.writeObject(Lists.newArrayList());
// return;
// }
// if(fileService == null){
// jsonGenerator.writeString(value);
// return;
// }
// String[] fileKeyArray = value.split(",");
// List<String> fileKeyList = Arrays.asList(fileKeyArray);
// List<FileVO> fileKeyVOList = fileService.getFileList(fileKeyList);
// jsonGenerator.writeObject(fileKeyVOList);
// }
//}
@@ -0,0 +1,28 @@
package net.lab1024.sa.common.common.json.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* Long类型序列化
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-06-02 22:55:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class LongJsonSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
String text = (value == null ? null : String.valueOf(value));
if (text != null) {
jsonGenerator.writeString(text);
}
}
}
@@ -0,0 +1,95 @@
package net.lab1024.sa.common.common.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* Spring Security
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/8/3 17:50
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public abstract class AbstractSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CorsFilter corsFilter;
@Autowired
private List<String> noNeedLoginUrlList;
@Autowired
private List<String> ignoreUrlList;
/**
* Token获取用户信息
*
* @return
*/
protected abstract BiFunction<String, HttpServletRequest, UserDetails> userFunction();
/**
* 需要认证的url集合
*
* @return
*/
protected abstract String[] getAuthenticatedUrlPatterns();
/**
* 不需要登录的url集合
*
* @return
*/
protected String[] getNoNeedLoginUrl() {
return noNeedLoginUrlList.toArray(new String[noNeedLoginUrlList.size()]);
}
/**
* 忽略的url集合
*
* @return
*/
protected String[] getIgnoreUrlList() {
return ignoreUrlList.toArray(new String[ignoreUrlList.size()]);
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// CSRF禁用,因为不使用session
.csrf().disable()
// 认证失败处理类
.exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationFailHandler()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
//忽略的url
.antMatchers(this.getIgnoreUrlList()).permitAll()
// 不需要登陆的url
.antMatchers(this.getNoNeedLoginUrl()).permitAll()
//需要校验权限的url
.antMatchers(getAuthenticatedUrlPatterns()).authenticated();
//防止xss攻击
httpSecurity.headers().xssProtection();
// token filter 进行校验
httpSecurity.addFilterBefore(new SecurityTokenFilter(this.userFunction()), UsernamePasswordAuthenticationFilter.class);
httpSecurity.addFilterBefore(corsFilter, SecurityTokenFilter.class);
// 禁用spring security 使用 X-Frame-Options防止网页被Frame
httpSecurity.headers().frameOptions().disable();
}
}
@@ -0,0 +1,43 @@
package net.lab1024.sa.common.common.security;
import com.alibaba.fastjson.JSONObject;
import net.lab1024.sa.common.common.code.ErrorCode;
import net.lab1024.sa.common.common.code.UserErrorCode;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录认证失败处理
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-08-26 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SecurityAuthenticationFailHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
this.outputResult(response, UserErrorCode.LOGIN_STATE_INVALID);
}
/**
* 输出
*
* @param response
* @param errorCode
* @throws IOException
*/
private void outputResult(HttpServletResponse response, ErrorCode errorCode) throws IOException {
String msg = JSONObject.toJSONString(ResponseDTO.error(errorCode));
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(msg);
response.flushBuffer();
}
}
@@ -0,0 +1,66 @@
package net.lab1024.sa.common.common.security;
import net.lab1024.sa.common.common.annoation.SaAuth;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.prepost.PrePostInvocationAttributeFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
/**
* 此类用于默认给所有接口添加权限 @saAuth.checkPermission('%s')
* %s 为类名.方法名
* 和使用@PreAuthorize("@saAuth.checkPermission('%s')") 效果一致
* 避免所有接口都添加一遍 减轻工作量
*
* @Author 1024创新实验室: 罗伊
* @Date 2021-08-30 23:08
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SecurityMethodSource extends PrePostAnnotationSecurityMetadataSource {
private static String EXPRESSION_FORMAT = "@%s.checkPermission('%s')";
private final PrePostInvocationAttributeFactory attributeFactory;
private String beanName;
public SecurityMethodSource(PrePostInvocationAttributeFactory attributeFactory, String beanName) {
super(attributeFactory);
this.attributeFactory = attributeFactory;
this.beanName = beanName;
}
@Override
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
//如果不存在SaAuth采用security认证模式
SaAuth saAuth = method.getAnnotation(SaAuth.class);
if (saAuth == null) {
return super.getAttributes(method, targetClass);
}
//存在添加以URL为权限字符串的校验模式
ArrayList<ConfigAttribute> configAttributes = new ArrayList(1);
String classFullName = targetClass.getName();
String methodName = method.getName();
String[] classNameArray = StringUtils.split(classFullName, "\\.");
String controllerName = classNameArray[classNameArray.length - 1];
String privilegeName = controllerName + "." + methodName;
String preAuthorizeAttribute = String.format(EXPRESSION_FORMAT, beanName, privilegeName);
PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(null, null, preAuthorizeAttribute);
if (pre != null) {
configAttributes.add(pre);
}
return configAttributes;
}
}
@@ -0,0 +1,74 @@
package net.lab1024.sa.common.common.security;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 校验权限
*
* @Author 1024创新实验室: 罗伊
* @Date 2022/5/12 21:50
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public abstract class SecurityPermissionCheckService {
/**
* 校验是否有权限
*
* @param permission
* @return
*/
public boolean checkPermission(String permission) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
return checkPermission(authentication, permission);
}
/**
* 校验是否有权限
*
* @param authentication
* @param permission
* @return
*/
public abstract boolean checkPermission(Authentication authentication, String permission);
/**
* 判断
*
* @param userDetails
* @param permissionStr
* @return
*/
protected boolean permissionJudge(UserDetails userDetails, String permissionStr) {
if (CollectionUtils.isEmpty(userDetails.getAuthorities())) {
return false;
}
if (StringUtils.isBlank(permissionStr)) {
return false;
}
String[] permissionArray = permissionStr.split(",");
for (String permission : permissionArray) {
if(userDetails.getAuthorities().contains(new SimpleGrantedAuthority(permission))){
return true;
}
}
return false;
}
}
@@ -0,0 +1,64 @@
package net.lab1024.sa.common.common.security;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.constant.RequestHeaderConst;
import net.lab1024.sa.common.common.domain.RequestUser;
import net.lab1024.sa.common.common.util.SmartRequestUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* 注意此处不能 加入@Component,否则对应ignoreUrl的相关请求 将会进入此Filter,并会覆盖CorsFilter
*
* @Author 1024创新实验室: 罗伊
* @Date 2022/5/12 21:50
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
public class SecurityTokenFilter extends OncePerRequestFilter {
private BiFunction<String,HttpServletRequest, UserDetails> userFunction;
public SecurityTokenFilter(BiFunction<String,HttpServletRequest, UserDetails> userFunction) {
this.userFunction = userFunction;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
//需要做token校验, 消息头的token优先于请求query参数的token
String xHeaderToken = request.getHeader(RequestHeaderConst.TOKEN);
String xRequestToken = request.getParameter(RequestHeaderConst.TOKEN);
String xAccessToken = null != xHeaderToken ? xHeaderToken : xRequestToken;
if (StringUtils.isBlank(xAccessToken)) {
chain.doFilter(request, response);
return;
}
//清理spring security
SecurityContextHolder.clearContext();
UserDetails loginUserDetail = userFunction.apply(xAccessToken,request);
if (null != loginUserDetail) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUserDetail, null, loginUserDetail.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
SmartRequestUtil.setRequestUser((RequestUser) loginUserDetail);
}
// 若未给予spring security上下文用户授权 则会授权失败 进入AuthenticationEntryPointImpl
chain.doFilter(request, response);
}
}
@@ -0,0 +1,40 @@
package net.lab1024.sa.common.common.swagger;
import net.lab1024.sa.common.common.enumeration.BaseEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 枚举类字段属性的 自定义 swagger 注解
*
* @Author 1024创新实验室: 胡克
* @Date 2019/05/16 23:18
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiModelPropertyEnum {
/**
* 枚举类对象
*
* @return
*/
Class<? extends BaseEnum> value();
String example() default "";
boolean hidden() default false;
boolean required() default true;
String dataType() default "";
String desc() default "";
}
@@ -0,0 +1,91 @@
//package net.lab1024.sa.common.common.swagger;
//
//import com.google.common.collect.LinkedListMultimap;
//import com.google.common.collect.Multimap;
//import io.swagger.models.Operation;
//import io.swagger.models.Path;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
//import org.springframework.context.annotation.Primary;
//import org.springframework.stereotype.Component;
//import springfox.documentation.service.ApiDescription;
//import springfox.documentation.service.ApiListing;
//import springfox.documentation.swagger2.mappers.ModelMapper;
//import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;
//
//import java.lang.reflect.Field;
//import java.lang.reflect.Modifier;
//import java.util.*;
//
//import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;
//
///**
// * 修改 api 顺序
// *
// * @Author 1024创新实验室: 胡克
// * @Date 2021/8/11 22:05
// * @Wechat zhuoda1024
// * @Email lab1024@163.com
// * @Copyright 1024创新实验室 https://1024lab.net
// */
//@ConditionalOnBean(ModelMapper.class)
//@Component
//@Primary
//public class Swagger2MapperImplExtension extends ServiceModelToSwagger2MapperImpl {
//
// @Override
// protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
// Map<String, Path> paths = new LinkedHashMap<>();
// Multimap<String, ApiListing> apiListingMap = LinkedListMultimap.create();
// Iterator iter = apiListings.entries().iterator();
// while (iter.hasNext()) {
// Map.Entry<String, ApiListing> entry = (Map.Entry<String, ApiListing>) iter.next();
// ApiListing apis = entry.getValue();
// List<ApiDescription> apiList = apis.getApis();
// apiList.sort((left, right) -> {
// int position1 = left.getOperations().get(0).getPosition();
// int position2 = right.getOperations().get(0).getPosition();
// if (position1 == position2) {
// return String.CASE_INSENSITIVE_ORDER.compare(left.getPath(), right.getPath());
// }
// return Integer.compare(position1, position2);
// });
// try {
// // 因ApiListing的属性都是final故需要通过反射来修改值
// modify(apis, "apis", apiList);
// } catch (Exception e) {
// e.printStackTrace();
// }
// apiListingMap.put(entry.getKey(), apis);
// }
//
// for (ApiListing each : apiListingMap.values()) {
// for (ApiDescription api : each.getApis()) {
// paths.put(api.getPath(), mapOperations(api, Optional.ofNullable(paths.get(api.getPath()))));
// }
// }
// return paths;
// }
//
// private Path mapOperations(ApiDescription api, Optional<Path> existingPath) {
// Path path = existingPath.orElse(new Path());
// for (springfox.documentation.service.Operation each : nullToEmptyList(api.getOperations())) {
// Operation operation = mapOperation(each);
// path.set(each.getMethod().toString().toLowerCase(), operation);
// }
// return path;
// }
//
// public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
// Field field = object.getClass().getDeclaredField(fieldName);
//
// Field modifiersField = Field.class.getDeclaredField("modifiers");
// modifiersField.setAccessible(true);
// modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
//
// if (!field.isAccessible()) {
// field.setAccessible(true);
// }
//
// field.set(object, newFieldValue);
// }
//}
@@ -0,0 +1,77 @@
package net.lab1024.sa.common.common.swagger;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import net.lab1024.sa.common.common.enumeration.BaseEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import java.lang.reflect.AnnotatedElement;
import static springfox.documentation.schema.Annotations.findPropertyAnnotation;
/**
* swagger 用于说明枚举类字段说明
* * SWAGGER_PLUGIN_ORDER+1 是将此配置放在原来的后面执行
*
* @Author 1024创新实验室: 胡克
* @Date 2019/8/11 15:36:56
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public class SwaggerApiModelPropertyEnumPlugin implements ModelPropertyBuilderPlugin {
@Override
public void apply(ModelPropertyContext context) {
Optional<ApiModelPropertyEnum> annotation = Optional.absent();
if (context.getAnnotatedElement().isPresent()) {
annotation = annotation.or(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
}
if (context.getBeanPropertyDefinition().isPresent()) {
annotation = annotation.or(findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelPropertyEnum.class));
}
if (annotation.isPresent()) {
ApiModelPropertyEnum anEnum = annotation.get();
String enumInfo = BaseEnum.getInfo(anEnum.value());
context.getBuilder()
.required(annotation.transform(toIsRequired()).or(false))
.description(anEnum.desc() + ":" + enumInfo)
.example(annotation.transform(toExample()).orNull())
.isHidden(anEnum.hidden());
}
}
@Override
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
static Function<ApiModelPropertyEnum, Boolean> toIsRequired() {
return annotation -> annotation.required();
}
public static Optional<ApiModelPropertyEnum> findApiModePropertyAnnotation(AnnotatedElement annotated) {
return Optional.fromNullable(AnnotationUtils.getAnnotation(annotated, ApiModelPropertyEnum.class));
}
static Function<ApiModelPropertyEnum, String> toExample() {
return annotation -> {
String example = annotation.example();
if (StringUtils.isBlank(example)) {
return "";
}
return example;
};
}
}
@@ -0,0 +1,79 @@
/**
* Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.lab1024.sa.common.common.util;
import java.security.MessageDigest;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class EncryptionKit {
public static String md5Encrypt(String srcStr) {
return encrypt("MD5", srcStr);
}
public static String sha1Encrypt(String srcStr) {
return encrypt("SHA-1", srcStr);
}
public static String sha256Encrypt(String srcStr) {
return encrypt("SHA-256", srcStr);
}
public static String sha384Encrypt(String srcStr) {
return encrypt("SHA-384", srcStr);
}
public static String sha512Encrypt(String srcStr) {
return encrypt("SHA-512", srcStr);
}
public static String encrypt(String algorithm, String srcStr) {
try {
StringBuilder result = new StringBuilder();
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] bytes = md.digest(srcStr.getBytes("utf-8"));
for (byte b : bytes) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1)
result.append("0");
result.append(hex);
}
return result.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String HMACSHA256(String data, String key) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toLowerCase();
} catch (Exception e) {
return "";
}
}
}
@@ -0,0 +1,542 @@
package net.lab1024.sa.common.common.util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Sean
* @createDate 2022/7/20-22:28
*/
public class HttpUtil {
private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);
private static PoolingHttpClientConnectionManager connMgr;
private static RequestConfig requestConfig;
private static final int MAX_TIMEOUT = 3600000;// 7秒
private static final String UTF_8 = "UTF-8";
public static final String JSON = "json";
public static final String XML = "xml";
static {
// 设置连接池
connMgr = new PoolingHttpClientConnectionManager();
// 设置连接池大小
connMgr.setMaxTotal(100);
connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
RequestConfig.Builder configBuilder = RequestConfig.custom();
// 设置连接超时
configBuilder.setConnectTimeout(MAX_TIMEOUT);
// 设置读取超时
configBuilder.setSocketTimeout(MAX_TIMEOUT);
// 设置从连接池获取连接实例的超时
configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
// 在提交请求之前 测试连接是否可用
configBuilder.setStaleConnectionCheckEnabled(true);
requestConfig = configBuilder.build();
}
/**
* 发送 GET 请求(HTTP),不带输入数据
*
* @param url
* @return
* @throws IOException
*/
public static String doGet(String url) throws IOException {
return doGet(url, null);
}
/**
* 发送 GET 请求(HTTP),K-V形式
*
* @param url
* @param params
* @return
* @throws IOException
*/
public static String doGet(String url, Map<String, String> params) throws IOException {
int i = 0;
if (params != null) {
StringBuffer param = new StringBuffer();
for (String key : params.keySet()) {
if (i == 0)
param.append("?");
else
param.append("&");
param.append(key).append("=").append(params.get(key));
i++;
}
url += param;
}
String result = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = null;
HttpEntity entity = null;
try {
HttpGet httpGet = new HttpGet(url);
response = httpclient.execute(httpGet);
// int statusCode = response.getStatusLine().getStatusCode();
entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
result = IOUtils.toString(instream, UTF_8);
}
} finally {
// 最后别忘了关闭应该关闭的资源,适当的释放资源
try {
// 这个方法也可以把底层的流给关闭了
EntityUtils.consume(entity);
// if (null != response) {
// response.close();
// }
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 发送 POST 请求(HTTP),不带输入数据
*
* @param apiUrl
* @return
* @throws ConnectTimeoutException
*/
public static String doPost(String apiUrl) throws IOException {
return doPost(apiUrl, new HashMap<String, String>());
}
/**
* 发送 POST 请求(HTTP),K-V形式
*
* @param apiUrl API接口URL
* @param params 参数map
* @return
* @throws ConnectTimeoutException
*/
public static String doPost(String apiUrl, Map<String, String> params) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String httpStr = null;
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
try {
httpPost.setConfig(requestConfig);
List<NameValuePair> pairList = new ArrayList<>(params.size());
for (Map.Entry<String, String> entry : params.entrySet()) {
NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
pairList.add(pair);
}
httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
httpStr = EntityUtils.toString(entity, "UTF-8");
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 发送 POST 请求(HTTP),JSON形式
*
* @param apiUrl
* @param content 内容
* @return
* @throws IOException
*/
public static String doPost(String apiUrl, String content, String type) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String httpStr = null;
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
try {
httpPost.setConfig(requestConfig);
StringEntity stringEntity = new StringEntity(content, "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
if (JSON.equals(type) || "application/json;charset=UTF-8".equals(type)) {
stringEntity.setContentType("application/json");
} else if (XML.equals(type)) {
stringEntity.setContentType("application/xml");
} else {
stringEntity.setContentType("text/plain");
}
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
// System.out.println(response.getStatusLine().getStatusCode());
httpStr = EntityUtils.toString(entity, "UTF-8");
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 发送 POST 请求(HTTP),JSON形式 + url k-v参数
* @param apiUrl
* @param content
* @param params
* @param type
* @return
* @throws IOException
*/
public static String doPost(String apiUrl, String content,Map<String, String> params, String type) throws IOException {
// url参数拼接
if (params != null) {
int i = 0;
StringBuffer param = new StringBuffer();
for (String key : params.keySet()) {
if (i == 0)
param.append("?");
else
param.append("&");
param.append(key).append("=").append(params.get(key));
i++;
}
apiUrl += param;
}
CloseableHttpClient httpClient = HttpClients.createDefault();
String httpStr = null;
log.info("本次请求apiUrl:"+apiUrl);
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
try {
httpPost.setConfig(requestConfig);
StringEntity stringEntity = new StringEntity(content, "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
if (JSON.equals(type)) {
stringEntity.setContentType("application/json");
} else if (XML.equals(type)) {
stringEntity.setContentType("application/xml");
} else {
stringEntity.setContentType("text/plain");
}
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
// System.out.println(response.getStatusLine().getStatusCode());
httpStr = EntityUtils.toString(entity, "UTF-8");
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
public static String doPost(String apiUrl, String content, String type,Map<String, String> headers) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String httpStr = null;
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
try {
httpPost.setConfig(requestConfig);
if (headers != null) {
for (String headerName : headers.keySet()) {
httpPost.setHeader(headerName, headers.get(headerName));
}
}
StringEntity stringEntity = new StringEntity(content, "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
if (JSON.equals(type)) {
stringEntity.setContentType("application/json");
} else if (XML.equals(type)) {
stringEntity.setContentType("application/xml");
} else {
stringEntity.setContentType("text/plain");
}
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
// System.out.println(response.getStatusLine().getStatusCode());
httpStr = EntityUtils.toString(entity, "UTF-8");
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 发送 SSL POST 请求(HTTPS),K-V形式
*
* @param apiUrl API接口URL
* @param params 参数map
* @return
*/
public static String doPostSSL(String apiUrl, Map<String, Object> params) {
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr)
.setDefaultRequestConfig(requestConfig).build();
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
String httpStr = null;
try {
httpPost.setConfig(requestConfig);
List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());
for (Map.Entry<String, Object> entry : params.entrySet()) {
NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
pairList.add(pair);
}
httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
}
httpStr = EntityUtils.toString(entity, "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 发送 SSL POST 请求(HTTPS),JSON形式
*
* @param apiUrl API接口URL
* @param json JSON对象
* @return
*/
public static String doPostSSL(String apiUrl, Object json) {
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr)
.setDefaultRequestConfig(requestConfig).build();
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
String httpStr = null;
try {
httpPost.setConfig(requestConfig);
StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
stringEntity.setContentType("application/json");
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
}
httpStr = EntityUtils.toString(entity, "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 创建SSL安全连接
*
* @return
*/
private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
SSLConnectionSocketFactory sslsf = null;
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl) throws IOException {
}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {
}
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
}
});
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return sslsf;
}
/**
* 发送 SSL POST 请求(HTTPS),加载证书
*
* @return
*/
public static String doPostSSL(String url, String content, String type, Map<String, String> headers, SSLConnectionSocketFactory sslsf) {
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr)
.setDefaultRequestConfig(requestConfig).build();
HttpPost httpPost = new HttpPost(url);
CloseableHttpResponse response = null;
String httpStr = null;
try {
httpPost.setConfig(requestConfig);
if (headers != null) {
for (String headerName : headers.keySet()) {
httpPost.setHeader(headerName, headers.get(headerName));
}
}
StringEntity stringEntity = new StringEntity(content, "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
if (JSON.equals(type)) {
stringEntity.setContentType("application/json");
} else if (XML.equals(type)) {
stringEntity.setContentType("application/xml");
} else {
stringEntity.setContentType("text/plain");
}
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
}
httpStr = EntityUtils.toString(entity, "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
/**
* 自定义POST带请求头
* 请求类型为为:application/json
*
*/
public static String doPostWithHeader(String apiUrl, String content, Map<String,String> map) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String httpStr = null;
HttpPost httpPost = new HttpPost(apiUrl);
CloseableHttpResponse response = null;
for(Map.Entry<String,String> entry : map.entrySet()){
httpPost.setHeader(entry.getKey(),entry.getValue());
}
try {
httpPost.setConfig(requestConfig);
StringEntity stringEntity = new StringEntity(content, "UTF-8");// 解决中文乱码问题
stringEntity.setContentEncoding("UTF-8");
stringEntity.setContentType("application/json");
httpPost.setEntity(stringEntity);
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
// System.out.println(response.getStatusLine().getStatusCode());
httpStr = EntityUtils.toString(entity, "UTF-8");
} finally {
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return httpStr;
}
}
@@ -0,0 +1,47 @@
package net.lab1024.sa.common.common.util;
import cn.hutool.core.util.StrUtil;
import org.apache.poi.util.StringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 加密
*/
public class Sha256Util {
/**
* 加密
* @param params
* @param accessToken
* @return
*/
public static String getSign(Map<String, Object> params, String accessToken) {
List<String> keys = new ArrayList<>(params.keySet());
List<String> tmp = new ArrayList<>();
Collections.sort(keys);
for (String key : keys) {
if (!StrUtil.isEmptyIfStr(params.get(key))) {
tmp.add(key + "=" + params.get(key));
}
}
String join = String.join("&", tmp);
return EncryptionKit.HMACSHA256(join, accessToken);
}
public static String getSignString(Map<String, String> params, String accessToken) {
List<String> keys = new ArrayList<>(params.keySet());
List<String> tmp = new ArrayList<>();
Collections.sort(keys);
for (String key : keys) {
if (!StrUtil.isEmptyIfStr(params.get(key))) {
tmp.add(key + "=" + params.get(key));
}
}
String join = String.join("&", tmp);
return EncryptionKit.HMACSHA256(join, accessToken);
}
}
@@ -0,0 +1,94 @@
package net.lab1024.sa.common.common.util;
import org.springframework.beans.BeanUtils;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* bean相关工具类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2018-01-15 10:48:23
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartBeanUtil {
/**
* 验证器
*/
private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
/**
* 复制bean的属性
*
* @param source 源 要复制的对象
* @param target 目标 复制到此对象
*/
public static void copyProperties(Object source, Object target) {
BeanUtils.copyProperties(source, target);
}
/**
* 复制对象
*
* @param source 源 要复制的对象
* @param target 目标 复制到此对象
* @param <T>
* @return
*/
public static <T> T copy(Object source, Class<T> target) {
if (source == null || target == null) {
return null;
}
try {
T newInstance = target.newInstance();
BeanUtils.copyProperties(source, newInstance);
return newInstance;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 复制list
*
* @param source
* @param target
* @param <T>
* @param <K>
* @return
*/
public static <T, K> List<K> copyList(List<T> source, Class<K> target) {
if (null == source || source.isEmpty()) {
return Collections.emptyList();
}
return source.stream().map(e -> copy(e, target)).collect(Collectors.toList());
}
/**
* 手动验证对象 Model的属性
* 需要配合 hibernate-validator 校验注解
*
* @param t
* @return String 返回null代表验证通过,否则返回错误的信息
*/
public static <T> String verify(T t) {
// 获取验证结果
Set<ConstraintViolation<T>> validate = VALIDATOR.validate(t);
if (validate.isEmpty()) {
// 验证通过
return null;
}
// 返回错误信息
List<String> messageList = validate.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
return messageList.toString();
}
}
@@ -0,0 +1,247 @@
package net.lab1024.sa.common.common.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* BigDecimal 工具类
*
* @Author 1024创新实验室: 胡克
* @Date 2018/01/17 13:54
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartBigDecimalUtil {
/**
* 金额 保留小数点 2
*/
public static final int AMOUNT_DECIMAL_POINT = 2;
public static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
/**
* 金额相关计算方法:四舍五入 保留2位小数点
*/
public static class Amount {
public static BigDecimal add(BigDecimal num1, BigDecimal num2) {
return setScale(num1.add(num2), AMOUNT_DECIMAL_POINT);
}
public static BigDecimal multiply(BigDecimal num1, BigDecimal num2) {
return setScale(num1.multiply(num2), AMOUNT_DECIMAL_POINT);
}
public static BigDecimal subtract(BigDecimal num1, BigDecimal num2) {
return setScale(num1.subtract(num2), AMOUNT_DECIMAL_POINT);
}
public static BigDecimal divide(BigDecimal num1, BigDecimal num2) {
return setScale(num1.divide(num2, RoundingMode.HALF_UP), AMOUNT_DECIMAL_POINT);
}
}
/**
* BigDecimal 加法 num1 + num2
* 未做非空校验
*
* @param num1
* @param num2
* @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT
* @return BigDecimal
*/
public static BigDecimal add(BigDecimal num1, BigDecimal num2, int point) {
return setScale(num1.add(num2), point);
}
/**
* 累加
*
* @param point
* @param array
* @return
*/
public static BigDecimal add(int point, BigDecimal... array) {
BigDecimal res = new BigDecimal(0);
for (BigDecimal item : array) {
if (item == null) {
res = res.add(BigDecimal.ZERO);
} else {
res = res.add(item);
}
}
return setScale(res, point);
}
/**
* BigDecimal 乘法 num1 x num2
* 未做非空校验
*
* @param num1
* @param num2
* @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT
* @return BigDecimal
*/
public static BigDecimal multiply(BigDecimal num1, BigDecimal num2, int point) {
return setScale(num1.multiply(num2), point);
}
/**
* BigDecimal 减法 num1 - num2
* 未做非空校验
*
* @param num1
* @param num2
* @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT
* @return BigDecimal
*/
public static BigDecimal subtract(BigDecimal num1, BigDecimal num2, int point) {
return setScale(num1.subtract(num2), point);
}
/**
* BigDecimal 除法 num1/num2
* 未做非空校验
*
* @param num1
* @param num2
* @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT
* @return BigDecimal
*/
public static BigDecimal divide(BigDecimal num1, BigDecimal num2, int point) {
return num1.divide(num2, point, RoundingMode.HALF_UP);
}
/**
* 设置小数点类型为 四舍五入
*
* @param num
* @param point
* @return BigDecimal
*/
public static BigDecimal setScale(BigDecimal num, int point) {
return num.setScale(point, RoundingMode.HALF_UP);
}
/**
* 比较 num1 是否大于 num2
*
* @param num1
* @param num2
* @return boolean
*/
public static boolean isGreaterThan(BigDecimal num1, BigDecimal num2) {
return num1.compareTo(num2) > 0;
}
/**
* 比较 num1 是否大于等于 num2
*
* @param num1
* @param num2
* @return boolean
*/
public static boolean isGreaterOrEqual(BigDecimal num1, BigDecimal num2) {
return isGreaterThan(num1, num2) || equals(num1, num2);
}
/**
* 比较 num1 是否小于 num2
*
* @param num1
* @param num2
* @return boolean
*/
public static boolean isLessThan(BigDecimal num1, BigDecimal num2) {
return num1.compareTo(num2) < 0;
}
/**
* 比较 num1 是否小于等于 num2
*
* @param num1
* @param num2
* @return boolean
*/
public static boolean isLessOrEqual(BigDecimal num1, BigDecimal num2) {
return isLessThan(num1, num2) || equals(num1, num2);
}
/**
* 比较 num1 是否等于 num2
*
* @param num1
* @param num2
* @return
*/
public static boolean equals(BigDecimal num1, BigDecimal num2) {
return num1.compareTo(num2) == 0;
}
/**
* 计算 num1 / num2 的百分比
*
* @param num1
* @param num2
* @param point 保留几位小数
* @return String
*/
public static BigDecimal percent(Integer num1, Integer num2, int point) {
if (num1 == null || num2 == null) {
return BigDecimal.ZERO;
}
if (num2.equals(0)) {
return BigDecimal.ZERO;
}
return percent(new BigDecimal(num1), new BigDecimal(num2), point);
}
/**
* 计算 num1 / num2 的百分比
*
* @param num1
* @param num2
* @param point 保留几位小数
* @return String
*/
public static BigDecimal percent(BigDecimal num1, BigDecimal num2, int point) {
if (num1 == null || num2 == null) {
return BigDecimal.ZERO;
}
if (equals(BigDecimal.ZERO, num2)) {
return BigDecimal.ZERO;
}
BigDecimal percent = num1.divide(num2, point + 2, RoundingMode.HALF_UP);
return percent.multiply(ONE_HUNDRED).setScale(point);
}
/**
* 比较 num1num2 返回最大的值
*
* @param num1
* @param num2
* @return BigDecimal
*/
public static BigDecimal max(BigDecimal num1, BigDecimal num2) {
return num1.compareTo(num2) > 0 ? num1 : num2;
}
/**
* 比较 num1num2 返回最小的值
*
* @param num1
* @param num2
* @return BigDecimal
*/
public static BigDecimal min(BigDecimal num1, BigDecimal num2) {
return num1.compareTo(num2) < 0 ? num1 : num2;
}
public static void main(String[] args) {
System.out.println(percent(new BigDecimal("3"), new BigDecimal("11"), 2));
System.out.println(percent(new BigDecimal("8"), new BigDecimal("11"), 2));
}
}
@@ -0,0 +1,41 @@
package net.lab1024.sa.common.common.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import static net.lab1024.sa.common.common.code.SystemErrorCode.SYSTEM_ERROR;
/**
* Easy Excel 工具类
*/
@Slf4j
public class SmartEasyExcelUtil {
public static void exportExcel(List<?> list, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {
try {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 这里需要设置不关闭流
EasyExcel.write(response.getOutputStream(), pojoClass).autoCloseStream(Boolean.FALSE).sheet(sheetName).doWrite(list);
}catch (Exception e){
e.printStackTrace();
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(JSON.toJSONString(ResponseDTO.error(SYSTEM_ERROR)));
}
}
}
@@ -0,0 +1,114 @@
package net.lab1024.sa.common.common.util;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* excel 工具类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2018/01/17 13:54
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
public class SmartEasyPoiExcelUtil {
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,
String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException {
ExportParams exportParams = new ExportParams(title, sheetName);
exportParams.setCreateHeadRows(isCreateHeader);
defaultExport(list, pojoClass, fileName, response, exportParams);
}
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
HttpServletResponse response) throws IOException {
defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
}
public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
defaultExport(list, fileName, response);
}
private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName,
HttpServletResponse response, ExportParams exportParams) throws IOException {
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
downloadExcel(fileName, workbook, response);
}
public static void downloadExcel(String fileName, Workbook workbook, HttpServletResponse response) {
try {
fileName = URLEncoder.encode(fileName, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error("", e);
}
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xls");
try {
workbook.write(response.getOutputStream());
workbook.close();
} catch (IOException e) {
log.error("", e);
}
}
private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
downloadExcel(fileName, workbook, response);
}
public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
if (StringUtils.isBlank(filePath)) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
} catch (NoSuchElementException e) {
//throw new NormalException("模板不能为空");
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
if (file == null) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
} catch (NoSuchElementException e) {
// throw new NormalException("excel文件不能为空");
} catch (Exception e) {
//throw new NormalException(e.getMessage());
System.out.println(e.getMessage());
}
return list;
}
}
@@ -0,0 +1,165 @@
package net.lab1024.sa.common.common.util;
import net.lab1024.sa.common.common.enumeration.BaseEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 枚举工具类
*
* @Author 1024创新实验室: 胡克
* @Date 2017/10/10 18:17
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartEnumUtil {
/**
* 校验参数与枚举类比较是否合法
*
* @param value 参数
* @param enumClass 枚举类必须实现BaseEnum接口
* @return boolean
* @Author 胡克
*/
public static boolean checkEnum(Object value, Class<? extends BaseEnum> enumClass) {
if (null == value) {
return false;
}
return Stream.of(enumClass.getEnumConstants()).anyMatch(e -> e.equalsValue(value));
}
/**
* 创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。
*
* @param enumClass
* @param exclude
* @param <T>
* @return
*/
public static <T extends BaseEnum> List<Object> differenceValueList(Class<? extends BaseEnum> enumClass, T... exclude) {
HashSet<Object> valueSet = new HashSet<>();
if (exclude != null) {
valueSet.addAll(Stream.of(exclude).map(BaseEnum::getValue).collect(Collectors.toSet()));
}
return Stream.of(enumClass.getEnumConstants())
.filter(e -> !valueSet.contains(e.getValue()))
.map(BaseEnum::getValue)
.collect(Collectors.toList());
}
/**
* 获取枚举类的说明 value : info 的形式
*
* @param enumClass
* @return String
*/
public static String getEnumDesc(Class<? extends BaseEnum> enumClass) {
BaseEnum[] enums = enumClass.getEnumConstants();
// value : info 的形式
StringBuilder sb = new StringBuilder();
for (BaseEnum baseEnum : enums) {
sb.append(baseEnum.getValue()).append("").append(baseEnum.getDesc()).append("");
}
return sb.toString();
}
/**
* 获取与参数相匹配的枚举类实例的 说明
*
* @param value 参数
* @param enumClass 枚举类必须实现BaseEnum接口
* @return String 如无匹配枚举则返回null
*/
public static String getEnumDescByValue(Object value, Class<? extends BaseEnum> enumClass) {
if (null == value) {
return null;
}
return Stream.of(enumClass.getEnumConstants())
.filter(e -> e.equalsValue(value))
.findFirst()
.map(BaseEnum::getDesc)
.orElse(null);
}
public static <T> String getEnumDescByValueList(Collection<T> values, Class<? extends BaseEnum> enumClass) {
if (CollectionUtils.isEmpty(values)) {
return "";
}
return Stream.of(enumClass.getEnumConstants()).filter(e -> values.contains(e.getValue())).map(BaseEnum::getDesc).collect(Collectors.joining(","));
}
/**
* 根据参数获取枚举类的实例
*
* @param value 参数
* @param enumClass 枚举类必须实现BaseEnum接口
* @return BaseEnum 无匹配值返回null
* @Author 胡克
*/
public static <T extends BaseEnum> T getEnumByValue(Object value, Class<T> enumClass) {
if (null == value) {
return null;
}
return Stream.of(enumClass.getEnumConstants())
.filter(e -> e.equalsValue(value))
.findFirst()
.orElse(null);
}
/**
* 根据实例描述与获取枚举类的实例
*
* @param desc 参数描述
* @param enumClass 枚举类必须实现BaseEnum接口
* @return BaseEnum 无匹配值返回null
* @Author 胡克
*/
public static <T extends BaseEnum> T getEnumByDesc(String desc, Class<T> enumClass) {
return Stream.of(enumClass.getEnumConstants())
.filter(e -> Objects.equals(e.getDesc(), desc))
.findFirst()
.orElse(null);
}
public static <T extends BaseEnum> T getEnumByName(String name, Class<T> enumClass) {
return Stream.of(enumClass.getEnumConstants())
.filter(e -> StringUtils.equalsIgnoreCase(e.toString(), name))
.findFirst()
.orElse(null);
}
/**
* 根据lambda getter/setter 注入
*
* @param list
* @param getter
* @param setter
* @param enumClass
* @param <T>
*/
public static <T> void inject(List<T> list, Function<T, Integer> getter, BiConsumer<T, String> setter, Class<? extends BaseEnum> enumClass) {
if (list == null || list.isEmpty()) {
return;
}
for (T t : list) {
Integer enumValue = getter.apply(t);
if (enumValue != null) {
setter.accept(t, getEnumDescByValue(enumValue, enumClass));
}
}
}
}
@@ -0,0 +1,122 @@
package net.lab1024.sa.common.common.util;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import net.lab1024.sa.common.common.domain.PageParam;
import net.lab1024.sa.common.common.domain.PageResult;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;
import java.util.stream.Collectors;
/**
* 分页工具类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-04-23 20:51:40
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartPageUtil {
/**
* 转换为查询参数
*
* @param baseDTO
* @return
*/
public static Page<?> convert2PageQuery(PageParam baseDTO) {
Page<?> page = new Page<>(baseDTO.getPageNum(), baseDTO.getPageSize());
// 设置排序字段
List<PageParam.SortItem> sortItemList = baseDTO.getSortItemList();
if (CollectionUtils.isNotEmpty(sortItemList)) {
List<OrderItem> orderItemList = sortItemList.stream().map(e -> new OrderItem(e.getColumn(), e.getIsAsc())).collect(Collectors.toList());
page.setOrders(orderItemList);
}
return page;
}
/**
* 转换为 PageResultDTO 对象
*
* @param page
* @param sourceList 原list
* @param targetClazz 目标类
* @return
*/
public static <T, E> PageResult<T> convert2PageResult(Page<?> page, List<E> sourceList, Class<T> targetClazz) {
return convert2PageResult(page, SmartBeanUtil.copyList(sourceList, targetClazz));
}
/**
* 转换为 PageResultDTO 对象
*
* @param page
* @param sourceList list
* @return
*/
public static <E> PageResult<E> convert2PageResult(Page<?> page, List<E> sourceList) {
PageResult<E> pageResult = new PageResult<>();
pageResult.setPageNum(page.getCurrent());
pageResult.setPageSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setList(sourceList);
pageResult.setEmptyFlag(CollectionUtils.isEmpty(sourceList));
return pageResult;
}
public static <E> PageResult<E> emptyResult(Page<?> page) {
PageResult<E> pageResult = new PageResult<>();
pageResult.setPageNum(page.getCurrent());
pageResult.setPageSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setList(null);
pageResult.setEmptyFlag(true);
return pageResult;
}
/**
* 转换分页结果对象
*
* @param pageResult
* @param targetClazz
* @return
*/
public static <E, T> PageResult<T> convert2PageResult(PageResult<E> pageResult, Class<T> targetClazz) {
PageResult<T> newPageResult = new PageResult<>();
newPageResult.setPageNum(pageResult.getPageNum());
newPageResult.setPageSize(pageResult.getPageSize());
newPageResult.setTotal(pageResult.getTotal());
newPageResult.setPages(pageResult.getPages());
newPageResult.setEmptyFlag(pageResult.getEmptyFlag());
newPageResult.setList(SmartBeanUtil.copyList(pageResult.getList(), targetClazz));
return newPageResult;
}
public static <T> PageResult subListPage(Integer pageNum, Integer pageSize, List<T> list) {
PageResult<T> pageRet = new PageResult<T>();
//总条数
int count = list.size();
int pages = count % pageSize == 0 ? count / pageSize : (count / pageSize + 1);
int fromIndex = (pageNum - 1) * pageSize;
int toIndex = pageNum * pageSize > count ? count : pageNum * pageSize;
if (pageNum > pages) {
pageRet.setList(Lists.newLinkedList());
pageRet.setPageNum(pageNum.longValue());
pageRet.setPages(Long.valueOf(pages));
pageRet.setTotal(Long.valueOf(count));
return pageRet;
}
List<T> pageList = list.subList(fromIndex, toIndex);
pageRet.setList(pageList);
pageRet.setPageNum(pageNum.longValue());
pageRet.setPages(Long.valueOf(pages));
pageRet.setTotal(Long.valueOf(count));
return pageRet;
}
}
@@ -0,0 +1,38 @@
package net.lab1024.sa.common.common.util;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.domain.RequestUser;
/**
* 请求用户 工具类
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
public class SmartRequestUtil {
private static final ThreadLocal<RequestUser> requestThreadLocal = new ThreadLocal<>();
public static void setRequestUser(RequestUser requestUser) {
requestThreadLocal.set(requestUser);
}
public static RequestUser getRequestUser() {
return requestThreadLocal.get();
}
public static Long getRequestUserId() {
RequestUser requestUser = getRequestUser();
return null == requestUser ? null : requestUser.getUserId();
}
public static void remove() {
requestThreadLocal.remove();
}
}
@@ -0,0 +1,334 @@
package net.lab1024.sa.common.common.util;
import cn.hutool.core.util.StrUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 独有的字符串工具类
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartStringUtil extends StrUtil {
// ===============split =======================
public static Set<String> splitConvertToSet(String str, String split) {
if (isEmpty(str)) {
return new HashSet<String>();
}
String[] splitArr = str.split(split);
HashSet<String> set = new HashSet<String>(splitArr.length);
for (String string : splitArr) {
set.add(string);
}
return set;
}
public static List<String> splitConvertToList(String str, String split) {
if (isEmpty(str)) {
return new ArrayList<String>();
}
String[] splitArr = str.split(split);
ArrayList<String> list = new ArrayList<String>(splitArr.length);
for (String string : splitArr) {
list.add(string);
}
return list;
}
// ===============split Integer=======================
public static List<Integer> splitConvertToIntList(String str, String split, int defaultVal) {
if (isEmpty(str)) {
return new ArrayList<Integer>();
}
String[] strArr = str.split(split);
List<Integer> list = new ArrayList<Integer>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
int parseInt = Integer.parseInt(strArr[i]);
list.add(parseInt);
} catch (NumberFormatException e) {
list.add(defaultVal);
continue;
}
}
return list;
}
public static Set<Integer> splitConvertToIntSet(String str, String split, int defaultVal) {
if (isEmpty(str)) {
return new HashSet<Integer>();
}
String[] strArr = str.split(split);
HashSet<Integer> set = new HashSet<Integer>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
int parseInt = Integer.parseInt(strArr[i]);
set.add(parseInt);
} catch (NumberFormatException e) {
set.add(defaultVal);
continue;
}
}
return set;
}
public static Set<Integer> splitConvertToIntSet(String str, String split) {
return splitConvertToIntSet(str, split, 0);
}
public static List<Integer> splitConvertToIntList(String str, String split) {
return splitConvertToIntList(str, split, 0);
}
public static int[] splitConvertToIntArray(String str, String split, int defaultVal) {
if (isEmpty(str)) {
return new int[0];
}
String[] strArr = str.split(split);
int[] result = new int[strArr.length];
for (int i = 0; i < strArr.length; i++) {
try {
result[i] = Integer.parseInt(strArr[i]);
} catch (NumberFormatException e) {
result[i] = defaultVal;
continue;
}
}
return result;
}
public static int[] splitConvertToIntArray(String str, String split) {
return splitConvertToIntArray(str, split, 0);
}
// ===============split 2 Long=======================
public static List<Long> splitConvertToLongList(String str, String split, long defaultVal) {
if (isEmpty(str)) {
return new ArrayList<Long>();
}
String[] strArr = str.split(split);
List<Long> list = new ArrayList<Long>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
long parseLong = Long.parseLong(strArr[i]);
list.add(parseLong);
} catch (NumberFormatException e) {
list.add(defaultVal);
continue;
}
}
return list;
}
public static List<Long> splitConvertToLongList(String str, String split) {
return splitConvertToLongList(str, split, 0L);
}
public static long[] splitConvertToLongArray(String str, String split, long defaultVal) {
if (isEmpty(str)) {
return new long[0];
}
String[] strArr = str.split(split);
long[] result = new long[strArr.length];
for (int i = 0; i < strArr.length; i++) {
try {
result[i] = Long.parseLong(strArr[i]);
} catch (NumberFormatException e) {
result[i] = defaultVal;
continue;
}
}
return result;
}
public static long[] splitConvertToLongArray(String str, String split) {
return splitConvertToLongArray(str, split, 0L);
}
// ===============split convert byte=======================
public static List<Byte> splitConvertToByteList(String str, String split, byte defaultVal) {
if (isEmpty(str)) {
return new ArrayList<Byte>();
}
String[] strArr = str.split(split);
List<Byte> list = new ArrayList<Byte>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
byte parseByte = Byte.parseByte(strArr[i]);
list.add(parseByte);
} catch (NumberFormatException e) {
list.add(defaultVal);
continue;
}
}
return list;
}
public static List<Byte> splitConvertToByteList(String str, String split) {
return splitConvertToByteList(str, split, (byte) 0);
}
public static byte[] splitConvertToByteArray(String str, String split, byte defaultVal) {
if (isEmpty(str)) {
return new byte[0];
}
String[] strArr = str.split(split);
byte[] result = new byte[strArr.length];
for (int i = 0; i < strArr.length; i++) {
try {
result[i] = Byte.parseByte(strArr[i]);
} catch (NumberFormatException e) {
result[i] = defaultVal;
continue;
}
}
return result;
}
public static byte[] splitConvertToByteArray(String str, String split) {
return splitConvertToByteArray(str, split, (byte) 0);
}
// ===============split convert double=======================
public static List<Double> splitConvertToDoubleList(String str, String split, double defaultVal) {
if (isEmpty(str)) {
return new ArrayList<Double>();
}
String[] strArr = str.split(split);
List<Double> list = new ArrayList<Double>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
double parseByte = Double.parseDouble(strArr[i]);
list.add(parseByte);
} catch (NumberFormatException e) {
list.add(defaultVal);
continue;
}
}
return list;
}
public static List<Double> splitConvertToDoubleList(String str, String split) {
return splitConvertToDoubleList(str, split, 0);
}
public static double[] splitConvertToDoubleArray(String str, String split, double defaultVal) {
if (isEmpty(str)) {
return new double[0];
}
String[] strArr = str.split(split);
double[] result = new double[strArr.length];
for (int i = 0; i < strArr.length; i++) {
try {
result[i] = Double.parseDouble(strArr[i]);
} catch (NumberFormatException e) {
result[i] = defaultVal;
continue;
}
}
return result;
}
public static double[] splitConvertToDoubleArray(String str, String split) {
return splitConvertToDoubleArray(str, split, 0);
}
// ===============split convert float=======================
public static List<Float> splitConvertToFloatList(String str, String split, float defaultVal) {
if (isEmpty(str)) {
return new ArrayList<Float>();
}
String[] strArr = str.split(split);
List<Float> list = new ArrayList<Float>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
try {
float parseByte = Float.parseFloat(strArr[i]);
list.add(parseByte);
} catch (NumberFormatException e) {
list.add(defaultVal);
continue;
}
}
return list;
}
public static List<Float> splitConvertToFloatList(String str, String split) {
return splitConvertToFloatList(str, split, 0f);
}
public static float[] splitConvertToFloatArray(String str, String split, float defaultVal) {
if (isEmpty(str)) {
return new float[0];
}
String[] strArr = str.split(split);
float[] result = new float[strArr.length];
for (int i = 0; i < strArr.length; i++) {
try {
result[i] = Float.parseFloat(strArr[i]);
} catch (NumberFormatException e) {
result[i] = defaultVal;
continue;
}
}
return result;
}
public static float[] splitConvertToFloatArray(String str, String split) {
return splitConvertToFloatArray(str, split, 0f);
}
public static String upperCaseFirstChar(String str) {
if (str != null && !str.isEmpty()) {
char firstChar = str.charAt(0);
if (Character.isUpperCase(firstChar)) {
return str;
} else {
char[] values = str.toCharArray();
values[0] = Character.toUpperCase(firstChar);
return new String(values);
}
} else {
return str;
}
}
public static String replace(String content, int begin, int end, String newStr) {
if (begin < content.length() && begin >= 0) {
if (end <= content.length() && end >= 0) {
if (begin > end) {
return content;
} else {
StringBuilder starStr = new StringBuilder();
for (int i = begin; i < end; ++i) {
starStr.append(newStr);
}
return content.substring(0, begin) + starStr + content.substring(end);
}
} else {
return content;
}
} else {
return content;
}
}
}
@@ -0,0 +1,98 @@
package net.lab1024.sa.common.common.util;
import java.util.regex.Pattern;
/**
* 验证工具类
*
* @Author 1024创新实验室: 胡克
* @Date 2017/11/06 10:54
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SmartVerificationUtil {
/**
* 手机号码验证规则
*/
public static final String PHONE_REGEXP = "^1[0-9]{10}";
/**
* 固定号码验证规则
*/
public static final String FIXED_PHONE_REGEXP = "^0\\d{2,3}-[1-9]\\d{6,7}$";
/**
* 密码正则校验
*/
public static final String PWD_REGEXP = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{6,32}$";
/**
* 车牌号
*/
public static final String CAR_NUMBER =
"([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]{1}(([A-HJ-Z]{1}[A-HJ-NP-Z0-9]{5})|([A-HJ-Z]{1}(([DF]{1}[A-HJ-NP-Z0-9]{1}[0-9]{4})|([0-9]{5}[DF]{1})))|" + "([A-HJ-Z" + "]{1}[A-D0-9]{1}[0-9]{3}警)))|" +
"([0-9]{6}使)|((([沪粤川云桂鄂陕蒙藏黑辽渝]{1}A)|鲁B|闽D|蒙E|蒙H)[0-9]{4}领)|(WJ[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼·•]{1}[0-9]{4}[TDSHBXJ0-9]{1})|" + "([VKHBSLJNGCE]{1}[A-DJ-PR" + "-TVY]{1}[0-9]{5})";
/**
* 日期年月日校验 yyyy-MM-dd HH:mm:ss
*/
public static final String DATE_TIME = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9" +
"]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
/**
* 日期校验 yyyy-MM-dd
*/
public static final String DATE = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))"
+ "|(02-(0[1-9]|[1][0-9]|2[0-8])))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)" + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9"
+ "][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|(" + "(([0-9]{2})(0[48]|[2468][048]|[13579][26])|(" + "(0[48" + "]|[2468][048]|[3579][26])00))-02-29)";
public static final String DATE_TIME_HM = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9])$";
/**
* 年月校验 例: 2019-10
*/
public static final String YEAR_MONTH = "^\\d{4}-((0([1-9]))|(1(0|1|2)))$";
/**
* 时间区间验证 10:23-19:00
*/
public static final String TIME_SECTION = "^(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])-(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])$";
/**
* 时间验证 10:23
*/
public static final String TIME = "^(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])$";
/**
* 身份证号
*/
public static final String ID_CARD = "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)";
/**
* URL
*/
public static final String URL = "[a-zA-z]+://[^\\s]*";
/**
* 邮箱
*/
public static final String EMAIL = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?";
/**
* 整数
*/
public static final String INTEGER = "^-?[1-9]\\d*$";
/**
* 小数
*/
public static final String DOUBLE = "^-?[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
public static void main(String[] args) {
boolean matches = Pattern.matches(INTEGER, "1");
System.out.println(matches);
}
}
@@ -0,0 +1,52 @@
package net.lab1024.sa.common.common.validator.enumeration;
import net.lab1024.sa.common.common.enumeration.BaseEnum;
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;
/**
* 自定义的属性校验注解,为了方便与校验属性的值是否为合法的枚举值
*
* @Author 1024创新实验室: 胡克
* @Date 2017/11/11 15:31
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.class)// 自定义验证的处理类
public @interface CheckEnum {
/**
* 默认的错误提示信息
*
* @return String
*/
String message();
/**
* 枚举类对象 必须实现BaseEnum接口
*
* @return
*/
Class<? extends BaseEnum> value();
/**
* 是否必须
*
* @return boolean
*/
boolean required() default false;
//下面这两个属性必须添加 :不然会报错
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,75 @@
package net.lab1024.sa.common.common.validator.enumeration;
import net.lab1024.sa.common.common.enumeration.BaseEnum;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 枚举类校验器
*
* @Author 1024创新实验室: 胡克
* @Date 2017/11/11 15:34
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class EnumValidator implements ConstraintValidator<CheckEnum, Object> {
/**
* 枚举类实例集合
*/
private List<Object> enumValList;
/**
* 是否必须
*/
private boolean required;
@Override
public void initialize(CheckEnum constraintAnnotation) {
// 获取注解传入的枚举类对象
required = constraintAnnotation.required();
Class<? extends BaseEnum> enumClass = constraintAnnotation.value();
enumValList = Stream.of(enumClass.getEnumConstants()).map(BaseEnum::getValue).collect(Collectors.toList());
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
// 判断是否必须
if (null == value) {
return !required;
}
if (value instanceof List) {
// 如果为 List 集合数据
return this.checkList((List<Object>) value);
}
// 校验是否为合法的枚举值
return enumValList.contains(value);
}
/**
* 校验集合类型
*
* @param list
* @return
*/
private boolean checkList(List<Object> list) {
if (required && list.isEmpty()) {
// 必须的情况下 list 不能为空
return false;
}
// 校验是否重复
long count = list.stream().distinct().count();
if (count != list.size()) {
return false;
}
return enumValList.containsAll(list);
}
}
@@ -0,0 +1,38 @@
/*
* @(#) PicType.java 2017年4月19日
*
* Copyright 2010 NetEase.com, Inc. All rights reserved.
*/
package net.lab1024.sa.common.common.wangyi.yidun.enums;
/**
*
* @author hzdingyong
* @version 2017年4月19日
*/
public enum PicType {
URL(1),
BASE64(2);
private int type;
private PicType(int type) {
this.type = type;
}
public static boolean isValidType(int type) {
if (type != 1 && type != 2) {
return false;
}
return true;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
@@ -0,0 +1,29 @@
/*
* @(#) SignatureMethodEnum.java 2021-06-11
*
* Copyright 2021 NetEase.com, Inc. All rights reserved.
*/
package net.lab1024.sa.common.common.wangyi.yidun.enums;
import org.apache.commons.lang3.StringUtils;
/**
* @author yidun
* @version 2021-06-11
*/
public enum SignatureMethodEnum {
MD5,
SHA1,
SHA256,
SM3;
public static boolean isValid(String signatureMethod) {
try {
SignatureMethodEnum signatureMethodEnum = SignatureMethodEnum.valueOf(StringUtils.upperCase(signatureMethod));
return signatureMethodEnum != null;
} catch (Exception e) {
return false;
}
}
}
@@ -0,0 +1,48 @@
package net.lab1024.sa.common.common.wangyi.yidun.resp;
/**
* Auto-generated: 2023-08-21 13:33:47
*
* @author json.cn (i@json.cn)
* @website http://www.json.cn/java2pojo/
*/
public class APIResponse {
private int code;
private String msg;
private APIResult result;
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public APIResult getResult() {
return result;
}
public void setResult(APIResult result) {
this.result = result;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("APIResponse [code=").append(code).append(", msg=").append(msg).append(", result=")
.append(result).append("]");
return builder.toString();
}
}
@@ -0,0 +1,50 @@
package net.lab1024.sa.common.common.wangyi.yidun.resp;
/**
* Auto-generated: 2023-08-21 13:33:47
*
* @author json.cn (i@json.cn)
* @website http://www.json.cn/java2pojo/
*/
public class APIResult {
private String taskId;
private int status;
private int reasonType;
private int isPayed;
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getTaskId() {
return taskId;
}
public void setStatus(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
public void setReasonType(int reasonType) {
this.reasonType = reasonType;
}
public int getReasonType() {
return reasonType;
}
public void setIsPayed(int isPayed) {
this.isPayed = isPayed;
}
public int getIsPayed() {
return isPayed;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("APIResult [taskId=").append(taskId).append(", status=").append(status).append(", reasonType=")
.append(reasonType).append(", isPayed=").append(isPayed).append("]");
return builder.toString();
}
}
@@ -0,0 +1,97 @@
/*
* @(#) ImageCheckAPIDemo.java 2016年3月15日
*
* Copyright 2010 NetEase.com, Inc. All rights reserved.
*/
package net.lab1024.sa.common.common.wangyi.yidun.sdk;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import net.lab1024.sa.common.common.wangyi.yidun.resp.APIResponse;
import net.lab1024.sa.common.common.wangyi.yidun.resp.APIResult;
import net.lab1024.sa.common.common.wangyi.yidun.utils.ConstantUtil;
import net.lab1024.sa.common.common.wangyi.yidun.utils.SignatureUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 银行卡认证 接口调用示例,该示例依赖以下jar包:
* 1. httpclient,用于发送http请求,详细见HttpClient4Utils.java
* 2. commons-codec,使用md5算法生成签名信息,详细见SignatureUtils.java
* 3. gson,用于做json解析
*
* @author yidun
*/
public class BankCardCheckAPI {
//public static void main(String[] args) {
// boolean check = check("刘小平", "36078219840215301X", "6214855100007273");
// System.out.println("check = " + check);
//}
private final static Logger log = LoggerFactory.getLogger(BankCardCheckAPI.class);
/**
* 业务ID,易盾根据产品业务特点分配
*/
private final static String BUSINESS_ID = "3cb726bd85104161b25613153c4fba7c";
/**
* 接口地址
*/
private final static String API_URL = "https://verify.dun.163.com/v1/bankcard/check";
/**
* 银行卡认证
* @param name
* @param idCardNo
* @param bankCardNo
* @return
* @throws Exception
*/
public static boolean check(String name, String idCardNo, String bankCardNo) {
Map<String, Object> params = new HashMap<>(10);
// 1.设置公共参数
params.put("secretId", ConstantUtil.SECRET_ID);
params.put("businessId", BUSINESS_ID);
params.put("version", "v1");
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
params.put("nonce", String.valueOf(new Random().nextInt()));
// params.put("signatureMethod", "SM3"); // 可选参数,可选值为MD5、SHA1、SHA256、SM3。如果不传该字段,默认采用MD5算法生成签名。
// 2.设置私有参数
params.put("name", name);
params.put("idCardNo", idCardNo.toUpperCase());
params.put("bankCardNo", bankCardNo);
// 3.生成签名信息
String signature = null;
try {
signature = SignatureUtils.genSignature(ConstantUtil.SECRET_KEY, params);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
params.put("signature", signature);
// 4.发送HTTP请求,这里使用的是HttpClient工具包,产品可自行选择自己熟悉的工具包发送请求
String response = HttpUtil.post(API_URL, params);
//5.解析报文返回
APIResponse jObject = JSON.parseObject(response, APIResponse.class);
log.info("银行卡 认证结果:{}", jObject.toString());
int code = jObject.getCode();
boolean result = false;
if (code == 200) {
APIResult resultObject = jObject.getResult();
int status = resultObject.getStatus();
if (status == 1) {
result = true;
}
}
return result;
}
}
@@ -0,0 +1,88 @@
/*
* @(#) ImageCheckAPIDemo.java 2016年3月15日
*
* Copyright 2010 NetEase.com, Inc. All rights reserved.
*/
package net.lab1024.sa.common.common.wangyi.yidun.sdk;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import net.lab1024.sa.common.common.wangyi.yidun.resp.APIResponse;
import net.lab1024.sa.common.common.wangyi.yidun.resp.APIResult;
import net.lab1024.sa.common.common.wangyi.yidun.utils.ConstantUtil;
import net.lab1024.sa.common.common.wangyi.yidun.utils.SignatureUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 实证认证-实名校验 接口调用示例,该示例依赖以下jar包: 1.
* httpclient,用于发送http请求,详细见HttpClient4Utils.java 2.
* commons-codec,使用md5算法生成签名信息,详细见SignatureUtils.java 3. gson,用于做json解析
*
* @author yidun
*/
public class IdCardCheckAPI {
private final static Logger log = LoggerFactory.getLogger(IdCardCheckAPI.class);
/**
* 业务ID,易盾根据产品业务特点分配
*/
private final static String BUSINESS_ID = "45a8fd254b4649e9bd25d773ac7ab666";
/**
* 易盾身份认证服务身份证实名认证在线检测接口地址
*/
private final static String API_URL = "https://verify.dun.163.com/v1/idcard/check";
/**
* 身份证 认证
*
* @param name
* @param cardNo
* @return
* @throws Exception
*/
public static boolean check(String name, String cardNo) throws Exception {
Map<String, Object> params = new HashMap<>(8);
// 1.设置公共参数
params.put("secretId", ConstantUtil.SECRET_ID);
params.put("businessId", BUSINESS_ID);
params.put("version", "v1");
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
params.put("nonce", String.valueOf(new Random().nextInt()));
// params.put("signatureMethod", "SM3"); //
// 可选参数,可选值为MD5、SHA1、SHA256、SM3。如果不传该字段,默认采用MD5算法生成签名。
// 2.设置私有参数
params.put("name", name);
params.put("cardNo", cardNo);
// 3.生成签名信息
String signature = SignatureUtils.genSignature(ConstantUtil.SECRET_KEY, params);
params.put("signature", signature);
// 4.发送HTTP请求,这里使用的是HttpClient工具包,产品可自行选择自己熟悉的工具包发送请求
String response = HttpUtil.post(API_URL, params);
// 5.解析接口返回值
// JsonObject jObject = new
// JsonParser().parse(response).getAsJsonObject();
APIResponse jObject = JSON.parseObject(response, APIResponse.class);
log.info("身份证 认证结果:", jObject.toString());
int code = jObject.getCode();
boolean result = false;
if (code == 200) {
APIResult resultObject = jObject.getResult();
int status = resultObject.getStatus();
if (status == 1) {
result = true;
}
}
return result;
}
}
@@ -0,0 +1,20 @@
package net.lab1024.sa.common.common.wangyi.yidun.utils;
/**
* 网易易盾 常量
* @author haomingming
*
*/
public class ConstantUtil {
/**
* 产品密钥ID,产品标识
*/
public final static String SECRET_ID = "0bcf9a5633eb9ca9d196583e67c3762b";
/**
* 产品私有密钥,服务端生成签名信息使用,请严格保管,避免泄露
*/
public final static String SECRET_KEY = "b31e8220d115b6531a22ee71d1e89936";
}
@@ -0,0 +1,71 @@
/*
* @(#) SignatureUtils.java 2016年2月2日
*
* Copyright 2010 NetEase.com, Inc. All rights reserved.
*/
package net.lab1024.sa.common.common.wangyi.yidun.utils;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Map;
import net.lab1024.sa.common.common.wangyi.yidun.enums.SignatureMethodEnum;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
/**
* 生成及验证签名信息工具类
* @author hzgaomin
* @version 2016年2月2日
*/
public class SignatureUtils {
/**
* 生成签名信息
* @param secretKey 产品私钥
* @param params 接口请求参数名和参数值map,不包括signature参数名
* @return
* @throws UnsupportedEncodingException
*/
public static String genSignature(String secretKey, Map<String, Object> params) throws UnsupportedEncodingException {
return genSignature(secretKey, params, (String) params.get("signatureMethod"));
}
/**
* 生成签名信息
* @param secretKey 产品私钥
* @param params 接口请求参数名和参数值map,不包括signature参数名
* @param signatureMethod 加密方法
* @return
* @throws UnsupportedEncodingException
*/
public static String genSignature(String secretKey, Map<String, Object> params, String signatureMethod) throws UnsupportedEncodingException {
// 1. 参数名按照ASCII码表升序排序
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
// 2. 按照排序拼接参数名与参数值
StringBuffer paramBuffer = new StringBuffer();
for (String key : keys) {
paramBuffer.append(key).append(params.get(key) == null ? "" : params.get(key));
}
// 3. 将secretKey拼接到最后
paramBuffer.append(secretKey);
if (StringUtils.isEmpty(signatureMethod)) {
// 4. MD5是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32个十六进制字符。
return DigestUtils.md5Hex(paramBuffer.toString().getBytes("UTF-8"));
} else {
switch (SignatureMethodEnum.valueOf(StringUtils.upperCase(signatureMethod))) {
case MD5:
return DigestUtils.md5Hex(paramBuffer.toString().getBytes("UTF-8"));
case SHA256:
return DigestUtils.sha256Hex(paramBuffer.toString().getBytes("UTF-8"));
default:
return "";
}
}
}
}
@@ -0,0 +1,71 @@
package net.lab1024.sa.common.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 异步调用线程配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@Configuration
public class AsyncConfig {
/**
* 线程池 配置bean名称
*/
public static final String ASYNC_EXECUTOR_THREAD_NAME = "smart-admin-async-executor";
/**
* 配置线程池
*
* @return
*/
@Bean(name = ASYNC_EXECUTOR_THREAD_NAME)
public AsyncTaskExecutor executor() {
int processors = Runtime.getRuntime().availableProcessors();
int threadCount = Math.max(1, processors - 1);
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 核心线程数量
taskExecutor.setCorePoolSize(threadCount);
// 最大线程数量
taskExecutor.setMaxPoolSize(threadCount);
taskExecutor.setThreadNamePrefix(ASYNC_EXECUTOR_THREAD_NAME);
taskExecutor.initialize();
return taskExecutor;
}
/**
* spring 异步任务 异常配置
*/
@Configuration
public static class AsyncExceptionConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}
/**
* 自定义异常处理
*/
public static class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.error("异步任务发生异常:{}, 参数:{}, ", method.getDeclaringClass().getSimpleName() + "." + method.getName(), Arrays.toString(objects), throwable);
}
}
}
@@ -0,0 +1,45 @@
package net.lab1024.sa.common.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 跨域配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2021/11/15 20:38
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class CorsFilterConfig {
@Value("${access-control-allow-origin}")
private String accessControlAllowOrigin;
/**
* 跨域配置
*
* @return
*/
@Bean
public CorsFilter corsFilter () {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// 设置访问源地址
config.addAllowedOriginPattern(accessControlAllowOrigin);
// 设置访问源请求头
config.addAllowedHeader("*");
// 设置访问源请求方法
config.addAllowedMethod("*");
// 对接口配置跨域设置
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
@@ -0,0 +1,197 @@
package net.lab1024.sa.common.config;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.domain.DataScopePlugin;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 数据源配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2017-11-28 15:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.driver-class-name}")
String driver;
@Value("${spring.datasource.url}")
String url;
@Value("${spring.datasource.username}")
String username;
@Value("${spring.datasource.password}")
String password;
@Value("${spring.datasource.initial-size}")
int initialSize;
@Value("${spring.datasource.min-idle}")
int minIdle;
@Value("${spring.datasource.max-active}")
int maxActive;
@Value("${spring.datasource.max-wait}")
long maxWait;
@Value("${spring.datasource.time-between-eviction-runs-millis}")
long timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.min-evictable-idle-time-millis}")
long minEvictableIdleTimeMillis;
@Value("${spring.datasource.filters}")
String filters;
@Value("${spring.datasource.druid.username}")
String druidUserName;
@Value("${spring.datasource.druid.password}")
String druidPassword;
@Value("${spring.datasource.druid.login.enabled}")
boolean druidLoginEnable;
@Value("${spring.datasource.druid.method.pointcut}")
String methodPointcut;
@Autowired
private MybatisPlusInterceptor paginationInterceptor;
@Autowired(required = false)
private DataScopePlugin dataScopePlugin;
@Bean
@Primary
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDbType(DbType.MYSQL.getDb());
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
druidDataSource.setValidationQuery("SELECT 1");
try {
druidDataSource.setFilters(filters);
ArrayList<Filter> arrayList = new ArrayList<>();
StatFilter statFilter = new StatFilter();
statFilter.setMergeSql(true);
statFilter.setSlowSqlMillis(500);
statFilter.setLogSlowSql(true);
arrayList.add(statFilter);
druidDataSource.setProxyFilters(arrayList);
druidDataSource.init();
} catch (SQLException e) {
log.error("初始化数据源出错", e);
}
return druidDataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
factoryBean.setDataSource(druidDataSource());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:/mapper/**/*.xml");
factoryBean.setMapperLocations(resources);
// 设置 MyBatis-Plus 分页插件 注意此处myBatisPlugin一定要放在后面
List<Interceptor> pluginsList = new ArrayList<>();
pluginsList.add(paginationInterceptor);
if (dataScopePlugin != null) {
pluginsList.add(dataScopePlugin);
}
factoryBean.setPlugins(pluginsList.toArray(new Interceptor[pluginsList.size()]));
return factoryBean.getObject();
}
/**
* 非正式环境 才加载
*
* @return
*/
@Conditional(SystemEnvironmentConfig.class)
@Bean
public ServletRegistrationBean<StatViewServlet> druidServlet() {
ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
Map<String, String> initParameters = new HashMap<String, String>();
//不设置用户名密码可以直接通过druid/index.html访问
if (druidLoginEnable) {
initParameters.put("loginUsername", druidUserName);
initParameters.put("loginPassword", druidPassword);
}
initParameters.put("resetEnable", "false");
servletRegistrationBean.setInitParameters(initParameters);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() {
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<WebStatFilter>();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/*");
return filterRegistrationBean;
}
@Bean
public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() {
JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
jdkRegexpMethodPointcut.setPatterns(methodPointcut);
return jdkRegexpMethodPointcut;
}
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor();
pointcutAdvisor.setPointcut(jdkRegexpMethodPointcut());
pointcutAdvisor.setAdvice(new DruidStatInterceptor());
return pointcutAdvisor;
}
}
@@ -0,0 +1,88 @@
package net.lab1024.sa.common.config;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
/**
* java8 localDate 时间类格式化配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2017-11-28 15:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class DateConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
builder.deserializers(new LocalDateDeserializer(DatePattern.NORM_DATE_FORMAT.getDateTimeFormatter()));
builder.deserializers(new LocalDateTimeDeserializer(DatePattern.NORM_DATETIME_FORMAT.getDateTimeFormatter()));
builder.serializers(new LocalDateSerializer(DatePattern.NORM_DATE_FORMAT.getDateTimeFormatter()));
builder.serializers(new LocalDateTimeSerializer(DatePattern.NORM_DATETIME_FORMAT.getDateTimeFormatter()));
};
}
/**
* string 转为 LocalDateTime 配置类
*
* @author 卓大
*/
@Configuration
public static class StringToLocalDateTime implements Converter<String, LocalDateTime> {
@Override
public LocalDateTime convert(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
LocalDateTime localDateTime;
try {
localDateTime = LocalDateTimeUtil.parse(str, DatePattern.NORM_DATETIME_FORMAT.getDateTimeFormatter());
} catch (DateTimeParseException e) {
throw new RuntimeException("请输入正确的日期格式:yyyy-MM-dd HH:mm:ss");
}
return localDateTime;
}
}
/**
* string 转为 LocalDate 配置类
*
* @author 卓大
*/
@Configuration
public static class StringToLocalDate implements Converter<String, LocalDate> {
@Override
public LocalDate convert(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
LocalDate localDate;
try {
localDate = LocalDateTimeUtil.parseDate(str, DatePattern.NORM_DATE_FORMAT.getDateTimeFormatter());
} catch (DateTimeParseException e) {
throw new RuntimeException("请输入正确的日期格式:yyyy-MM-dd");
}
return localDate;
}
}
}
@@ -0,0 +1,85 @@
package net.lab1024.sa.common.config;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import lombok.Data;
import net.lab1024.sa.common.module.support.file.service.FileStorageCloudServiceImpl;
import net.lab1024.sa.common.module.support.file.service.FileStorageLocalServiceImpl;
import net.lab1024.sa.common.module.support.file.service.IFileStorageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 文件上传 配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2019-09-02 23:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
@Configuration
public class FileCloudConfig {
@Value("${file.storage.cloud.region}")
private String region;
@Value("${file.storage.cloud.endpoint}")
private String endpoint;
@Value("${file.storage.cloud.bucket-name}")
private String bucketName;
@Value("${file.storage.cloud.access-key}")
private String accessKey;
@Value("${file.storage.cloud.secret-key}")
private String secretKey;
@Value("${file.storage.cloud.url.expire}")
private Long urlExpire;
@Value("${file.storage.cloud.url.public}")
private String publicUrl;
/**
* 初始化 云oss client 配置
*
* @return
*/
@Bean
@ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = "cloud")
public AmazonS3 initAmazonS3() {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setProtocol(Protocol.HTTPS);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
.withClientConfiguration(clientConfig)
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region))
.withPathStyleAccessEnabled(false)
.build();
return s3Client;
}
@Bean
@ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = "cloud")
public IFileStorageService initCloudFileService() {
return new FileStorageCloudServiceImpl();
}
@Bean
@ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = "local")
public IFileStorageService initLocalFileService() {
return new FileStorageLocalServiceImpl();
}
}
@@ -0,0 +1,37 @@
package net.lab1024.sa.common.config;
import net.lab1024.sa.common.module.support.heartbeat.core.HeartBeatManager;
import net.lab1024.sa.common.module.support.heartbeat.core.IHeartBeatRecordHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 心跳配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2018/10/9 18:47
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class HeartBeatConfig {
/**
* 间隔时间
*/
@Value("${heart-beat.interval-seconds}")
private Long intervalSeconds;
@Autowired
private IHeartBeatRecordHandler heartBeatRecordHandler;
@Bean
public HeartBeatManager heartBeatManager() {
return new HeartBeatManager(intervalSeconds * 1000L, heartBeatRecordHandler);
}
}
@@ -0,0 +1,50 @@
package net.lab1024.sa.common.config;
import net.lab1024.sa.common.common.interceptor.AbstractInterceptor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* web相关配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Autowired(required = false)
private List<HandlerInterceptor> interceptorList;
@Override
public void addInterceptors (InterceptorRegistry registry) {
if (CollectionUtils.isEmpty(interceptorList)) {
return;
}
interceptorList.forEach(e->{
registry.addInterceptor(e).addPathPatterns("/**");
});
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/preview/**");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/druidMonitor").setViewName("redirect:druid/index.html");
registry.addViewController("/swaggerApi").setViewName("redirect:swagger-ui.html");
}
}
@@ -0,0 +1,33 @@
package net.lab1024.sa.common.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* mp 插件
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
@@ -0,0 +1,56 @@
package net.lab1024.sa.common.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.IOException;
import java.util.List;
/**
* yaml 读取配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
@Slf4j
public class PostProcessorConfig implements EnvironmentPostProcessor {
private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
MutablePropertySources propertySources = environment.getPropertySources();
this.loadProperty(propertySources);
}
private void loadProperty(MutablePropertySources propertySources) {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] resources = resolver.getResources("classpath*:sa-*.yaml");
if (resources.length < 1) {
return;
}
for (Resource resource : resources) {
log.info("初始化系统配置:{}", resource.getFilename());
List<PropertySource<?>> load = loader.load(resource.getFilename(), resource);
load.forEach(propertySources::addLast);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,72 @@
package net.lab1024.sa.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
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.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* redis配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
//@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.setDefaultSerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
@@ -0,0 +1,38 @@
package net.lab1024.sa.common.config;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.module.support.reload.ReloadCommand;
import net.lab1024.sa.common.module.support.reload.core.SmartReloadManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* reload配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/9/1 21:40
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@Configuration
public class ReloadConfig {
/**
* 间隔时间
*/
@Value("${reload.interval-seconds}")
private Integer intervalSeconds;
@Autowired
private ReloadCommand reloadCommand;
@Bean
public SmartReloadManager initSmartReloadManager() {
// 创建 Reload Manager 调度器
return new SmartReloadManager(reloadCommand,intervalSeconds);
}
}
@@ -0,0 +1,40 @@
package net.lab1024.sa.common.config;
import net.lab1024.sa.common.common.constant.StringConst;
import net.lab1024.sa.common.common.util.SmartRequestUtil;
import net.lab1024.sa.common.module.support.repeatsubmit.RepeatSubmitAspect;
import net.lab1024.sa.common.module.support.repeatsubmit.ticket.RepeatSubmitCaffeineTicket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 重复提交配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2021/10/9 18:47
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class RepeatSubmitConfig {
@Bean
public RepeatSubmitAspect repeatSubmitAspect() {
RepeatSubmitCaffeineTicket caffeineTicket = new RepeatSubmitCaffeineTicket(this::ticket);
return new RepeatSubmitAspect(caffeineTicket);
}
/**
* 获取指明某个用户的凭证
*
* @return
*/
private String ticket(String servletPath) {
Long userId = SmartRequestUtil.getRequestUserId();
if (null == userId) {
return StringConst.EMPTY;
}
return servletPath + "_" + userId;
}
}
@@ -0,0 +1,130 @@
package net.lab1024.sa.common.config;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* http请求配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class RestTemplateConfig {
@Value("${http.pool.max-total}")
private Integer maxTotal;
@Value("${http.pool.connect-timeout}")
private Integer connectTimeout;
@Value("${http.pool.read-timeout}")
private Integer readTimeout;
@Value("${http.pool.write-timeout}")
private Integer writeTimeout;
@Value("${http.pool.keep-alive}")
private Integer keepAlive;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(this.clientHttpRequestFactory());
List<HttpMessageConverter<?>> messageConverterList = restTemplate.getMessageConverters();
messageConverterList.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
messageConverterList.addAll(this.converters());
return restTemplate;
}
public List<HttpMessageConverter<?>> converters() {
List<HttpMessageConverter<?>> converters = new ArrayList<>();
HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
fastMediaTypes.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
converters.add(converter);
converters.add(fastConverter);
return converters;
}
public OkHttp3ClientHttpRequestFactory clientHttpRequestFactory() {
return new OkHttp3ClientHttpRequestFactory(httpClientBuilder());
}
public OkHttpClient httpClientBuilder() {
return new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.connectionPool(this.pool())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.build();
}
public ConnectionPool pool() {
return new ConnectionPool(maxTotal, keepAlive, TimeUnit.MILLISECONDS);
}
@Bean
public X509TrustManager x509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
@Bean
public SSLSocketFactory sslSocketFactory() {
try {
//信任任何链接
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,47 @@
package net.lab1024.sa.common.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.Task;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 定时任务调度 配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
private ScheduledTaskRegistrar taskRegistrar;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
}
public String destroy() {
List<Task> taskList = new ArrayList<>();
taskList.addAll(taskRegistrar.getCronTaskList());
taskList.addAll(taskRegistrar.getTriggerTaskList());
taskList.addAll(taskRegistrar.getFixedDelayTaskList());
taskList.addAll(taskRegistrar.getFixedRateTaskList());
taskRegistrar.destroy();
List<String> taskNameList = taskList.stream().map(Task::toString).collect(Collectors.toList());
return "已关闭 @Scheduled定时任务:" + taskNameList.size() + "个!";
}
}
@@ -0,0 +1,206 @@
package net.lab1024.sa.common.config;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.constant.RequestHeaderConst;
import net.lab1024.sa.common.common.swagger.SwaggerApiModelPropertyEnumPlugin;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 根据SwaggerTagConst内部类动态生成Swagger group
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020-03-25 22:54:46
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@EnableSwagger2
@Configuration
@Conditional(SystemEnvironmentConfig.class)
public class SwaggerConfig implements EnvironmentAware, BeanDefinitionRegistryPostProcessor {
/**
* 文档标题
*/
private String title;
/**
* 文档描述
*/
private String description;
/**
* api版本
*/
private String version;
/**
* service url
*/
private String teamUrl;
/**
* host
*/
private String host;
private String tagClass;
@Bean
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public SwaggerApiModelPropertyEnumPlugin swaggerEnum() {
return new SwaggerApiModelPropertyEnumPlugin();
}
@Override
public void setEnvironment(Environment environment) {
this.title = environment.getProperty("swagger.title");
this.description = environment.getProperty("swagger.description");
this.version = environment.getProperty("swagger.version");
this.host = environment.getProperty("swagger.host");
this.tagClass = environment.getProperty("swagger.tag-class");
this.teamUrl = environment.getProperty("swagger.team-url");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
Map<String, List<String>> groupMap = this.buildGroup();
for (Map.Entry<String, List<String>> entry : groupMap.entrySet()) {
String group = entry.getKey();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Docket.class, () -> this.baseDocket(group, entry.getValue()));
BeanDefinition beanDefinition = builder.getRawBeanDefinition();
registry.registerBeanDefinition(group + "Api", beanDefinition);
}
}
@SneakyThrows
private Map<String, List<String>> buildGroup() {
Class<?> clazz = Class.forName(tagClass);
Class<?>[] innerClazz = clazz.getClasses();
Map<String, List<String>> groupMap = new HashMap<>(16);
for (Class<?> cls : innerClazz) {
String group = cls.getSimpleName();
List<String> apiTags = Lists.newArrayList();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
boolean isFinal = Modifier.isFinal(field.getModifiers());
if (isFinal) {
apiTags.add(field.get(null).toString());
}
}
groupMap.put(group, apiTags);
}
return groupMap;
}
private Docket baseDocket(String groupName, List<String> apiTagList) {
// 配置全局参数
List<Parameter> parameterList = this.generateParameter();
Docket docket = new Docket(DocumentationType.SWAGGER_2).groupName(groupName)
.forCodeGeneration(true)
.select()
// 过滤规则
.apis(this.getControllerPredicate(apiTagList))
// 与 过滤规则 controller 包路径 二选一
// .apis(RequestHandlerSelectors.basePackage(packAge))
.paths(PathSelectors.any())
.build().apiInfo(this.apiInfo())
.globalOperationParameters(parameterList);
if (StringUtils.isNotBlank(host)) {
docket = docket.host(host);
}
return docket;
}
private Predicate<RequestHandler> getControllerPredicate(List<String> apiTagList) {
Predicate<RequestHandler> methodPredicate = (input) -> {
Api api = null;
Optional<Api> apiOptional = input.findControllerAnnotation(Api.class);
if (apiOptional.isPresent()) {
api = apiOptional.get();
}
if (api == null) {
return false;
}
List<String> tags = Arrays.asList(api.tags());
if (apiTagList.containsAll(tags)) {
return true;
}
return false;
};
Predicate controllerPredicate = Predicates.or(RequestHandlerSelectors.withClassAnnotation(RestController.class), RequestHandlerSelectors.withClassAnnotation(Controller.class));
return Predicates.and(controllerPredicate, methodPredicate);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title(title)
.description(description)
.version(version)
.termsOfServiceUrl(teamUrl)
.contact(new Contact("", teamUrl, ""))
.build();
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
/**
* 生成共用请求参数
*
* @return
*/
private List<Parameter> generateParameter() {
// 配置全局参数 token
Parameter token = new ParameterBuilder().name(RequestHeaderConst.TOKEN)
.description("token")
.modelRef(new ModelRef("string"))
.parameterType("header").defaultValue("1")
.required(false)
.build();
return Lists.newArrayList(token);
}
}
@@ -0,0 +1,49 @@
package net.lab1024.sa.common.config;
import net.lab1024.sa.common.common.domain.SystemEnvironment;
import net.lab1024.sa.common.common.enumeration.SystemEnvironmentEnum;
import net.lab1024.sa.common.common.util.SmartEnumUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* 系统环境
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/08/13 18:56
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class SystemEnvironmentConfig implements Condition {
@Value("${spring.profiles.active}")
private String systemEnvironment;
@Value("${project.name}")
private String projectName;
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String property = conditionContext.getEnvironment().getProperty("spring.profiles.active");
return StringUtils.isNotBlank(property) && !SystemEnvironmentEnum.PROD.equalsValue(property);
}
@Bean
public SystemEnvironment initEnvironment() {
SystemEnvironmentEnum currentEnvironment = SmartEnumUtil.getEnumByValue(systemEnvironment, SystemEnvironmentEnum.class);
if (currentEnvironment == null) {
throw new ExceptionInInitializerError("无法获取当前环境!请在 application.yaml 配置参数:spring.profiles.active");
}
if (StringUtils.isBlank(projectName)) {
throw new ExceptionInInitializerError("无法获取当前项目名称!请在 application.yaml 配置参数:project.name");
}
return new SystemEnvironment(currentEnvironment == SystemEnvironmentEnum.PROD, projectName, currentEnvironment);
}
}
@@ -0,0 +1,150 @@
package net.lab1024.sa.common.config;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.annoation.NoNeedLogin;
import net.lab1024.sa.common.common.annoation.SaAuth;
import net.lab1024.sa.common.common.domain.RequestUrlVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* url配置
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
@Slf4j
public class UrlConfig {
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
/**
* 获取每个方法的请求路径
*
* @return
*/
@Bean
public Map<Method, Set<String>> methodUrlMap() {
Map<Method, Set<String>> methodUrlMap = Maps.newHashMap();
//获取url与类和方法的对应信息
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
RequestMappingInfo requestMappingInfo = entry.getKey();
Set<String> urls = requestMappingInfo.getPatternsCondition().getPatterns();
if (CollectionUtils.isEmpty(urls)) {
continue;
}
HandlerMethod handlerMethod = entry.getValue();
methodUrlMap.put(handlerMethod.getMethod(), urls);
}
return methodUrlMap;
}
/**
* 需要进行url权限校验的方法
*
* @param methodUrlMap
* @return
*/
@Bean
public List<RequestUrlVO> authUrl(Map<Method, Set<String>> methodUrlMap) {
List<RequestUrlVO> authUrlList = Lists.newArrayList();
for (Map.Entry<Method, Set<String>> entry : methodUrlMap.entrySet()) {
Method method = entry.getKey();
SaAuth saAuth = method.getAnnotation(SaAuth.class);
if (null == saAuth) {
continue;
}
List<RequestUrlVO> requestUrlList = this.buildRequestUrl(method, entry.getValue());
authUrlList.addAll(requestUrlList);
}
log.info("需要权限校验的URL{}", authUrlList.stream().map(e -> e.getUrl()).collect(Collectors.toList()));
return authUrlList;
}
private List<RequestUrlVO> buildRequestUrl(Method method, Set<String> urlSet) {
List<RequestUrlVO> requestUrlList = Lists.newArrayList();
if (CollectionUtils.isEmpty(urlSet)) {
return requestUrlList;
}
//url对应的方法名称
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
List<String> list = StrUtil.split(className, ".");
String controllerName = list.get(list.size() - 1);
String name = controllerName + "." + methodName;
//swagger 说明信息
String methodComment = null;
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
if (apiOperation != null) {
methodComment = apiOperation.value();
}
for (String url : urlSet) {
RequestUrlVO requestUrlVO = new RequestUrlVO();
requestUrlVO.setUrl(url);
requestUrlVO.setName(name);
requestUrlVO.setComment(methodComment);
requestUrlList.add(requestUrlVO);
}
return requestUrlList;
}
/**
* 获取无需登录可以匿名访问的url信息
*
* @return
*/
@Bean
public List<String> noNeedLoginUrlList(Map<Method, Set<String>> methodUrlMap) {
List<String> noNeedLoginUrlList = Lists.newArrayList();
for (Map.Entry<Method, Set<String>> entry : methodUrlMap.entrySet()) {
Method method = entry.getKey();
NoNeedLogin noNeedLogin = method.getAnnotation(NoNeedLogin.class);
if (null == noNeedLogin) {
continue;
}
noNeedLoginUrlList.addAll(entry.getValue());
}
log.info("不需要登录的URL{}", noNeedLoginUrlList);
return noNeedLoginUrlList;
}
/**
* 获取忽略的url信息
*
* @return
*/
@Bean
public List<String> ignoreUrlList() {
List<String> ignoreUrlList = Lists.newArrayList();
ignoreUrlList.add("/swagger-ui.html");
ignoreUrlList.add("/swagger-resources/**");
ignoreUrlList.add("/webjars/**");
ignoreUrlList.add("/druid/**");
ignoreUrlList.add("/*/api-docs");
return ignoreUrlList;
}
}
@@ -0,0 +1,14 @@
package net.lab1024.sa.common.constant;
/**
* 缓存key常量
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class CacheKeyConst {
}
@@ -0,0 +1,31 @@
package net.lab1024.sa.common.constant;
/**
* redis key 常量类
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class RedisKeyConst {
public static final String SEPARATOR = ":";
public static class Support {
public static final String FILE_URL = "file:";
public static final String FILE_VO = "file-vo:";
public static final String SERIAL_NUMBER_LAST_INFO = "serial-number:last-info";
public static final String SERIAL_NUMBER = "serial-number:";
public static final String CAPTCHA = "captcha:";
public static final String TOKEN = "token:";
}
}
@@ -0,0 +1,18 @@
package net.lab1024.sa.common.constant;
/**
* reload 项目
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class ReloadConst {
public static final String CONFIG_RELOAD = "system_config";
public static final String CACHE_SERVICE = "cache_service";
}
@@ -0,0 +1,49 @@
package net.lab1024.sa.common.constant;
/**
* swagger
*
* @Author 1024创新实验室: 罗伊
* @Date 2022-05-30 21:22:12
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class SwaggerTagConst {
public static class Support {
public static final String CACHE = "业务支撑-缓存";
public static final String CAPTCHA = "业务支撑-验证码";
public static final String OPERATE_LOG = "业务支撑-用户操作记录";
public static final String LOGIN_LOG = "业务支撑-登录日志";
public static final String RELOAD = "业务支撑-reload";
public static final String SERIAL_NUMBER = "业务支撑-id生成器";
public static final String HEART_BEAT = "业务支撑-服务心跳";
public static final String FILE = "业务支撑-文件服务";
public static final String CONFIG = "业务支撑-系统参数";
public static final String DATA_TRACER = "业务支撑-数据变动记录";
public static final String DICT = "业务支撑-数据字典";
public static final String CODE_GENERATOR = "业务支撑-代码生成";
public static final String CHANGE_LOG = "业务支撑-更新日志";
public static final String HELP_DOC = "业务支撑-帮助文档";
public static final String FEEDBACK = "业务支撑-意见反馈";
public static final String TABLE_COLUMN = "业务支撑-列自定义";
}
}
@@ -0,0 +1,18 @@
package net.lab1024.sa.common.constant;
/**
* url前缀
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/10/03 20:48
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class UrlPrefixConst {
public static final String SUPPORT = "/support";
public static final String THIRD = "/third";
}
@@ -0,0 +1,126 @@
package net.lab1024.sa.common.handler;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.code.SystemErrorCode;
import net.lab1024.sa.common.common.code.UserErrorCode;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import net.lab1024.sa.common.common.domain.SystemEnvironment;
import net.lab1024.sa.common.common.exception.BusinessException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.List;
import java.util.stream.Collectors;
/**
* 全局异常拦截
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2020/8/25 21:57
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@Autowired
private SystemEnvironment systemEnvironment;
/**
* json 格式错误 缺少请求体
*/
@ResponseBody
@ExceptionHandler({HttpMessageNotReadableException.class})
public ResponseDTO<?> jsonFormatExceptionHandler(Exception e) {
if (!systemEnvironment.isProd()) {
log.error("全局JSON格式错误异常,URL:{}", getCurrentRequestUrl(), e);
}
return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "参数JSON格式错误");
}
/**
* json 格式错误 缺少请求体
*/
@ResponseBody
@ExceptionHandler({TypeMismatchException.class, BindException.class})
public ResponseDTO<?> paramExceptionHandler(Exception e) {
if (!systemEnvironment.isProd()) {
log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e);
}
if (e instanceof BindException) {
if (e instanceof MethodArgumentNotValidException) {
List<FieldError> fieldErrors = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors();
List<String> msgList = fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.toList());
return ResponseDTO.error(UserErrorCode.PARAM_ERROR, String.join(",", msgList));
}
List<FieldError> fieldErrors = ((BindException) e).getFieldErrors();
List<String> error = fieldErrors.stream().map(field -> field.getField() + ":" + field.getRejectedValue()).collect(Collectors.toList());
String errorMsg = UserErrorCode.PARAM_ERROR.getMsg() + ":" + error;
return ResponseDTO.error(UserErrorCode.PARAM_ERROR, errorMsg);
}
return ResponseDTO.error(UserErrorCode.PARAM_ERROR);
}
/**
* 权限异常
*/
@ResponseBody
@ExceptionHandler({AccessDeniedException.class})
public ResponseDTO<?> permissionExceptionHandler(AccessDeniedException e) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
/**
* 业务异常
*/
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ResponseDTO<?> businessExceptionHandler(BusinessException e) {
if (!systemEnvironment.isProd()) {
log.error("全局业务异常,URL:{}", getCurrentRequestUrl(), e);
}
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, e.getMessage());
}
/**
* 其他全部异常
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(Throwable.class)
public ResponseDTO<?> errorHandler(Throwable e) {
log.error("捕获全局异常,URL:{}", getCurrentRequestUrl(), e);
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, systemEnvironment.isProd() ? null : e.toString());
}
/**
* 获取当前请求url
*/
private String getCurrentRequestUrl() {
RequestAttributes request = RequestContextHolder.getRequestAttributes();
if (null == request) {
return null;
}
ServletRequestAttributes servletRequest = (ServletRequestAttributes) request;
return servletRequest.getRequest().getRequestURI();
}
}
@@ -0,0 +1,54 @@
package net.lab1024.sa.common.listener;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* 启动监听器
*
* @Author 1024创新实验室: 罗伊
* @Date 2021-12-23 23:45:26
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Slf4j
@Component
@Order(value = 1024)
public class SmartApplicationListener implements ApplicationListener<WebServerInitializedEvent> {
@Override
public void onApplicationEvent(WebServerInitializedEvent webServerInitializedEvent) {
WebServer server = webServerInitializedEvent.getWebServer();
WebServerApplicationContext context = webServerInitializedEvent.getApplicationContext();
Environment env = context.getEnvironment();
//获取服务信息
String ip = NetUtil.getLocalhost().getHostAddress();
Integer port = server.getPort();
String contextPath = env.getProperty("server.servlet.context-path");
if (contextPath == null) {
contextPath = "";
}
String profile = env.getProperty("spring.profiles.active");
String projectName = env.getProperty("project.name");
//拼接服务地址
String title = String.format("-------------【%s】 service is runningcurrent profile is 【%s】-------------", projectName, profile);
String localhostUrl = URLUtil.normalize(String.format("http://localhost:%d%s", port, contextPath), false, true);
String externalUrl = URLUtil.normalize(String.format("http://%s:%d%s", ip, port, contextPath), false, true);
String swaggerUrl = URLUtil.normalize(String.format("http://localhost:%d%s/swagger-ui.html", port, contextPath), false, true);
log.info("\n{}\n" +
"\tLocal:\t\t{}" +
"\n\tExternal:\t{}" +
"\n\tSwagger:\t{}" +
"\n-------------------------------------------------------------------------------------\n",
title, localhostUrl, externalUrl, swaggerUrl);
}
}
@@ -0,0 +1,78 @@
package net.lab1024.sa.common.module.support.cache;
import com.google.common.collect.Lists;
import net.lab1024.sa.common.constant.ReloadConst;
import net.lab1024.sa.common.module.support.reload.core.annoation.SmartReload;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 缓存操作
*
* @Author 1024创新实验室: 罗伊
* @Date 2021/10/11 20:07
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Service
public class CacheService {
@Resource
private CaffeineCacheManager caffeineCacheManager;
/**
* 获取所有缓存名称
*
* @return
*/
public List<String> cacheNames() {
return Lists.newArrayList(caffeineCacheManager.getCacheNames());
}
/**
* 某个缓存下的所有key
*
* @param cacheName
* @return
*/
public List<String> cacheKey(String cacheName) {
CaffeineCache cache = (CaffeineCache) caffeineCacheManager.getCache(cacheName);
if (cache == null) {
return Lists.newArrayList();
}
Set<Object> cacheKey = cache.getNativeCache().asMap().keySet();
return cacheKey.stream().map(e -> e.toString()).collect(Collectors.toList());
}
/**
* 移除某个key
*
* @param cacheName
*/
public void removeCache(String cacheName) {
CaffeineCache cache = (CaffeineCache) caffeineCacheManager.getCache(cacheName);
if (cache != null) {
cache.clear();
}
}
@SmartReload(ReloadConst.CACHE_SERVICE)
public void clearAllCache() {
Collection<String> cacheNames = caffeineCacheManager.getCacheNames();
for (String name : cacheNames) {
CaffeineCache cache = (CaffeineCache) caffeineCacheManager.getCache(name);
if (cache != null) {
cache.clear();
}
}
}
}
@@ -0,0 +1,36 @@
package net.lab1024.sa.common.module.support.captcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.lab1024.sa.common.common.controller.SupportBaseController;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import net.lab1024.sa.common.constant.SwaggerTagConst;
import net.lab1024.sa.common.module.support.captcha.domain.CaptchaVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 图形验证码业务
*
* @Author 1024创新实验室: 胡克
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
//@Api(tags = SwaggerTagConst.Support.CAPTCHA)
//@RestController
//public class CaptchaController extends SupportBaseController {
//
// @Autowired
// private CaptchaService captchaService;
//
// @ApiOperation("获取图形验证码 @author 胡克")
// @GetMapping("/captcha")
// public ResponseDTO<CaptchaVO> generateCaptcha() {
// return ResponseDTO.ok(captchaService.generateCaptcha());
// }
//
//}
@@ -0,0 +1,114 @@
//package net.lab1024.sa.common.module.support.captcha;
//
//import com.google.code.kaptcha.impl.DefaultKaptcha;
//import lombok.extern.slf4j.Slf4j;
//import net.lab1024.sa.common.common.constant.StringConst;
//import net.lab1024.sa.common.common.domain.ResponseDTO;
//import net.lab1024.sa.common.common.domain.SystemEnvironment;
//import net.lab1024.sa.common.common.exception.BusinessException;
//import net.lab1024.sa.common.constant.RedisKeyConst;
//import net.lab1024.sa.common.module.support.captcha.domain.CaptchaForm;
//import net.lab1024.sa.common.module.support.captcha.domain.CaptchaVO;
//import net.lab1024.sa.common.module.support.redis.RedisService;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//import org.springframework.util.Base64Utils;
//
//import javax.imageio.ImageIO;
//import java.awt.image.BufferedImage;
//import java.io.ByteArrayOutputStream;
//import java.util.Objects;
//import java.util.UUID;
//
///**
// * 图形验证码 服务
// *
// * @Author 1024创新实验室: 胡克
// * @Date 2021/8/31 20:52
// * @Wechat zhuoda1024
// * @Email lab1024@163.com
// * @Copyright 1024创新实验室 https://1024lab.net
// */
//@Slf4j
//@Service
//public class CaptchaService {
//
// /**
// * 过期时间:65秒
// */
// private static final long EXPIRE_SECOND = 65L;
//
// @Autowired
// private DefaultKaptcha defaultKaptcha;
// @Autowired
// private SystemEnvironment systemEnvironment;
// @Autowired
// private RedisService redisService;
//
// /**
// * 生成图形验证码
// * 默认 1 分钟有效期
// *
// * @return
// */
// public CaptchaVO generateCaptcha() {
// String captchaText = defaultKaptcha.createText();
// BufferedImage image = defaultKaptcha.createImage(captchaText);
//
// String base64Code;
// try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
// ImageIO.write(image, "jpg", os);
// base64Code = Base64Utils.encodeToString(os.toByteArray());
// } catch (Exception e) {
// log.error("generateCaptcha error:", e);
// throw new BusinessException("生成验证码错误");
// }
//
// /**
// * 返回验证码对象
// * 图片 base64格式
// */
// // uuid 唯一标识
// String uuid = UUID.randomUUID().toString().replace("-", StringConst.EMPTY);
//
// CaptchaVO captchaVO = new CaptchaVO();
// captchaVO.setCaptchaUuid(uuid);
// captchaVO.setCaptchaBase64Image("data:image/png;base64," + base64Code);
// captchaVO.setExpireSeconds(EXPIRE_SECOND);
// if (!systemEnvironment.isProd()) {
// captchaVO.setCaptchaText(captchaText);
// }
// String redisCaptchaKey = redisService.generateRedisKey(RedisKeyConst.Support.CAPTCHA, uuid);
// redisService.set(redisCaptchaKey, captchaText, EXPIRE_SECOND);
// return captchaVO;
// }
//
// /**
// * 校验图形验证码
// *
// * @param captchaForm
// * @return
// */
// public ResponseDTO<String> checkCaptcha(CaptchaForm captchaForm) {
// if (StringUtils.isBlank(captchaForm.getCaptchaUuid()) || StringUtils.isBlank(captchaForm.getCaptchaCode())) {
// return ResponseDTO.userErrorParam("请输入正确验证码");
// }
// /**
// * 1、校验redis里的验证码
// * 2、校验成功后,删除redis
// */
// String redisCaptchaKey = redisService.generateRedisKey(RedisKeyConst.Support.CAPTCHA, captchaForm.getCaptchaUuid());
// String redisCaptchaCode = redisService.get(redisCaptchaKey);
// if (StringUtils.isBlank(redisCaptchaCode)) {
// return ResponseDTO.userErrorParam("验证码已过期,请刷新重试");
// }
// if (!Objects.equals(redisCaptchaCode, captchaForm.getCaptchaCode())) {
// return ResponseDTO.userErrorParam("验证码错误,请输入正确的验证码");
// }
// // 删除已使用的验证码
// redisService.delete(redisCaptchaKey);
// return ResponseDTO.ok();
// }
//
//}
@@ -0,0 +1,38 @@
package net.lab1024.sa.common.module.support.captcha.config;
import com.google.common.collect.Lists;
import java.awt.*;
import java.util.List;
import java.util.Random;
/**
* 验证码颜色
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class CaptchaColor {
public static Color getColor() {
List<Color> colors = Lists.newArrayList();
colors.add(new Color(0, 135, 255));
colors.add(new Color(51, 153, 51));
colors.add(new Color(255, 102, 102));
colors.add(new Color(255, 153, 0));
colors.add(new Color(153, 102, 0));
colors.add(new Color(153, 102, 153));
colors.add(new Color(51, 153, 153));
colors.add(new Color(102, 102, 255));
colors.add(new Color(0, 102, 204));
colors.add(new Color(204, 51, 51));
colors.add(new Color(128, 153, 65));
Random random = new Random();
int colorIndex = random.nextInt(10);
return colors.get(colorIndex);
}
}
@@ -0,0 +1,46 @@
package net.lab1024.sa.common.module.support.captcha.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* 验证码配置
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Configuration
public class CaptchaConfig {
@Bean
public DefaultKaptcha getDefaultKaptcha() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty("kaptcha.border", "no");
properties.setProperty("kaptcha.border.color", "34,114,200");
properties.setProperty("kaptcha.image.width", "125");
properties.setProperty("kaptcha.image.height", "45");
properties.setProperty("kaptcha.textproducer.char.string", "123456789abcdefghkmnpqrstuvwxyabcdefghkmnpqrstuvwxyz");
properties.setProperty("kaptcha.textproducer.char.length", "4");
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Arial Narrow,Serif,Helvetica,Tahoma,Times New Roman,Verdana");
properties.setProperty("kaptcha.textproducer.font.size", "38");
properties.setProperty("kaptcha.background.clear.from", "white");
properties.setProperty("kaptcha.background.clear.to", "white");
properties.setProperty("kaptcha.word.impl", CaptchaWordRenderer.class.getName());
properties.setProperty("kaptcha.noise.impl", CaptchaNoise.class.getName());
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
@@ -0,0 +1,44 @@
package net.lab1024.sa.common.module.support.captcha.config;
import com.google.code.kaptcha.NoiseProducer;
import com.google.code.kaptcha.util.Configurable;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 验证码加噪处理
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class CaptchaNoise extends Configurable implements NoiseProducer {
public CaptchaNoise() {
}
@Override
public void makeNoise(BufferedImage image, float factorOne, float factorTwo, float factorThree, float factorFour) {
int width = image.getWidth();
int height = image.getHeight();
Graphics2D graph = (Graphics2D) image.getGraphics();
graph.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
graph.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
Random random = new Random();
int noiseLineNum = random.nextInt(3);
if (noiseLineNum == 0) {
noiseLineNum = 1;
}
for (int i = 0; i < noiseLineNum; i++) {
graph.setColor(CaptchaColor.getColor());
graph.drawLine(random.nextInt(width), random.nextInt(height), 10 + random.nextInt(20), 10 + random.nextInt(20));
}
graph.dispose();
}
}
@@ -0,0 +1,74 @@
package net.lab1024.sa.common.module.support.captcha.config;
import com.google.code.kaptcha.text.WordRenderer;
import com.google.code.kaptcha.util.Configurable;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 验证码字体生成
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
public class CaptchaWordRenderer extends Configurable implements WordRenderer {
public CaptchaWordRenderer() {
}
@Override
public BufferedImage renderWord(String word, int width, int height) {
int fontSize = this.getConfig().getTextProducerFontSize();
Font[] fonts = this.getConfig().getTextProducerFonts(fontSize);
int charSpace = this.getConfig().getTextProducerCharSpace();
BufferedImage image = new BufferedImage(width, height, 2);
Graphics2D g2D = image.createGraphics();
g2D.setColor(Color.WHITE);
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2D.setRenderingHints(hints);
g2D.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
FontRenderContext frc = g2D.getFontRenderContext();
Random random = new Random();
int startPosY = (height - fontSize) / 5 + fontSize;
char[] wordChars = word.toCharArray();
Font[] chosenFonts = new Font[wordChars.length];
int[] charWidths = new int[wordChars.length];
int widthNeeded = 0;
int startPosX;
for (startPosX = 0; startPosX < wordChars.length; ++startPosX) {
chosenFonts[startPosX] = fonts[random.nextInt(fonts.length)];
char[] charToDraw = new char[]{wordChars[startPosX]};
GlyphVector gv = chosenFonts[startPosX].createGlyphVector(frc, charToDraw);
charWidths[startPosX] = (int) gv.getVisualBounds().getWidth();
if (startPosX > 0) {
widthNeeded += 2;
}
widthNeeded += charWidths[startPosX];
}
startPosX = (width - widthNeeded) / 2;
for (int i = 0; i < wordChars.length; ++i) {
g2D.setColor(CaptchaColor.getColor());
g2D.setFont(chosenFonts[i].deriveFont(Font.PLAIN));
char[] charToDraw = new char[]{wordChars[i]};
g2D.drawChars(charToDraw, 0, charToDraw.length, startPosX, startPosY);
startPosX = startPosX + charWidths[i] + charSpace;
}
return image;
}
}
@@ -0,0 +1,28 @@
package net.lab1024.sa.common.module.support.captcha.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 图形验证码 表单
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021-09-02 20:21:10
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class CaptchaForm {
@ApiModelProperty(value = "验证码")
@NotBlank(message = "验证码不能为空")
private String captchaCode;
@ApiModelProperty(value = "验证码uuid标识")
@NotBlank(message = "验证码uuid标识不能为空")
private String captchaUuid;
}
@@ -0,0 +1,29 @@
package net.lab1024.sa.common.module.support.captcha.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 图形验证码 VO
*
* @Author 1024创新实验室-主任: 卓大
* @Date 2021/8/31 20:52
* @Wechat zhuoda1024
* @Email lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net
*/
@Data
public class CaptchaVO {
@ApiModelProperty("验证码唯一标识")
private String captchaUuid;
@ApiModelProperty("验证码图片内容-生产环境无效")
private String captchaText;
@ApiModelProperty("验证码Base64图片")
private String captchaBase64Image;
@ApiModelProperty("过期时间(秒)")
private Long expireSeconds;
}

Some files were not shown because too many files have changed in this diff Show More