feat:V3.1.1整合remi-comm到remi-cloud中

This commit is contained in:
dianjiu
2024-09-11 17:41:17 +08:00
parent e111c59a69
commit 28d62f6cf4
245 changed files with 20975 additions and 154 deletions

View File

@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>remi-comm-util</artifactId>
<name>remi-comm-util</name>
<description>remi-comm-util</description>
<parent>
<groupId>ai.remi.top.cloud</groupId>
<artifactId>remi-comm</artifactId>
<version>3.1.1</version>
</parent>
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
<distributionManagement>
<repository>
<id>maven-releases</id>
<name>release</name>
<url>https://repository.njydsz.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-snapshots</id>
<name>snapshot</name>
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<dependencies>
<!--common-core-->
<dependency>
<groupId>ai.remi.top.cloud</groupId>
<artifactId>remi-comm-core</artifactId>
</dependency>
<!-- Jaxb -->
<dependency>
<artifactId>jaxb-api</artifactId>
<groupId>javax.xml.bind</groupId>
</dependency>
<!--fastjson-->
<dependency>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
</dependency>
<!-- gson -->
<dependency>
<artifactId>gson</artifactId>
<groupId>com.google.code.gson</groupId>
</dependency>
<!--jackson-core -->
<dependency>
<artifactId>jackson-core</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</dependency>
<dependency>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</dependency>
<dependency>
<artifactId>jackson-databind</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</dependency>
<!--user-agent-->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!--ip2region-->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
</dependency>
<!--监控相关-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
</dependency>
<!--hutool-->
<dependency>
<artifactId>hutool-core</artifactId>
<groupId>cn.hutool</groupId>
</dependency>
<dependency>
<artifactId>hutool-extra</artifactId>
<groupId>cn.hutool</groupId>
</dependency>
<dependency>
<artifactId>hutool-all</artifactId>
<groupId>cn.hutool</groupId>
</dependency>
<!--okhttp3-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<!-- httpclient -->
<dependency>
<artifactId>httpclient</artifactId>
<groupId>org.apache.httpcomponents</groupId>
</dependency>
<!--javax-->
<dependency>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</dependency>
<!-- dom4j -->
<dependency>
<artifactId>dom4j</artifactId>
<groupId>org.dom4j</groupId>
</dependency>
<!-- commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</dependency>
<dependency>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</dependency>
<dependency>
<artifactId>commons-net</artifactId>
<groupId>commons-net</groupId>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
</dependency>
<dependency>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</dependency>
<dependency>
<artifactId>commons-fileupload</artifactId>
<groupId>commons-fileupload</groupId>
</dependency>
<!--slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--easyexcel-->
<dependency>
<artifactId>easyexcel</artifactId>
<groupId>com.alibaba</groupId>
</dependency>
<!--validator-->
<dependency>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</dependency>
<dependency>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate</groupId>
</dependency>
<!--reactor-->
<dependency>
<artifactId>reactor-core</artifactId>
<groupId>io.projectreactor</groupId>
</dependency>
<!--spring-web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,705 @@
package ai.remi.comm.util.array;
import cn.hutool.core.collection.CollectionUtil;
import java.lang.reflect.Array;
import java.util.*;
public class ArrayUtils {
/**
* 判断数组是否为空
*
* @param array 数组
* @return 布尔值
*/
public static boolean isNotEmpty(Object[] array) {
return !isEmpty(array);
}
/**
* 判断数组是否非空
*
* @param array 数组
* @return 返回布尔值
*/
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(boolean[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(byte[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(char[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(double[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(float[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(int[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(long[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为空
*
* @param array 数组
* @return 若数组为null, 或长度为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(short[] array) {
return array == null || array.length == 0;
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(boolean[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(byte[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(char[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(double[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(float[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(int[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(long[] array) {
return !isEmpty(array);
}
/**
* 数组是否为不空
*
* @param array 数组
* @return 若数组不为null, 而且长度不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(short[] array) {
return !isEmpty(array);
}
/**
* 判断参数是否是一个数组
*
* @param obj 对象
* @return 布尔值
*/
public static boolean isArray(Object obj) {
return obj != null && obj.getClass().isArray();
}
/**
* 将参数组装成数组
*
* @param obj 参数对象
* @return 返回对象数组
*/
public static <E> E[] asArray(E... obj) {
return obj;
}
/**
* 将参数集合转换为数组表示
*
* @param collection 集合参数
* @return 布尔值
*/
public static <E> E[] asArray(Collection<E> collection) {
if (collection == null || collection.size() == 0) {
return null;
}
int length = collection.size();
E e = collection.iterator().next();
@SuppressWarnings("unchecked")
E[] array = (E[]) Array.newInstance(e.getClass(), length);
return collection.toArray(array);
}
/**
* 获取数组元素的实际数据类型
*
* @param array 数组
* @return 布尔值
*/
public static <E> Class<E> getElementType(E[] array) {
Class<?> clas = array.getClass();
Class<E> type = (Class<E>) clas.getComponentType();
return type;
}
/**
* 获取数组元素的实际数据类型
*
* @param array 数组
* @return 布尔值
*/
public static Class<?> getElementType(Object array) {
if (!isArray(array)) {
throw new IllegalArgumentException("argument must be an array");
}
return array.getClass().getComponentType();
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static <E> List<E> toList(E[] array) {
return Arrays.asList(array);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Boolean> toList(boolean[] array) {
int length = Array.getLength(array);
return asList(new Boolean[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Byte> toList(byte[] array) {
int length = Array.getLength(array);
return asList(new Byte[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Character> toList(char[] array) {
int length = Array.getLength(array);
return asList(new Character[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Double> toList(double[] array) {
int length = Array.getLength(array);
return asList(new Double[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Float> toList(float[] array) {
int length = Array.getLength(array);
return asList(new Float[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Integer> toList(int[] array) {
int length = Array.getLength(array);
return asList(new Integer[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Long> toList(long[] array) {
int length = Array.getLength(array);
return asList(new Long[length], array, length);
}
/**
* 数组转化为List
*
* @param array 数组
* @return 布尔值
*/
public static List<Short> toList(short[] array) {
int length = Array.getLength(array);
return asList(new Short[length], array, length);
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return
*/
public static <E> boolean contains(E[] array, E arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 布尔值
*/
public static boolean contains(byte[] array, byte arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 布尔值
*/
public static boolean contains(char[] array, char arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 布尔值
*/
public static boolean contains(short[] array, short arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 返回布尔值
*/
public static boolean contains(int[] array, int arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 返回布尔值
*/
public static boolean contains(long[] array, long arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 返回布尔值
*/
public static boolean contains(float[] array, float arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 返回布尔值
*/
public static boolean contains(double[] array, double arg) {
return indexOf(array, arg) >= 0;
}
/**
* 数组元素中是否包含参数对象
*
* @param array 数组
* @param arg 元素参数
* @return 返回布尔值
*/
public static boolean contains(boolean[] array, boolean arg) {
return indexOf(array, arg) >= 0;
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static <E> int indexOf(E[] array, E element) {
int size = array.length;
if (element == null) {
for (int i = 0; i < size; i++) {
if (array[i] == null) {
return i;
}
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(array[i])) {
return i;
}
}
}
return -1;
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(boolean[] array, boolean element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(byte[] array, byte element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(char[] array, char element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(double[] array, double element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(float[] array, float element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(int[] array, int element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(long[] array, long element) {
return indexFrom(array, element);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
public static int indexOf(short[] array, short element) {
return indexFrom(array, element);
}
/**
* 列举
*
* @param array 数组
* @return
*/
public static <E> Enumeration<E> enumeration(E[] array) {
return new ArrayEnumeration<E>(array);
}
/**
* 元素所在数组的索引
*
* @param array 数组
* @param element 元素
* @return 若数组中不存在该元素, 则返回-1
*/
private static int indexFrom(Object array, Object element) {
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
Object e = Array.get(array, i);
if (element.equals(e)) {
return i;
}
}
return -1;
}
/**
* 数组转化为List
*
* @param target 目标数组
* @param origin 源数组对象
* @param length 数组长度
* @return
*/
private static <E> List<E> asList(E[] target, Object origin, int length) {
// java.lang.ArrayStoreException
// System.arraycopy(origin, 0, target, 0, length);
for (int i = 0; i < length; i++) {
target[i] = (E) Array.get(origin, i);
}
return Arrays.asList(target);
}
/**
* 获取int的list中的最大值
*
* @param list
* @return 返回int最大值
*/
private static int getListMaxValue(List<Integer> list) {
return Collections.max(list);
}
/**
* 获取int的list中的最大值的下标
*
* @param list
* @return 返回int最大值
*/
private static int getListMaxValueIndex(List<Integer> list) {
int max = list.get(0);
// 最大值下标
int max_a = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) > list.get(max_a)) {
max = list.get(i);
max_a = i;
}
}
return max_a;
}
/**
* 获取int的list中的最小值
*
* @param list
* @return 返回int最小值
*/
private static int getListMinValue(List<Integer> list) {
return Collections.min(list);
}
/**
* 获取int的list中的最大值的下标
*
* @param list list
* @return 返回int最下值的下标
*/
private static int getListMinValueIndex(List<Integer> list) {
int min = list.get(0);
// 最大值下标
int min_a = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) < list.get(min_a)) {
min_a = i;
}
}
return min_a;
}
/**
* 数组列举
*/
private static class ArrayEnumeration<E> implements Enumeration<E> {
private E[] es;
private int index;
private int length;
private ArrayEnumeration(E[] es) {
this.es = es;
this.length = es.length;
}
@Override
public boolean hasMoreElements() {
return index < length;
}
@Override
public E nextElement() {
return es[index++];
}
}
/**
* 链表中随机选择一定数量的元素
*
* @param list 对象链表
* @param num 选择链表长度
* @return 字符串链表
*/
public static <T> List<T> getRandomList(List<T> list, int num) {
if (CollectionUtil.isEmpty(list)) {
return new ArrayList<>();
}
if (list.size() <= num) {
return list;
}
Collections.shuffle(list);
return list.subList(0, num);
}
}

View File

@@ -0,0 +1,157 @@
package ai.remi.comm.util.array;
import java.util.Arrays;
public class SortUtils {
/**
* 如果找到了直接进行返回,如果没有找到就继续去找
*
* @param arr 数组
* @param key 关键字
* @return 位置
*/
public static int binarySearch(int[] arr, int key) {
int i = 0;
int j = arr.length - 1;
while (i < j) {
int middle = i + (j - i) / 2; //防止middle的和超过Integer.MAX_VALUE的值
if (key > arr[middle]) {
i = middle + 1;
} else if (key < arr[middle]) {
j = middle - 1;
} else {
return middle;
}
}
return -1;
}
/**
* 选择排序
*
* @param arr 数组
* @return int[] 数组
*/
public static int[] selectSort(int[] arr) {
if(arr == null || arr.length < 2) {
return arr;
}
int len = arr.length;
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
if (arr[i] > arr[j]) {
swap(arr, i, j);
}
}
}
return arr;
}
/**
* 快速排序
*
* @param arr 数组
*/
public static void quickSort(int[] arr) {
int low = 0;
int high = arr.length - 1;
quickSortHelper(arr, low, high);
}
/**
* 快速排序,递归算法
*
* @param arr 数组
* @param low 低位
* @param high 高位
*/
public static void quickSortHelper(int[] arr, int low, int high) {
int start = low;
int end = high;
int key = arr[start];
while (start < end) {
// 要从尾到前面进行比较
while (start < end && arr[end] >= key) {
end--;
}
if (arr[end] <= key) {
swap(arr, start, end);
}
// 要从前到后进行比较
while (start < end && arr[start] <= key) {
start++;
}
if (arr[start] >= key) {
swap(arr, start, end);
}
}
if (start > low) {
quickSortHelper(arr, low, start - 1);
}
if (end < high) {
quickSortHelper(arr, end + 1, high);
}
}
/**
* 快速排序,递归算法
*
* @param arr 输入数组
* @return 新数组
*/
public static int[] quickSort2(int[] arr) {
if (arr == null || arr.length < 2) {
return arr;
}
int pivot = arr[arr.length / 2];
int[] left = Arrays.stream(arr).boxed().filter(e -> e < pivot).mapToInt(e -> e).toArray();
int[] middle = Arrays.stream(arr).boxed().filter(e -> e == pivot).mapToInt(e -> e).toArray();
int[] right = Arrays.stream(arr).boxed().filter(e -> e > pivot).mapToInt(e -> e).toArray();
return concat(quickSort2(left), middle, quickSort2(right));
}
/**
* 冒泡排序
*
* @param arr 数组
*/
public static void bubbleSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
int len = arr.length;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}
/**
* 交换他们数字的值
*
* @param arr 数组
* @param i 位置i
* @param j 位置j
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static int[] concat(int[] left, int[] middle, int[] right) {
int totalLength = left.length + middle.length + right.length;
int[] result = new int[totalLength];
System.arraycopy(left, 0, result, 0, left.length);
System.arraycopy(middle, 0, result, left.length, middle.length);
System.arraycopy(right, 0, result, left.length + middle.length, right.length);
return result;
}
}

View File

@@ -0,0 +1,220 @@
package ai.remi.comm.util.asserts;
import ai.remi.comm.util.collection.CollectionUtils;
import ai.remi.comm.util.object.ObjectUtils;
import ai.remi.comm.util.string.StringUtils;
import lombok.SneakyThrows;
import java.util.Collection;
import java.util.Map;
/**
* 断言工具类
*/
public class AssertUtils {
/**
* 如果不是true,则抛异常
* @param expression
* @param msg
*/
@SneakyThrows
public static void isTrue(boolean expression, String msg) {
if (!expression) {
throw new RuntimeException(msg);
}
}
/**
* 如果不是false,则抛异常
* @param expression
* @param msg
*/
@SneakyThrows
public static void isFalse(boolean expression, String msg) {
if (expression) {
throw new RuntimeException(msg);
}
}
/**
* 如果不是空或者空字符串,则抛异常
* @param str
* @param msg
*/
@SneakyThrows
public static void isEmpty(String str, String msg) {
if (StringUtils.hasText(str)) {
throw new RuntimeException(msg);
}
}
/**
* 如果是空或者空字符串,则抛异常
* @param str
* @param msg
*/
@SneakyThrows
public static void isNotEmpty(String str, String msg) {
if (!StringUtils.hasText(str)) {
throw new RuntimeException(msg);
}
}
/**
* 如果数组为不空或者长度大于等于1,则抛异常
* @param str
* @param msg
*/
@SneakyThrows
public static void isEmpty(Object[] str, String msg) {
if (!ObjectUtils.isEmpty(str)) {
throw new RuntimeException(msg);
}
}
/**
* 如果数组为空或者长度小于1,则抛异常
* @param str
* @param msg
*/
@SneakyThrows
public static void isNotEmpty(Object[] str, String msg) {
if (ObjectUtils.isEmpty(str)) {
throw new RuntimeException(msg);
}
}
/**
* 如果集合不为空或者长度大于等于1,则抛异常
* @param collection
* @param msg
*/
@SneakyThrows
public static void isEmpty(Collection collection, String msg) {
if (CollectionUtils.isNotEmpty(collection)) {
throw new RuntimeException(msg);
}
}
/**
* 如果集合为空或者长度小于1,则抛异常
* @param collection
* @param msg
*/
@SneakyThrows
public static void isNotEmpty(Collection collection, String msg) {
if (CollectionUtils.isEmpty(collection)) {
throw new RuntimeException(msg);
}
}
/**
* 如果集合不为空或者长度大于等于1,则抛异常
* @param map
* @param msg
*/
@SneakyThrows
public static void isEmpty(Map map, String msg) {
if (CollectionUtils.isNotEmpty(map)) {
throw new RuntimeException(msg);
}
}
/**
* 如果集合为空或者长度小于1,则抛异常
* @param map
* @param msg
*/
@SneakyThrows
public static void isNotEmpty(Map map, String msg) {
if (CollectionUtils.isEmpty(map)) {
throw new RuntimeException(msg);
}
}
/**
* 如果对象不为空,则抛异常
* @param object
* @param msg
*/
@SneakyThrows
public static void isNull(Object object, String msg){
if (object != null) {
throw new RuntimeException(msg);
}
}
/**
* 如果对象空,则抛异常
* @param object
* @param msg
*/
@SneakyThrows
public static void isNotNull(Object object, String msg){
if (object == null) {
throw new RuntimeException(msg);
}
}
/**
* 如果对象不为空,则抛异常
* @param objects
* @param msg
*/
@SneakyThrows
public static void isNull(Object[] objects, String msg) {
if (!ObjectUtils.isEmpty(objects)) {
throw new RuntimeException(msg);
}
}
/**
* 如果对象空,则抛异常
* @param objects
* @param msg
*/
@SneakyThrows
public static void isNotNull(Object[] objects, String msg) {
if (ObjectUtils.isEmpty(objects)) {
throw new RuntimeException(msg);
}
}
/**
* 比较对象
* @param obj1
* @param obj2
* @param msg
*/
@SneakyThrows
public static void equals(Object obj1, Object obj2, String msg) {
if (!equals(obj1, obj2)) {
throw new RuntimeException(msg);
}
}
/**
* 比较对象的相等
* @param cs1
* @param cs2
* @return
*/
public static boolean equals(final Object cs1, final Object cs2) {
if (cs1 == cs2) {
return true;
}
if (null == cs1 && null != cs2) {
return false;
}
if (null != cs1 && null == cs2) {
return false;
}
if (cs1 == null || null == cs2) {
return true;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
return cs1.equals(cs2);
}
}

View File

@@ -0,0 +1,48 @@
package ai.remi.comm.util.auth;
import ai.remi.comm.core.enums.IdentityTypeEnum;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc AuthInfo
*/
public interface AuthInfo {
/**
* 用户系统语言
*/
String getUserLanguage();
/**
* 用户唯一标识
*/
String getUniqueId();
/**
* 部门租户号
*/
String getDeptTenantId();
/**
* 公司租户号
*/
String getCompanyTenantId();
/**
* 身份类型
*/
IdentityTypeEnum getIdentityTypeEnum();
/**
* 服务类型
*/
String getServiceTypeCode();
/**
* 鉴权Token
* @return
*/
String getAccessToken();
}

View File

@@ -0,0 +1,120 @@
package ai.remi.comm.util.auth;
import ai.remi.comm.core.enums.IdentityTypeEnum;
import ai.remi.comm.core.enums.PermissionScopeEnum;
import java.util.Set;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc AuthInfoUtils
*/
public class AuthInfoUtils {
/**
* 获取认证信息
*/
public static AuthInfo getAuthInfo() {
return RequestHolder.getAuthInfo();
}
/**
* 获取用户语言
*/
public static String getUserLanguage() {
return RequestHolder.getAuthInfo().getUserLanguage();
}
/**
* 鉴权Token
* @return
*/
public static String getAccessToken() {
return RequestHolder.getCompanyAuthInfo().getAccessToken();
}
/**
* 获取用户唯一id 对应 {@link IdentityTypeEnum}
*/
public static String getUniqueId() {
return RequestHolder.getAuthInfo().getUniqueId();
}
/**
* 获取部门租户号
*/
public static String getDeptTenantId() {
return RequestHolder.getAuthInfo().getDeptTenantId();
}
/**
* 获取公司租户号
*/
public static String getCompanyTenantId() {
return RequestHolder.getAuthInfo().getCompanyTenantId();
}
/**
* 获取用户类型 瑞米官方账户、集团公司账户、访客体验用户
*/
public static IdentityTypeEnum getIdentityTypeEnum() {
return RequestHolder.getAuthInfo().getIdentityTypeEnum();
}
/**
* 获取当前服务类型,主要是给feign调用内部服务时使用
*/
public static String getServiceTypeCode() {
return RequestHolder.getAuthInfo().getServiceTypeCode();
}
/**
* 获取权限范围
*/
public static PermissionScopeEnum getPermissionScopeEnum() {
return RequestHolder.getCompanyAuthInfo().getPermissionScope();
}
/**
* 当权限范围为 {@link PermissionScopeEnum } 时,
* 为当前请求可操作、查询的公司id集合
*/
public static Set<String> getHasPermissionCompanyIds() {
return RequestHolder.getCompanyAuthInfo().getHasPermissionCompanyIds();
}
/**
* 获取瑞米信息
*
* @return 瑞米信息
* @createTime 2022/1/6 19:35
*/
//public static CustomerAuthInfo getCustomerAuthInfo() {
// return RequestHolder.getCustomerAuthInfo();
//}
/**
* 获取公司信息
*
* @return 客户信息
* @createTime 2022/1/6 19:35
*/
public static CompanyAuthInfo getCompanyAuthInfo() {
return RequestHolder.getCompanyAuthInfo();
}
/**
* 获取信息
*
* @return 访客信息
* @createTime 2022/1/6 19:35
*/
//public static CompanyAuthInfo getCompanyAuthInfo() {
// return RequestHolder.getCompanyAuthInfo();
//}
}

View File

@@ -0,0 +1,68 @@
package ai.remi.comm.util.auth;
import ai.remi.comm.core.enums.IdentityTypeEnum;
import ai.remi.comm.core.enums.PermissionScopeEnum;
import ai.remi.comm.core.enums.ServiceTypeEnum;
import lombok.Data;
import java.util.Set;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc CompanyAuthInfo
*/
@Data
public class CompanyAuthInfo implements AuthInfo {
/**
* 用户系统语言
*/
private String userLanguage;
/**
* 根据 {@link IdentityTypeEnum} 不同代表不同的身份
* 用户id、不同端代表对应的id
*/
private String uniqueId;
/**
* 部门租户号
*/
private String deptTenantId;
/**
* 公司租户号
*/
private String companyTenantId;
/**
* 鉴权Token
*/
private String accessToken;
/**
* 权限范围
*/
private PermissionScopeEnum permissionScope;
/**
* 如果具有集团范围权限时,这个值为拥有这个权限的公司id集合
*/
private Set<String> hasPermissionCompanyIds;
/**
* 如果具有公司范围权限时,这个值为拥有这个权限的部门id集合
*/
private Set<String> hasPermissionDeptIds;
@Override
public IdentityTypeEnum getIdentityTypeEnum() {
return IdentityTypeEnum.COMPANY;
}
@Override
public String getServiceTypeCode() {
return ServiceTypeEnum.WEB_SERVICE.getCode();
}
}

View File

@@ -0,0 +1,79 @@
package ai.remi.comm.util.auth;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc RequestHolder
*/
@Slf4j
public class RequestHolder {
private static final ThreadLocal<AuthInfo> authInfoHolder = new ThreadLocal();
private static final ThreadLocal<HttpServletRequest> requestHolder = new ThreadLocal();
/**
* 使用实例:
* CompanyAuthInfo companyAuthInfo = new CompanyAuthInfo();
* companyAuthInfo.setStoreId(pageRenderRealTimeDTO.getStoreId());
* companyAuthInfo.setCompanyId(pageRenderRealTimeDTO.getCompanyId());
* companyAuthInfo.setPermissionScope(PermissionScopeEnum.COMPANY);
* RequestHolder.add(companyAuthInfo);
* @param authInfo
*/
public static void add(AuthInfo authInfo) {
authInfoHolder.set(authInfo);
}
public static void add(HttpServletRequest request) {
requestHolder.set(request);
}
public static AuthInfo getAuthInfo() {
AuthInfo authInfo = authInfoHolder.get();
if (authInfo == null) {
log.warn("当前线程AuthInfo为空,请检查");
}
return authInfo;
}
/*public static RemiAuthInfo getRemiAuthInfo() {
AuthInfo authInfo = getAuthInfo();
if (authInfo instanceof RemiAuthInfo){
return (RemiAuthInfo) authInfo;
}
throw new RuntimeException("类型转换错误");
}*/
public static CompanyAuthInfo getCompanyAuthInfo() {
AuthInfo authInfo = getAuthInfo();
if (authInfo instanceof CompanyAuthInfo) {
return (CompanyAuthInfo) authInfo;
}
throw new RuntimeException("类型转换错误");
}
/*public static VisitorAuthInfo getVisitorAuthInfo() {
AuthInfo authInfo = getAuthInfo();
if (authInfo instanceof VisitorAuthInfo){
return (VisitorAuthInfo) authInfo;
}
throw new RuntimeException("类型转换错误");
}*/
public static HttpServletRequest getCurrentRequest() {
return requestHolder.get();
}
public static void remove() {
authInfoHolder.remove();
requestHolder.remove();
}
}

View File

@@ -0,0 +1,42 @@
package ai.remi.comm.util.auth;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc TenantHolder
*/
public class TenantHolder {
/**
* 是否是管理员
*/
private static final ThreadLocal<Boolean> isAdminThreadLocal = new ThreadLocal<>();
/**
* 是否是不拦截的请求
*/
private static final ThreadLocal<Boolean> urlIgnoreThreadLocal = new ThreadLocal<>();
public static Boolean isAdmin() {
return isAdminThreadLocal.get();
}
public static void admin(boolean isAdmin) {
isAdminThreadLocal.set(isAdmin);
}
public static Boolean getIgnoredRequest() {
return urlIgnoreThreadLocal.get();
}
public static void setIgnoredRequest(boolean ignoredRequest) {
urlIgnoreThreadLocal.set(ignoredRequest);
}
public static void remove() {
isAdminThreadLocal.remove();
urlIgnoreThreadLocal.remove();
}
}

View File

@@ -0,0 +1,126 @@
package ai.remi.comm.util.bean;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import java.lang.reflect.Field;
import java.util.*;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc BeanCopyUtils
*/
public class BeanCopyUtils {
/**
* 浅拷贝list
*
* @param source 数据源
* @param clazz 对象
* @return LIST
*/
public static List copyListProperties(List source, Class clazz) {
List target = new ArrayList();
source.forEach(o -> {
try {
target.add(JSONObject.parseObject(JSONObject.toJSONString(o), clazz));
} catch (Exception e) {
e.printStackTrace();
}
});
return target;
}
/**
* 源对象和目标对象浅拷贝 PS:目标对象和源对象中的属性名称需一至,否则无法copy
*
* @param sourceObj 源对象
* @param targetObj 目标对象
*/
public static void copyPropertiesThird(Object sourceObj, Object targetObj) {
BeanUtils.copyProperties(sourceObj, targetObj);
}
public static <T> T copyPropertiesThird(Object sourceObj, Class<T> calzz) {
if (Objects.isNull(sourceObj) || Objects.isNull(calzz)) {
return null;
}
T c = null;
try {
// c = calzz.newInstance();
c = calzz.getDeclaredConstructor().newInstance();
BeanCopyUtils.copyPropertiesThird(sourceObj, c);
} catch (Exception e) {
System.out.println("BeanCopyUtils -> copyPropertiesThird error:" + e);
}
return c;
}
/**
* 转换list泛型
*
* @param source 数据源
* @param clazz 对象
* @return LIST
*/
public static <T> List<T> coverList(List source, Class<T> clazz) {
List<T> res = new ArrayList<>();
source.forEach(o -> res.add(BeanCopyUtils.copyPropertiesThird(o, clazz)));
return res;
}
public static Map<String, Object> entityToMap(Object object) {
Map<String, Object> reMap = new HashMap();
if (object == null) {
return null;
} else {
List<Field> fields = new ArrayList();
List<String> fieldsName = new ArrayList();
for(Class tempClass = object.getClass(); tempClass != null; tempClass = tempClass.getSuperclass()) {
fields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
}
List<Field> childFields = Arrays.asList(object.getClass().getDeclaredFields());
Iterator var6 = childFields.iterator();
Field field;
while(var6.hasNext()) {
field = (Field)var6.next();
fieldsName.add(field.getName());
}
try {
var6 = fields.iterator();
while(var6.hasNext()) {
field = (Field)var6.next();
try {
Field f;
Object o;
if (fieldsName.contains(field.getName())) {
f = object.getClass().getDeclaredField(field.getName());
f.setAccessible(true);
o = f.get(object);
reMap.put(field.getName(), o);
} else {
f = object.getClass().getSuperclass().getDeclaredField(field.getName());
f.setAccessible(true);
o = f.get(object);
reMap.put(field.getName(), o);
}
} catch (Exception var10) {
var10.printStackTrace();
}
}
} catch (SecurityException var11) {
var11.printStackTrace();
}
return reMap;
}
}
}

View File

@@ -0,0 +1,465 @@
package ai.remi.comm.util.collection;
import ai.remi.comm.util.array.ArrayUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
public class CollectionUtils {
public static final String DESC = "desc";
public static final String ASC = "asc";
/**
* 集合是否为空
*
* @param collection 集合
* @return 若集合为null, 或集合大小为0, 则返回true, 否则返回false
*/
public static boolean isEmpty(Collection<?> collection) {
return collection == null || collection.size() == 0;
}
/**
* Map是否为空
*
* @param map
* @return
*/
public static boolean isEmpty(Map<?, ?> map) {
return map == null || map.isEmpty();
}
/**
* 集合是否不为空
*
* @param collection 集合
* @return 若集合不为null, 而且集合大小不为0, 则返回true, 否则返回false
*/
public static boolean isNotEmpty(Collection<?> collection) {
return !isEmpty(collection);
}
/**
* Map是否不为空
*
* @param map
* @return
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* 参数转换为List集合
*
* @param objs 参数对象
* @return 返回泛型
*/
public static <E> List<E> asList(E... objs) {
return Arrays.asList(objs);
}
/**
* 参数集合转换为List集合
*
* @param collection 集合参数
* @return 返回list泛型
*/
public static <E> List<E> asList(Collection<E> collection) {
if (collection == null) {
return null;
}
if (collection instanceof List) {
return (List<E>) collection;
}
return new ArrayList<E>(collection);
}
/**
* 参数转换为Set集合
*
* @param objs 参数对象
* @return 返回set泛型
*/
public static <E> Set<E> asSet(E... objs) {
return new HashSet<E>(Arrays.asList(objs));
}
/**
* 参数转换为Set集合
*
* @param collection 集合参数
* @return 返回set泛型
*/
public static <E> Set<E> asSet(Collection<E> collection) {
if (collection == null) {
return null;
}
if (collection instanceof Set) {
return (Set<E>) collection;
}
return new HashSet<E>(collection);
}
/**
* 将集合转换为数组
*
* @param collection 集合
* @returns 返回数组
*/
public static <E> E[] toArray(Collection<E> collection) {
return ArrayUtils.asArray(collection);
}
/**
* 创建ArrayList实例
*
* @return 返回list
*/
public static <E> List<E> newList() {
return new ArrayList<E>();
}
/**
* 创建一个指定容量的ArrayList实例
*
* @param size 大小
* @return 返回list
*/
public static <E> List<E> newList(int size) {
return new ArrayList<E>(size);
}
/**
* 创建一个HashSet实例
*
* @return 返回set泛型
*/
public static <E> Set<E> newSet() {
return new HashSet<E>(16, .75f);
}
/**
* 创建一个指定容量大小的HashSet实例
*
* @param initialCapacity 初始容量
* @param loadFactor 加载因子
* @return 返回set
*/
public static <E> Set<E> newSet(int initialCapacity, double loadFactor) {
return new HashSet<E>(initialCapacity, (float) loadFactor);
}
/**
* 获取map的最小key的value
*
* @param map 传入map的值
* @return String
*/
public static String getMinKeysValue(Map<Integer, String> map) {
if (map == null || map.size() < 1) {
return new String();
}
int key = map.keySet().stream().min(Comparator.comparing(Function.identity())).get();
return map.get(key);
}
/**
* 对list中的元素按升序排列.
*
* @param list 排序集合
* @param field 排序字段
* @return
*/
public static List<?> sort(List<?> list, final String field) {
return sort(list, field, null);
}
/**
* 对list中的元素进行排序.
*
* @param list 排序集合
* @param field 排序字段
* @param sort 排序方式: SortList.DESC(降序) SortList.ASC(升序).
*/
@SuppressWarnings("unchecked")
public static List<?> sort(List<?> list, final String field,
final String sort) {
Collections.sort(list, new Comparator() {
public int compare(Object a, Object b) {
int ret = 0;
try {
Field f = a.getClass().getDeclaredField(field);
f.setAccessible(true);
Class<?> type = f.getType();
if (type == int.class) {
ret = Integer.compare(f.getInt(a), f
.getInt(b));
} else if (type == double.class) {
ret = Double.compare(f.getDouble(a), f
.getDouble(b));
} else if (type == long.class) {
ret = Long.compare(f.getLong(a), f
.getLong(b));
} else if (type == float.class) {
ret = Float.compare(f.getFloat(a), f
.getFloat(b));
} else if (type == Date.class) {
ret = ((Date) f.get(a)).compareTo((Date) f.get(b));
} else if (isImplementsOf(type, Comparable.class)) {
ret = ((Comparable) f.get(a)).compareTo(f
.get(b));
} else {
ret = String.valueOf(f.get(a)).compareTo(
String.valueOf(f.get(b)));
}
} catch (SecurityException | NoSuchFieldException | IllegalAccessException |
IllegalArgumentException e) {
e.printStackTrace();
}
if (sort != null && sort.equalsIgnoreCase(DESC)) {
return -ret;
} else {
return ret;
}
}
});
return list;
}
/**
* 对list中的元素按fields和sorts进行排序,
* fields[i]指定排序字段,sorts[i]指定排序方式.如果sorts[i]为空则默认按升序排列.
*
* @param list
* @param fields
* @param sorts
*/
@SuppressWarnings("unchecked")
public static List<?> sort(List<?> list, String[] fields, String[] sorts) {
if (fields != null && fields.length > 0) {
for (int i = fields.length - 1; i >= 0; i--) {
final String field = fields[i];
String tmpSort = ASC;
if (sorts != null && sorts.length > i && sorts[i] != null) {
tmpSort = sorts[i];
}
final String sort = tmpSort;
Collections.sort(list, new Comparator() {
public int compare(Object a, Object b) {
int ret = 0;
try {
Field f = a.getClass().getDeclaredField(field);
f.setAccessible(true);
Class<?> type = f.getType();
if (type == int.class) {
ret = ((Integer) f.getInt(a))
.compareTo(f.getInt(b));
} else if (type == double.class) {
ret = ((Double) f.getDouble(a))
.compareTo(f.getDouble(b));
} else if (type == long.class) {
ret = ((Long) f.getLong(a)).compareTo(f
.getLong(b));
} else if (type == float.class) {
ret = ((Float) f.getFloat(a))
.compareTo(f.getFloat(b));
} else if (type == Date.class) {
ret = ((Date) f.get(a)).compareTo((Date) f
.get(b));
} else if (isImplementsOf(type, Comparable.class)) {
ret = ((Comparable) f.get(a))
.compareTo(f.get(b));
} else {
ret = String.valueOf(f.get(a)).compareTo(
String.valueOf(f.get(b)));
}
} catch (SecurityException | NoSuchFieldException | IllegalArgumentException |
IllegalAccessException e) {
e.printStackTrace();
}
if (sort != null && sort.equalsIgnoreCase(DESC)) {
return -ret;
} else {
return ret;
}
}
});
}
}
return list;
}
/**
* 默认按正序排列
*
* @param list
* @param method
*/
public static List<?> sortByMethod(List<?> list, final String method) {
return sortByMethod(list, method, null);
}
@SuppressWarnings("unchecked")
public static List<?> sortByMethod(List<?> list, final String method,
final String sort) {
Collections.sort(list, new Comparator() {
public int compare(Object a, Object b) {
int ret = 0;
try {
Method m = a.getClass().getMethod(method, null);
m.setAccessible(true);
Class<?> type = m.getReturnType();
if (type == int.class) {
ret = ((Integer) m.invoke(a, null))
.compareTo((Integer) m.invoke(b, null));
} else if (type == double.class) {
ret = ((Double) m.invoke(a, null)).compareTo((Double) m
.invoke(b, null));
} else if (type == long.class) {
ret = ((Long) m.invoke(a, null)).compareTo((Long) m
.invoke(b, null));
} else if (type == float.class) {
ret = ((Float) m.invoke(a, null)).compareTo((Float) m
.invoke(b, null));
} else if (type == Date.class) {
ret = ((Date) m.invoke(a, null)).compareTo((Date) m
.invoke(b, null));
} else if (isImplementsOf(type, Comparable.class)) {
ret = ((Comparable) m.invoke(a, null))
.compareTo(m.invoke(b, null));
} else {
ret = String.valueOf(m.invoke(a, null)).compareTo(
String.valueOf(m.invoke(b, null)));
}
if (isImplementsOf(type, Comparable.class)) {
ret = ((Comparable) m.invoke(a, null))
.compareTo(m.invoke(b, null));
} else {
ret = String.valueOf(m.invoke(a, null)).compareTo(
String.valueOf(m.invoke(b, null)));
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ne) {
ne.printStackTrace();
}
if (sort != null && sort.toLowerCase().equals(DESC)) {
return -ret;
} else {
return ret;
}
}
});
return list;
}
@SuppressWarnings("unchecked")
public static List<?> sortByMethod(List<?> list, final String methods[],
final String sorts[]) {
if (methods != null && methods.length > 0) {
for (int i = methods.length - 1; i >= 0; i--) {
final String method = methods[i];
String tmpSort = ASC;
if (sorts != null && sorts.length > i && sorts[i] != null) {
tmpSort = sorts[i];
}
final String sort = tmpSort;
Collections.sort(list, new Comparator() {
public int compare(Object a, Object b) {
int ret = 0;
try {
Method m = a.getClass().getMethod(method, null);
m.setAccessible(true);
Class<?> type = m.getReturnType();
if (type == int.class) {
ret = ((Integer) m.invoke(a, null))
.compareTo((Integer) m.invoke(b, null));
} else if (type == double.class) {
ret = ((Double) m.invoke(a, null))
.compareTo((Double) m.invoke(b, null));
} else if (type == long.class) {
ret = ((Long) m.invoke(a, null))
.compareTo((Long) m.invoke(b, null));
} else if (type == float.class) {
ret = ((Float) m.invoke(a, null))
.compareTo((Float) m.invoke(b, null));
} else if (type == Date.class) {
ret = ((Date) m.invoke(a, null))
.compareTo((Date) m.invoke(b, null));
} else if (isImplementsOf(type, Comparable.class)) {
ret = ((Comparable) m.invoke(a, null))
.compareTo(m.invoke(b,
null));
} else {
ret = String.valueOf(m.invoke(a, null))
.compareTo(
String.valueOf(m
.invoke(b, null)));
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ne) {
ne.printStackTrace();
}
if (sort != null && sort.toLowerCase().equals(DESC)) {
return -ret;
} else {
return ret;
}
}
});
}
}
return list;
}
/**
* 判断对象实现的所有接口中是否包含szInterface
*
* @param clazz
* @param szInterface
*/
public static boolean isImplementsOf(Class<?> clazz, Class<?> szInterface) {
boolean flag = false;
Class<?>[] face = clazz.getInterfaces();
for (Class<?> c : face) {
if (c == szInterface) {
flag = true;
} else {
flag = isImplementsOf(c, szInterface);
}
}
if (!flag && null != clazz.getSuperclass()) {
return isImplementsOf(clazz.getSuperclass(), szInterface);
}
return flag;
}
/**
* 根据集合的某个指定字段去重
* 使用方式:
* list.stream().filter(CollectionUtils.distinctByKey(RoleVO::getId)).collect(Collectors.toList());
*
* @param keyExtractor 需要去重的字段
* @param <T>
* @return java.util.function.Predicate<T>
*/
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}

View File

@@ -0,0 +1,26 @@
package ai.remi.comm.util.cron;
import org.springframework.scheduling.support.CronExpression;
/**
* Quartz Cron 表达式的工具类
*/
public class CronUtils {
/**
* 校验 CRON 表达式是否有效
*
* @param cronExpression CRON 表达式
* @return 是否有效
*/
public static boolean isValid(String cronExpression) {
return CronExpression.isValidExpression(cronExpression);
}
public static void main(String[] args) {
String validCron = "0 0 12 * * ?";
String invalidCron = "invalid";
System.out.println("Valid Cron: " + isValid(validCron)); // 输出 true
System.out.println("Invalid Cron: " + isValid(invalidCron)); // 输出 false
}
}

View File

@@ -0,0 +1,727 @@
package ai.remi.comm.util.date;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* 时间处理工具类
*
* @author ws
* @mail 1720696548@qq.com
* @date 2020/4/24 0024 9:54
* @return
*/
public class LocalDateTimeUtils {
/**
* 时间格式
*/
private static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
private static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
private static final String YYYY_MM_DD = "yyyy-MM-dd";
private static final String YYYY_MM = "yyyy-MM";
private static final String YYYY = "yyyy";
/**
* 获取时间类型
* 1-包含开始和结束时间(默认)
* 2-包含结束-不包含开始时间 // 开始时间+1天
* 3-包含开始-不包含结束时间 // 结束时间-1天
* 4-不包含开始和结束时间 // 开始时间+1天 or 结束时间-1天
*/
private static final int BETWEEN_TYPE_ONE = 1;
private static final int BETWEEN_TYPE_TWO = 2;
private static final int BETWEEN_TYPE_THREE = 3;
private static final int BETWEEN_TYPE_FOUR = 4;
private static Random random;
static {
try {
random = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 判断时间 小于
* <P> t1 < t2 = true (如:2019-10-13 11:11:00 < 2020-11-13 13:13:00 = true) </P>
*
* @author wangsong
*/
public static boolean isBefore(LocalDateTime t1, LocalDateTime t2) {
return t1.isBefore(t2);
}
/**
* 判断时间 大于
* <P> t1 > t2 = true </P>
*
* @author wangsong
*/
public static boolean isAfter(LocalDateTime t1, LocalDateTime t2) {
return t1.isAfter(t2);
}
/**
* 自构建 LocalDateTime ==> 年,月,日,时,分
*
* @author wangsong
*/
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
return LocalDateTime.of(year, month, dayOfMonth, hour, minute);
}
/**
* 自构建 LocalDateTime ==> 年,月,日,时,分,秒,毫秒(精确到9位数)
*
* @author wangsong
*/
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
}
//========================================================================================================
//========================================================================================================
//========================================================================================================
//============================================== 时间获取 =================================================
//========================================================================================================
//========================================================================================================
/**
* 获取指定某一天的开始时间 00:00:00
*
* @param time
* @return java.time.LocalDateTime
* @author wangsong
* @date 2020/12/24 0024 15:10
* @version 1.0.1
*/
public static LocalDateTime getDayStart(LocalDateTime time) {
return time.withHour(0)
.withMinute(0)
.withSecond(0)
.withNano(0);
}
/**
* 获取指定某一天的结束时间 23:59:59.999999
*
* @author wangsong
*/
public static LocalDateTime getDayEnd(LocalDateTime time) {
// 年 月 天 时 分 秒 毫秒(这里精确到6位数)
return time.withHour(23)
.withMinute(59)
.withSecond(59)
.withNano(999999);
}
/**
* 获取指定时间是周几 1到7
*
* @author wangsong
*/
public static int week(LocalDateTime time) {
return time.getDayOfWeek().getValue();
}
/**
* 获取指定时间之后的日期
* <P> 根据field不同加不同值 , field为ChronoUnit.*
* 秒 ChronoUnit.SECONDS
* 分 ChronoUnit.MINUTES
* 时 ChronoUnit.HOURS
* 半天 ChronoUnit.HALF_DAYS
* 天 ChronoUnit.DAYS
* 月 ChronoUnit.MONTHS
* 年 ChronoUnit.YEARS
* </P>
*
* @author wangsong
*/
public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
return time.plus(number, field);
}
/**
* 获取两个日期的时间差
*
* @param startTime 开始时间
* @param endTime 计算时间
* @param field 根据field不同减不同值 , field 为 ChronoUnit.*
* @return startTime小 endTime大 返回正数,则反之
* @author wangsong
* <p>
* 秒 ChronoUnit.SECONDS
* 分 ChronoUnit.MINUTES
* 时 ChronoUnit.HOURS
* 半天 ChronoUnit.HALF_DAYS
* 天 ChronoUnit.DAYS
* 月 ChronoUnit.MONTHS
* 年 ChronoUnit.YEARS
* </P>
*/
public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
if (field == ChronoUnit.YEARS) {
return period.getYears();
}
if (field == ChronoUnit.MONTHS) {
return period.getYears() * 12L + period.getMonths();
}
return field.between(startTime, endTime);
}
/**
* 获取指定时间之前的日期
*
* @author wangsong
* <P> 根据field不同减不同值, field 为 ChronoUnit.*
* 秒 ChronoUnit.SECONDS
* 分 ChronoUnit.MINUTES
* 时 ChronoUnit.HOURS
* 半天 ChronoUnit.HALF_DAYS
* 天 ChronoUnit.DAYS
* 月 ChronoUnit.MONTHS
* 年 ChronoUnit.YEARS
* </P>
* @version 1.0.1
*/
public static LocalDateTime subtract(LocalDateTime time, long number, TemporalUnit field) {
return time.minus(number, field);
}
/**
* 获取指定时间 加或减N周的第一天 00:00:00
*
* @author wangsong
*/
public static LocalDateTime weekFirstDay(LocalDateTime time, int num) {
int week = week(LocalDateTime.now());
LocalDateTime newTime = subtract(LocalDateTime.now(), week - 1L, ChronoUnit.DAYS);
newTime = plus(newTime, num * 7L, ChronoUnit.DAYS);
return getDayStart(newTime);
}
/**
* 获取指定时间 加或减N周的最后一天 23:59:59:999999
*
* @author wangsong
*/
public static LocalDateTime weekLastDay(LocalDateTime time, int num) {
int week = week(LocalDateTime.now());
LocalDateTime newTime = plus(LocalDateTime.now(), 7L - week, ChronoUnit.DAYS);
newTime = plus(newTime, num * 7L, ChronoUnit.DAYS);
return getDayEnd(newTime);
}
/**
* 获取指定月 加或减N月的第一天 00:00:00
*
* @author wangsong
*/
public static LocalDateTime monthFirstDay(LocalDateTime time, int num) {
LocalDateTime newTime = plus(time, num, ChronoUnit.MONTHS);
newTime = newTime.with(TemporalAdjusters.firstDayOfMonth());
return getDayStart(newTime);
}
/**
* 获取指定月 加或减N月的最后一天 23:59:59:999999
*
* @author wangsong
*/
public static LocalDateTime monthLastDay(LocalDateTime time, int num) {
LocalDateTime newTime = plus(time, num, ChronoUnit.MONTHS);
newTime = newTime.with(TemporalAdjusters.lastDayOfMonth());
return getDayEnd(newTime);
}
/**
* 获取指定年 加或减N年的第一天 00:00:00
*
* @author wangsong
*/
public static LocalDateTime yearFirstDay(LocalDateTime time, int num) {
LocalDateTime newTime = plus(time, num, ChronoUnit.YEARS);
int year = newTime.getYear();
// 年 月 天 时 分 秒 毫秒(这里精确到9位数)
return LocalDateTime.of(year, 1, 1, 0, 0, 0);
}
/**
* 获取指定年 加或减N年最后一天 23:59:59:999999
*
* @author wangsong
*/
public static LocalDateTime yearLastDay(LocalDateTime time, int num) {
LocalDateTime newTime = subtract(time, num, ChronoUnit.YEARS);
int year = newTime.getYear();
// 年 月 天 时 分 秒 毫秒(这里精确到6位数)
return LocalDateTime.of(year, 12, 31, 23, 59, 59, 999999);
}
/**
* 获取17位时间戳字符串+3位随机数
* <p> 这里增加了线程锁和延时一毫秒,单体项目100%不会重复,可用于生成订单号 </p>
* 20200101125959999 2020-01-01 12:59:59:999
*
* @return
* @author wangsong
*/
public static synchronized String getNo() {
String timeStamp = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
timeStamp += (random.nextInt(10) + "") + (random.nextInt(10) + "") + (random.nextInt(10) + "");
return timeStamp;
}
/**
* 获取整点-- 把指定时间的 分+秒设置为0
*
* @param time time
* @return java.time.LocalDateTime
* @author wangsong
* @date 2020/12/24 0024 15:10
* @version 1.0.1
*/
public static LocalDateTime getTheHour(LocalDateTime time) {
// 分 // 秒 // 毫秒(这里精确到9位数)
return time.withMinute(0)
.withSecond(0)
.withNano(0);
}
/**
* 获取整分-- 把指定时间的 秒设置为0
* <p>
* // * 如:
* // * 2020-01-01 12:10 ===> 等于 2020-01-01 12:20
* // * 2020-01-01 12:11 ===> 等于 2020-01-01 12:20
* // * 2020-01-01 12:19 ===> 等于 2020-01-01 12:20
* </P>
*
* @param time
* @return java.time.LocalDateTime
* @author wangsong
* @date 2020/12/24 0024 15:21
* @version 1.0.1
*/
public static LocalDateTime getTheMinute(LocalDateTime time) {
// 秒 // 毫秒(这里精确到9位数)
return time.withSecond(0).withNano(0);
}
//========================================================================================================
//========================================================================================================
//========================================================================================================
//============================================== 转换相关 =================================================
//========================================================================================================
//========================================================================================================
/**
* LocalDateTime 转为 天 的字符串,如 1号返回 01
*
* @author wangsong
*/
public static Integer parseDayInt(LocalDateTime time) {
return Integer.parseInt(parse(time, "dd"));
}
/**
* Date 转 LocalDateTime
*
* @author wangsong
*/
public static LocalDateTime parseLdt(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
/**
* LocalDateTime 转 Date
*
* @author wangsong
*/
public static Date parseDate(LocalDateTime time) {
return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
}
/**
* LocalDateTime 转 毫秒
*
* @author wangsong
*/
public static Long parseMillisecond(LocalDateTime time) {
return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
* LocalDateTime 转 秒
*
* @author wangsong
*/
public static Long parseSecond(LocalDateTime time) {
return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
}
/**
* 将时间戳转 为 LocalDateTime
*
* @param timestamp
* @return java.lang.String
* @author wangsong
* @date 2021/5/12 0012 17:13
* @version 1.0.1
*/
public static LocalDateTime parseTimestamp(Long timestamp) {
return LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneOffset.ofHours(8));
}
/**
* 将LocalDateTime 转 为时间戳
*
* @return java.lang.String
* @author wangsong
* @date 2021/5/12 0012 17:13
* @version 1.0.1
*/
public static Long parseTimestamp(LocalDateTime time) {
return time.toEpochSecond(ZoneOffset.ofHours(8));
}
/**
* String 类型转成 LocalDateTime ,必须为完整时间,如:2020-01-20 00:00:00
*
* @param timeStr 时间字符串
* @return java.time.LocalDateTime
*/
public static LocalDateTime parse(String timeStr) {
return parse(timeStr, YYYY_MM_DD_HH_MM_SS);
}
/**
* String (2020-01-20 00:00:00)类型转成 LocalDateTime
*
* @param timeStr timeStr 时间字符串
* @param pattern pattern 格式
* @return java.time.LocalDateTime
*/
public static LocalDateTime parse(String timeStr, String pattern) {
if (pattern.equals(YYYY)) {
timeStr += "-01-01 00:00:00";
} else if (pattern.equals(YYYY_MM)) {
timeStr += "-01 00:00:00";
} else if (pattern.equals(YYYY_MM_DD)) {
timeStr += " 00:00:00";
} else if (pattern.equals(YYYY_MM_DD_HH)) {
timeStr += ":00:00";
} else if (pattern.equals(YYYY_MM_DD_HH_MM)) {
timeStr += ":00";
}
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
return LocalDateTime.parse(timeStr, dtf);
}
/**
* LocalDateTime 转完整 String 类型的时间 如:2020-01-20 00:00:00
*
* @param time time
* @return java.lang.String
*/
public static String parse(LocalDateTime time) {
return parse(time, YYYY_MM_DD_HH_MM_SS);
}
/**
* LocalDateTime 转指定类型的字符串
*
* @param time time 时间
* @param pattern pattern 格式
* @return java.lang.String
* @author wangsong
*/
public static String parse(LocalDateTime time, String pattern) {
if (time == null) {
return null;
}
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
return df.format(time);
}
/**
* Date 转指定格式的字符串
*
* @param time
* @author wangsong
*/
public static String parse(Date time, String pattern) {
if (time == null) {
return null;
}
SimpleDateFormat format = new SimpleDateFormat(pattern);
return format.format(time);
}
/**
* 获取指定天的24小时(0-23) | yyyy-MM-dd HH 格式
*
* @param t 开始月
* @return
*/
public static List<String> getDay24Hour(LocalDateTime t) {
if (t == null) {
return new ArrayList<>();
}
List<String> times = new ArrayList<>();
String time = parse(t, YYYY_MM_DD);
int hourNum = 24;
for (int i = 0; i < hourNum; i++) {
if (i < 10) {
times.add(time + " 0" + i);
} else {
times.add(time + " " + i);
}
}
return times;
}
/**
* 获取每一天的时间 (指定时间 前n月前的第一天 到 n月后的最后一天的所有时间)
* <P> 一天一条数据 List<DateDays> </P>
*
* @param startNum 前n月,当前月开始为 0
* @param endNum 后n月,当前月就是为 0
* @return java.util.List<com.lplb.common.utils.LocalDateTimeUtil.DateDays>
* @author wangsong
*/
public static List<DateDays> getBetweenDaysUpListByMonth(LocalDateTime time, Integer startNum, Integer endNum) {
// 本月第一天 00:00:00
LocalDateTime startTime = monthFirstDay(time, startNum);
// n月后的最后一天 23:59:59.999
LocalDateTime endTime = monthLastDay(time, endNum);
return getBetweenDaysUpList(startTime, endTime, BETWEEN_TYPE_ONE);
}
/**
* 获取每一天的时间 (指定开始时间和结束时间)
* <p>
* 一天一条数据 List<DateDays>
* 返回数据包括 开始时间 和 结束时间 的当天数据
* </P>
*
* @param startTime 开始时间 (时分秒已开始时间位为准)
* @param endTime 结束时间
* @param type 1-包含开始和结束时间 2-包含结束-不包含开始时间 3-包含开始-不包含结束时间 4-不包含开始和结束时间
* @return java.util.List<com.lplb.common.utils.LocalDateTimeUtil.DateDays>
* @author wangsong
*/
public static List<DateDays> getBetweenDaysUpList(LocalDateTime startTime, LocalDateTime endTime, Integer type) {
List<DateDays> dateDaysList = new ArrayList<>();
List<LocalDateTime> betweenList = getBetweenDaysList(startTime, endTime, type);
for (LocalDateTime localDateTime : betweenList) {
dateDaysList.add(new DateDays(localDateTime, week(localDateTime)));
}
return dateDaysList;
}
/**
* 获取指定开始时间到指定结束时间的每一天, 包括开始时间,不包括结束时间,如:2020-5-16到2020-5-18 获得时间为:[2020-5-16,2020-5-17]
*
* @param startTime
* @param endTime
* @param type 1-包含开始和结束时间 2-包含结束-不包含开始时间 3-包含开始-不包含结束时间 4-不包含开始和结束时间
* @return java.util.List<java.time.LocalDateTime>
* @author wangsong
* @date 2020/12/24 0024 15:16
* @version 1.0.1
*/
public static List<LocalDateTime> getBetweenDaysList(LocalDateTime startTime, LocalDateTime endTime, Integer type) {
// 指定开始时间 00:00:00 // 指定结束时间 00:00:00
LocalDateTime oldStartTime = getDayStart(startTime);
LocalDateTime oldEndTime = getDayStart(endTime);
// 1-包含开始和结束时间(默认) BetweenType
// 2-包含结束-不包含开始时间 // 开始时间+1天
// 3-包含开始-不包含结束时间 // 结束时间-1天
// 4-不包含开始和结束时间 // 开始时间+1天 or 结束时间-1天
if (type == BETWEEN_TYPE_TWO) {
oldStartTime = plus(oldStartTime, 1, ChronoUnit.DAYS);
} else if (type == BETWEEN_TYPE_THREE) {
oldEndTime = subtract(endTime, 1, ChronoUnit.DAYS);
} else if (type == BETWEEN_TYPE_FOUR) {
oldStartTime = plus(oldStartTime, 1, ChronoUnit.DAYS);
oldEndTime = subtract(endTime, 1, ChronoUnit.DAYS);
}
// 返回数据
List<LocalDateTime> everyDays = new ArrayList<>();
// 第一天数据
everyDays.add(oldStartTime);
while (true) {
// 获取之后的每一天时间
LocalDateTime nextDay = plus(everyDays.get(everyDays.size() - 1), 1, ChronoUnit.DAYS);
// 大于最后一天-跳出循环
if (isAfter(nextDay, oldEndTime)) {
break;
}
everyDays.add(nextDay);
}
return everyDays;
}
/**
* 获取月 (返回每一个月的字串, yyyy-MM 格式)
* <p> 包含结束月,不包含开始月 </>
*
* @param startTime 开始月
* @param endTime 结束月
* @return
*/
public static List<String> getBetweenMonthsList(LocalDateTime startTime, LocalDateTime endTime) {
List<String> times = new ArrayList<>();
if (startTime != null && endTime != null) {
// 获取开始月的第一天
endTime = monthFirstDay(endTime, 0);
times.add(parse(startTime, YYYY_MM));
while (isBefore(startTime, endTime)) {
startTime = plus(startTime, 1, ChronoUnit.MONTHS);
times.add(parse(startTime, YYYY_MM));
}
}
return times;
}
/**
* 获取日期端的数据保存对象
*
* @author ws
* @mail 1720696548@qq.com
* @date 2020/5/7 0007 9:41
*/
public static class DateDays {
// 当天时间- 年月日/00:00:00
private LocalDateTime dayTime;
// 当天是周几
private int week;
public DateDays(LocalDateTime dayTime, int week) {
this.dayTime = dayTime;
this.week = week;
}
public LocalDateTime getDayTime() {
return dayTime;
}
public void setDayTime(LocalDateTime dayTime) {
this.dayTime = dayTime;
}
public int getWeek() {
return week;
}
public void setWeek(int week) {
this.week = week;
}
}
/**
* 计算两个日期之间的天数
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 从开始日期到结束日期(包括这两个日期)之间的总天数
*/
public static long betweenDays(LocalDate startDate, LocalDate endDate) {
List<LocalDate> dates = new ArrayList<>();
while (!startDate.isEqual(endDate)) {
dates.add(startDate);
startDate = startDate.plusDays(1);
}
dates.add(endDate);
long totalDays = dates.size();
return totalDays;
}
/**
* 计算两个日期之间的工作日数,移除了星期六和星期日
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 两个日期之间的工作日数
*/
public static long removeWeekends(LocalDate startDate, LocalDate endDate) {
List<LocalDate> dates = new ArrayList<>();
while (!startDate.isEqual(endDate)) {
dates.add(startDate);
startDate = startDate.plusDays(1);
}
dates.add(endDate);
long totalDays = dates.size();
long weekends = 0;
for (LocalDate date : dates) {
if (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY) {
weekends++;
}
}
return totalDays - weekends;
}
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2024, 8, 22);
LocalDate endDate = LocalDate.of(2024, 8, 26);
long daysBetween = betweenDays(startDate, endDate);
System.out.println("Total days between: " + daysBetween);
long weekendsRemoved = removeWeekends(startDate, endDate);
System.out.println("Days without weekends: " + weekendsRemoved);
}
}

View File

@@ -0,0 +1,82 @@
package ai.remi.comm.util.file;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.Objects;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc FileTypeUtils
*/
public class FileTypeUtils {
/**
* 获取文件类型
* <p>
* 例如: startdis.txt, 返回: txt
*
* @param file 文件名
* @return 后缀(不含".")
*/
public static String getFileType(File file) {
if (null == file) {
return StringUtils.EMPTY;
}
return getFileType(file.getName());
}
/**
* 获取文件类型
* <p>
* 例如: startdis.txt, 返回: txt
*
* @param fileName 文件名
* @return 后缀(不含".")
*/
public static String getFileType(String fileName) {
int separatorIndex = fileName.lastIndexOf(".");
if (separatorIndex < 0) {
return "";
}
return fileName.substring(separatorIndex + 1).toLowerCase();
}
/**
* 获取文件类型
*
* @param photoByte 文件字节码
* @return 后缀(不含".")
*/
public static String getFileExtendName(byte[] photoByte) {
String strFileExtendName = "JPG";
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
&& ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) {
strFileExtendName = "GIF";
} else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) {
strFileExtendName = "JPG";
} else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
strFileExtendName = "BMP";
} else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) {
strFileExtendName = "PNG";
}
return strFileExtendName;
}
/**
* 获取文件名的后缀
*
* @param file 表单文件
* @return 后缀名
*/
public static final String getExtension(MultipartFile file) {
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension)) {
extension = MediaType.getExtension(Objects.requireNonNull(file.getContentType()));
}
return extension;
}
}

View File

@@ -0,0 +1,293 @@
package ai.remi.comm.util.file;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc FileUtils
*/
public class FileUtils {
/**
* 字符常量:斜杠 {@code '/'}
*/
public static final char SLASH = '/';
/**
* 字符常量:反斜杠 {@code '\\'}
*/
public static final char BACKSLASH = '\\';
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException {
FileInputStream fis = null;
try {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
throw e;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
//路径校验不存在就创建对应的目录
public static void filePath(String path) {
File file = new File(path);
// 判断路径是否存在,不存在创建
if (!file.exists()) {
file.mkdirs();
}
}
/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath) {
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}
/**
* 文件名称验证
*
* @param filename 文件名称
* @return true 正常 false 非法
*/
public static boolean isValidFilename(String filename) {
return filename.matches(FILENAME_PATTERN);
}
/**
* 检查文件是否可下载
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
public static boolean checkAllowDownload(String resource) {
// 禁止目录上跳级别
if (StringUtils.contains(resource, "..")) {
return false;
}
// 检查允许下载的文件规则
if (ArrayUtils.contains(MediaType.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) {
return true;
}
// 不在允许下载的文件规则
return false;
}
/**
* 下载文件名重新编码
*
* @param request 请求对象
* @param fileName 文件名
* @return 编码后的文件名
*/
public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
final String agent = request.getHeader("USER-AGENT");
String filename = fileName;
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
filename = new String(fileName.getBytes(), "ISO8859-1");
} else if (agent.contains("Chrome")) {
// google浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
/**
* 返回文件名
*
* @param filePath 文件
* @return 文件名
*/
public static String getName(String filePath) {
if (null == filePath) {
return null;
}
int len = filePath.length();
if (0 == len) {
return filePath;
}
if (isFileSeparator(filePath.charAt(len - 1))) {
// 以分隔符结尾的去掉结尾分隔符
len--;
}
int begin = 0;
char c;
for (int i = len - 1; i > -1; i--) {
c = filePath.charAt(i);
if (isFileSeparator(c)) {
// 查找最后一个路径分隔符(/或者\)
begin = i + 1;
break;
}
}
return filePath.substring(begin, len);
}
/**
* 是否为Windows或者Linux(Unix)文件分隔符<br>
* Windows平台下分隔符为\,Linux(Unix)为/
*
* @param c 字符
* @return 是否为Windows或者Linux(Unix)文件分隔符
*/
public static boolean isFileSeparator(char c) {
return SLASH == c || BACKSLASH == c;
}
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
* @return
*/
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
String percentEncodedFileName = percentEncode(realFileName);
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=")
.append(percentEncodedFileName)
.append(";")
.append("filename*=")
.append("utf-8''")
.append(percentEncodedFileName);
response.setHeader("Content-disposition", contentDispositionValue.toString());
response.setHeader("download-filename", percentEncodedFileName);
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public static String percentEncode(String s) throws UnsupportedEncodingException {
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
public static String formatSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "GB";
}
return fileSizeString;
}
public static BigDecimal formatKB(Long fileSize) {
DecimalFormat df = new DecimalFormat("#.000");
if (fileSize == 0) {
return new BigDecimal(0.000);
}
return new BigDecimal(fileSize).divide(new BigDecimal(1024)).setScale(3, RoundingMode.HALF_UP);
}
/**
* @param url 指定文件的位置
* @param content 异常输出的内容
* @throws Exception
*/
public static void writeFile(String url, String content) throws Exception {
File file = new File(url);
FileWriter fw = null;
//文件不存在创建新文件
if (!file.exists()) {
file.createNewFile();
} else {
deleteFile(url);
file.createNewFile();
}
String writeDate = content;
try {
fw = new FileWriter(file, true);
fw.write(writeDate + "\r\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fw != null) {
fw.close();
}
}
}
}

View File

@@ -0,0 +1,67 @@
package ai.remi.comm.util.file;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc ImageUtils
*/
public class ImageUtils {
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
public static byte[] getImage(String imagePath) {
InputStream is = getFile(imagePath);
try {
return IOUtils.toByteArray(is);
} catch (Exception e) {
log.error("图片加载异常 {}", e);
return null;
} finally {
IOUtils.closeQuietly(is);
}
}
public static InputStream getFile(String imagePath) {
try {
byte[] result = readFile(imagePath);
result = Arrays.copyOf(result, result.length);
return new ByteArrayInputStream(result);
} catch (Exception e) {
log.error("获取图片异常 {}", e);
}
return null;
}
/**
* 读取文件为字节数据
*
* @param url 地址
* @return 字节数据
*/
public static byte[] readFile(String url) {
InputStream in = null;
try {
// 网络地址
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
urlConnection.setDoInput(true);
in = urlConnection.getInputStream();
return IOUtils.toByteArray(in);
} catch (Exception e) {
log.error("访问文件异常 {}", e);
return null;
} finally {
IOUtils.closeQuietly(in);
}
}
}

View File

@@ -0,0 +1,56 @@
package ai.remi.comm.util.file;
/**
* 媒体类型工具类
*
* @author startdis
*/
public class MediaType {
public static final String IMAGE_PNG = "image/png";
public static final String IMAGE_JPG = "image/jpg";
public static final String IMAGE_JPEG = "image/jpeg";
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb"};
public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf"};
public static String getExtension(String prefix) {
switch (prefix) {
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
return "jpg";
case IMAGE_JPEG:
return "jpeg";
case IMAGE_BMP:
return "bmp";
case IMAGE_GIF:
return "gif";
default:
return "";
}
}
}

View File

@@ -0,0 +1,148 @@
package ai.remi.comm.util.ftp;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc FtpUtils
*/
public class FtpUtils {
/**
* Description: 向FTP服务器上传文件
*
* @param host FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param basePath FTP服务器基础目录
* @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath
* @param filename 上传到FTP服务器上的文件名
* @param input 输入流
* @return 成功返回true,否则返回false
*/
public static boolean uploadFile(String host, int port, String username, String password, String basePath,
String filePath, String filename, InputStream input) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);// 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login(username, password);// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
// 切换到上传目录
if (!ftp.changeWorkingDirectory(basePath + filePath)) {
// 如果目录不存在创建目录
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) {
continue;
}
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
// 设置上传文件的类型为二进制类型
ftp.setFileType(FTP.BINARY_FILE_TYPE);
// 上传文件
if (!ftp.storeFile(filename, input)) {
return result;
}
input.close();
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
/**
* Description: 从FTP服务器下载文件
*
* @param host FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param remotePath FTP服务器上的相对路径
* @param fileName 要下载的文件名
* @param localPath 下载后保存到本地的路径
* @return
*/
public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
String fileName, String localPath) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login(username, password);// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(fileName)) {
File localFile = new File(localPath + "/" + ff.getName());
OutputStream is = new FileOutputStream(localFile);
ftp.retrieveFile(ff.getName(), is);
is.close();
}
}
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
public static void main(String[] args) {
try {
FileInputStream in = new FileInputStream(new File("D:\\temp\\image\\gaigeming.jpg"));
boolean flag = uploadFile("192.168.25.133", 21, "ftpuser", "ftpuser", "/app/startdis/excal", "/2022/07/11",
"gaigeming.jpg", in);
System.out.println(flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,33 @@
package ai.remi.comm.util.hash;
import cn.hutool.core.lang.hash.MurmurHash;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc HashUtils
*/
public class HashUtils {
private static char[] CHARS = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
private static int SIZE = CHARS.length;
private static String convertDecToBase62(long num) {
StringBuilder sb = new StringBuilder();
while (num > 0) {
int i = (int) (num % SIZE);
sb.append(CHARS[i]);
num /= SIZE;
}
return sb.reverse().toString();
}
public static String hashToBase62(String str) {
int i = MurmurHash.hash32(str);
long num = i < 0 ? Integer.MAX_VALUE - (long) i : i;
return convertDecToBase62(num);
}
}

View File

@@ -0,0 +1,138 @@
package ai.remi.comm.util.html;
import ai.remi.comm.util.string.StringUtils;
/**
* 转义和反转义工具类
*/
public class EscapeUtils {
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
private static final char[][] TEXT = new char[64][];
static {
for (int i = 0; i < 64; i++) {
TEXT[i] = new char[]{(char) i};
}
// special HTML characters
TEXT['\''] = "&#039;".toCharArray(); // 单引号
TEXT['"'] = "&#34;".toCharArray(); // 双引号
TEXT['&'] = "&#38;".toCharArray(); // &符
TEXT['<'] = "&#60;".toCharArray(); // 小于号
TEXT['>'] = "&#62;".toCharArray(); // 大于号
}
/**
* 转义文本中的HTML字符为安全的字符
*
* @param text 被转义的文本
* @return 转义后的文本
*/
public static String escape(String text) {
return encode(text);
}
/**
* 还原被转义的HTML特殊字符
*
* @param content 包含转义符的HTML内容
* @return 转换后的字符串
*/
public static String unescape(String content) {
return decode(content);
}
/**
* 清除所有HTML标签,但是不删除标签内的内容
*
* @param content 文本
* @return 清除标签后的文本
*/
public static String clean(String content) {
return new HTMLFilter().filter(content);
}
/**
* Escape编码
*
* @param text 被编码的文本
* @return 编码后的字符
*/
private static String encode(String text) {
if (StringUtils.isEmpty(text)) {
return StringUtils.EMPTY;
}
final StringBuilder tmp = new StringBuilder(text.length() * 6);
char c;
for (int i = 0; i < text.length(); i++) {
c = text.charAt(i);
if (c < 256) {
tmp.append("%");
if (c < 16) {
tmp.append("0");
}
tmp.append(Integer.toString(c, 16));
} else {
tmp.append("%u");
if (c <= 0xfff) {
// issue#I49JU8@Gitee
tmp.append("0");
}
tmp.append(Integer.toString(c, 16));
}
}
return tmp.toString();
}
/**
* Escape解码
*
* @param content 被转义的内容
* @return 解码后的字符串
*/
public static String decode(String content) {
if (StringUtils.isEmpty(content)) {
return content;
}
StringBuilder tmp = new StringBuilder(content.length());
int lastPos = 0, pos = 0;
char ch;
while (lastPos < content.length()) {
pos = content.indexOf("%", lastPos);
if (pos == lastPos) {
if (content.charAt(pos + 1) == 'u') {
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
tmp.append(ch);
lastPos = pos + 6;
} else {
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
tmp.append(ch);
lastPos = pos + 3;
}
} else {
if (pos == -1) {
tmp.append(content.substring(lastPos));
lastPos = content.length();
} else {
tmp.append(content.substring(lastPos, pos));
lastPos = pos;
}
}
}
return tmp.toString();
}
public static void main(String[] args) {
String html = "<script>alert(1);</script>";
String escape = EscapeUtils.escape(html);
// String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
// String html = "<123";
// String html = "123>";
System.out.println("clean: " + EscapeUtils.clean(html));
System.out.println("escape: " + escape);
System.out.println("unescape: " + EscapeUtils.unescape(escape));
}
}

View File

@@ -0,0 +1,495 @@
package ai.remi.comm.util.html;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* HTML过滤器,用于去除XSS漏洞隐患。
*/
public final class HTMLFilter {
/**
* regex flag union representing /si modifiers in php
**/
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
private static final Pattern P_END_ARROW = Pattern.compile("^>");
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_AMP = Pattern.compile("&");
private static final Pattern P_QUOTE = Pattern.compile("\"");
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
// @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
/**
* set of allowed html elements, along with allowed attributes for each element
**/
private final Map<String, List<String>> vAllowed;
/**
* counts of open tags for each (allowable) html element
**/
private final Map<String, Integer> vTagCounts = new HashMap<>();
/**
* html elements which must always be self-closing (e.g. "<img />")
**/
private final String[] vSelfClosingTags;
/**
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
**/
private final String[] vNeedClosingTags;
/**
* set of disallowed html elements
**/
private final String[] vDisallowed;
/**
* attributes which should be checked for valid protocols
**/
private final String[] vProtocolAtts;
/**
* allowed protocols
**/
private final String[] vAllowedProtocols;
/**
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
**/
private final String[] vRemoveBlanks;
/**
* entities allowed within html markup
**/
private final String[] vAllowedEntities;
/**
* flag determining whether comments are allowed in input String.
*/
private final boolean stripComment;
private final boolean encodeQuotes;
/**
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
* becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
*/
private final boolean alwaysMakeTags;
/**
* Default constructor.
*/
public HTMLFilter() {
vAllowed = new HashMap<>();
final ArrayList<String> a_atts = new ArrayList<>();
a_atts.add("href");
a_atts.add("target");
vAllowed.put("a", a_atts);
final ArrayList<String> img_atts = new ArrayList<>();
img_atts.add("src");
img_atts.add("width");
img_atts.add("height");
img_atts.add("alt");
vAllowed.put("img", img_atts);
final ArrayList<String> no_atts = new ArrayList<>();
vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts);
vSelfClosingTags = new String[]{"img"};
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
vDisallowed = new String[]{};
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
vProtocolAtts = new String[]{"src", "href"};
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = false;
}
/**
* Map-parameter configurable constructor.
*
* @param conf map containing configuration. keys match field names.
*/
@SuppressWarnings("unchecked")
public HTMLFilter(final Map<String, Object> conf) {
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
vDisallowed = (String[]) conf.get("vDisallowed");
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
}
private void reset() {
vTagCounts.clear();
}
// ---------------------------------------------------------------
// my versions of some PHP library functions
public static String chr(final int decimal) {
return String.valueOf((char) decimal);
}
public static String htmlSpecialChars(final String s) {
String result = s;
result = regexReplace(P_AMP, "&amp;", result);
result = regexReplace(P_QUOTE, "&quot;", result);
result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result;
}
// ---------------------------------------------------------------
/**
* given a user submitted input String, filter out any invalid or restricted html.
*
* @param input text (i.e. submitted by a user) than may contain html
* @return "clean" version of input, with only valid, whitelisted html elements allowed
*/
public String filter(final String input) {
reset();
String s = input;
s = escapeComments(s);
s = balanceHTML(s);
s = checkTags(s);
s = processRemoveBlanks(s);
// s = validateEntities(s);
return s;
}
public boolean isAlwaysMakeTags() {
return alwaysMakeTags;
}
public boolean isStripComments() {
return stripComment;
}
private String escapeComments(final String s) {
final Matcher m = P_COMMENTS.matcher(s);
final StringBuffer buf = new StringBuffer();
if (m.find()) {
final String match = m.group(1); // (.*?)
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
}
m.appendTail(buf);
return buf.toString();
}
private String balanceHTML(String s) {
if (alwaysMakeTags) {
//
// try and form html
//
s = regexReplace(P_END_ARROW, "", s);
// 不追加结束标签
s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
} else {
//
// escape stray brackets
//
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
//
// the last regexp causes '<>' entities to appear
// (we need to do a lookahead assertion so that the last bracket can
// be used in the next pass of the regexp)
//
s = regexReplace(P_BOTH_ARROWS, "", s);
}
return s;
}
private String checkTags(String s) {
Matcher m = P_TAGS.matcher(s);
final StringBuffer buf = new StringBuffer();
while (m.find()) {
String replaceStr = m.group(1);
replaceStr = processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
}
m.appendTail(buf);
// these get tallied in processTag
// (remember to reset before subsequent calls to filter method)
final StringBuilder sBuilder = new StringBuilder(buf.toString());
for (String key : vTagCounts.keySet()) {
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
sBuilder.append("</").append(key).append(">");
}
}
s = sBuilder.toString();
return s;
}
private String processRemoveBlanks(final String s) {
String result = s;
for (String tag : vRemoveBlanks) {
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
}
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
}
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
}
return result;
}
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement);
}
private String processTag(final String s) {
// ending tags
Matcher m = P_END_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
if (allowed(name)) {
if (!inArray(name, vSelfClosingTags)) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) - 1);
return "</" + name + ">";
}
}
}
}
// starting tags
m = P_START_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
final String body = m.group(2);
String ending = m.group(3);
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
if (allowed(name)) {
final StringBuilder params = new StringBuilder();
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<>();
final List<String> paramValues = new ArrayList<>();
while (m2.find()) {
paramNames.add(m2.group(1)); // ([a-z0-9]+)
paramValues.add(m2.group(3)); // (.*?)
}
while (m3.find()) {
paramNames.add(m3.group(1)); // ([a-z0-9]+)
paramValues.add(m3.group(3)); // ([^\"\\s']+)
}
String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++) {
paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii);
// debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
if (allowedAttribute(name, paramName)) {
if (inArray(paramName, vProtocolAtts)) {
paramValue = processParamProtocol(paramValue);
}
params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
}
}
if (inArray(name, vSelfClosingTags)) {
ending = " /";
}
if (inArray(name, vNeedClosingTags)) {
ending = "";
}
if (ending == null || ending.length() < 1) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) + 1);
} else {
vTagCounts.put(name, 1);
}
} else {
ending = " /";
}
return "<" + name + params + ending + ">";
} else {
return "";
}
}
// comments
m = P_COMMENT.matcher(s);
if (!stripComment && m.find()) {
return "<" + m.group() + ">";
}
return "";
}
private String processParamProtocol(String s) {
s = decodeEntities(s);
final Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) {
final String protocol = m.group(1);
if (!inArray(protocol, vAllowedProtocols)) {
// bad protocol, turn into local anchor link instead
s = "#" + s.substring(protocol.length() + 1);
if (s.startsWith("#//")) {
s = "#" + s.substring(3);
}
}
}
return s;
}
private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer();
Matcher m = P_ENTITY.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.decode(match).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENCODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
s = validateEntities(s);
return s;
}
private String validateEntities(final String s) {
StringBuffer buf = new StringBuffer();
// validate entities throughout the string
Matcher m = P_VALID_ENTITIES.matcher(s);
while (m.find()) {
final String one = m.group(1); // ([^&;]*)
final String two = m.group(2); // (?=(;|&|$))
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
}
m.appendTail(buf);
return encodeQuotes(buf.toString());
}
private String encodeQuotes(final String s) {
if (encodeQuotes) {
StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_QUOTES.matcher(s);
while (m.find()) {
final String one = m.group(1); // (>|^)
final String two = m.group(2); // ([^<]+?)
final String three = m.group(3); // (<|$)
// 不替换双引号为&quot;,防止json格式无效 regexReplace(P_QUOTE, "&quot;", two)
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
}
m.appendTail(buf);
return buf.toString();
} else {
return s;
}
}
private String checkEntity(final String preamble, final String term) {
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
}
private boolean isValidEntity(final String entity) {
return inArray(entity, vAllowedEntities);
}
private static boolean inArray(final String s, final String[] array) {
for (String item : array) {
if (item != null && item.equals(s)) {
return true;
}
}
return false;
}
private boolean allowed(final String name) {
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
}
private boolean allowedAttribute(final String name, final String paramName) {
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
}
}

View File

@@ -0,0 +1,98 @@
package ai.remi.comm.util.http;
import org.springframework.util.StringUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* cookie操作工具
*/
public class CookieUtils {
/**
* 按名称获取cookie
*
* @param request
* @param name
* @return
*/
public static Cookie getCookie(String name, HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null || !StringUtils.hasLength(name)) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
/**
* 按名称获取cookie中的值
*
* @param request
* @param name
* @return
*/
public static String getCookieValue(String name, HttpServletRequest request) {
Cookie cookie = getCookie(name, request);
return cookie == null ? null : cookie.getValue();
}
/**
* 添加cookie
*
* @param name
* @param value
* @param path
* @param request
* @param response
*/
public static void addCookie(String name, String value, String path, HttpServletRequest request,
HttpServletResponse response) {
Cookie cookie = new Cookie(name, value);
if (path != null) {
cookie.setPath(path);
}
if ("https".equals(request.getScheme())) {
cookie.setSecure(true);
}
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
/**
* 更新cookie中的值
*
* @param name
* @param value
* @param request
*/
public static void updateCookie(String name, String value, HttpServletRequest request) {
Cookie cookie = CookieUtils.getCookie(name, request);
cookie.setValue(value);
}
/**
* 清除cookie
*
* @param name
* @param path
* @param response
*/
public static void removeCookie(String name, String path, HttpServletResponse response) {
Cookie cookie = new Cookie(name, null);
if (path != null) {
cookie.setPath(path);
}
cookie.setMaxAge(-1000);
response.addCookie(cookie);
}
}

View File

@@ -0,0 +1,232 @@
package ai.remi.comm.util.http;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
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.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc HttpClientUtils
*/
public class HttpClientUtils {
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
/**
* Post请求
* @param url
* @param param
* @return
*/
public static String doPost(String url, Map<String, Object> param, Map<String, Object> headData) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
if (param != null) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for (String key : param.keySet()) {
formParams.add(new BasicNameValuePair(key, String.valueOf(param.get(key))));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams,"UTF-8");
httpPost.setEntity(entity);
}
//携带head数据
if (headData != null && headData.size() > 0) {
for (String key : headData.keySet()) {
httpPost.setHeader(key, (String) headData.get(key));
}
}
//执行post请求
response = httpClient.execute(httpPost);
if (response!=null && response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(),"UTF-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (response != null) {
response.close();
}
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
public static String doPostJson(String url, String json, Map<String, String> headData) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
//携带head数据
if (headData != null && headData.size() > 0) {
for (String key : headData.keySet()) {
httpPost.setHeader(key, (String) headData.get(key));
}
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
}

View File

@@ -0,0 +1,394 @@
package ai.remi.comm.util.http;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import ai.remi.comm.core.constant.Constants;
import ai.remi.comm.core.constant.TokenConstants;
import ai.remi.comm.core.result.ResultBean;
import ai.remi.comm.util.string.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc 客户端工具类
*/
@Slf4j
public class ServletUtils {
/**
* 获取请求token
*/
public static String getToken(ServerHttpRequest request) {
String token = request.getHeaders().getFirst(TokenConstants.SUPPLY_AUTHORIZATION);
if (StrUtil.isBlank(token)) {
token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
}
return getToken(token);
}
/**
* 获取请求token
*/
public static String getToken(String token) {
if (StrUtil.isNotEmpty(token) && StrUtil.startWith(token, TokenConstants.PREFIX)) {
token = StringUtils.replaceFirst(token, TokenConstants.PREFIX, StrUtil.EMPTY);
}
return token;
}
/**
* 鉴权失败处理
*/
public static Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, 401);
}
/**
* 增加请求头
*/
public static void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
if (value == null) {
return;
}
String valueStr = value.toString();
String valueEncode = ServletUtils.urlEncode(valueStr);
mutate.header(name, valueEncode);
}
/**
* 移除请求头
*/
public static void removeHeader(ServerHttpRequest.Builder mutate, String name) {
mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
}
/**
* 获取参数Map
*/
public static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
for (String value : values) {
parameters.add(key, value);
}
});
return parameters;
}
/**
* 获取String参数
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue) {
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String[]> getParams(ServletRequest request) {
final Map<String, String[]> map = request.getParameterMap();
return Collections.unmodifiableMap(map);
}
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String> getParamMap(ServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
params.put(entry.getKey(), ArrayUtil.join(entry.getValue(), StrUtil.COMMA));
}
return params;
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
try {
return getRequestAttributes().getRequest();
} catch (Exception e) {
return null;
}
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
try {
return getRequestAttributes().getResponse();
} catch (Exception e) {
return null;
}
}
/**
* 获取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
try {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
} catch (Exception e) {
return null;
}
}
public static String getHeader(HttpServletRequest request, String name) {
String value = request.getHeader(name);
if (StringUtils.isEmpty(value)) {
return StringUtils.EMPTY;
}
return urlDecode(value);
}
public static Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedCaseInsensitiveMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
*/
public static void renderString(HttpServletResponse response, String string) {
try {
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.contains("application/json")) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
}
/**
* 内容编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str) {
try {
return URLEncoder.encode(str, Constants.UTF8);
} catch (UnsupportedEncodingException e) {
return StringUtils.EMPTY;
}
}
/**
* 内容解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str) {
try {
return URLDecoder.decode(str, Constants.UTF8);
} catch (UnsupportedEncodingException e) {
return StringUtils.EMPTY;
}
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value) {
return webFluxResponseWriter(response, HttpStatus.OK, value, 500);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code) {
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, int code) {
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param contentType content-type
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code) {
response.setStatusCode(status);
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
ResultBean<?> result = ResultBean.error(String.valueOf(code), value.toString());
DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
/**
* 设置servlet响应
*
* @param response HttpServletResponse
* @param value 响应内容
*/
public static void webResponseWriter(HttpServletResponse response, Object value) {
webResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, value);
}
/**
* 设置servlet响应
*
* @param response HttpServletResponse
* @param contentType content-type
* @param value 响应内容
*/
public static void webResponseWriter(HttpServletResponse response, String contentType, Object value) {
response.setContentType(contentType);
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
Writer writer = null;
try {
writer = response.getWriter();
writer.write(JSON.toJSONString(value));
writer.flush();
} catch (IOException var8) {
throw new UtilException(var8);
} finally {
IoUtil.close(writer);
}
}
}

View File

@@ -0,0 +1,27 @@
package ai.remi.comm.util.http;
/**
* url工具类
*/
public class UrlUtils {
/**
* @return {@code true} if the url is an http: url.
*/
public static boolean isHttpUrl(String url) {
return (null != url)
&& (url.length() > 6)
&& url.substring(0, 7).equalsIgnoreCase("http://");
}
/**
* @return {@code true} if the url is an https: url.
*/
public static boolean isHttpsUrl(String url) {
return (null != url)
&& (url.length() > 7)
&& url.substring(0, 8).equalsIgnoreCase("https://");
}
}

View File

@@ -0,0 +1,240 @@
package ai.remi.comm.util.id;
import java.util.Random;
import java.math.BigDecimal;
/**
* 随机方法工具类
*
* @author dianjiu
*/
public class RandomUtils {
static Random random = new Random();
static String GREATER_THAN = "x must be greater than or equal 0";
static String Y_GREATER_THAN_X = "y must be greater than x";
private static final int DISPLAYABLE_MIN_INDEX = 33;
private static final int DISPLAYABLE_MAX_INDEX = 127 - 1;
private static final String ALL_CHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LETTER_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String NUMBER_CHAR = "0123456789";
private static final ThreadLocal<Random> local = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random();
}
};
/**
* 获取定长的随机数,包含大小写、数字
*
* @param length 随机数长度
* @return 返回字符串
*/
public static String generateString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(ALL_CHAR.charAt(random.nextInt(ALL_CHAR.length())));
}
return sb.toString();
}
/**
* 获取定长的随机数,包含大小写字母
*
* @param length 随机数长度
* @return 返回字符串
*/
public static String generateMixString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(LETTER_CHAR.charAt(random.nextInt(LETTER_CHAR.length())));
}
return sb.toString();
}
/**
* 获取定长的随机数,只包含小写字母
*
* @param length 随机数长度
* @return 返回字符串
*/
public static String generateLowerString(int length) {
return generateMixString(length).toLowerCase();
}
/**
* 获取定长的随机数,只包含大写字母
*
* @param length 随机数长度
* @return 返回字符串
*/
public static String generateUpperString(int length) {
return generateMixString(length).toUpperCase();
}
/**
* 获取定长的随机数,只包含数字
*
* @param length 随机数长度
* @return 返回字符串
*/
public static String generateNumberString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(NUMBER_CHAR.charAt(random.nextInt(NUMBER_CHAR.length())));
}
return sb.toString();
}
/**
* 获取Random实例
*
* @return 返回随机值
*/
public static Random getRandom() {
return local.get();
}
/**
* 产生[0, x]区间的随机数
*
* @param x > 0
* @return
*/
public static int intSeed(int x) {
return intSeed(0, x);
}
/**
* 产生[x, y]区间的随机数
*
* @param x >= 0
* @param y > x
* @return 返回int数
*/
public static int intSeed(int x, int y) {
if (x < 0) { // ensure x >= 0
throw new IllegalArgumentException(
Y_GREATER_THAN_X);
}
if (x >= y) { // ensure y > x
throw new IllegalArgumentException("");
}
return x + getRandom().nextInt(y - x + 1);
}
/**
* 产生[0, x]区间的随机数
*
* @param x> 0
* @return 返回长整型
*/
public static long longSeed(long x) {
return longSeed(0, x);
}
/**
* 产生[x, y]区间的随机数
*
* @param x >= 0
* @param y > x
* @return 返回长整型
*/
public static long longSeed(long x, long y) {
if (x < 0) { // ensure x >= 0
throw new IllegalArgumentException(
GREATER_THAN);
}
if (x >= y) { // ensure y > x
throw new IllegalArgumentException(Y_GREATER_THAN_X);
}
return Math.abs(getRandom().nextLong() % (y - x + 1)) + x;
}
/**
* 产生[0, x]区间的随机小数
*
* @param x > 0
* @return 返回浮点数
*/
public static float floatSeed(float x) {
return (float) doubleSeed(0., x);
}
/**
* 产生[x, y]区间的随机小数
*
* @param x >= 0
* @param y > x
* @return 返回浮点数
*/
public static float floatSeed(float x, float y) {
return (float) doubleSeed(x, y);
}
/**
* 产生[0, x]区间的随机小数
*
* @param x > 0
* @return 返回double类型
*/
public static double doubleSeed(double x) {
return doubleSeed(0., x);
}
/**
* 产生[x, y]区间的随机小数
*
* @param x >= 0
* @param y > x
* @return 返回double类型
*/
public static double doubleSeed(double x, double y) {
if (x < 0) { // ensure x >= 0
throw new IllegalArgumentException(
"GREATER_THAN");
}
if (x >= y) { // ensure y > x
throw new IllegalArgumentException("Y_GREATER_THAN_X");
}
BigDecimal dx = new BigDecimal(String.valueOf(x));
BigDecimal dy = new BigDecimal(String.valueOf(y));
double diff = dy.subtract(dx).doubleValue();
dx = dx.add(new BigDecimal(String.valueOf(getRandom().nextDouble()
* diff)));
return dx.doubleValue();
}
/**
* 随机产生true或false
*
* @return 返回布尔类型
*/
public static boolean boolSeed() {
return intSeed(0, 1) == 0 ? false : true;
}
/**
* 随机产生有效的可显示的字符
*
* @param x >= 33
* @param y > x & <= 126
* @return 返回char
*/
public static char charSeed(char x, char y) {
if (x < DISPLAYABLE_MIN_INDEX) { // ensure x >= 33 ('!')
throw new IllegalArgumentException(
"x must be greater than or equal '!'");
}
if (x >= y) { // ensure y > x
throw new IllegalArgumentException("Y_GREATER_THAN_X");
}
if (y > DISPLAYABLE_MAX_INDEX) { // ensure y <= 126 ('~')
throw new IllegalArgumentException(
"y must be less than or equal '~'");
}
return (char) (getRandom().nextInt(y - x + 1) + x);
}
}

View File

@@ -0,0 +1,121 @@
package ai.remi.comm.util.id;
import ai.remi.comm.util.ip.MacAddressUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class SequenceUtils {
private static final Logger log = LoggerFactory.getLogger(SequenceUtils.class);
public static String OLD_DATETIME = "";
/**
* 静态属性
*/
public static int STATIC_SEQUENCE = 0;
/**
* 默认节点
*/
public static String DEFAULT_NODE_NUMBER = "01";
public static String STATIC_NODE_NUMBER = "--";
/**
* 生成20位的流水号
*
* @return 流水号
*/
public static synchronized String next() {
String currentDateTime = getCurrentSystemDateTime();
if (null == currentDateTime) {
log.error("获取系统日期失败");
return null;
}
StringBuffer sequenceNumber = new StringBuffer();
sequenceNumber.append(currentDateTime.substring(0, 8));
sequenceNumber.append(getNodeNumber());
sequenceNumber.append(currentDateTime.substring(8));
sequenceNumber.append(nextSequence());
return sequenceNumber.toString();
}
public static final String initNodeNumber(String nodeNumbers) {
if (STATIC_NODE_NUMBER.equals("--")) {
if (null != nodeNumbers && !nodeNumbers.equals("")) {
String ipAddressConfigValue = nodeNumbers;
log.info("ARE config.node.number : " + ipAddressConfigValue);
if (ipAddressConfigValue.indexOf(",") > -1) {
String hostIpAddress = MacAddressUtils.getAllHostMacAddress();//获得本机IP
log.info("hostIpAddress : " + hostIpAddress);
String[] ipAddressValues = ipAddressConfigValue.split(",");
for (String ipvalue : ipAddressValues) {
String[] ipNode = ipvalue.split("=");
if (ipNode != null && ipNode.length > 0 && hostIpAddress.indexOf(ipNode[0]) > -1) {
STATIC_NODE_NUMBER = ipNode[1];
}
}
if (STATIC_NODE_NUMBER.equals("--")) {
log.error("GET MAC BIND NODE ERROR . ");
STATIC_NODE_NUMBER = DEFAULT_NODE_NUMBER;
}
} else {
STATIC_NODE_NUMBER = nodeNumbers;
}
log.info("STATIC_NODE_SEQUENCE_NUMBER : " + STATIC_NODE_NUMBER);
if (STATIC_NODE_NUMBER.length() != 2) {
log.error("系统节点号必须2位");
}
} else {
STATIC_NODE_NUMBER = DEFAULT_NODE_NUMBER;
}
}
return STATIC_NODE_NUMBER;
}
public static final String getNodeNumber() {
return STATIC_NODE_NUMBER;
}
/**
* 同一时刻只有一个访问
*
* @return
*/
private static final synchronized String nextSequence() {
STATIC_SEQUENCE = (STATIC_SEQUENCE + 1) % 10000;
return String.format("%04d", STATIC_SEQUENCE);
}
/**
* 获取系统当前日期,格式为yyyyMMddHHmmSS
*
* @return 当前系统日期
*/
private static synchronized String getCurrentSystemDateTime() {
String currentdatetime = null;
synchronized (OLD_DATETIME) {
currentdatetime = (new java.text.SimpleDateFormat("yyyyMMddHHmmss")).format(new Date());
/**
* 判断是否是新的时间,如果是新时间则STATIC_SEQUENCE从0开始计数
*/
if (!currentdatetime.equals(OLD_DATETIME)) {
STATIC_SEQUENCE = 0;
OLD_DATETIME = currentdatetime;
}
}
return currentdatetime;
}
}

View File

@@ -0,0 +1,194 @@
package ai.remi.comm.util.id;
import ai.remi.comm.util.hash.HashUtils;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc SnowflakeIDUtils
*/
public class SnowflakeUtils {
private static final SnowflakeUtils intance = new SnowflakeUtils(1, 1, 1);
//因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。
//下面两个每个5位,加起来就是10位的工作机器id
/**
* 机器ID 2进制5位 32位减掉1位 31个
*/
private long workerId;
/**
* //机房ID 2进制5位 32位减掉1位 31个
*/
private long datacenterId;
/**
* 12位的序列号,代表一毫秒内生成的多个id的最新序号 4096 -1 = 4095 个
*/
private long sequence;
/**
* 设置一个时间初始值 2^41 - 1 差不多可以用69年
*/
private long twepoch = 1888888888L;
/**
* 5位的机器id
*/
private long workerIdBits = 5L;
/**
* 5位的机房id
*/
private long datacenterIdBits = 5L;
/**
* 每毫秒内产生的id数 2 的 12次方
*/
private long sequenceBits = 12L;
/**
* 这个是二进制运算,就是5 bit最多只能有31个数字,也就是说机器id最多只能是32以内
*/
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
/**
* 这个是一个意思,就是5 bit最多只能有31个数字,机房id最多只能是32以内
*/
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 记录产生时间毫秒数,判断是否是同1毫秒
*/
private long lastTimestamp = -1L;
public long getWorkerId() {
return workerId;
}
public long getDatacenterId() {
return datacenterId;
}
public long getTimestamp() {
return System.currentTimeMillis();
}
public static SnowflakeUtils getInstance() {
return intance;
}
public static SnowflakeUtils getInstance(long workerId, long datacenterId) {
return new SnowflakeUtils(workerId, datacenterId, 1);
}
/**
* 构造方法
*
* @param workerId
* @param datacenterId
* @param sequence
*/
public SnowflakeUtils(long workerId, long datacenterId, long sequence) {
// 检查机房id和机器id是否超过31 不能小于0
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
this.sequence = sequence;
}
public synchronized String nextShortId() {
return HashUtils.hashToBase62(this.nextIdStr());
}
public synchronized String nextIdStr() {
return Long.toString(this.nextId());
}
/**
* 这个是核心方法,通过调用nextId()方法,让当前这台机器上的snowflake算法程序生成一个全局唯一的id
*
* @return
*/
public synchronized long nextId() {
// 这儿就是获取当前时间戳,单位是毫秒
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
System.err.printf(
"clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
// 下面是说假设在同一个毫秒内,又发送了一个请求生成一个id
// 这个时候就得把seqence序号给递增1,最多就是4096
if (lastTimestamp == timestamp) {
// 这个意思是说一个毫秒内最多只能有4096个数字,无论你传递多少进来,
//这个位运算保证始终就是在4096这个范围内,避免你自己传递个sequence超过了4096这个范围
sequence = (sequence + 1) & sequenceMask;
//当某一毫秒的时间,产生的id数 超过4095,系统会进入等待,直到下一毫秒,系统继续产生ID
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
// 这儿记录一下最近一次生成id的时间戳,单位是毫秒
lastTimestamp = timestamp;
// 这儿就是最核心的二进制位运算操作,生成一个64bit的id
// 先将当前时间戳左移,放到41 bit那儿;将机房id左移放到5 bit那儿;将机器id左移放到5 bit那儿;将序号放最后12 bit
// 最后拼接起来成一个64 bit的二进制数字,转换成10进制就是个long型
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) | sequence;
}
/**
* 当某一毫秒的时间,产生的id数 超过4095,系统会进入等待,直到下一毫秒,系统继续产生ID
*
* @param lastTimestamp
* @return
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
//获取当前时间戳
private long timeGen() {
return System.currentTimeMillis();
}
/**
* main 测试类
*
* @param args
*/
public static void main(String[] args) {
//SnowflakeIDUtils snowflakeIDUtils = new SnowflakeIDUtils(1, 1, 1);
//SnowflakeIDUtils instance = getInstance(1, 1);
System.out.println(getInstance().nextId());
System.out.println(getInstance(2,1).nextId());
//for (int i = 0; i < 9; i++) {
// System.out.println(getInstance().nextId());
// //System.out.println(instance.nextShortId());
// //System.out.println(snowflakeIDUtils.nextId());
//}
}
}

View File

@@ -0,0 +1,26 @@
package ai.remi.comm.util.id;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
/**
* 链路追踪工具类
*/
public class TracerUtils {
/**
* 私有化构造方法
*/
private TracerUtils() {
}
/**
* 获得链路追踪编号,直接返回 SkyWalking 的 TraceId。
* 如果不存在的话为空字符串!!!
*
* @return 链路追踪编号
*/
public static String getTraceId() {
return TraceContext.traceId();
}
}

View File

@@ -0,0 +1,72 @@
package ai.remi.comm.util.id;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc UUIDUtils
*/
public class UUIDUtils {
/**
* All possible chars for representing a number as a String
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/NumberUtil.java#L113
*/
private final static byte[] DIGITS = {
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z'
};
/**
* 生成不带有-的UUID字符串
*
* @return 不带有-的UUID字符串
*/
public static String simpleUuid() {
return uuid().replaceAll("-", "");
}
/**
* 生成带有-的UUID字符串
*
* @return 带有-的UUID字符串
*/
public static String uuid() {
ThreadLocalRandom random = ThreadLocalRandom.current();
long lsb = random.nextLong();
long msb = random.nextLong();
byte[] buf = new byte[32];
formatUnsignedLong(lsb, buf, 20, 12);
formatUnsignedLong(lsb >>> 48, buf, 16, 4);
formatUnsignedLong(msb, buf, 12, 4);
formatUnsignedLong(msb >>> 16, buf, 8, 4);
formatUnsignedLong(msb >>> 32, buf, 0, 8);
return new String(buf, StandardCharsets.UTF_8);
}
/**
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L348
*/
private static void formatUnsignedLong(long val, byte[] buf, int offset, int len) {
int charPos = offset + len;
int radix = 1 << 4;
int mask = radix - 1;
do {
buf[--charPos] = DIGITS[((int) val) & mask];
val >>>= 4;
} while (charPos > offset);
}
}

View File

@@ -0,0 +1,240 @@
package ai.remi.comm.util.ip;
import ai.remi.comm.util.string.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc IpUtils IP地址工具类
*/
public class IpAddrUtils {
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
}
/**
* 检查是否为内部IP地址
*
* @param ip IP地址
* @return 结果
*/
public static boolean internalIp(String ip) {
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}
/**
* 检查是否为内部IP地址
*
* @param addr byte地址
* @return 结果
*/
private static boolean internalIp(byte[] addr) {
if (StringUtils.isNull(addr) || addr.length < 2) {
return true;
}
final byte b0 = addr[0];
final byte b1 = addr[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0) {
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4) {
return true;
}
case SECTION_5:
switch (b1) {
case SECTION_6:
return true;
}
default:
return false;
}
}
/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text) {
if (text.length() == 0) {
return null;
}
byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try {
long l;
int i;
switch (elements.length) {
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) {
return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) {
return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i) {
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) {
return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i) {
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
} catch (NumberFormatException e) {
return null;
}
return bytes;
}
/**
* 获取IP地址
*
* @return 本地IP地址
*/
public static String getHostIp() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
}
return "127.0.0.1";
}
/**
* 获取主机名
*
* @return 本地主机名
*/
public static String getHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
}
return "未知";
}
/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
public static String getMultistageReverseProxyIp(String ip) {
// 多级反向代理检测
if (ip != null && ip.indexOf(",") > 0) {
final String[] ips = ip.trim().split(",");
for (String subIp : ips) {
if (false == isUnknown(subIp)) {
ip = subIp;
break;
}
}
}
return ip;
}
/**
* 检测给定字符串是否为未知,多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
public static boolean isUnknown(String checkString) {
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
/**
* 验证IP字符串是否合规
*
* @param ip ip字符串
* @return true标识合规
*/
public static boolean validIp(String ip) {
String pattern = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(ip);
boolean matches = m.matches();
return matches;
}
}

View File

@@ -0,0 +1,127 @@
package ai.remi.comm.util.ip;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc IpUtils IP归属地工具类
*/
@Slf4j
public class IpInfoUtils {
private static Searcher searcher;
static {
try (InputStream inputStream = IpInfoUtils.class.getClassLoader().getResourceAsStream("ip2region.xdb")) {
if (inputStream == null) {
throw new IOException("ip2region.xdb loading failed.");
}
byte[] buffer = new byte[8192];
int bytesRead;
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
searcher = Searcher.newWithBuffer(output.toByteArray());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取 ip 对应的信息
* @param ip
* @return 格式: 中国|0|浙江|杭州|电信
*/
public static IpInfo getInfo(String ip) {
IpInfo ipInfo = new IpInfo(ip);
if (!IpAddrUtils.validIp(ip)) {
log.warn("========非法 IP 格式========");
return ipInfo;
}
try {
convert(searcher.search(ip),ipInfo);
} catch (Exception e) {
throw new RuntimeException(e);
}
return ipInfo;
}
private static IpInfo convert(String regionStr,IpInfo ipInfo) {
if (regionStr == null || regionStr.length() == 0) {
return null;
}
String[] regionSplit = regionStr.split("\\|");
if (regionSplit.length != 5) {
return null;
}
ipInfo.setCountry("0".equals(regionSplit[0]) ? null : regionSplit[0]);
ipInfo.setRegion("0".equals(regionSplit[1]) ? null : regionSplit[1]);
ipInfo.setProvince("0".equals(regionSplit[2]) ? null : regionSplit[2]);
ipInfo.setCity("0".equals(regionSplit[3]) ? null : regionSplit[3]);
ipInfo.setIsp("0".equals(regionSplit[4]) ? null : regionSplit[4]);
return ipInfo;
}
@Setter
@Getter
@Accessors(chain = true)
@ToString
public static class IpInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 国家
*/
private String country = "未知";
/**
* 区域
*/
private String region = "未知";
/**
* 省份
*/
private String province = "未知";
/**
* 城市
*/
private String city = "未知";
/**
* 运营商
*/
private String isp = "未知";
/**
* IP地址
*/
private String ip;
public IpInfo(String ip) {
this.ip = ip;
}
}
public static void main(String[] args) {
IpInfo info = getInfo("14.29.139.251");
System.out.println(info.toString());
}
}

View File

@@ -0,0 +1,73 @@
package ai.remi.comm.util.ip;
import ai.remi.comm.util.id.SequenceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Properties;
public class MacAddressUtils {
private static final Logger log = LoggerFactory.getLogger(SequenceUtils.class);
public static String os;
static {
Properties prop = System.getProperties();
os = prop.getProperty("os.name");
log.info("OS : " + os);
}
public static String getAllHostMacAddress() {
String hostIpAddress = "";
try {
Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress inetAddress = null;
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
if (ni.getInetAddresses().hasMoreElements()) {
inetAddress = (InetAddress) ni.getInetAddresses().nextElement();
if (!inetAddress.isLoopbackAddress()) {
hostIpAddress += getMac(inetAddress) + ",";
log.info("host MAC : " + getMac(inetAddress));
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return hostIpAddress;
}
public static String getMac(InetAddress ia) throws SocketException {
//获取网卡,获取地址
byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
//LoggerFactory.getLogger(MacAddress.class).info("mac数组长度:"+mac.length);
StringBuffer sb = new StringBuffer("");
for (int i = 0; i < mac.length; i++) {
if (i != 0) {
if (os.startsWith("win") || os.startsWith("Win")) {
sb.append("-");//win
} else {
sb.append(":");//linux
}
}
//字节转换为整数
int temp = mac[i] & 0xff;
String str = Integer.toHexString(temp);
if (str.length() == 1) {
sb.append("0" + str);
} else {
sb.append(str);
}
}
return sb.toString().toUpperCase();
}
}

View File

@@ -0,0 +1,23 @@
package ai.remi.comm.util.merge;
import java.util.List;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc MergeUtils
*/
public class MergeUtils {
/**
*
* @param listA 需要合并的A对象集合
* @param listB 需要合并的B对象集合
* @param compare 对比A和B对象,如果true 就执行 merge方法
* @param merge 合并A和B对象,需要用户自己实现
* @param <R> 返回值的对象
* @param <T> 被合并的对象
*/
public static <R,T> void merge(List<R> listA, List<T> listB, Merged.Compare<R,T> compare, Merged<R, T> merge){
merge.apply(listA,listB,compare);
}
}

View File

@@ -0,0 +1,27 @@
package ai.remi.comm.util.merge;
import java.util.List;
/**
*
* @param <R> 返回值的对象类型
* @param <T> 需要被合并的类型
*/
@FunctionalInterface
public interface Merged<R,T> {
void merge(R r, T t);
default void apply(List<R> listA, List<T> listB,Compare<R,T> compare){
listA.forEach(a-> listB.forEach(b -> {
if(compare.compare(a,b)){
merge(a,b);
}
}));
}
@FunctionalInterface
interface Compare<R,T>{
boolean compare(R r,T t);
}
}

View File

@@ -0,0 +1,266 @@
package ai.remi.comm.util.money;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 金钱处理工具类
*
* @author dianjiu
*/
public class MoneyUtils {
/**
* 汉语中数字大写
*/
private static final String[] CN_UPPER_NUMBER = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
/**
* 汉语中货币单位大写
*/
private static final String[] CN_UPPER_MONETRAY_UNIT = {"分", "角", "元", "拾", "佰", "仟", "万", "拾",
"佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾",
"佰", "仟"};
/**
* 特殊字符:整
*/
private static final String CN_FULL = "";
/**
* 特殊字符:负
*/
private static final String CN_NEGATIVE = "负";
/**
* 零元整
*/
private static final String CN_ZEOR_FULL = "零元整";
/**
* 金额的精度,默认值为2
*/
private static final int MONEY_PRECISION = 2;
/**
* 人民币转换为大写,格式为:x万x千x百x十x元x角x分
*
* @param numberOfMoney 传入的金额
* @return 字符串
*/
public static String number2CNMontray(String numberOfMoney) {
return number2CNMontray(new BigDecimal(numberOfMoney));
}
/**
* 人民币转换为大写,格式为:x万x千x百x十x元x角x分
*
* @param numberOfMoney 传入的金额
* @return 字符串
*/
public static String number2CNMontray(BigDecimal numberOfMoney) {
StringBuilder sb = new StringBuilder();
int signum = numberOfMoney.signum();
if (signum == 0) {
return CN_ZEOR_FULL;
}
long number = numberOfMoney.movePointRight(MONEY_PRECISION).setScale(0, 4).abs().longValue();
long scale = number % 100;
int numUnit = 0;
int numIndex = 0;
boolean getZero = false;
// 判断最后两位数,一共有四中情况:00 = 0, 01 = 1, 10, 11
if (!(scale > 0)) {
numIndex = 2;
number = number / 100;
getZero = true;
}
if ((scale > 0) && (!(scale % 10 > 0))) {
numIndex = 1;
number = number / 10;
getZero = true;
}
int zeroSize = 0;
while (true) {
if (number <= 0) {
break;
}
// 每次获取到最后一个数
numUnit = (int) (number % 10);
if (numUnit > 0) {
if ((numIndex == 9) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
}
if ((numIndex == 13) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
}
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
getZero = false;
zeroSize = 0;
} else {
++zeroSize;
if (!(getZero)) {
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
}
if (numIndex == 2) {
if (number > 0) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
} else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
getZero = true;
}
// 让number每次都去掉最后一个数
number = number / 10;
++numIndex;
}
// 如果signum == -1,则说明输入的数字为负数,就在最前面追加特殊字符:负
if (signum == -1) {
sb.insert(0, CN_NEGATIVE);
}
// 输入的数字小数点后两位为"00"的情况,则要在最后追加特殊字符:整
if (!(scale > 0)) {
sb.append(CN_FULL);
}
return sb.toString();
}
/**
* 将人民币转换为会计格式金额(xxxx,xxxx,xxxx.xx),保留两位小数
*
* @param money 待转换的金额
* @return 字符串
*/
public static String accountantMoney(BigDecimal money) {
return accountantMoney(money, 2, 1);
}
/**
* 格式化金额,显示为xxx万元,xxx百万,xxx亿
*
* @param money 待处理的金额
* @param scale 小数点后保留的位数
* @param divisor 格式化值(10:十元、100:百元,1000千元,10000万元......)
* @return 字符串
*/
public static String getFormatMoney(BigDecimal money, int scale, double divisor) {
return formatMoney(money, scale, divisor) + getCellFormat(divisor);
}
/**
* 获取会计格式的人民币(格式为:xxxx,xxxx,xxxx.xx)
*
* @param money 待处理的金额
* @param scale 小数点后保留的位数
* @param divisor 格式化值(10:十元、100:百元,1000千元,10000万元......)
* @return 字符串
*/
public static String getAccountantMoney(BigDecimal money, int scale, double divisor) {
return accountantMoney(money, scale, divisor) + getCellFormat(divisor);
}
/**
* 将人民币转换为会计格式金额(xxxx,xxxx,xxxx.xx)
*
* @param money 待处理的金额
* @param scale 小数点后保留的位数
* @param divisor 格式化值
* @return 字符串
*/
private static String accountantMoney(BigDecimal money, int scale, double divisor) {
String disposeMoneyStr = formatMoney(money, scale, divisor);
int dotPosition = disposeMoneyStr.indexOf('.');
String exceptDotMoeny = null;//小数点之前的字符串
String dotMeony = null;//小数点之后的字符串
if (dotPosition > 0) {
exceptDotMoeny = disposeMoneyStr.substring(0, dotPosition);
dotMeony = disposeMoneyStr.substring(dotPosition);
} else {
exceptDotMoeny = disposeMoneyStr;
}
//负数处理
int negativePosition = exceptDotMoeny.indexOf('-');
if (negativePosition == 0) {
exceptDotMoeny = exceptDotMoeny.substring(1);
}
StringBuilder reverseExceptDotMoney = new StringBuilder(exceptDotMoeny);
reverseExceptDotMoney.reverse();//字符串倒转
char[] moneyChar = reverseExceptDotMoney.toString().toCharArray();
StringBuilder returnMeony = new StringBuilder();//返回值
for (int i = 0; i < moneyChar.length; i++) {
if (i != 0 && i % 3 == 0) {
returnMeony.append(",");//每隔3位加','
}
returnMeony.append(moneyChar[i]);
}
returnMeony.reverse();//字符串倒转
if (dotPosition > 0) {
returnMeony.append(dotMeony);
}
if (negativePosition == 0) {
return "-" + returnMeony.toString();
} else {
return returnMeony.toString();
}
}
/**
* 格式化金额,显示为xxx万元,xxx百万,xxx亿
*
* @param money 待处理的金额
* @param scale 小数点后保留的位数
* @param divisor 格式化值
* @return 字符串
*/
private static String formatMoney(BigDecimal money, int scale, double divisor) {
if (divisor == 0) {
return "0.00";
}
if (scale < 0) {
return "0.00";
}
BigDecimal divisorBD = BigDecimal.valueOf(divisor);
return money.divide(divisorBD, scale, RoundingMode.HALF_UP).toString();
}
private static String getCellFormat(double divisor) {
String str = String.valueOf(divisor);
int len = str.substring(0, str.indexOf('.')).length();
String cell = "";
switch (len) {
case 1:
cell = "元";
break;
case 2:
cell = "十元";
break;
case 3:
cell = "百元";
break;
case 4:
cell = "千元";
break;
case 5:
cell = "万元";
break;
case 6:
cell = "十万元";
break;
case 7:
cell = "百万元";
break;
case 8:
cell = "千万元";
break;
case 9:
cell = "亿元";
break;
case 10:
cell = "十亿元";
break;
default:
cell = "-1";
}
return cell;
}
}

View File

@@ -0,0 +1,103 @@
package ai.remi.comm.util.number;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc BigDecimalUtils
*/
public class BigDecimalUtils {
/**
* 中位数
*/
public static BigDecimal median(List<BigDecimal> list) {
if (null == list) {
return null;
}
Collections.sort(list);
int size = list.size();
if (size % 2 == 1) {
return list.get((size - 1) / 2);
} else {
return (list.get(size / 2 - 1).add(list.get(size / 2))).divide(new BigDecimal(2), 3);
}
}
/**
* 排序
*/
public static List<BigDecimal> sort(List<BigDecimal> list) {
if (null == list) {
return null;
}
Collections.sort(list);
return list;
}
/**
* 最大值
*/
public static BigDecimal max(List<BigDecimal> list) {
if (null == list) {
return null;
}
// BigDecimal max = Collections.max(list);
BigDecimal sum = list.get(0);
for (int i = 1; i < list.size(); i++) {
sum = sum.max(list.get(i));
}
return sum;
}
/**
* 最小值
*/
public static BigDecimal min(List<BigDecimal> list) {
if (null == list) {
return null;
}
// BigDecimal min = Collections.min(list);
BigDecimal sum = list.get(0);
for (int i = 1; i < list.size(); i++) {
sum = sum.min(list.get(i));
}
return sum;
}
/**
* 平均值
*
* @return
*/
public static BigDecimal avg(List<BigDecimal> list) {
if (null == list) {
return null;
}
BigDecimal sum = list.get(0);
for (int i = 1; i < list.size(); i++) {
sum = sum.add(list.get(i));
}
BigDecimal sum1 = new BigDecimal(list.size());
BigDecimal avg = sum.divide(sum1, 2);
System.out.println(avg);
return avg;
}
}

View File

@@ -0,0 +1,301 @@
package ai.remi.comm.util.object;
import ai.remi.comm.util.string.StringUtils;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc ObjectUtils 对象工具箱
*/
public class ObjectUtils {
/**
* 判断字符串是否为true
*
* @param str
* @return
*/
public static boolean isStrTrue(String str) {
return StringUtils.isNotEmpty(str) && "true".equals(str);
}
/**
* 判断对象是否不为空
*
* @param object
* @return: boolean
*/
public static boolean isNotEmpty(Object object) {
return !isEmpty(object);
}
/**
* 判断对象是否为空
*
* @param object
* @return: boolean
*/
public static boolean isEmpty(Object object) {
boolean aNull = isNull(object);
if (!aNull) {
//普通的类对象
Field[] fields = object.getClass().getDeclaredFields();
//先假设全部属性都是空的,所以只要出现一个属性不为空的就不需要在循环判断
try {
for (Field field : fields) {
field.setAccessible(true);
if (!"serialVersionUID".equals(field.getName()) && !ObjectUtils.isNull(field.get(object))) {
return false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
/**
* 判断对象是否不为空
*
* @param object
* @return: boolean
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* 判断对象是否为空
*
* @param object
* @return: boolean
*/
public static boolean isNull(Object object) {
//判断对象是否为null
if (null == object) {
return true;
}
//判断对象是否为容器对象类型
if (object instanceof Optional) {
return !((Optional) object).isPresent();
}
//判断对象是否为字符集合类型
if (object instanceof CharSequence) {
return ((CharSequence) object).length() == 0;
}
//判断对象是否为数组类型
if (object.getClass().isArray()) {
return Array.getLength(object) == 0;
}
//判断对象是否为集合类型
if (object instanceof Collection) {
return ((Collection) object).isEmpty();
}
//判断对象是否为Map
return object instanceof Map ? ((Map) object).isEmpty() : false;
}
/**
* 判断obejct对象中除了names里面的字段,其他字段都为null(已知对象类型)
*
* @param object
* @param names
* @return
*/
public static boolean isEmpty(Object object, String... names) {
Field[] fields = object.getClass().getDeclaredFields();
//用于判断所有属性是否为空,如果参数为空则不查询
boolean flag = true;
for (Field field : fields) {
//不检查 直接取值
field.setAccessible(true);
try {
String fieldName = field.getName();
List<String> nameList = new ArrayList<>();
if (null != names && names.length != 0) {
nameList = Arrays.asList(names);
}
if (!nameList.contains(fieldName) && !Objects.isNull(field.get(object))) {
//不为空
flag = false;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return flag;
}
/**
* 判断object对象中除了names里面的字段,其他字段都为null或者是""(已知对象类型)
*
* @param object
* @param names
* @return
*/
public static boolean isBlank(Object object, String... names) {
Field[] fields = object.getClass().getDeclaredFields();
//用于判断所有属性是否为空,如果参数为空则不查询
boolean flag = true;
for (Field field : fields) {
//不检查 直接取值
field.setAccessible(true);
try {
String fieldName = field.getName();
List<String> nameList = new ArrayList<>();
if (null != names && names.length != 0) {
nameList = Arrays.asList(names);
}
Object value = field.get(object);
if (!nameList.contains(fieldName) && !isEmpty(value)) {
//不为空
flag = false;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return flag;
}
/**
* 利用反射 将Java实体转化为 map
*
* @param object object
* @return map
* @version 1.0
*/
public static Map<String, Object> objectToMap(Object object) {
Map<String, Object> reMap = new HashMap<>();
if (object == null) {
return null;
}
List<Field> fields = new ArrayList<>();
List<Field> childFields;
List<String> fieldsName = new ArrayList<>();
Class tempClass = object.getClass();
//当父类为null的时候说明到达了最上层的父类(Object类).
while (tempClass != null) {
fields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
//得到父类,然后赋给自己
tempClass = tempClass.getSuperclass();
}
childFields = Arrays.asList(object.getClass().getDeclaredFields());
for (Field field : childFields) {
fieldsName.add(field.getName());
}
try {
for (Field field : fields) {
try {
if (fieldsName.contains(field.getName())) {
Field f = object.getClass().getDeclaredField(field.getName());
f.setAccessible(true);
Object o = f.get(object);
reMap.put(field.getName(), o);
} else {
Field f = object.getClass().getSuperclass().getDeclaredField(field.getName());
f.setAccessible(true);
Object o = f.get(object);
reMap.put(field.getName(), o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
return reMap;
}
/**
* 利用反射将map集合封装成bean对象
*
* @param map
* @param clazz
* @return
*/
public static <T> T mapToObject(Map<Object, Object> map, Class<?> clazz) throws Exception {
Object obj = clazz.newInstance();
if (map != null && !map.isEmpty() && map.size() > 0) {
for (Map.Entry<Object, Object> entry : map.entrySet()) {
String propertyName = String.valueOf(entry.getKey()); // 属性名
Object value = entry.getValue(); // 属性值
String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
Field field = getClassField(clazz, propertyName); //获取和map的key匹配的属性名称
if (field == null) {
continue;
}
Class<?> fieldTypeClass = field.getType();
value = convertValType(value, fieldTypeClass);
try {
clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
return (T) obj;
}
/**
* 根据给定对象类匹配对象中的特定字段
*
* @param clazz
* @param fieldName
* @return
*/
private static Field getClassField(Class<?> clazz, String fieldName) {
if (Object.class.getName().equals(clazz.getName())) {
return null;
}
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
Class<?> superClass = clazz.getSuperclass(); //如果该类还有父类,将父类对象中的字段也取出
if (superClass != null) { //递归获取
return getClassField(superClass, fieldName);
}
return null;
}
/**
* 将map的value值转为实体类中字段类型匹配的方法
*
* @param value
* @param fieldTypeClass
* @return
*/
private static Object convertValType(Object value, Class<?> fieldTypeClass) {
Object retVal = null;
if (Long.class.getName().equals(fieldTypeClass.getName())
|| long.class.getName().equals(fieldTypeClass.getName())) {
retVal = Long.parseLong(value.toString());
} else if (Integer.class.getName().equals(fieldTypeClass.getName())
|| int.class.getName().equals(fieldTypeClass.getName())) {
retVal = Integer.parseInt(value.toString());
} else if (Float.class.getName().equals(fieldTypeClass.getName())
|| float.class.getName().equals(fieldTypeClass.getName())) {
retVal = Float.parseFloat(value.toString());
} else if (Double.class.getName().equals(fieldTypeClass.getName())
|| double.class.getName().equals(fieldTypeClass.getName())) {
retVal = Double.parseDouble(value.toString());
} else {
retVal = value;
}
return retVal;
}
}

View File

@@ -0,0 +1,5 @@
package ai.remi.comm.util.object;
public class SerializeUtils {
}

View File

@@ -0,0 +1,54 @@
package ai.remi.comm.util.page;
import java.util.ArrayList;
import java.util.List;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc PageUtils 分页工具箱
*/
public class PageUtils {
/**
* 开始分页
* @param list
* @param pageNum 页码
* @param pageSize 每页多少数据
* @param <T>
* @return
*/
public static <T> List<T> startPage(List<T> list, int pageNum, int pageSize){
if(null == list){
return new ArrayList<T>();
}
if(list.size() == 0){
return list;
}
if(pageNum == 0){
pageNum = 1;
}
int count = list.size(); //记录总数
int pageCount = 0; //页数
if(count % pageSize == 0){
pageCount = count / pageSize;
}else{
pageCount = count / pageSize + 1;
}
int fromIndex = 0; //开始索引
int toIndex = 0; //结束索引
if(pageNum > pageCount){
return new ArrayList<T>();
}
if(pageNum != pageCount){
fromIndex = (pageNum -1) * pageSize;
toIndex = fromIndex + pageSize;
}else {
fromIndex = (pageNum - 1) * pageSize;
toIndex = count;
}
return list.subList(fromIndex,toIndex);
}
}

View File

@@ -0,0 +1,405 @@
package ai.remi.comm.util.regex;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
*/
public class RegexUtils {
/******************** 正则相关常量 ********************/
/**
* 正则:手机号(简单)
*/
public static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$";
/**
* 正则:手机号(精确)
* <p>移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188</p>
* <p>联通:130、131、132、145、155、156、175、176、185、186</p>
* <p>电信:133、153、173、177、180、181、189</p>
* <p>全球星:1349</p>
* <p>虚拟运营商:170</p>
*/
public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$";
/**
* 正则:电话号码
*/
public static final String REGEX_TEL = "^0\\d{2,3}[- ]?\\d{7,8}";
/**
* 正则:身份证号码15位
*/
public static final String REGEX_ID_CARD15 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";
/**
* 正则:身份证号码18位
*/
public static final String REGEX_ID_CARD18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$";
/**
* 正则:邮箱
*/
public static final String REGEX_EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
/**
* 正则:URL
*/
public static final String REGEX_URL = "[a-zA-z]+://[^\\s]*";
/**
* 正则:汉字
*/
public static final String REGEX_ZH = "^[\\u4e00-\\u9fa5]+$";
/**
* 正则:用户名,取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位
*/
public static final String REGEX_USERNAME = "^[\\w\\u4e00-\\u9fa5]{6,20}(?<!_)$";
/**
* 正则:yyyy-MM-dd格式的日期校验,已考虑平闰年
*/
public static final String REGEX_DATE = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";
/**
* 正则:IP地址
*/
public static final String REGEX_IP = "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
/**
* 正则:双字节字符(包括汉字在内)
*/
public static final String REGEX_DOUBLE_BYTE_CHAR = "[^\\x00-\\xff]";
/**
* 正则:空白行
*/
public static final String REGEX_BLANK_LINE = "\\n\\s*\\r";
/**
* 正则:中国邮政编码
*/
public static final String REGEX_ZIP_CODE = "[1-9]\\d{5}(?!\\d)";
/**
* 正则:正整数
*/
public static final String REGEX_POSITIVE_INTEGER = "^[1-9]\\d*$";
/**
* 正则:负整数
*/
public static final String REGEX_NEGATIVE_INTEGER = "^-[1-9]\\d*$";
/**
* 正则:整数
*/
public static final String REGEX_INTEGER = "^-?[1-9]\\d*$";
/**
* 正则:非负整数(正整数 + 0)
*/
public static final String REGEX_NOT_NEGATIVE_INTEGER = "^[1-9]\\d*|0$";
/**
* 正则:非正整数(负整数 + 0)
*/
public static final String REGEX_NOT_POSITIVE_INTEGER = "^-[1-9]\\d*|0$";
/**
* 正则:正浮点数
*/
public static final String REGEX_POSITIVE_FLOAT = "^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
/**
* 正则:负浮点数
*/
public static final String REGEX_NEGATIVE_FLOAT = "^-[1-9]\\d*\\.\\d*|-0\\.\\d*[1-9]\\d*$";
/**
* 正则:整数或者浮点数
*/
public static final String REGEX_INTEGER_OR_FLOAT = "^-?(\\d|([1-9]\\d+))(\\.\\d+)?$";
/**
* 验证手机号(简单)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileSimple(CharSequence input) {
return isMatch(REGEX_MOBILE_SIMPLE, input);
}
/**
* 验证手机号(精确)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileExact(CharSequence input) {
return isMatch(REGEX_MOBILE_EXACT, input);
}
/**
* 验证电话号码
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isTel(CharSequence input) {
return isMatch(REGEX_TEL, input);
}
/**
* 验证身份证号码15位
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIDCard15(CharSequence input) {
return isMatch(REGEX_ID_CARD15, input);
}
/**
* 验证身份证号码18位
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIDCard18(CharSequence input) {
return isMatch(REGEX_ID_CARD18, input);
}
/**
* 验证邮箱
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isEmail(CharSequence input) {
return isMatch(REGEX_EMAIL, input);
}
/**
* 验证URL
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isURL(CharSequence input) {
return isMatch(REGEX_URL, input);
}
/**
* 验证汉字
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isZh(CharSequence input) {
return isMatch(REGEX_ZH, input);
}
/**
* 验证用户名
* <p>取值范围为a-z,A-Z,0-9,"_",汉字,不能以"_"结尾,用户名必须是6-20位</p>
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isUsername(CharSequence input) {
return isMatch(REGEX_USERNAME, input);
}
/**
* 验证yyyy-MM-dd格式的日期校验,已考虑平闰年
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isDate(CharSequence input) {
return isMatch(REGEX_DATE, input);
}
/**
* 验证IP地址
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIP(CharSequence input) {
return isMatch(REGEX_IP, input);
}
/**
* 验证是否为双字节字符(包括汉字在内)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isDoubleByteChar(CharSequence input) {
return isMatch(REGEX_DOUBLE_BYTE_CHAR, input);
}
/**
* 验证是否空白行
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isBlankLine(CharSequence input) {
return isMatch(REGEX_BLANK_LINE, input);
}
/**
* 验证是否中国邮政编码
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isZipCode(CharSequence input) {
return isMatch(REGEX_ZIP_CODE, input);
}
/**
* 验证是否正整数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isPositiveInteger(CharSequence input) {
return isMatch(REGEX_POSITIVE_INTEGER, input);
}
/**
* 验证是否负整数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isNegativeInteger(CharSequence input) {
return isMatch(REGEX_NEGATIVE_INTEGER, input);
}
/**
* 验证是否为整数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isRegexInteger(CharSequence input) {
return isMatch(REGEX_INTEGER, input);
}
/**
* 验证是否为非负整数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isNotNegativeInteger(CharSequence input) {
return isMatch(REGEX_NOT_NEGATIVE_INTEGER, input);
}
/**
* 验证是否为非正整数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isNotPositiveInteger(CharSequence input) {
return isMatch(REGEX_NOT_POSITIVE_INTEGER, input);
}
/**
* 验证是否正浮点数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isPositiveFloat(CharSequence input) {
return isMatch(REGEX_POSITIVE_FLOAT, input);
}
/**
* 验证是否负浮点数
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean NEGATIVE_FLOAT(CharSequence input) {
return isMatch(REGEX_NEGATIVE_FLOAT, input);
}
/**
* 验证是否空白行
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIntegerOrFloat(CharSequence input) {
return isMatch(REGEX_INTEGER_OR_FLOAT, input);
}
/**
* 判断是否匹配正则
*
* @param regex 正则表达式
* @param input 要匹配的字符串
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMatch(String regex, CharSequence input) {
return input != null && input.length() > 0 && Pattern.matches(regex, input);
}
/**
* 获取正则匹配的部分
*
* @param regex 正则表达式
* @param input 要匹配的字符串
* @return 正则匹配的部分
*/
public static List<String> getMatches(String regex, CharSequence input) {
if (input == null) {
return null;
}
List<String> matches = new ArrayList<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
matches.add(matcher.group());
}
return matches;
}
/**
* 获取正则匹配分组
*
* @param input 要分组的字符串
* @param regex 正则表达式
* @return 正则匹配分组
*/
public static String[] getSplits(String input, String regex) {
if (input == null) {
return null;
}
return input.split(regex);
}
/**
* 替换正则匹配的第一部分
*
* @param input 要替换的字符串
* @param regex 正则表达式
* @param replacement 代替者
* @return 替换正则匹配的第一部分
*/
public static String getReplaceFirst(String input, String regex, String replacement) {
if (input == null) {
return null;
}
return Pattern.compile(regex).matcher(input).replaceFirst(replacement);
}
/**
* 替换所有正则匹配的部分
*
* @param input 要替换的字符串
* @param regex 正则表达式
* @param replacement 代替者
* @return 替换所有正则匹配的部分
*/
public static String getReplaceAll(String input, String regex, String replacement) {
if (input == null) {
return null;
}
return Pattern.compile(regex).matcher(input).replaceAll(replacement);
}
}

View File

@@ -0,0 +1,29 @@
package ai.remi.comm.util.saml;
import cn.hutool.core.codec.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
public class SAMLUtils {
/**
* 解析SAMLRequest SAMLResponse
*/
public static String decodeAndInflateXML(String samlStr) throws Exception {
// base64解码
byte[] decodedBytes = Base64.decode(java.net.URLDecoder.decode(samlStr, "utf-8"));
// 获取输入流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodedBytes);
InflaterInputStream inflaterInputStream = new InflaterInputStream(byteArrayInputStream, new Inflater(true));
byte[] buffer = new byte[decodedBytes.length];
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// 信息写到输出流
for (int i = 0; i != -1; i = inflaterInputStream.read(buffer)) {
byteArrayOutputStream.write(buffer, 0, i);
}
return new String(byteArrayOutputStream.toByteArray(), "UTF-8");
}
}

View File

@@ -0,0 +1,264 @@
package ai.remi.comm.util.security;
import cn.hutool.core.exceptions.UtilException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @date 2022-07-26
* @desc AesUtils 加/解密工具类
* 使用密钥时请使用 initKey() 方法来生成随机密钥
* initKey 方法内部使用 java.crypto.KeyGenerator 密钥生成器来生成特定于 AES 算法参数集的随机密钥
* 使用密钥生成器生成的密钥能保证更强的随机性
* 生成的二进制密钥建议使用 Hex 进行编码
*/
public class AesUtils {
private AesUtils() {
}
/**
* 密钥算法类型
*/
public static final String KEY_ALGORITHM = "AES";
/**
* 密钥的默认位长度
*/
public static final int DEFAULT_KEY_SIZE = 128;
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ECB_PKCS_5_PADDING = "AES/ECB/PKCS5Padding";
public static final String ECB_NO_PADDING = "AES/ECB/NoPadding";
public static String base64Encode(byte[] bytes) {
return Base64.encodeBase64String(bytes);
}
public static byte[] base64Decode(String base64Code) {
return Base64.decodeBase64(base64Code);
}
public static byte[] aesEncryptToBytes(String content, String hexAesKey) throws Exception {
return encrypt(content.getBytes(StandardCharsets.UTF_8), Hex.decodeHex(hexAesKey.toCharArray()));
}
public static String aesEncrypt(String content, String hexAesKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, hexAesKey));
}
public static String aesDecryptByBytes(byte[] encryptBytes, String hexAesKey) throws Exception {
byte[] decrypt = decrypt(encryptBytes, Hex.decodeHex(hexAesKey.toCharArray()));
return new String(decrypt, StandardCharsets.UTF_8);
}
public static String aesDecrypt(String encryptStr, String hexAesKey) throws Exception {
return aesDecryptByBytes(base64Decode(encryptStr), hexAesKey);
}
/**
* 生成 Hex 格式默认长度的随机密钥
* 32,解二进制后为 16 个字节
*
* @return String Hex 格式的随机密钥
*/
public static String initHexKey() {
return Hex.encodeHexString(initKey());
}
/**
* 生成默认长度的随机密钥
* 默认长度为 128
*
* @return byte[] 二进制密钥
*/
public static byte[] initKey() {
return initKey(DEFAULT_KEY_SIZE);
}
/**
* 生成密钥
* 128、192、256 可选
*
* @param keySize 密钥长度
* @return byte[] 二进制密钥
*/
public static byte[] initKey(int keySize) {
// AES 要求密钥长度为 128 位、192 位或 256 位
if (keySize != 128 && keySize != 192 && keySize != 256) {
throw new RuntimeException("error keySize: " + keySize);
}
// 实例化
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new UtilException("no such algorithm exception: " + KEY_ALGORITHM, e);
}
keyGenerator.init(keySize);
// 生成秘密密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获得密钥的二进制编码形式
return secretKey.getEncoded();
}
/**
* 转换密钥
*
* @param key 二进制密钥
* @return Key 密钥
*/
private static Key toKey(byte[] key) {
// 实例化 DES 密钥材料
return new SecretKeySpec(key, KEY_ALGORITHM);
}
/**
* 加密
*
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密的数据
*/
public static byte[] encrypt(byte[] data, byte[] key) {
return encrypt(data, key, ECB_PKCS_5_PADDING);
}
/**
* 加密
*
* @param data 待加密数据
* @param key 密钥
* @param cipherAlgorithm 算法/工作模式/填充模式
* @return byte[] 加密的数据
*/
public static byte[] encrypt(byte[] data, byte[] key, final String cipherAlgorithm) {
// 还原密钥
Key k = toKey(key);
try {
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
// 初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, k);
// 发现使用 NoPadding 时,使用 ZeroPadding 填充
if (ECB_NO_PADDING.equals(cipherAlgorithm)) {
return cipher.doFinal(formatWithZeroPadding(data, cipher.getBlockSize()));
}
// 执行操作
return cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException("AES encrypt error", e);
}
}
/**
* 解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密的数据
*/
public static byte[] decrypt(byte[] data, byte[] key) {
return decrypt(data, key, ECB_PKCS_5_PADDING);
}
/**
* 解密
*
* @param data 待解密数据
* @param key 密钥
* @param cipherAlgorithm 算法/工作模式/填充模式
* @return byte[] 解密的数据
*/
public static byte[] decrypt(byte[] data, byte[] key, final String cipherAlgorithm) {
// 还原密钥
Key k = toKey(key);
try {
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
// 初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, k);
// 发现使用 NoPadding 时,使用 ZeroPadding 填充
if (ECB_NO_PADDING.equals(cipherAlgorithm)) {
return removeZeroPadding(cipher.doFinal(data), cipher.getBlockSize());
}
// 执行操作
return cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException("AES decrypt error", e);
}
}
private static byte[] formatWithZeroPadding(byte[] data, final int blockSize) {
final int length = data.length;
final int remainLength = length % blockSize;
if (remainLength > 0) {
byte[] inputData = new byte[length + blockSize - remainLength];
System.arraycopy(data, 0, inputData, 0, length);
return inputData;
}
return data;
}
private static byte[] removeZeroPadding(byte[] data, final int blockSize) {
final int length = data.length;
final int remainLength = length % blockSize;
if (remainLength == 0) {
// 解码后的数据正好是块大小的整数倍,说明可能存在补 0 的情况,去掉末尾所有的 0
int i = length - 1;
while (i >= 0 && 0 == data[i]) {
i--;
}
byte[] outputData = new byte[i + 1];
System.arraycopy(data, 0, outputData, 0, outputData.length);
return outputData;
}
return data;
}
public static void main(String[] args) throws Exception {
//long current = Calendar.getInstance().getTimeInMillis();
//long current = 1616031425922L;
//System.out.println("\n当前时间戳为:" + current);
// 使用密钥生成器 KeyGenerator 生成的 16 字节随机密钥的 hex 字符串,使用时解 hex 得到二进制密钥
//byte[] bytes = AesUtils.initKey();
//String aesKey = Hex.encodeHexString(bytes);
String aesKey = "c39de8d1308e0ad7afbe1b4749c5d3a9";
System.out.println("\n当前密钥为" + aesKey);
//String content = "{\"isPhone\":\"0\",\"userid\":\"zhangsan\",\"passwd\":\"123456\",\"timestamp\":1610610307826}";
String content = "tya_40hyJF";
System.out.println("\nAES加密前:" + content);
String encrypt = aesEncrypt(content, aesKey);
System.out.println("\nAES加密后:" + encrypt);
String decrypt = aesDecrypt(encrypt, aesKey);
System.out.println("\nAES解密后:" + decrypt);
//String bb = "{\"isPhone\":\"0\",\"userid\":\"zhangsan\",\"passwd\":\"123456\",\"timestamp\":1610610307826}";
//String md5 = DigestUtils.md5DigestAsHex(bb.getBytes("UTF-8"));
//System.out.println("\nmd5加密后:" + md5);
}
}

View File

@@ -0,0 +1,132 @@
package ai.remi.comm.util.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Base64;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc Base64Kits
*/
public class Base64Utils {
public static final String CHARSET = "utf-8";
private static final Logger logger = LoggerFactory.getLogger(Base64Utils.class);
public static void main(String[] args) throws UnsupportedEncodingException {
//测试FileBase64
//long start = System.currentTimeMillis();
//String imgBase64Str = Base64Utils.convertFileToBase64("C:\\demos\\a3fa6ce0-b9a9-4313-93f0-501d1149596c.jpg");
//System.out.println("本地图片转换Base64:" + imgBase64Str);
//System.out.println("Base64字符串length=" + imgBase64Str.length());
//Base64Utils.convertBase64ToFile(imgBase64Str, "C:\\demos\\", "test.jpg");
//System.out.println("duration:" + (System.currentTimeMillis() - start));
//测试StringBase64
long start = System.currentTimeMillis();
//ThisIsMyCustomSecretKey012345678
//String base64Str = Base64Utils.encode("RemiAdminNacosCustomSecretKey2024");
String base64Str = Base64Utils.encode("RemiAdminNacosCustomSecretKey2024");
System.out.println("字符串加密后的Base64为:" + base64Str);
System.out.println("Base64字符串length=" + base64Str.length());
String decode = Base64Utils.decode(base64Str);
//String decode = Base64Utils.decode("VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=");
System.out.println("Base64解密后的字符串为:"+decode);
System.out.println("duration:" + (System.currentTimeMillis() - start));
}
/**
* 字符串解密
*/
public static String decode(String data) {
try {
if (null == data) {
return null;
}
return new String(Base64.getDecoder().decode(data.getBytes(CHARSET)), CHARSET);
} catch (UnsupportedEncodingException e) {
logger.error(String.format("字符串:%s,解密异常", data), e);
}
return null;
}
/**
* 字符串加密
*/
public static String encode(String data) {
try {
if (null == data) {
return null;
}
return new String(Base64.getEncoder().encode(data.getBytes(CHARSET)), CHARSET);
} catch (UnsupportedEncodingException e) {
logger.error(String.format("字符串:%s,加密异常", data), e);
}
return null;
}
/**
* 本地文件(图片、excel等)转换成Base64字符
*/
public static String convertFileToBase64(String filePath) throws UnsupportedEncodingException {
byte[] data = null;
// 读取图片字节数组
try {
InputStream in = new FileInputStream(filePath);
System.out.println("文件大小(字节)=" + in.available());
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组进行Base64编码,得到Base64编码的字符串
return new String(Base64.getEncoder().encode(data), CHARSET);
}
/**
* 将base64字符串,生成文件
*/
public static File convertBase64ToFile(String fileBase64String, String filePath, String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
File dir = new File(filePath);
//判断文件目录是否存在
if (!dir.exists() && dir.isDirectory()) {
dir.mkdirs();
}
byte[] bfile = Base64.getDecoder().decode(fileBase64String);
file = new File(filePath + File.separator + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bfile);
return file;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}

View File

@@ -0,0 +1,82 @@
package ai.remi.comm.util.security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
/**
* DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
* 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
* 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
* 注意:DES加密和解密过程中,密钥长度都必须是8的倍数
*/
public class DesUtils {
public DesUtils() {
}
// 测试
public static void main(String args[]) {
// 待加密内容
String str = "cryptology";
// 密码,长度要是8的倍数
String password = "95880288";
byte[] result;
try {
result = DesUtils.encrypt(str.getBytes(), password);
System.out.println("加密后: " + result);
byte[] decryResult = DesUtils.decrypt(result, password);
System.out.println("解密后: " + new String(decryResult));
} catch (UnsupportedEncodingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
public static byte[] encrypt(byte[] datasource, String password) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] src, String password) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
// Cipher
// 对象
// 将DESKeySpec对象转换成SecretKey对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
// 真正开始解密操作
return cipher.doFinal(src);
}
}

View File

@@ -0,0 +1,78 @@
package ai.remi.comm.util.security;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import lombok.SneakyThrows;
import org.apache.commons.lang3.Validate;
/**
* 不可逆加密工具类
*/
public class DigestUtils {
private static SecureRandom random = new SecureRandom();
/**
* 生成随机的Byte[]作为salt密钥.
*
* @param numBytes byte数组的大小
*/
public static byte[] genSalt(int numBytes) {
Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes);
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
/**
* 对字符串进行散列, 支持md5与sha1算法.
*
* @param input 需要散列的字符串
* @param algorithm 散列算法("SHA-1"、"MD5")
* @param salt
* @param iterations 迭代次数
* @return
*/
@SneakyThrows
public static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
MessageDigest digest = MessageDigest.getInstance(algorithm);
if (salt != null) {
digest.update(salt);
}
byte[] result = digest.digest(input);
for (int i = 1; i < iterations; i++) {
digest.reset();
result = digest.digest(result);
}
return result;
}
/**
* 对文件进行sha1散列.
*
* @param input 需要散列的流
* @param algorithm 散列算法("SHA-1"、"MD5")
*/
@SneakyThrows
public static byte[] digest(InputStream input, String algorithm) throws IOException {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
int bufferLength = 8 * 1024;
byte[] buffer = new byte[bufferLength];
int read = input.read(buffer, 0, bufferLength);
while (read > -1) {
messageDigest.update(buffer, 0, read);
read = input.read(buffer, 0, bufferLength);
}
return messageDigest.digest();
}
}

View File

@@ -0,0 +1,48 @@
package ai.remi.comm.util.security;
import java.security.MessageDigest;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc Md5Utils
*/
public class Md5Utils {
/**
* 将给定的字符串MD5加密
*
* @param string 给定的字符串
* @return MD5加密后生成的字符串
*/
public static String encode(String string) {
String result = null;
try {
char[] charArray = string.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++) {
byteArray[i] = (byte) charArray[i];
}
StringBuffer hexValue = new StringBuffer();
byte[] md5Bytes = MessageDigest.getInstance("MD5")
.digest(byteArray);
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
result = hexValue.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String encode = encode("1122");
System.out.println(encode);
}
}

View File

@@ -0,0 +1,32 @@
package ai.remi.comm.util.security;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc PwdUtils 用户密码工具类
*/
public class PwdUtils {
//private final static String DEFAULT_PASS="Remi2022";
private final static String DEFAULT_PASS="Remi@123";
public static boolean isValidPassword(String password,String encodePassword) {
return encode(password).equals(encodePassword);
}
public static String encode(String s){
return Md5Utils.encode(s);
}
public static String getDefaultPassEncryption(){
return encode(DEFAULT_PASS);
}
public static void main(String[] args) {
System.out.println(getDefaultPassEncryption());
System.out.println(Md5Utils.encode(DEFAULT_PASS));
}
}

View File

@@ -0,0 +1,75 @@
package ai.remi.comm.util.security;
/**
* @author DianJiu 【公众号 点九开源】
* @email lidianjiu@njydsz.com
* @date 2022-07-26
* @desc 公钥加密,私钥解密;私钥加签,公钥验签。
*/
public class Rsa2Demo {
public static void main(String[] args) {
mookHttp();
}
public static void mookHttp(){
Rsa2Utils.initRSAKey(2048);
// 初始化A公司的公钥、私钥
String privateKeyA= "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1YbT3O4Rd2F5d7R/+61clUBvGtpnYYzDsUCmVLCYnE1zCNQawi5ga+cpdgyafOLFJcVGfcHEushXgJ3XFp0mriRCKnBiA0OwoNa0sVZyW46eLsYhxx6aNmcsfk04xUNR52FYRD3gvLpfIXHlW4Zib9FtYJThjXo6kSLrZbh2f9gaYNlJzJn8tWljI3sPgzgvvVCtPbwFOW5D7Pt7n/nsL3AUM5ZqItRBvlkejitbdjYlg2WXJA6pDYtAxO9+iwiDsftQqF8QzXiZDTBEr+jqKPk3ZpYpuE8nXSWpx/1c4ujhI6R+/CVvj4PEccfDs9x2dusVLgVdYgXxFY4jyyFhrAgMBAAECggEBAJdxCAaw89jjMg9cUC2o0289DqQAjD1GvG9ikwWRAh34JaelXHuFYi+LxjIDsfiY/jVi3xKvcGDbojYw3D12aqVFYMFKiY7sYXFFN9zfcknttFOHnHPbja2G7jjj5hJ4+Z7uSRYfg2ppjaNlyo4G+EOmZ6oWEZmuNozmiNPIBAYsmNXmxK7jmFKsMr8dN8oTraP2j5rjpWwvcoqoJKacGLY8dV8/miGlaTyJzrJT/JRbvPl1pCe9W5MMv2XhwaIrpM2kPuO1HQjBLgsFXQyYxAP0BvqID7QX+MYK104VcpuuAARLqZZUwEZP2quJUMxT973KUlLkBUdgfrLoElvNXOECgYEA/1x4botRAudqjaWH4UTAqaCy0/WrWluZqGxaZn/aS3BdFYya/zMH8kY6s16yKZ5qErxNamQWrGElpHHR8dz3fqkPp5cjqYRcxztPhtCxwkNO5lPRZPIngD7c4CNN1nKV9rO1+a4ALDZJzOKYZSybwOYWkKfEC9+ZNQz2mk98TNECgYEAtdXcba2ayxb6BypunV8xXgX7e57b7VmwSARJGjGAwJJ+Y9drFTFrn/Ei+Tl6r+lnjB7fDejlzxCKQDtP+ZwEMWKaE+LWiHDMucAC5x77wlaWzLEMSpfBsNp2Sw9PmAoQrteHFKJ6V03jMJR2SB3ihH1uj99+4i6U9svHa+Y0cHsCgYAqSMGYbHFJrdAzDEnnv163t+hkuLVbDPfwr6B4gItBGqYPP20a/PQ/5ekqcm/F/HlMCOo4x8IJYTy+cip1hkVlL9FrytcY5tYGF4gfpscIh+S0twRhVse7sK0aYD4vWGIEq9ViNrHIoGSwDIV3m19fHbp20ZDg9nGEG1VqT+chQQKBgQCukOr2rJUP5jYRDQ52rL3TO0EMlB0lR1ZyPRMFP4MQ3VLTfSrDhNeDDFf8Fc+P9C7BmZ2gV/fQC1v+gDKuOrbXxoaPEtXM1SXmKc1fnyIpl0Fcr5hSQFDl/UVVmBRcrUUI5cc76yQyjobOy6imYXJmqZisLO8+K2Q9brM8BhxP4wKBgQDd0r1LAXXDmfEdtZAz0kfhssWVb2E/w+TSyvSqFsvJh8bCrZ18WgUeiAya47mjXCUqB8dOUTPjtO8HqfUfqI+Qr0agdErt1BvoBD10ntVowbOJrj0RJLfFr8YLrHhGkLPTZzt17upv+l5x+pyMaDPxePXO8jy1Nk3rL2okpHqW6A==";
String publicKeyA= "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtWG09zuEXdheXe0f/utXJVAbxraZ2GMw7FAplSwmJxNcwjUGsIuYGvnKXYMmnzixSXFRn3BxLrIV4Cd1xadJq4kQipwYgNDsKDWtLFWcluOni7GIccemjZnLH5NOMVDUedhWEQ94Ly6XyFx5VuGYm/RbWCU4Y16OpEi62W4dn/YGmDZScyZ/LVpYyN7D4M4L71QrT28BTluQ+z7e5/57C9wFDOWaiLUQb5ZHo4rW3Y2JYNllyQOqQ2LQMTvfosIg7H7UKhfEM14mQ0wRK/o6ij5N2aWKbhPJ10lqcf9XOLo4SOkfvwlb4+DxHHHw7PcdnbrFS4FXWIF8RWOI8shYawIDAQAB";
// 初始化B公司的公钥、私钥
String privateKeyB="MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCD9IqMkrTxcsS/ldiY4ryZzTPY2mPiqjh6bTWCfR1+TJfh7cH9H7TH3cPWfizwa/nb9JaAqpZFEmkn1aprNKkjnZM6F1bW9F5N02mARxxUUL4J+BCnYjNwj/f25b8VQp6XrA37P3mi2Z97m9xBdGSooLCPhsFKFzq99wCJHzBivGCmlvr9IgFbsiYkjdOuMn4EFFhGqubfazECrbpVYQPzq0eeEOOal11ACmMysTinHg9DEG4X73Q9lT5Cwb38sm7mmq6e8PkWUDzKbG+CQxG/IBEio35/OB7zNcJ9G87eUIK0s5OVApxdBGFBfG6gHOjx+iTwJyEpZziZljLZf+07AgMBAAECggEAcHYHax1R54IoGxyr2ElN8ksIiCZBARqQPg87jrXxYAYJYD2RmpjeK4Ve9jzdMh7keUkwyAIbRk0VoCSjNPFRwg/3PYhMs7DberrW7MQuadHS1Y49K1svehzJefx+6bC4l43E8MA9e8S7/s5sXsDDVVB2iiyQKgQ4RVTxeOxDAbJOOSj5QZxqwR4x2JalDGFawhKsX9d2l1fQAV/JdDKKK1xqgRzvWqub9MhZzH9Cf1o+gqQ20paFwAiuHVfJpc1QjgdHI9ExDn45jqAhxe6C+YqeUVHrl0cFaCMnrSkQAcvTUT6ancZY3QW/yJlil3boQojmy+P2RkFESqnEz3EWqQKBgQDL1y7AAfUMsdjYXE+hnADuQznAv01IwcoNYmInXGhGTiAwfpQPNYsi/+u4ia0l1Myu1SVt1QcDdemLEo5YKAQepHHJ6Zi/CZNvfKSfKhbnSzDJzxBX3garSdV65rkLMCPxOEFDZtoF//kgDQg3Pl0fsHORw5isvbHqfFb689sP7wKBgQCluGz0MID2Fh/29Q001toQ1wRHjpuo5FdKn+NkWfDCdaZX3T0XmyF9vNpQM02HsC7Dpipakk/ex/ZJr277DRCWP5WuhjMHgIT6KUannMT4ARj0hmEqdwiAYlZGcK9PKhpERWDrlG4tXO+MsLAiBRA/R0SPZyeuybtoVxZ+XBOrdQKBgBa9T5LN5Rdgc69XRO7jZ1stFrFA5g86xx6NHiQD9AH7zy15wWyc7YOfBx3UBgPVZGwQjRdej2S8b6w7CrQc6rC8aZE7xPVyzQa/4eF7oYh14+BvgAQ9WYMcPntyZ6wu16OeQfGR9Lp8nr8LlSIMi/jwB0R4jHygwMtGybE/KO3zAoGAByqMe5rFWN7oDvPV2F0aHPRPWRDPpmQJak6ztJk3EhGoWdBVXfn1XsyV3DX7ukxiGU/MMRJ2pbmb6t/NOsn716N0Q5HGDyL9nRu/1GuxENBrVdehyAZRtcuK04z358J4VE9zu3w1r3x/V2QkmbQCWdopGtJpIuPSWNa7QEeXCikCgYAri2pTViyR3o98uGpCxVLFp8zLF6YHh8ufjGyhp/l/wk928rmXJM5nSlJYuFJ7MgvOjeJK6u0ebGDX58lvuSN6o6EeFWw3H/WFxEqHAJETpkOl7ya7hbJABCFzL2xG5oCDHLzpykENUrIs2ZpmvND5yiFwqfjqThmKzXcH6oBS7w==";
String publicKeyB="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg/SKjJK08XLEv5XYmOK8mc0z2Npj4qo4em01gn0dfkyX4e3B/R+0x93D1n4s8Gv52/SWgKqWRRJpJ9WqazSpI52TOhdW1vReTdNpgEccVFC+CfgQp2IzcI/39uW/FUKel6wN+z95otmfe5vcQXRkqKCwj4bBShc6vfcAiR8wYrxgppb6/SIBW7ImJI3TrjJ+BBRYRqrm32sxAq26VWED86tHnhDjmpddQApjMrE4px4PQxBuF+90PZU+QsG9/LJu5pqunvD5FlA8ymxvgkMRvyARIqN+fzge8zXCfRvO3lCCtLOTlQKcXQRhQXxuoBzo8fok8CchKWc4mZYy2X/tOwIDAQAB";
// 初始化请求、响应数据
String req ="1111111111111";
String resp ="22222222222222";
/**
* (公钥加密,私钥解密;私钥签名,公钥验签。)
* 模拟A公司向B公司发送请求
* B公司验签后解密请求报文
* B公司处理完自己的业务后
* 并对响应报文加密和加签
* A公司收到B公司响应后
* A公司验签后解密响应
*/
//请求
System.out.println("A向B 发送请求开始==========");
System.out.println("加密前的请求数据为===>"+req);
//用B公司的公钥加密请求
String encryptByPublicKeyB = Rsa2Utils.buildRSAEncryptByPublicKey(req, publicKeyB);
System.out.println("用B公司的公钥加密请求===>"+encryptByPublicKeyB);
//用A公司的私钥生成签名
String reqSignature = Rsa2Utils.buildRSASignByPrivateKey(encryptByPublicKeyB, privateKeyA);
System.out.println("用A公司的私钥生成签名===>"+reqSignature);
System.out.println("B收到A的请求开始==========");
//用A公司的公钥验证签名
boolean SignatureBoolByPublicKeyA = Rsa2Utils.buildRSAverifyByPublicKey(encryptByPublicKeyB, publicKeyA, reqSignature);
System.out.println("用A公司的公钥验证签名===>"+SignatureBoolByPublicKeyA);
//用B公司的私钥解密请求
String decryptByPrivateKeyB = Rsa2Utils.buildRSADecryptByPrivateKey(encryptByPublicKeyB, privateKeyB);
System.out.println("用B公司的私钥解密请求===>"+decryptByPrivateKeyB);
//响应
System.out.println("B发送A的响应开始==========");
System.out.println("加密前的响应数据为===>"+resp);
//用A公司的公钥加密响应
String encryptByPublicKeyA = Rsa2Utils.buildRSAEncryptByPublicKey(resp, publicKeyA);
System.out.println("用A公司的公钥加密请求===>"+encryptByPublicKeyA);
//用B公司的私钥生成签名
String respSignature = Rsa2Utils.buildRSASignByPrivateKey(encryptByPublicKeyA, privateKeyB);
System.out.println("用B公司的私钥生成签名===>"+respSignature);
System.out.println("A收到B的响应开始==========");
//用B公司的公钥验证签名
boolean SignatureBoolByPublicKeyB = Rsa2Utils.buildRSAverifyByPublicKey(encryptByPublicKeyA, publicKeyB, respSignature);
System.out.println("用B公司的公钥验证签名===>"+SignatureBoolByPublicKeyB);
//用A公司的私钥解密响应
String decryptByPrivateKeyA = Rsa2Utils.buildRSADecryptByPrivateKey(encryptByPublicKeyA, privateKeyA);
System.out.println("用A公司的私钥解密请求===>"+decryptByPrivateKeyA);
}
}

View File

@@ -0,0 +1,253 @@
package ai.remi.comm.util.security;
import org.apache.commons.io.IOUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc Rsa2Utils
*/
public class Rsa2Utils {
public static final String CHARSET = "UTF-8";
//密钥算法
public static final String ALGORITHM_RSA = "RSA";
//RSA 签名算法
public static final String ALGORITHM_RSA_SIGN = "SHA256WithRSA";
public static final int ALGORITHM_RSA_PRIVATE_KEY_LENGTH = 2048;
//用于封装随机产生的公钥与私钥
private static Map<String, String> keyPairMap = new HashMap<String, String>();
private Rsa2Utils() {
}
public static void main(String[] args) {
//生成公钥私钥
initRSAKey(2048);
//私钥
String privateKey = keyPairMap.get("privateKey");
System.out.println("生成私钥:"+privateKey);
//String privateKey="MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH4u7Shk55VvrOt7pEcyV4eLETNVgec1hGwtRc/YicYLNS8SSQlozESidoo7rh03QYHrEKswhltPfo63fOydkFWMAbX1M9VbJQin9OR2Xxu/OGBAUrXPArdfzlLpMtG+xsG2iapVBXOHx77E1DX0AehDw/jDGAawlOyqSavdWlVDDLQP2312FLvR9TjfBly9P3oQbbum9JrSwgkJM+rjwvElUC4Rs48w6l0RI+hJIe4RIoTyXefBQI4jNUrcVsJZpJEtp4khlmDJKx632fumg9zi4tctS/3MZTGoJaA1zei/UuzXD33nHsL+6ZAwCSayidLeXjKCn5CCAQO6PGKg2pAgMBAAECggEAA/+fJWj4YucBh2cXe80N39YSPL8hbyKBjpDRLLcJp48rpyoZwCay1C5jkW1NDL1tIhpjEkK4lUhEeU1UjTdudvPqi+GhSaXQNlo+57L38BkBaxnjfJWUXFo03+TJnupjFVqLAiTycXw4yUXV2dYq8zFT/zVvvBDoE8Jr/ohzoKYAb4ziahDPg7D15oaX8S6dAa/qBoSapLSO+rN6eELEqAaH8r4QVCtVpVzDLXcIpF9kgaJmAkJfrb9Cmi6dA7MBbwCjEK/mtyGJTZaw7ZTJR6+CumPmGZCjWppNawX/8ISYbZeAmX9mGSEp6iI17ciYZt79YfQGDOSvRgjBA67vrQKBgQDu4X5AVaxQwLKLFfuhoim9ZmB4/MAQntvCD5Oe7RQM/eepSX9LIuDcoj7tDjqCvPemEosLoR05WHxe8eLNFwcUzkiQFdhB2lNn02rBn8rCHTwZvf1WHwhkNTi0/szRgZexzRIqrUJrNlAiezsbcYxeoOsLqnKzQExNM4mTvPkcDwKBgQDWNgyPHTGXLpXjCPJ8HF92xveUOwXb+H8SVs5AVHwg+kJNvtjqAwASPnaBs9xMCEaXChF/2O04AUB29comjPZ3By0VmWiH3ngOucsIGih/9RDs0JTWaNaMDYvhA9huXKeIRpo8hyTLcLJ8Y0XVHgi8a68tnP+qfA5kANC17kDixwKBgQC9ayLQYt7rfZFWBo1soojUfZyb81ddFoqNfAqDZ9yRXLhYnUYJz1NcwG6DTNgKmUsKbgPBqfThZw/fvZApLkxYLCaP0jKULUobtyIc/NcrS0E/7E44/wyJYUZhBvZkXo1p2IHCQ3a6SuwKG4tH/Kbg1lrq+jJPfvnB8c7yzlL98wKBgBHKbWKZdxvqR5KSlKkQJjGUNs291S++xLb+NKUNHz4R6t3QIu3Uj/Xz8B23lW1PJqW2tVtb5d/H4tW+diqbfIDIPMtVcWQPawM2FRG4MnLmJKC2dhYUoPUCzwJCMoB/+34K9xZd1wV6d6hzCkK3+tvDScpNBsLfCMbvdmYVwpfTAoGBAMv12bQYwCK/EmezCl484AvNJ9/oIjqz1QyK141HXb5QXIXN4DL//TcngslDvqpqvoVXM4TRoc8Ne6aQeRaNgIeOuYeyixWi48x6csN5FC41lnUdEkPYIxqZCrkxglS8J/oLKRiu385gQPxd2EqVE21snajRoY3CiKXQkchxyycB";
//公钥
String publicKey = keyPairMap.get("publicKey");
System.out.println("生成公钥:"+publicKey);
//String publicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx+Lu0oZOeVb6zre6RHMleHixEzVYHnNYRsLUXP2InGCzUvEkkJaMxEonaKO64dN0GB6xCrMIZbT36Ot3zsnZBVjAG19TPVWyUIp/Tkdl8bvzhgQFK1zwK3X85S6TLRvsbBtomqVQVzh8e+xNQ19AHoQ8P4wxgGsJTsqkmr3VpVQwy0D9t9dhS70fU43wZcvT96EG27pvSa0sIJCTPq48LxJVAuEbOPMOpdESPoSSHuESKE8l3nwUCOIzVK3FbCWaSRLaeJIZZgySset9n7poPc4uLXLUv9zGUxqCWgNc3ov1Ls1w995x7C/umQMAkmsonS3l4ygp+QggEDujxioNqQIDAQAB";
//私钥加密解密
String encryptByPrivateKey = buildRSAEncryptByPrivateKey("ABCabc123测试", privateKey);
System.out.println("私钥加密:"+encryptByPrivateKey);
String decryptByPublicKey = buildRSADecryptByPublicKey(encryptByPrivateKey, publicKey);
System.out.println("公钥解密:"+decryptByPublicKey);
//公钥加密解密
//String encryptByPublicKey = buildRSAEncryptByPublicKey("ABCabc123测试", publicKey);
//System.out.println("公钥加密:"+encryptByPublicKey);
//String decryptByPrivateKey = buildRSADecryptByPrivateKey(encryptByPublicKey, privateKey);
//System.out.println("私钥解密:"+decryptByPrivateKey);
//使用私钥生成数字签名
String privateValue = buildRSASignByPrivateKey("ABCabc123测试", privateKey);
System.out.println("私钥加签:"+privateValue);
//使用公钥校验数字签名
boolean publicValue = buildRSAverifyByPublicKey("ABCabc123测试", publicKey, privateValue);
System.out.println("公钥验签:"+publicValue);
}
/**
* 初始化RSA算法密钥对
*
* @param keysize RSA1024已经不安全了,建议2048
* @return 经过Base64编码后的公私钥Map, 键名分别为publicKey和privateKey
*/
public static void initRSAKey(int keysize) {
if (keysize != ALGORITHM_RSA_PRIVATE_KEY_LENGTH) {
throw new IllegalArgumentException("RSA1024已经不安全了,请使用" + ALGORITHM_RSA_PRIVATE_KEY_LENGTH + "初始化RSA密钥对");
}
//为RSA算法创建一个KeyPairGenerator对象
KeyPairGenerator kpg;
try {
kpg = KeyPairGenerator.getInstance(ALGORITHM_RSA);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("No such algorithm-->[" + ALGORITHM_RSA + "]");
}
//初始化KeyPairGenerator对象,不要被initialize()源码表面上欺骗,其实这里声明的size是生效的
kpg.initialize(ALGORITHM_RSA_PRIVATE_KEY_LENGTH);
//生成密匙对
KeyPair keyPair = kpg.generateKeyPair();
//得到公钥
Key publicKey = keyPair.getPublic();
String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
//得到私钥
Key privateKey = keyPair.getPrivate();
String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr);
}
/**
* RSA算法公钥加密数据
*
* @param data 待加密的明文字符串
* @param key RSA公钥字符串
* @return RSA公钥加密后的经过Base64编码的密文字符串
*/
public static String buildRSAEncryptByPublicKey(String data, String key) {
try {
//通过X509编码的Key指令获得公钥对象
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET)));
} catch (Exception e) {
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法公钥解密数据
*
* @param data 待解密的经过Base64编码的密文字符串
* @param key RSA公钥字符串
* @return RSA公钥解密后的明文字符串
*/
public static String buildRSADecryptByPublicKey(String data, String key) {
try {
//通过X509编码的Key指令获得公钥对象
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.getDecoder().decode(data)), CHARSET);
} catch (Exception e) {
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法私钥加密数据
*
* @param data 待加密的明文字符串
* @param key RSA私钥字符串
* @return RSA私钥加密后的经过Base64编码的密文字符串
*/
public static String buildRSAEncryptByPrivateKey(String data, String key) {
try {
//通过PKCS#8编码的Key指令获得私钥对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET)));
} catch (Exception e) {
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法私钥解密数据
* @param data 待解密的经过Base64编码的密文字符串
* @param key RSA私钥字符串
* @return RSA私钥解密后的明文字符串
*/
public static String buildRSADecryptByPrivateKey(String data, String key) {
try {
//通过PKCS#8编码的Key指令获得私钥对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.getDecoder().decode(data)), CHARSET);
} catch (Exception e) {
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法使用私钥对数据生成数字签名
*
* @param data 待签名的明文字符串
* @param key RSA私钥字符串
* @return RSA私钥签名后的经过Base64编码的字符串
*/
public static String buildRSASignByPrivateKey(String data, String key) {
try {
//通过PKCS#8编码的Key指令获得私钥对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(ALGORITHM_RSA_SIGN);
signature.initSign(privateKey);
signature.update(data.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(signature.sign());
} catch (Exception e) {
throw new RuntimeException("签名字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法使用公钥校验数字签名
*
* @param data 参与签名的明文字符串
* @param key RSA公钥字符串
* @param sign RSA签名得到的经过Base64编码的字符串
* @return true--验签通过,false--验签未通过
*/
public static boolean buildRSAverifyByPublicKey(String data, String key, String sign) {
try {
//通过X509编码的Key指令获得公钥对象
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
Signature signature = Signature.getInstance(ALGORITHM_RSA_SIGN);
signature.initVerify(publicKey);
signature.update(data.getBytes(CHARSET));
return signature.verify(Base64.getDecoder().decode(sign));
} catch (Exception e) {
throw new RuntimeException("验签字符串[" + data + "]时遇到异常", e);
}
}
/**
* RSA算法分段加解密数据
*
* @param cipher 初始化了加解密工作模式后的javax.crypto.Cipher对象
* @param opmode 加解密模式,值为javax.crypto.Cipher.ENCRYPT_MODE/DECRYPT_MODE
* @return 加密或解密后得到的数据的字节数组
*/
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas) {
int maxBlock = 0;
if (opmode == Cipher.DECRYPT_MODE) {
maxBlock = ALGORITHM_RSA_PRIVATE_KEY_LENGTH / 8;
} else {
maxBlock = ALGORITHM_RSA_PRIVATE_KEY_LENGTH / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
int i = 0;
try {
while (datas.length > offSet) {
if (datas.length - offSet > maxBlock) {
buff = cipher.doFinal(datas, offSet, maxBlock);
} else {
buff = cipher.doFinal(datas, offSet, datas.length - offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
} catch (Exception e) {
throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
}
byte[] resultDatas = out.toByteArray();
IOUtils.closeQuietly(out);
return resultDatas;
}
}

View File

@@ -0,0 +1,89 @@
package ai.remi.comm.util.string;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 字符集工具类
*
* @author startdis
*/
public class CharsetUtils {
/**
* ISO-8859-1
*/
public static final String ISO_8859_1 = "ISO-8859-1";
/**
* UTF-8
*/
public static final String UTF_8 = "UTF-8";
/**
* GBK
*/
public static final String GBK = "GBK";
/**
* ISO-8859-1
*/
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
/**
* UTF-8
*/
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
/**
* GBK
*/
public static final Charset CHARSET_GBK = Charset.forName(GBK);
/**
* 转换为Charset对象
*
* @param charset 字符集,为空则返回默认字符集
* @return Charset
*/
public static Charset charset(String charset) {
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, String srcCharset, String destCharset) {
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, Charset srcCharset, Charset destCharset) {
if (null == srcCharset) {
srcCharset = StandardCharsets.ISO_8859_1;
}
if (null == destCharset) {
destCharset = StandardCharsets.UTF_8;
}
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) {
return source;
}
return new String(source.getBytes(srcCharset), destCharset);
}
/**
* @return 系统字符集编码
*/
public static String systemCharset() {
return Charset.defaultCharset().name();
}
}

View File

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

View File

@@ -0,0 +1,77 @@
package ai.remi.comm.util.string;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
/**
* 字符串格式化
*
* @author startdis
*/
public class StringFormatterUtils {
public static final String EMPTY_JSON = "{}";
public static final char C_BACKSLASH = '\\';
public static final char C_DELIM_START = '{';
public static final char C_DELIM_END = '}';
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public static String format(final String strPattern, final Object... argArray) {
if (StringUtils.isEmpty(strPattern) || ObjectUtils.isEmpty(argArray)) {
return strPattern;
}
final int strPatternLength = strPattern.length();
// 初始化定义好的长度以获得更好的性能
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;
int delimIndex;// 占位符所在位置
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
if (delimIndex == -1) {
if (handledPosition == 0) {
return strPattern;
} else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
} else {
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {
// 转义符之前还有一个转义符,占位符依旧有效
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(StringConvertUtils.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
} else {
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(C_DELIM_START);
handledPosition = delimIndex + 1;
}
} else {
// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(StringConvertUtils.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
}
}
// 加入最后一个占位符后所有的字符
sbuf.append(strPattern, handledPosition, strPattern.length());
return sbuf.toString();
}
}

View File

@@ -0,0 +1,521 @@
package ai.remi.comm.util.string;
import org.springframework.util.AntPathMatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 字符串工具类
*
* @author startdis
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 空字符串
*/
private static final String NULLSTR = "";
/**
* 下划线
*/
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空,包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true:为空 false:非空
*/
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public static boolean isNull(Object object) {
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* 如果给定字符串{@code str}中不包含{@code appendStr},则在{@code str}后追加{@code appendStr};
* 如果已包含{@code appendStr},则在{@code str}后追加{@code otherwise}
*
* @param str 给定的字符串
* @param appendStr 需要追加的内容
* @param otherwise 当{@code appendStr}不满足时追加到{@code str}后的内容
* @return 追加后的字符串
*/
public static String appendIfNotContain(String str, String appendStr, String otherwise) {
if (isEmpty(str) || isEmpty(appendStr)) {
return str;
}
if (str.contains(appendStr)) {
return str.concat(otherwise);
}
return str.concat(appendStr);
}
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str) {
return (str == null ? "" : str.trim());
}
/**
* 自定义分割函数,返回第一个
*
* @param str 待分割的字符串
* @param delim 分隔符
* @return 分割后的第一个字符串
*/
public static String splitFirst(final String str, final String delim) {
if (null == str || org.apache.commons.lang3.StringUtils.isEmpty(delim)) {
return str;
}
int index = str.indexOf(delim);
if (index < 0) {
return str;
}
if (index == 0) {
// 一开始就是分隔符,返回空串
return "";
}
return str.substring(0, index);
}
/**
* 自定义分割函数,返回全部
*
* @param str 待分割的字符串
* @param delim 分隔符
* @return 分割后的返回结果
*/
public static List<String> splitStr(String str, final String delim) {
if (null == str) {
return new ArrayList<>(0);
}
if (StringUtils.isEmpty(delim)) {
List<String> result = new ArrayList<>(1);
result.add(str);
return result;
}
final List<String> stringList = new ArrayList<>();
while (true) {
int index = str.indexOf(delim);
if (index < 0) {
stringList.add(str);
break;
}
stringList.add(str.substring(0, index));
str = str.substring(index + delim.length());
}
return stringList;
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
return NULLSTR;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULLSTR;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return NULLSTR;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str) {
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str) {
int strLen = str.length();
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
if (isEmpty(params) || isEmpty(template)) {
return template;
}
return StringFormatterUtils.format(template, params);
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str != null && strs != null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
List<String> camels = splitStr(name, "_");
for (String camel : camels) {
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如:user_name->userName
*/
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == SEPARATOR) {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
/**
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static final String padl(final Number num, final int size) {
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static final String padl(final String s, final int size, final char c) {
final StringBuilder sb = new StringBuilder(size);
if (s != null) {
final int len = s.length();
if (s.length() <= size) {
for (int i = size - len; i > 0; i--) {
sb.append(c);
}
sb.append(s);
} else {
return s.substring(len - size, len);
}
} else {
for (int i = size; i > 0; i--) {
sb.append(c);
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,31 @@
package ai.remi.comm.util.url;
import org.springframework.util.AntPathMatcher;
import java.util.List;
import java.util.Set;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc 请求路径忽略工具类
*/
public class UrlIgnoreUtils {
private static final AntPathMatcher matcher = new AntPathMatcher();
public static boolean isIgnoreUrl(Set<String> ignoreUrl, String requestPath) {
return ignoreUrl.stream().anyMatch((url) -> {
//判断请求的url是否在忽略拦截的url中
return matcher.match(url, requestPath);
});
}
public static boolean isIgnoreUrl(List<String> ignoreUrl, String requestPath) {
return ignoreUrl.stream().anyMatch((url) -> {
//判断请求的url是否在忽略拦截的url中
return matcher.match(url, requestPath);
});
}
}

View File

@@ -0,0 +1,31 @@
package ai.remi.comm.util.url;
import cn.hutool.core.collection.CollectionUtil;
import org.springframework.util.AntPathMatcher;
import java.util.Collection;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @desc 请求路径匹配工具类
*/
public class UrlMatchUtils {
private static final AntPathMatcher matcher = new AntPathMatcher();
/**
* 集合内所有正则是否包含 请求路径
* @param patterns 所有正则
* @param requestPath 请求路径
* @return 返回是否在包含在内
*/
public static boolean contain(Collection<String> patterns, String requestPath){
if (CollectionUtil.isEmpty(patterns)){
return false;
}
return patterns.stream().anyMatch((pattern) -> {
//判断请求的url是否在忽略拦截的url中
return matcher.match(pattern, requestPath);
});
}
}

View File

@@ -0,0 +1,550 @@
package ai.remi.comm.util.xml;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author dianjiu【公众号 点九开源】
* @email dianjiuxyz@gmail.com
* @date 2022-07-26
* @desc DOMUtils
*/
public class DOMUtils {
/**
* 添加根节点元素
*
* @param document 根文档
* @param rootName 根节点名称
* @return 新增节点
*/
public static Element addRoot(Document document, String rootName) {
// 添加子节点元素
return document.addElement(rootName);
}
/**
* 添加根节点元素
*
* @param document 根文档
* @param rootName 根节点名称
* @param rootValue 根节点值
* @return 新增节点
*/
public static Element addRoot(Document document, String rootName, String rootValue) {
// 添加子节点元素
Element root = document.addElement(rootName);
// 为子节点元素设值
root.setText(rootValue == null ? "" : rootValue);
return root;
}
/**
* 添加根节点元素
*
* @param document 根文档
* @param rootName 根节点名称
* @param attributes 根节点属性
* @return 新增节点
*/
public static Element addRoot(Document document, String rootName, Map<String, String> attributes) {
// 添加子节点元素
Element root = document.addElement(rootName);
// 为子节点元素设属性
if (MapUtils.isEmpty(attributes)) {
return root;
}
attributes.forEach((key, value) -> {
if (key.contains(":")) {
//处理冒号属性问题
root.addNamespace(key.substring(key.indexOf(":")+1), value);
}
root.addAttribute(key, value);
});
return root;
}
/**
* 添加根节点元素
*
* @param document 根文档
* @param rootName 根节点名称
* @param rootValue 根节点值
* @param attributes 根节点属性
* @return 新增节点
*/
public static Element addRoot(Document document, String rootName, String rootValue, Map<String, String> attributes) {
// 添加子节点元素
Element root = document.addElement(rootName);
// 为子节点元素设值
root.setText(rootValue == null ? "" : rootValue);
// 为子节点元素设属性
if (MapUtils.isEmpty(attributes)) {
return root;
}
attributes.forEach((key, value) -> {
if (key.contains(":")) {
//处理冒号属性问题
root.addNamespace(key.substring(key.indexOf(":")+1), value);
}
root.addAttribute(key, value);
});
return root;
}
/**
* 添加孩子节点元素
*
* @param parent 父节点
* @param childName 孩子节点名称
* @return 新增节点
*/
public static Element addChild(Element parent, String childName) {
// 添加子节点元素
return parent.addElement(childName);
}
/**
* 添加孩子节点元素
*
* @param parent 父节点
* @param childName 孩子节点名称
* @param childValue 孩子节点值
* @return 新增节点
*/
public static Element addChild(Element parent, String childName, String childValue) {
// 添加子节点元素
Element child = parent.addElement(childName);
// 为子节点元素设值
child.setText(childValue == null ? "" : childValue);
return child;
}
/**
* 添加孩子节点元素
*
* @param parent 父节点
* @param childName 孩子节点名称
* @param attributes 孩子节点属性
* @return 新增节点
*/
public static Element addChild(Element parent, String childName, Map<String, String> attributes) {
// 添加子节点元素
Element child = parent.addElement(childName);
// 为子节点元素设属性
if (MapUtils.isEmpty(attributes)) {
return child;
}
attributes.forEach((key, value) -> {
if (key.contains(":")) {
//处理冒号属性问题
//child.addNamespace(key.substring(key.indexOf(":")+1), value);
}
child.addAttribute(key, value);
});
return child;
}
/**
* 添加孩子节点元素
*
* @param parent 父节点
* @param childName 孩子节点名称
* @param childValue 孩子节点值
* @param attributes 孩子节点属性
* @return 新增节点
*/
public static Element addChild(Element parent, String childName, String childValue, Map<String, String> attributes) {
// 添加子节点元素
Element child = parent.addElement(childName);
// 为子节点元素设值
child.setText(childValue == null ? "" : childValue);
// 为子节点元素设属性
if (MapUtils.isEmpty(attributes)) {
return child;
}
attributes.forEach((key, value) -> {
if (key.contains(":")) {
//处理冒号属性问题
//child.addNamespace(key.substring(key.indexOf(":")+1), value);
}
child.addAttribute(key, value);
});
return child;
}
/**
* 将文档对象写入对应的文件中
*
* @param xmlstr 字符串
* @param path 写入文档的路径
* @throws IOException
*/
public final static void writeXmlStrToFile(String xmlstr, String path) throws Exception {
if (StringUtils.isBlank(xmlstr)) {
return;
}
Document document = DocumentHelper.parseText(xmlstr);
writeXMLToFile(document, path);
}
/**
* 将文档对象写入对应的文件中
*
* @param document 文档对象
* @param path 写入文档的路径
* @throws IOException
*/
public final static void writeXMLToFile(Document document, String path) throws IOException {
if (document == null || path == null) {
return;
}
XMLWriter writer = new XMLWriter(new FileWriter(path));
writer.write(document);
writer.close();
}
/**
* 将文档对象写入对应的文件中
*
* @param document 文档对象
* @param path 写入文档的路径
* @throws IOException
*/
public final static void writeXMLToFile(Document document, String path, String encoding) throws IOException {
if (document == null || path == null) {
return;
}
// 设置生成xml的格式
OutputFormat format = OutputFormat.createPrettyPrint();
encoding = StringUtils.isBlank(encoding) ? "UTF-8" : encoding;
// 设置编码格式
format.setEncoding(encoding);
XMLWriter writer = new XMLWriter(new FileWriter(path), format);
writer.write(document);
writer.close();
}
/**
* 通过文件的路径获取xml的document对象
*
* @param path 文件的路径
* @return 返回文档对象
*/
public static Document getXMLByFilePath(String path) {
if (null == path) {
return null;
}
Document document = null;
try {
SAXReader reader = new SAXReader();
document = reader.read(new File(path));
} catch (Exception e) {
e.printStackTrace();
}
return document;
}
/**
* 通过xml字符获取document文档
*
* @param xmlstr 要序列化的xml字符
* @return 返回文档对象
* @throws DocumentException
*/
public static Document getXMLByString(String xmlstr) throws DocumentException {
if (xmlstr == "" || xmlstr == null) {
return null;
}
Document document = DocumentHelper.parseText(xmlstr);
return document;
}
/**
* 获取某个元素的所有的子节点
*
* @param node 制定节点
* @return 返回所有的子节点
*/
public static List<Element> getChildElements(Element node) {
if (null == node) {
return null;
}
@SuppressWarnings("unchecked")
List<Element> lists = node.elements();
return lists;
}
/**
* 获取指定节点的子节点
*
* @param node 父节点
* @param childnode 指定名称的子节点
* @return 返回指定的子节点
*/
public static Element getChildElement(Element node, String childnode) {
if (null == node || null == childnode || "".equals(childnode)) {
return null;
}
return node.element(childnode);
}
/**
* 获取所有的属性值
*
* @param node
* @param arg
* @return
*/
public static Map<String, String> getAttributes(Element node, String... arg) {
if (node == null || arg.length == 0) {
return null;
}
Map<String, String> attrMap = new HashMap<String, String>();
for (String attr : arg) {
String attrValue = node.attributeValue(attr);
attrMap.put(attr, attrValue);
}
return attrMap;
}
/**
* 获取element的单个属性
*
* @param node 需要获取属性的节点对象
* @param attr 需要获取的属性值
* @return 返回属性的值
*/
public static String getAttribute(Element node, String attr) {
if (null == node || attr == null || "".equals(attr)) {
return "";
}
return node.attributeValue(attr);
}
/**
* DOM4j的Document对象转为XML报文串
*
* @param document
* @param charset
* @return 经过解析后的xml字符串
*/
public static String documentToString(Document document, String charset) {
StringWriter stringWriter = new StringWriter();
OutputFormat format = OutputFormat.createPrettyPrint();// 获得格式化输出流
format.setEncoding(charset);// 设置字符集,默认为UTF-8
XMLWriter xmlWriter = new XMLWriter(stringWriter, format);// 写文件流
try {
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return stringWriter.toString();
}
/**
* 去掉声明头的(即<?xml...?>去掉)
*
* @param document
* @param charset
* @return
*/
public static String documentToStringNoDeclaredHeader(Document document, String charset) {
String xml = documentToString(document, charset);
return xml.replaceFirst("\\s*<[^<>]+>\\s*", "");
}
/**
* 解析XML为Document对象
*
* @param xml 被解析的XMl
* @return Document
*/
public final static Element parseXml(String xml) {
StringReader sr = new StringReader(xml);
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(sr);
} catch (DocumentException e) {
e.printStackTrace();
}
Element rootElement = document != null ? document.getRootElement() : null;
return rootElement;
}
/**
* 获取element对象的text的值
*
* @param e 节点的对象
* @param tac 节点的tac
* @return
*/
public final static String getText(Element e, String tac) {
Element _e = e.element(tac);
if (_e != null) {
return _e.getText();
} else {
return null;
}
}
/**
* 获取去除空格的字符串
*
* @param e
* @param tac
* @return
*/
public final static String getTextTrim(Element e, String tac) {
Element _e = e.element(tac);
if (_e != null) {
return _e.getTextTrim();
} else {
return null;
}
}
/**
* 获取节点值.节点必须不能为空,否则抛错
*
* @param parent 父节点
* @param tac 想要获取的子节点
* @return 返回子节点
*/
public final static String getTextTrimNotNull(Element parent, String tac) {
Element e = parent.element(tac);
if (e == null) {
throw new NullPointerException("节点为空");
} else {
return e.getTextTrim();
}
}
/**
* 节点必须不能为空,否则抛错
*
* @param parent 父节点
* @param tac 想要获取的子节点
* @return 子节点
*/
public final static Element elementNotNull(Element parent, String tac) {
Element e = parent.element(tac);
if (e == null) {
throw new NullPointerException("节点为空");
} else {
return e;
}
}
/**
* 将对象直接转换成String类型的 XML输出
*
* @param obj
* @return
*/
public static String convertToXml(Object obj) {
// 创建输出流
StringWriter sw = new StringWriter();
try {
// 利用jdk中自带的转换类实现
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
// 格式化xml输出的格式
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
// 将对象转换成输出流形式的xml
marshaller.marshal(obj, sw);
} catch (JAXBException e) {
e.printStackTrace();
}
return sw.toString();
}
/**
* 将对象根据路径转换成xml文件
*
* @param obj
* @param path
* @return
*/
public static void convertToXml(Object obj, String path) {
try {
// 利用jdk中自带的转换类实现
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
// 格式化xml输出的格式
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
// 将对象转换成输出流形式的xml
// 创建输出流
FileWriter fw = null;
try {
fw = new FileWriter(path);
} catch (IOException e) {
e.printStackTrace();
}
marshaller.marshal(obj, fw);
} catch (JAXBException e) {
e.printStackTrace();
}
}
/**
* 将String类型的xml转换成对象
*/
public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
Object xmlObject = null;
try {
JAXBContext context = JAXBContext.newInstance(clazz);
// 进行将Xml转成对象的核心接口
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader sr = new StringReader(xmlStr);
xmlObject = unmarshaller.unmarshal(sr);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
/**
* 将file类型的xml转换成对象
*/
public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
Object xmlObject = null;
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
FileReader fr = null;
try {
fr = new FileReader(xmlPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
xmlObject = unmarshaller.unmarshal(fr);
} catch (JAXBException e) {
e.printStackTrace();
}
return xmlObject;
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
-->
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
<id>remi-comm-util</id>
<classpath>
<dir name="D:/Codes/startdis/startdis-comm/remi-comm-util/target/classes">
</dir>
</classpath>
</application>