~
This commit is contained in:
202
mjkf-xinke-common/pom.xml
Normal file
202
mjkf-xinke-common/pom.xml
Normal file
@@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>mjkf.xinke</groupId>
|
||||
<artifactId>mjkf-xinke-boot</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mjkf-xinke-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>基础通用模块</description>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>admin</id>
|
||||
<name>release</name>
|
||||
<url>http://192.168.137.98:8081/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>xx</id>
|
||||
<name>snapshot</name>
|
||||
<url>http://192.168.137.98:8081/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<dependencies>
|
||||
|
||||
<!-- validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- aop -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- processor -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis-plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- easy-trans -->
|
||||
<dependency>
|
||||
<groupId>com.fhs-opensource</groupId>
|
||||
<artifactId>easy-trans-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mybatis-plus-annotation</artifactId>
|
||||
<groupId>com.baomidou</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>springfox-schema</artifactId>
|
||||
<groupId>io.springfox</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<groupId>commons-collections</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- easy-trans-mybatis-plus-extend -->
|
||||
<dependency>
|
||||
<groupId>com.fhs-opensource</groupId>
|
||||
<artifactId>easy-trans-mybatis-plus-extend</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mybatis-plus-extension</artifactId>
|
||||
<groupId>com.baomidou</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- redis -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- jackson-core -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- jackson-databind -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- hutool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- pinyin4j -->
|
||||
<dependency>
|
||||
<groupId>com.belerweb</groupId>
|
||||
<artifactId>pinyin4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- ip2region -->
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- knife4j -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- easy-poi -->
|
||||
<dependency>
|
||||
<groupId>cn.afterturn</groupId>
|
||||
<artifactId>easypoi-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>javassist</artifactId>
|
||||
<groupId>org.javassist</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>poi</artifactId>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>poi-ooxml-schemas</artifactId>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- sm-crypto -->
|
||||
<dependency>
|
||||
<groupId>com.antherd</groupId>
|
||||
<artifactId>sm-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- easyexcel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- json-flattener -->
|
||||
<dependency>
|
||||
<groupId>com.github.wnameless.json</groupId>
|
||||
<artifactId>json-flattener</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,21 @@
|
||||
|
||||
package mjkf.xinke.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 自定义日志注解
|
||||
*
|
||||
*
|
||||
* @date 2022/6/20 14:25
|
||||
**/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface CommonLog {
|
||||
|
||||
/**
|
||||
* 日志的名称,例如:"修改菜单"
|
||||
*/
|
||||
String value() default "未命名";
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
|
||||
package mjkf.xinke.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 自定义节流防抖注解
|
||||
*
|
||||
*
|
||||
* @date 2022/6/20 14:25
|
||||
**/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface CommonNoRepeat {
|
||||
|
||||
/**
|
||||
* 间隔时间(ms),小于此时间视为重复提交,默认5000ms
|
||||
*/
|
||||
int interval() default 5000;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
|
||||
package mjkf.xinke.common.annotation;
|
||||
|
||||
import mjkf.xinke.common.pojo.CommonWrapperInterface;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 自定义包装注解,对响应结果包装
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:12
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CommonWrapper {
|
||||
|
||||
/**
|
||||
* 具体包装类
|
||||
*/
|
||||
Class<? extends CommonWrapperInterface<?>>[] value();
|
||||
}
|
75
mjkf-xinke-common/src/main/java/mjkf/xinke/common/cache/CommonCacheOperator.java
vendored
Normal file
75
mjkf-xinke-common/src/main/java/mjkf/xinke/common/cache/CommonCacheOperator.java
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
package mjkf.xinke.common.cache;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 通用Redis缓存操作器
|
||||
*
|
||||
*
|
||||
* @date 2022/6/21 16:00
|
||||
**/
|
||||
@Component
|
||||
public class CommonCacheOperator {
|
||||
|
||||
/** 所有缓存Key的前缀 */
|
||||
private static final String CACHE_KEY_PREFIX = "Cache:";
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public void put(String key, Object value) {
|
||||
redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).set(value);
|
||||
}
|
||||
|
||||
public void put(String key, Object value, long timeoutSeconds) {
|
||||
redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).set(value, timeoutSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
return redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).get();
|
||||
}
|
||||
|
||||
public void remove(String... key) {
|
||||
ArrayList<String> keys = CollectionUtil.toList(key);
|
||||
List<String> withPrefixKeys = keys.stream().map(i -> CACHE_KEY_PREFIX + i).collect(Collectors.toList());
|
||||
redisTemplate.delete(withPrefixKeys);
|
||||
}
|
||||
|
||||
public Collection<String> getAllKeys() {
|
||||
Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
|
||||
if (keys != null) {
|
||||
// 去掉缓存key的common prefix前缀
|
||||
return keys.stream().map(key -> StrUtil.removePrefix(key, CACHE_KEY_PREFIX)).collect(Collectors.toSet());
|
||||
} else {
|
||||
return CollectionUtil.newHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Object> getAllValues() {
|
||||
Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
|
||||
if (keys != null) {
|
||||
return redisTemplate.opsForValue().multiGet(keys);
|
||||
} else {
|
||||
return CollectionUtil.newArrayList();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getAllKeyValues() {
|
||||
Collection<String> allKeys = this.getAllKeys();
|
||||
HashMap<String, Object> results = MapUtil.newHashMap();
|
||||
for (String key : allKeys) {
|
||||
results.put(key, this.get(key));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
|
||||
package mjkf.xinke.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 通用删除标志枚举
|
||||
*
|
||||
*
|
||||
* @date 2021/10/11 14:02
|
||||
**/
|
||||
@Getter
|
||||
public enum CommonDeleteFlagEnum {
|
||||
|
||||
/** 未删除 */
|
||||
NOT_DELETE,
|
||||
|
||||
/** 已删除 */
|
||||
DELETED
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
|
||||
package mjkf.xinke.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 异常码枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 16:09
|
||||
**/
|
||||
@Getter
|
||||
public enum CommonExceptionEnum {
|
||||
|
||||
OK200(200, "请求成功"),
|
||||
ERROR401(401, "未登录"),
|
||||
ERROR403(403, "无权限"),
|
||||
ERROR404(404, "路径不存在"),
|
||||
ERROR405(405, "请求方法不正确"),
|
||||
ERROR415(415, "参数传递异常"),
|
||||
ERROR500(500, "业务异常");
|
||||
|
||||
private final Integer code;
|
||||
|
||||
private final String message;
|
||||
|
||||
CommonExceptionEnum(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
|
||||
package mjkf.xinke.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 通用排序方式枚举
|
||||
*
|
||||
*
|
||||
* @date 2022/7/13 17:48
|
||||
**/
|
||||
@Getter
|
||||
public enum CommonSortOrderEnum {
|
||||
|
||||
/** 升序 */
|
||||
ASC("ASCEND"),
|
||||
|
||||
/** 降序 */
|
||||
DESC("DESCEND");
|
||||
|
||||
private final String value;
|
||||
|
||||
CommonSortOrderEnum(String value) {
|
||||
this.value = value.toUpperCase();
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
boolean flag = ASC.getValue().toLowerCase().equals(value) || DESC.getValue().toLowerCase().equals(value);
|
||||
if(!flag) {
|
||||
throw new CommonException("不支持该排序方式:{}", value);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
|
||||
package mjkf.xinke.common.excel;
|
||||
|
||||
import com.alibaba.excel.metadata.Head;
|
||||
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* EasyExcel自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法
|
||||
*
|
||||
*
|
||||
* @date 2023/3/6 13:21
|
||||
**/
|
||||
public class CommonExcelCustomMergeStrategy extends AbstractMergeStrategy {
|
||||
|
||||
/**
|
||||
* 分组,每几行合并一次
|
||||
*/
|
||||
private final List<Integer> exportFieldGroupCountList;
|
||||
|
||||
/**
|
||||
* 目标合并列index
|
||||
*/
|
||||
private final Integer targetColumnIndex;
|
||||
|
||||
/**
|
||||
* 需要开始合并单元格的首行index
|
||||
*/
|
||||
private Integer rowIndex;
|
||||
|
||||
/**
|
||||
* exportDataList为待合并目标列的值
|
||||
*
|
||||
*
|
||||
* @date 2023/3/6 13:23
|
||||
**/
|
||||
public CommonExcelCustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
|
||||
this.exportFieldGroupCountList = getGroupCountList(exportDataList);
|
||||
this.targetColumnIndex = targetColumnIndex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
|
||||
|
||||
if (null == rowIndex) {
|
||||
rowIndex = cell.getRowIndex();
|
||||
}
|
||||
// 仅从首行以及目标列的单元格开始合并,忽略其他
|
||||
if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
|
||||
mergeGroupColumn(sheet);
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeGroupColumn(Sheet sheet) {
|
||||
int rowCount = rowIndex;
|
||||
for (Integer count : exportFieldGroupCountList) {
|
||||
if(count == 1) {
|
||||
rowCount += count;
|
||||
continue ;
|
||||
}
|
||||
// 合并单元格
|
||||
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
|
||||
sheet.addMergedRegionUnsafe(cellRangeAddress);
|
||||
rowCount += count;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
|
||||
*
|
||||
*
|
||||
* @date 2023/3/6 13:23
|
||||
**/
|
||||
private List<Integer> getGroupCountList(List<String> exportDataList){
|
||||
if (CollectionUtils.isEmpty(exportDataList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Integer> groupCountList = new ArrayList<>();
|
||||
int count = 1;
|
||||
|
||||
for (int i = 1; i < exportDataList.size(); i++) {
|
||||
if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
|
||||
count++;
|
||||
} else {
|
||||
groupCountList.add(count);
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
// 处理完最后一条后
|
||||
groupCountList.add(count);
|
||||
return groupCountList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
|
||||
package mjkf.xinke.common.exception;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 通用异常
|
||||
*
|
||||
*
|
||||
* @date 2020/4/8 15:54
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class CommonException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String msg;
|
||||
|
||||
public CommonException() {
|
||||
super("服务器异常");
|
||||
this.code = 500;
|
||||
this.msg = "服务器异常";
|
||||
}
|
||||
|
||||
public CommonException(String msg, Object... arguments) {
|
||||
super(StrUtil.format(msg, arguments));
|
||||
this.code = 500;
|
||||
this.msg = StrUtil.format(msg, arguments);
|
||||
}
|
||||
|
||||
public CommonException(Integer code, String msg, Object... arguments) {
|
||||
super(StrUtil.format(msg, arguments));
|
||||
this.code = code;
|
||||
this.msg = StrUtil.format(msg, arguments);
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
|
||||
package mjkf.xinke.common.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||
import mjkf.xinke.common.util.CommonCryptogramUtil;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Sm4Cbc加解密
|
||||
*
|
||||
*
|
||||
* @date 2022/9/30 15:24
|
||||
**/
|
||||
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||
public class CommonSm4CbcTypeHandler<T> extends BaseTypeHandler<T> {
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
|
||||
ps.setString(i, CommonCryptogramUtil.doSm4CbcEncrypt((String)parameter));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@Override
|
||||
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
String columnValue = rs.getString(columnName);
|
||||
//有一些可能是空字符
|
||||
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@Override
|
||||
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
String columnValue = rs.getString(columnIndex);
|
||||
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@Override
|
||||
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
String columnValue = cs.getString(columnIndex);
|
||||
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
|
||||
}
|
||||
}
|
@@ -0,0 +1,164 @@
|
||||
|
||||
package mjkf.xinke.common.listener;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 通用数据变化事件中心 事件发布器
|
||||
*
|
||||
*
|
||||
* @date 2023/3/3 10:14
|
||||
**/
|
||||
public class CommonDataChangeEventCenter {
|
||||
|
||||
// --------- 注册侦听器
|
||||
|
||||
private static List<CommonDataChangeListener> listenerList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 获取已注册的所有侦听器
|
||||
* @return /
|
||||
*/
|
||||
public static List<CommonDataChangeListener> getListenerList() {
|
||||
return listenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置侦听器集合
|
||||
* @param listenerList /
|
||||
*/
|
||||
public static void setListenerList(List<CommonDataChangeListener> listenerList) {
|
||||
if(listenerList == null) {
|
||||
throw new CommonException("重置的侦听器集合不可以为空");
|
||||
}
|
||||
CommonDataChangeEventCenter.listenerList = listenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个侦听器
|
||||
* @param listener /
|
||||
*/
|
||||
public static void registerListener(CommonDataChangeListener listener) {
|
||||
if(listener == null) {
|
||||
throw new CommonException("注册的侦听器不可以为空");
|
||||
}
|
||||
listenerList.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一组侦听器
|
||||
* @param listenerList /
|
||||
*/
|
||||
public static void registerListenerList(List<CommonDataChangeListener> listenerList) {
|
||||
if(listenerList == null) {
|
||||
throw new CommonException("注册的侦听器不可以为空");
|
||||
}
|
||||
for (CommonDataChangeListener listener : listenerList) {
|
||||
if(listener == null) {
|
||||
throw new CommonException("注册的侦听器不可以为空");
|
||||
}
|
||||
}
|
||||
CommonDataChangeEventCenter.listenerList.addAll(listenerList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个侦听器
|
||||
* @param listener /
|
||||
*/
|
||||
public static void removeListener(CommonDataChangeListener listener) {
|
||||
listenerList.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定类型的所有侦听器
|
||||
* @param cls /
|
||||
*/
|
||||
public static void removeListener(Class<? extends CommonDataChangeListener> cls) {
|
||||
ArrayList<CommonDataChangeListener> listenerListCopy = new ArrayList<>(listenerList);
|
||||
for (CommonDataChangeListener listener : listenerListCopy) {
|
||||
if(cls.isAssignableFrom(listener.getClass())) {
|
||||
listenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有已注册的侦听器
|
||||
*/
|
||||
public static void clearListener() {
|
||||
listenerList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已经注册了指定侦听器
|
||||
* @param listener /
|
||||
* @return /
|
||||
*/
|
||||
public static boolean hasListener(CommonDataChangeListener listener) {
|
||||
return listenerList.contains(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已经注册了指定类型的侦听器
|
||||
* @param cls /
|
||||
* @return /
|
||||
*/
|
||||
public static boolean hasListener(Class<? extends CommonDataChangeListener> cls) {
|
||||
for (CommonDataChangeListener listener : listenerList) {
|
||||
if(cls.isAssignableFrom(listener.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------- 事件发布-添加 --------- //
|
||||
|
||||
/**
|
||||
* 执行添加事件发布,数据集合
|
||||
*
|
||||
*
|
||||
* @date 2023/3/3 10:22
|
||||
**/
|
||||
public static void doAddWithData(String dataType, JSONArray jsonArray) {
|
||||
for (CommonDataChangeListener listener : listenerList) {
|
||||
listener.doAddWithDataIdList(dataType, jsonArray.stream().map(o -> JSONUtil.parseObj(o).getStr("id")).collect(Collectors.toList()));
|
||||
listener.doAddWithDataList(dataType, jsonArray);
|
||||
}
|
||||
}
|
||||
|
||||
// --------- 事件发布-更新 --------- //
|
||||
|
||||
/**
|
||||
* 执行更新事件发布,数据集合
|
||||
*
|
||||
*
|
||||
* @date 2023/3/3 10:22
|
||||
**/
|
||||
public static void doUpdateWithData(String dataType, JSONArray jsonArray) {
|
||||
for (CommonDataChangeListener listener : listenerList) {
|
||||
listener.doUpdateWithDataIdList(dataType, jsonArray.stream().map(o -> JSONUtil.parseObj(o).getStr("id")).collect(Collectors.toList()));
|
||||
listener.doUpdateWithDataList(dataType, jsonArray);
|
||||
}
|
||||
}
|
||||
|
||||
// --------- 事件发布-删除 --------- //
|
||||
|
||||
/**
|
||||
* 执行删除事件发布,ID集合
|
||||
*
|
||||
*
|
||||
* @date 2023/3/3 10:22
|
||||
**/
|
||||
public static void doDeleteWithDataId(String dataType, List<String> dataIdList) {
|
||||
for (CommonDataChangeListener listener : listenerList) {
|
||||
listener.doDeleteWithDataIdList(dataType, dataIdList);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
|
||||
package mjkf.xinke.common.listener;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用数据变化侦听器,你可以实现该侦听器接口,在数据新增、更新、删除时进行一些AOP操作
|
||||
*
|
||||
*
|
||||
* @date 2023/3/3 10:14
|
||||
**/
|
||||
public interface CommonDataChangeListener {
|
||||
|
||||
/**
|
||||
* 执行添加,ID集合
|
||||
*
|
||||
* @param dataType 数据类型,如USER、ORG,自行定义
|
||||
* @param dataIdList 被添加的数据ID集合
|
||||
*
|
||||
* @date 2023/3/3 10:24
|
||||
**/
|
||||
void doAddWithDataIdList(String dataType, List<String> dataIdList);
|
||||
|
||||
/**
|
||||
* 执行添加,数据集合
|
||||
*
|
||||
* @param dataType 数据类型,如USER、ORG,自行定义
|
||||
* @param jsonArray 被添加的数据集合
|
||||
*
|
||||
* @date 2023/3/3 10:24
|
||||
**/
|
||||
void doAddWithDataList(String dataType, JSONArray jsonArray);
|
||||
|
||||
/**
|
||||
* 执行更新,ID集合
|
||||
*
|
||||
* @param dataType 数据类型,如USER、ORG,自行定义
|
||||
* @param dataIdList 被更新的数据ID集合
|
||||
*
|
||||
* @date 2023/3/3 10:24
|
||||
**/
|
||||
void doUpdateWithDataIdList(String dataType, List<String> dataIdList);
|
||||
|
||||
/**
|
||||
* 执行更新,数据集合
|
||||
*
|
||||
* @param dataType 数据类型,如USER、ORG,自行定义
|
||||
* @param jsonArray 被更新的数据集合
|
||||
*
|
||||
* @date 2023/3/3 10:24
|
||||
**/
|
||||
void doUpdateWithDataList(String dataType, JSONArray jsonArray);
|
||||
|
||||
/**
|
||||
* 执行删除,ID集合
|
||||
*
|
||||
* @param dataType 数据类型,如USER、ORG,自行定义
|
||||
* @param dataIdList 被删除的数据ID集合
|
||||
*
|
||||
* @date 2023/3/3 10:24
|
||||
**/
|
||||
void doDeleteWithDataIdList(String dataType, List<String> dataIdList);
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
|
||||
package mjkf.xinke.common.page;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mjkf.xinke.common.util.CommonServletUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用分页请求
|
||||
*
|
||||
*
|
||||
* @date 2021/12/18 14:43
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonPageRequest {
|
||||
|
||||
private static final String PAGE_SIZE_PARAM_NAME = "size";
|
||||
|
||||
private static final String PAGE_PARAM_NAME = "current";
|
||||
|
||||
private static final Integer PAGE_SIZE_MAX_VALUE = 100;
|
||||
|
||||
public static <T> Page<T> defaultPage() {
|
||||
return defaultPage(null);
|
||||
}
|
||||
|
||||
public static <T> Page<T> defaultPage(List<OrderItem> orderItemList) {
|
||||
|
||||
int size = 20;
|
||||
|
||||
int page = 1;
|
||||
|
||||
//每页条数
|
||||
String pageSizeString = CommonServletUtil.getParamFromRequest(PAGE_SIZE_PARAM_NAME);
|
||||
if (ObjectUtil.isNotEmpty(pageSizeString)) {
|
||||
try {
|
||||
size = Convert.toInt(pageSizeString);
|
||||
if(size > PAGE_SIZE_MAX_VALUE) {
|
||||
size = PAGE_SIZE_MAX_VALUE;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 分页条数转换异常:", e);
|
||||
size = 20;
|
||||
}
|
||||
}
|
||||
|
||||
//第几页
|
||||
String pageString = CommonServletUtil.getParamFromRequest(PAGE_PARAM_NAME);
|
||||
if (ObjectUtil.isNotEmpty(pageString)) {
|
||||
try {
|
||||
page = Convert.toInt(pageString);
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 分页页数转换异常:", e);
|
||||
page = 1;
|
||||
}
|
||||
}
|
||||
Page<T> objectPage = new Page<>(page, size);
|
||||
if (ObjectUtil.isNotEmpty(orderItemList)) {
|
||||
objectPage.setOrders(orderItemList);
|
||||
}
|
||||
return objectPage;
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
|
||||
package mjkf.xinke.common.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通用基础字段实体:创建时间、创建人、修改时间、修改人,需要此通用字段的实体可继承此类,
|
||||
* 继承此类要求数据表有对应的字段
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @date 2020/3/10 16:02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class CommonEntity implements Serializable {
|
||||
|
||||
/** 删除标志 */
|
||||
@TableLogic
|
||||
@ApiModelProperty(value = "删除标志", position = 999)
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String deleteFlag;
|
||||
|
||||
/** 创建时间 */
|
||||
@ApiModelProperty(value = "创建时间", position = 1000)
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 创建人 */
|
||||
@ApiModelProperty(value = "创建人", position = 1001)
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createUser;
|
||||
|
||||
/** 更新时间 */
|
||||
@ApiModelProperty(value = "更新时间", position = 1002)
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
/** 更新人 */
|
||||
@ApiModelProperty(value = "更新人", position = 1003)
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private String updateUser;
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
|
||||
package mjkf.xinke.common.pojo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import springfox.documentation.builders.ResponseMessageBuilder;
|
||||
import springfox.documentation.service.ResponseMessage;
|
||||
import mjkf.xinke.common.enums.CommonExceptionEnum;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 对Ajax请求返回Json格式数据的简易封装
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 16:08
|
||||
**/
|
||||
public class CommonResult<T> implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final int CODE_SUCCESS = 200;
|
||||
public static final int CODE_ERROR = 500;
|
||||
|
||||
@ApiModelProperty(value = "状态码")
|
||||
private int code;
|
||||
|
||||
@ApiModelProperty(value = "提示语")
|
||||
private String msg;
|
||||
|
||||
@ApiModelProperty(value = "返回数据")
|
||||
private T data;
|
||||
|
||||
public CommonResult() {
|
||||
}
|
||||
|
||||
public CommonResult(int code, String msg, T data) {
|
||||
this.setCode(code);
|
||||
this.setMsg(msg);
|
||||
this.setData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取code
|
||||
* @return code
|
||||
*/
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取msg
|
||||
* @return msg
|
||||
*/
|
||||
public String getMsg() {
|
||||
return this.msg;
|
||||
}
|
||||
/**
|
||||
* 获取data
|
||||
* @return data
|
||||
*/
|
||||
public T getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给code赋值,连缀风格
|
||||
* @param code code
|
||||
* @return 对象自身
|
||||
*/
|
||||
public CommonResult<T> setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给msg赋值,连缀风格
|
||||
* @param msg msg
|
||||
* @return 对象自身
|
||||
*/
|
||||
public CommonResult<T> setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给data赋值,连缀风格
|
||||
* @param data data
|
||||
* @return 对象自身
|
||||
*/
|
||||
public CommonResult<T> setData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ============================ 构建 ==================================
|
||||
|
||||
// 构建成功
|
||||
public static <T> CommonResult<T> ok() {
|
||||
return new CommonResult<>(CODE_SUCCESS, "操作成功", null);
|
||||
}
|
||||
public static <T> CommonResult<T> ok(String msg) {
|
||||
return new CommonResult<>(CODE_SUCCESS, msg, null);
|
||||
}
|
||||
public static <T> CommonResult<T> code(int code) {
|
||||
return new CommonResult<>(code, null, null);
|
||||
}
|
||||
public static <T> CommonResult<T> data(T data) {
|
||||
return new CommonResult<>(CODE_SUCCESS, "操作成功", data);
|
||||
}
|
||||
|
||||
// 构建失败
|
||||
public static <T> CommonResult<T> error() {
|
||||
return new CommonResult<>(CODE_ERROR, "服务器异常", null);
|
||||
}
|
||||
public static <T> CommonResult<T> error(String msg) {
|
||||
return new CommonResult<>(CODE_ERROR, msg, null);
|
||||
}
|
||||
|
||||
// 构建指定状态码
|
||||
public static <T> CommonResult<T> get(int code, String msg, T data) {
|
||||
return new CommonResult<>(code, msg, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{"
|
||||
+ "\"code\": " + this.getCode()
|
||||
+ ", \"msg\": \"" + this.getMsg() + "\""
|
||||
+ ", \"data\": \"" + this.getData() + "\""
|
||||
+ "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应状态码集合
|
||||
*
|
||||
*
|
||||
* @date 2022/7/25 13:36
|
||||
**/
|
||||
public static List<ResponseMessage> responseList() {
|
||||
return Arrays.stream(CommonExceptionEnum.values()).map(commonExceptionEnum -> new ResponseMessageBuilder()
|
||||
.code(commonExceptionEnum.getCode()).message(commonExceptionEnum.getMessage()).build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
|
||||
package mjkf.xinke.common.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 可被校验的通用List
|
||||
*
|
||||
*
|
||||
* @date 2022/7/28 16:08
|
||||
**/
|
||||
@Data
|
||||
public class CommonValidList<E> implements List<E> {
|
||||
|
||||
@Valid
|
||||
private List<E> list = new LinkedList<>();
|
||||
|
||||
@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,21 @@
|
||||
|
||||
package mjkf.xinke.common.pojo;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
|
||||
/**
|
||||
* 通用包装接口
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:17
|
||||
*/
|
||||
public interface CommonWrapperInterface<T> {
|
||||
|
||||
/**
|
||||
* 执行包装
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:17
|
||||
*/
|
||||
JSONObject doWrap(T wrapperObject);
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
|
||||
package mjkf.xinke.common.prop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 通用基础配置
|
||||
*
|
||||
*
|
||||
* @date 2022/1/2 17:03
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "mjkf-xinke.config.common")
|
||||
public class CommonProperties {
|
||||
|
||||
/** 前端地址 */
|
||||
private String frontUrl;
|
||||
|
||||
/** 后端地址 */
|
||||
private String backendUrl;
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
|
||||
package mjkf.xinke.common.sse;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 通用SSE参数
|
||||
*
|
||||
* @author diantu
|
||||
* @date 2023/7/10
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class CommonSseParam {
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String loginId;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
|
||||
package mjkf.xinke.common.timer;
|
||||
|
||||
/**
|
||||
* 定时器执行者,定时器都要实现本接口,并需要把实现类加入到spring容器中
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 16:09
|
||||
**/
|
||||
public interface CommonTimerTaskRunner {
|
||||
|
||||
/**
|
||||
* 任务执行的具体内容
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 16:09
|
||||
**/
|
||||
void action();
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 通用头像工具类,生成文字头像
|
||||
*
|
||||
*
|
||||
* @date 2022/7/5 17:36
|
||||
**/
|
||||
public class CommonAvatarUtil {
|
||||
|
||||
/**
|
||||
* 绘制字体头像,如果是英文名,只显示首字母大写,
|
||||
* 如果是中文名,只显示最后两个字
|
||||
* 返回图片base64
|
||||
*
|
||||
*
|
||||
* @date 2022/7/5 17:36
|
||||
**/
|
||||
public static String generateImg(String name) {
|
||||
int width = 100;
|
||||
int height = 100;
|
||||
int nameLength = name.length();
|
||||
String nameWritten;
|
||||
// 如果用户输入的姓名少于等于2个字符,不用截取
|
||||
if (nameLength <= 2) {
|
||||
nameWritten = name;
|
||||
} else {
|
||||
// 如果用户输入的姓名大于等于3个字符,截取后面两位
|
||||
String first = StrUtil.sub(name, 0, 1);
|
||||
if (isChinese(first)) {
|
||||
// 截取倒数两位汉字
|
||||
nameWritten = name.substring(nameLength - 2);
|
||||
} else {
|
||||
// 截取前面的两个英文字母
|
||||
nameWritten = StrUtil.sub(name, 0, 1).toUpperCase();
|
||||
}
|
||||
}
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2 = (Graphics2D) bufferedImage.getGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2.setBackground(getRandomColor());
|
||||
g2.clearRect(0, 0, width, height);
|
||||
g2.setPaint(Color.WHITE);
|
||||
Font font;
|
||||
// 两个字及以上
|
||||
if(nameWritten.length() >= 2) {
|
||||
font = new Font("微软雅黑", Font.BOLD, 30);
|
||||
g2.setFont(font);
|
||||
String firstWritten = StrUtil.sub(nameWritten, 0, 1);
|
||||
String secondWritten = StrUtil.sub(nameWritten, 0, 2);
|
||||
// 两个中文 如 言曌
|
||||
if (isChinese(firstWritten) && isChinese(secondWritten)) {
|
||||
g2.drawString(nameWritten, 20, 60);
|
||||
}
|
||||
// 首中次英 如 罗Q
|
||||
else if (isChinese(firstWritten) && !isChinese(secondWritten)) {
|
||||
g2.drawString(nameWritten, 27, 60);
|
||||
// 首英 如 AB
|
||||
} else {
|
||||
nameWritten = nameWritten.substring(0,1);
|
||||
}
|
||||
}
|
||||
// 一个字
|
||||
if(nameWritten.length() == 1) {
|
||||
// 中文
|
||||
if(isChinese(nameWritten)) {
|
||||
font = new Font("微软雅黑", Font.PLAIN, 50);
|
||||
g2.setFont(font);
|
||||
g2.drawString(nameWritten, 25, 70);
|
||||
} else {
|
||||
font = new Font("微软雅黑", Font.PLAIN, 55);
|
||||
g2.setFont(font);
|
||||
g2.drawString(nameWritten.toUpperCase(), 33, 67);
|
||||
}
|
||||
}
|
||||
return ImgUtil.toBase64DataUri(bufferedImage, "jpg");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得随机颜色
|
||||
*
|
||||
*
|
||||
* @date 2022/7/5 17:41
|
||||
**/
|
||||
private static Color getRandomColor() {
|
||||
String[] beautifulColors =
|
||||
new String[]{"114,101,230", "255,191,0", "0,162,174", "245,106,0", "24,144,255", "96,109,128"};
|
||||
String[] color = beautifulColors[RandomUtil.randomInt(beautifulColors.length)].split(StrUtil.COMMA);
|
||||
return new Color(Integer.parseInt(color[0]), Integer.parseInt(color[1]),
|
||||
Integer.parseInt(color[2]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为中文
|
||||
*
|
||||
*
|
||||
* @date 2022/7/5 17:41
|
||||
**/
|
||||
private static boolean isChinese(String str) {
|
||||
String regEx = "[\\u4e00-\\u9fa5]+";
|
||||
Pattern p = Pattern.compile(regEx);
|
||||
Matcher m = p.matcher(str);
|
||||
return m.find();
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import com.antherd.smcrypto.sm2.Sm2;
|
||||
import com.antherd.smcrypto.sm3.Sm3;
|
||||
import com.antherd.smcrypto.sm4.Sm4;
|
||||
import com.antherd.smcrypto.sm4.Sm4Options;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 加密工具类,本框架目前使用 https://github.com/antherd/sm-crypto 项目中一些加解密方式
|
||||
* 使用小伙伴需要过等保密评相关,请在此处更改为自己的加密方法,或加密机,使用加密机同时需要替换公钥,私钥在内部无法导出,提供加密的方法
|
||||
* 如果不涉及到加密机方面的内容,请更改公私要为自己重新生成的,生成方式请看集成的sm-crypto主页
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonCryptogramUtil {
|
||||
|
||||
/** 公钥 */
|
||||
private static final String PUBLIC_KEY = "04298364ec840088475eae92a591e01284d1abefcda348b47eb324bb521bb03b0b2a5bc393f6b71dabb8f15c99a0050818b56b23f31743b93df9cf8948f15ddb54";
|
||||
|
||||
/** 私钥 */
|
||||
private static final String PRIVATE_KEY = "3037723d47292171677ec8bd7dc9af696c7472bc5f251b2cec07e65fdef22e25";
|
||||
|
||||
/** SM4的对称秘钥(生产环境需要改成自己使用的) 16 进制字符串,要求为 128 比特 */
|
||||
private static final String KEY = "0123456789abcdeffedcba9876543210";
|
||||
|
||||
/**
|
||||
* 加密方法(Sm2 的专门针对前后端分离,非对称秘钥对的方式,暴露出去的公钥,对传输过程中的密码加个密)
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 待加密数据
|
||||
* @return 加密后的密文
|
||||
*/
|
||||
public static String doSm2Encrypt(String str) {
|
||||
return Sm2.doEncrypt(str, PUBLIC_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密方法
|
||||
* 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 密文
|
||||
* @return 解密后的明文
|
||||
*/
|
||||
public static String doSm2Decrypt(String str) {
|
||||
// 解密
|
||||
return Sm2.doDecrypt(str, PRIVATE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密方法
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 待加密数据
|
||||
* @return 加密后的密文
|
||||
*/
|
||||
public static String doSm4CbcEncrypt(String str) {
|
||||
// SM4 加密 cbc模式
|
||||
Sm4Options sm4Options4 = new Sm4Options();
|
||||
sm4Options4.setMode("cbc");
|
||||
sm4Options4.setIv("fedcba98765432100123456789abcdef");
|
||||
return Sm4.encrypt(str, KEY, sm4Options4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密方法
|
||||
* 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 密文
|
||||
* @return 解密后的明文
|
||||
*/
|
||||
public static String doSm4CbcDecrypt(String str) {
|
||||
// 解密,cbc 模式,输出 utf8 字符串
|
||||
Sm4Options sm4Options8 = new Sm4Options();
|
||||
sm4Options8.setMode("cbc");
|
||||
sm4Options8.setIv("fedcba98765432100123456789abcdef");
|
||||
String docString = Sm4.decrypt(str, KEY, sm4Options8);
|
||||
if ("".equals(docString)) {
|
||||
log.warn(">>> 字段解密失败,返回原文值:{}", str);
|
||||
return str;
|
||||
} else {
|
||||
return docString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 纯签名
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 待签名数据
|
||||
* @return 签名结果
|
||||
*/
|
||||
public static String doSignature(String str) {
|
||||
return Sm2.doSignature(str, PRIVATE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名结果
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param originalStr 签名原文数据
|
||||
* @param str 签名结果
|
||||
* @return 是否通过
|
||||
*/
|
||||
public static boolean doVerifySignature(String originalStr, String str) {
|
||||
return Sm2.doVerifySignature(originalStr, str, PUBLIC_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过杂凑算法取得hash值,用于做数据完整性保护
|
||||
*
|
||||
*
|
||||
* @date 2022/9/15 21:51
|
||||
* @param str 字符串
|
||||
* @return hash 值
|
||||
*/
|
||||
public static String doHashValue(String str) {
|
||||
return Sm3.sm3(str);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 文件下载工具类,使用本类前,对参数校验的异常使用CommonResponseUtil.renderError()方法进行渲染
|
||||
*
|
||||
*
|
||||
* @date 2020/8/5 21:45
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonDownloadUtil {
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param file 要下载的文件
|
||||
* @param response 响应
|
||||
*
|
||||
* @date 2020/8/5 21:46
|
||||
*/
|
||||
public static void download(File file, HttpServletResponse response) {
|
||||
download(file.getName(), FileUtil.readBytes(file), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
*
|
||||
* @date 2022/7/31 10:57
|
||||
*/
|
||||
public static void download(String fileName, byte[] fileBytes, HttpServletResponse response) {
|
||||
try {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
|
||||
response.addHeader("Content-Length", "" + fileBytes.length);
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
||||
response.setContentType("application/octet-stream;charset=UTF-8");
|
||||
IoUtil.write(response.getOutputStream(), true, fileBytes);
|
||||
} catch (IOException e) {
|
||||
log.error(">>> 文件下载异常:", e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
/**
|
||||
* 通用邮件工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/8/25 15:10
|
||||
**/
|
||||
public class CommonEmailUtil {
|
||||
|
||||
/**
|
||||
* 判断是否邮箱
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 13:32
|
||||
**/
|
||||
public static boolean isEmail(String email) {
|
||||
return Validator.isEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验邮箱格式
|
||||
*
|
||||
*
|
||||
* @date 2022/8/15 13:32
|
||||
**/
|
||||
public static void validEmail(String emails) {
|
||||
StrUtil.split(emails, StrUtil.COMMA).forEach(email -> {
|
||||
if(!isEmail(email)) {
|
||||
throw new CommonException("邮件地址:{}格式错误", email);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* 过滤器异常工具类,用于处理过滤器中的异常
|
||||
* 原理:将异常转发到/errorView进行处理
|
||||
*
|
||||
*
|
||||
* @date 2022/7/18 18:59
|
||||
**/
|
||||
public class CommonFilterExceptionUtil {
|
||||
|
||||
/**
|
||||
* 处理过滤器中的异常
|
||||
*
|
||||
*
|
||||
* @date 2022/7/18 19:00
|
||||
**/
|
||||
public static void handleFilterException(ServletRequest request, ServletResponse response, Exception e) {
|
||||
try {
|
||||
request.setAttribute("model", e);
|
||||
request.getRequestDispatcher("/errorView").forward(request, response);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.net.Ipv4Util;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 根据ip地址定位工具类,离线方式
|
||||
* 参考地址:https://gitee.com/lionsoul/ip2region/tree/master/binding/java
|
||||
*
|
||||
*
|
||||
* @date 2020/3/16 11:25
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonIpAddressUtil {
|
||||
|
||||
private static final String LOCAL_REMOTE_HOST = "0:0:0:0:0:0:0:1";
|
||||
|
||||
private static final Searcher searcher;
|
||||
|
||||
static {
|
||||
String fileName = "/ip2region.xdb";
|
||||
File existFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
|
||||
if(!FileUtil.exist(existFile)) {
|
||||
InputStream resourceAsStream = CommonIpAddressUtil.class.getResourceAsStream(fileName);
|
||||
FileUtil.writeFromStream(resourceAsStream, existFile);
|
||||
}
|
||||
|
||||
String dbPath = existFile.getPath();
|
||||
|
||||
// 1、从 dbPath 加载整个 xdb 到内存。
|
||||
byte[] cBuff;
|
||||
try {
|
||||
cBuff = Searcher.loadContentFromFile(dbPath);
|
||||
} catch (Exception e) {
|
||||
log.error(">>> CommonIpAddressUtil初始化异常:", e);
|
||||
throw new CommonException("CommonIpAddressUtil初始化异常");
|
||||
}
|
||||
|
||||
// 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
|
||||
try {
|
||||
searcher = Searcher.newWithBuffer(cBuff);
|
||||
} catch (Exception e) {
|
||||
log.error(">>> CommonIpAddressUtil初始化异常:", e);
|
||||
throw new CommonException("CommonIpAddressUtil初始化异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端ip
|
||||
*
|
||||
*
|
||||
* @date 2020/3/19 9:32
|
||||
*/
|
||||
public static String getIp(HttpServletRequest request) {
|
||||
if (ObjectUtil.isEmpty(request)) {
|
||||
return Ipv4Util.LOCAL_IP;
|
||||
} else {
|
||||
try {
|
||||
String remoteHost = ServletUtil.getClientIP(request);
|
||||
return LOCAL_REMOTE_HOST.equals(remoteHost) ? Ipv4Util.LOCAL_IP : remoteHost;
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 获取客户端ip异常:", e);
|
||||
return Ipv4Util.LOCAL_IP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IP地址离线获取城市
|
||||
*
|
||||
*
|
||||
* @date 2022/4/27 23:14
|
||||
*/
|
||||
public static String getCityInfo(String ip) {
|
||||
try {
|
||||
ip = ip.trim();
|
||||
// 3、执行查询
|
||||
String region = searcher.searchByStr(ip);
|
||||
return region.replace("0|", "").replace("|0", "");
|
||||
} catch (Exception e) {
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring切面工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:51
|
||||
*/
|
||||
public class CommonJoinPointUtil {
|
||||
|
||||
/**
|
||||
* 获取切面的参数JSON
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:51
|
||||
*/
|
||||
public static String getArgsJsonString(JoinPoint joinPoint) {
|
||||
Signature signature = joinPoint.getSignature();
|
||||
// 参数名数组
|
||||
String[] parameterNames = ((MethodSignature) signature).getParameterNames();
|
||||
// 构造参数组集合
|
||||
Map<String, Object> map = MapUtil.newHashMap();
|
||||
Object[] args = joinPoint.getArgs();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if(ObjectUtil.isNotEmpty(args[i]) && isUsefulParam(args[i])) {
|
||||
if(JSONUtil.isTypeJSON(StrUtil.toString(args[i]))) {
|
||||
map.put(parameterNames[i], JSONUtil.parseObj(args[i]));
|
||||
} else {
|
||||
map.put(parameterNames[i], JSONUtil.toJsonStr(args[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return JSONUtil.toJsonStr(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要拼接的参数,过滤掉HttpServletRequest,MultipartFile,HttpServletResponse等类型参数
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:51
|
||||
*/
|
||||
private static boolean isUsefulParam(Object arg) {
|
||||
return !(arg instanceof MultipartFile) &&
|
||||
!(arg instanceof HttpServletRequest) &&
|
||||
!(arg instanceof HttpServletResponse);
|
||||
}
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 通用获取当前网速工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/1 23:45
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonNetWorkInfoUtil {
|
||||
|
||||
/**
|
||||
* 网速测速时间2s
|
||||
*/
|
||||
private static final int SLEEP_SECONDS = 2;
|
||||
|
||||
/**
|
||||
* 获取网络上下行速率,格式{"UP": "123KB/S, "DOWN": "345KB/S"}
|
||||
*
|
||||
*
|
||||
* @date 2022/9/1 23:51
|
||||
*/
|
||||
public static Map<String, String> getNetworkUpRate() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
Process pro = null;
|
||||
Runtime r = Runtime.getRuntime();
|
||||
BufferedReader input = null;
|
||||
try {
|
||||
boolean isWindows = SystemUtil.getOsInfo().isWindows();
|
||||
String command = isWindows ? "netstat -e" : "ifconfig";
|
||||
pro = r.exec(command);
|
||||
input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
|
||||
long[] result1 = readInLine(input, isWindows);
|
||||
Thread.sleep(SLEEP_SECONDS * 1000);
|
||||
pro.destroy();
|
||||
input.close();
|
||||
pro = r.exec(command);
|
||||
input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
|
||||
long[] result2 = readInLine(input, isWindows);
|
||||
String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
|
||||
.div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
|
||||
String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
|
||||
.div(NumberUtil.sub(result2[1], result1[1]), SLEEP_SECONDS)));
|
||||
result.put("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
|
||||
result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
|
||||
} catch (Exception e) {
|
||||
log.info(">>> 网络测速失败:", e);
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
log.info(">>> 网络测速失败:", e);
|
||||
}
|
||||
}
|
||||
Optional.ofNullable(pro).ifPresent(Process::destroy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String formatNumber(double f) {
|
||||
return new Formatter().format("%.2f", f).toString();
|
||||
}
|
||||
|
||||
private static long[] readInLine(BufferedReader input, boolean isWindows) {
|
||||
long[] arr = new long[2];
|
||||
StringTokenizer tokenStat;
|
||||
try {
|
||||
if (isWindows) {
|
||||
// 获取windows环境下的网口上下行速率
|
||||
input.readLine();
|
||||
input.readLine();
|
||||
input.readLine();
|
||||
input.readLine();
|
||||
tokenStat = new StringTokenizer(input.readLine());
|
||||
tokenStat.nextToken();
|
||||
arr[0] = Long.parseLong(tokenStat.nextToken());
|
||||
arr[1] = Long.parseLong(tokenStat.nextToken());
|
||||
} else {
|
||||
// 获取linux环境下的网口上下行速率
|
||||
long rx = 0, tx = 0;
|
||||
String line = null;
|
||||
//RX packets:4171603 errors:0 dropped:0 overruns:0 frame:0
|
||||
//TX packets:4171603 errors:0 dropped:0 overruns:0 carrier:0
|
||||
while ((line = input.readLine()) != null) {
|
||||
if (line.contains("RX packets")) {
|
||||
rx += Long.parseLong(line.substring(line.indexOf("RX packets") + 11, line.indexOf(" ",
|
||||
line.indexOf("RX packets") + 11)));
|
||||
} else if (line.contains("TX packets")) {
|
||||
tx += Long.parseLong(line.substring(line.indexOf("TX packets") + 11, line.indexOf(" ",
|
||||
line.indexOf("TX packets") + 11)));
|
||||
}
|
||||
}
|
||||
arr[0] = rx;
|
||||
arr[1] = tx;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 网络测速异常:", e);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import mjkf.xinke.common.pojo.CommonResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 通用响应工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 9:40
|
||||
**/
|
||||
public class CommonResponseUtil {
|
||||
|
||||
/**
|
||||
* 以流的方式响应错误信息,默认错误消息
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 9:41
|
||||
**/
|
||||
public static void renderError(HttpServletResponse response) throws IOException {
|
||||
renderError(response, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以流的方式响应错误信息,指定错误消息
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 9:41
|
||||
**/
|
||||
public static void renderError(HttpServletResponse response, String msg) throws IOException {
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(ObjectUtil.isNotEmpty(msg)?CommonResult.error(msg):CommonResult.error()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以流的方式响应错误信息,指定错误码和错误消息
|
||||
*
|
||||
*
|
||||
* @date 2022/8/4 9:41
|
||||
**/
|
||||
public static void renderError(HttpServletResponse response, Integer code, String msg) throws IOException {
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(CommonResult.get(code, msg, null)));
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import mjkf.xinke.common.exception.CommonException;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* HttpServlet工具类,获取当前request和response
|
||||
*
|
||||
*
|
||||
* @date 2020/3/30 15:09
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonServletUtil {
|
||||
|
||||
/**
|
||||
* 从请求中中获取参数
|
||||
*
|
||||
*
|
||||
* @date 2021/10/14 10:44
|
||||
**/
|
||||
public static String getParamFromRequest(String paramName) {
|
||||
HttpServletRequest request = getRequest();
|
||||
|
||||
// 1. 尝试从请求体里面读取
|
||||
String paramValue = request.getParameter(paramName);
|
||||
|
||||
// 2. 尝试从header里读取
|
||||
if (ObjectUtil.isEmpty(paramValue)) {
|
||||
paramValue = request.getHeader(paramName);
|
||||
}
|
||||
// 3. 尝试从cookie里读取
|
||||
if (ObjectUtil.isEmpty(paramValue)) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if(ObjectUtil.isNotEmpty(cookies)) {
|
||||
for (Cookie cookie : cookies) {
|
||||
String cookieName = cookie.getName();
|
||||
if (cookieName.equals(paramName)) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4. 返回
|
||||
return paramValue;
|
||||
}
|
||||
|
||||
public static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes servletRequestAttributes;
|
||||
try {
|
||||
servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 非Web上下文无法获取Request:", e);
|
||||
throw new CommonException("非Web上下文无法获取Request");
|
||||
}
|
||||
if (servletRequestAttributes == null) {
|
||||
throw new CommonException("非Web上下文无法获取Request");
|
||||
} else {
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpServletResponse getResponse() {
|
||||
ServletRequestAttributes servletRequestAttributes;
|
||||
try {
|
||||
servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
} catch (Exception e) {
|
||||
log.error(">>> 非Web上下文无法获取Response:", e);
|
||||
throw new CommonException("非Web上下文无法获取Response");
|
||||
}
|
||||
if (servletRequestAttributes == null) {
|
||||
throw new CommonException("非Web上下文无法获取Response");
|
||||
} else {
|
||||
return servletRequestAttributes.getResponse();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWeb() {
|
||||
return RequestContextHolder.getRequestAttributes() != null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,172 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间格式化工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/6/24 15:28
|
||||
**/
|
||||
public class CommonTimeFormatUtil {
|
||||
|
||||
private static final long ONE_MINUTE_SECONDS = 60;
|
||||
|
||||
private static final int BEFORE_DAWN_HOUR = 6;
|
||||
|
||||
private static final int MORNING_END_HOUR = 12;
|
||||
|
||||
private static final int NOON_END_HOUR = 13;
|
||||
|
||||
private static final int AFTERNOON_END_HOUR = 18;
|
||||
|
||||
private static final int NIGHT_END_HOUR = 24;
|
||||
|
||||
/**
|
||||
* 将日期格式化为仿微信的日期
|
||||
*
|
||||
*
|
||||
* @date 2022/6/24 15:28
|
||||
**/
|
||||
public static String formatWxPastTime(Date date) {
|
||||
if (DateUtil.between(date, DateUtil.date(), DateUnit.SECOND, false) < 0) {
|
||||
//今天之后的时间显示年月日时分
|
||||
return DateUtil.format(date, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
|
||||
} else {
|
||||
//如果是今年
|
||||
if (DateUtil.thisYear() == DateUtil.year(date)) {
|
||||
//如果是今天
|
||||
if (DateUtil.isSameDay(date, DateUtil.date())) {
|
||||
//相差分钟数
|
||||
long betweenMinute = DateUtil.between(date, DateUtil.date(), DateUnit.MINUTE);
|
||||
//如果在1小时之内
|
||||
if (betweenMinute < ONE_MINUTE_SECONDS) {
|
||||
//一分钟之内,显示刚刚
|
||||
if (betweenMinute < 1) {
|
||||
return "刚刚";
|
||||
} else {
|
||||
//一分钟之外,显示xx分钟前
|
||||
return betweenMinute + "分钟前";
|
||||
}
|
||||
} else {
|
||||
//一小时之外,显示时分
|
||||
return getTodayHour(date) + " " + DateUtil.format(date, "HH:mm");
|
||||
}
|
||||
} else if (DateUtil.isSameDay(date, DateUtil.yesterday())) {
|
||||
//如果是昨天,显示昨天时分
|
||||
return "昨天 " + DateUtil.format(date, "HH:mm");
|
||||
} else if (isThisWeek(date)) {
|
||||
//如果是本周
|
||||
String weekday;
|
||||
//获取是本周的第几天
|
||||
int dayOfWeek = DateUtil.dayOfWeek(date) - 1;
|
||||
switch (dayOfWeek) {
|
||||
case 1:
|
||||
weekday = "周一";
|
||||
break;
|
||||
case 2:
|
||||
weekday = "周二";
|
||||
break;
|
||||
case 3:
|
||||
weekday = "周三";
|
||||
break;
|
||||
case 4:
|
||||
weekday = "周四";
|
||||
break;
|
||||
case 5:
|
||||
weekday = "周五";
|
||||
break;
|
||||
case 6:
|
||||
weekday = "周六";
|
||||
break;
|
||||
default:
|
||||
weekday = "周日";
|
||||
break;
|
||||
}
|
||||
//显示本周时分
|
||||
return weekday + " " + DateUtil.format(date, "HH:mm");
|
||||
} else {
|
||||
//否则显示月日时分
|
||||
return DateUtil.format(date, "MM-dd HH:mm");
|
||||
}
|
||||
} else {
|
||||
//本年之外显示年月日时分
|
||||
return DateUtil.format(date, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将秒数格式化为天时分秒
|
||||
*
|
||||
*
|
||||
* @date 2022/6/24 15:29
|
||||
**/
|
||||
public static String formatSeconds(long secondsParam) {
|
||||
String result;
|
||||
long days = secondsParam / ( ONE_MINUTE_SECONDS * ONE_MINUTE_SECONDS * NIGHT_END_HOUR);
|
||||
long hours = (secondsParam % ( ONE_MINUTE_SECONDS * ONE_MINUTE_SECONDS * NIGHT_END_HOUR)) / (ONE_MINUTE_SECONDS * ONE_MINUTE_SECONDS);
|
||||
long minutes = (secondsParam % ( ONE_MINUTE_SECONDS * ONE_MINUTE_SECONDS)) /ONE_MINUTE_SECONDS;
|
||||
long seconds = secondsParam % ONE_MINUTE_SECONDS;
|
||||
if(days > 0) {
|
||||
result = days + "天" + hours + "小时" + minutes + "分钟" + seconds + "秒";
|
||||
} else if(hours > 0) {
|
||||
result = hours + "小时" + minutes + "分钟" + seconds + "秒";
|
||||
} else if(minutes > 0) {
|
||||
result = minutes + "分钟" + seconds + "秒";
|
||||
} else {
|
||||
result = seconds + "秒";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断日期是否是本周
|
||||
*
|
||||
* @param date 要判断的日期
|
||||
* @return boolean
|
||||
*
|
||||
* @date 2020/8/6 12:10
|
||||
**/
|
||||
private static boolean isThisWeek(Date date) {
|
||||
//获取本周开始时间
|
||||
DateTime beginOfWeek = DateUtil.beginOfWeek(DateUtil.date());
|
||||
//获取与本周开始时间相差的天数
|
||||
long betweenBegin = DateUtil.between(date, beginOfWeek, DateUnit.DAY, false) + 1;
|
||||
//如果是同一天,或相差天数小于0,则是本周
|
||||
return DateUtil.isSameDay(date, beginOfWeek) || betweenBegin < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据今天日期获取早中晚
|
||||
*
|
||||
*
|
||||
* @date 2020/8/6 14:42
|
||||
**/
|
||||
private static String getTodayHour(Date date) {
|
||||
String result = "";
|
||||
int hour = DateUtil.hour(date, true);
|
||||
if (hour >= 0 && hour <= BEFORE_DAWN_HOUR) {
|
||||
result = "凌晨";
|
||||
}
|
||||
if (hour > BEFORE_DAWN_HOUR && hour < MORNING_END_HOUR) {
|
||||
result = "上午";
|
||||
}
|
||||
if (hour == MORNING_END_HOUR) {
|
||||
result = "中午";
|
||||
}
|
||||
if (hour >= NOON_END_HOUR && hour <= AFTERNOON_END_HOUR) {
|
||||
result = "下午";
|
||||
}
|
||||
if (hour > AFTERNOON_END_HOUR && hour <= NIGHT_END_HOUR) {
|
||||
result = "晚上";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
|
||||
package mjkf.xinke.common.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.http.useragent.Browser;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 用户代理工具类
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:34
|
||||
*/
|
||||
public class CommonUaUtil {
|
||||
|
||||
/**
|
||||
* 获取客户端浏览器
|
||||
*
|
||||
*
|
||||
* @date 2020/3/19 14:53
|
||||
*/
|
||||
public static String getBrowser(HttpServletRequest request) {
|
||||
UserAgent userAgent = getUserAgent(request);
|
||||
if (ObjectUtil.isEmpty(userAgent)) {
|
||||
return StrUtil.DASHED;
|
||||
} else {
|
||||
String browser = userAgent.getBrowser().toString();
|
||||
return "Unknown".equals(browser) ? StrUtil.DASHED : browser;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端操作系统
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:36
|
||||
*/
|
||||
public static String getOs(HttpServletRequest request) {
|
||||
UserAgent userAgent = getUserAgent(request);
|
||||
if (ObjectUtil.isEmpty(userAgent)) {
|
||||
return StrUtil.DASHED;
|
||||
} else {
|
||||
String os = userAgent.getOs().toString();
|
||||
return "Unknown".equals(os) ? StrUtil.DASHED : os;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求代理头
|
||||
*
|
||||
*
|
||||
* @date 2022/9/2 15:36
|
||||
*/
|
||||
private static UserAgent getUserAgent(HttpServletRequest request) {
|
||||
String userAgentStr = ServletUtil.getHeaderIgnoreCase(request, "User-Agent");
|
||||
UserAgent userAgent = UserAgentUtil.parse(userAgentStr);
|
||||
if (ObjectUtil.isNotEmpty(userAgentStr)) {
|
||||
if ("Unknown".equals(userAgent.getBrowser().getName())) {
|
||||
userAgent.setBrowser(new Browser(userAgentStr, null, ""));
|
||||
}
|
||||
}
|
||||
return userAgent;
|
||||
}
|
||||
}
|
BIN
mjkf-xinke-common/src/main/resources/ip2region.xdb
Normal file
BIN
mjkf-xinke-common/src/main/resources/ip2region.xdb
Normal file
Binary file not shown.
Reference in New Issue
Block a user