Files
redbbs-pro/src/net/tccn/bbs/base/Utils.java
2023-06-25 03:59:02 +08:00

750 lines
24 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package net.tccn.bbs.base;
import net.tccn.bbs.base.util.Kv;
import org.redkale.source.DataJdbcSource;
import org.redkale.source.DataSource;
import org.redkale.source.Flipper;
import org.redkale.util.Comment;
import org.redkale.util.Reproduce;
import org.redkale.util.Sheet;
import org.redkale.util.Utility;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class Utils {
private Utils() {
}
public static String dateFmt(long time) {
/**
* 刚刚 60秒内 60 * 1000
* x分钟前 1小时候内 60 * 60*1000
* x小时前 1天内 24 * 60*60*1000
* x天前 1周内 7 * 24*60*60*1000
* 年-月-日 1周前
*/
long now = System.currentTimeMillis();
long diff = now - time;
if (diff < 60 * 1000)
return "刚刚";
else if (diff < 60 * 60 * 1000)
return Math.floorDiv(diff, 60 * 1000) + "分钟前";
else if (diff < 24 * 60 * 60 * 1000)
return Math.floorDiv(diff, 60 * 60 * 1000) + "小时前";
else if (diff > 24 * 60 * 60 * 1000 && diff < 7 * 24 * 60 * 60 * 1000)
return Math.floorDiv(diff, 24 * 60 * 60 * 1000) + "天前";
else
return new SimpleDateFormat("yyyy-MM-dd").format(time);
}
public static String delHTMLTag(String htmlStr) {
String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式
Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
Matcher m_script = p_script.matcher(htmlStr);
htmlStr = m_script.replaceAll(""); //过滤script标签
Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
Matcher m_style = p_style.matcher(htmlStr);
htmlStr = m_style.replaceAll(""); //过滤style标签
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
Matcher m_html = p_html.matcher(htmlStr);
htmlStr = m_html.replaceAll(""); //过滤html标签
return htmlStr.trim(); //返回文本字符串
}
public static <T> T[] listToArray(List list, T[] ts) {
for (int i = 0; i < list.size(); i++) {
ts[0] = (T) list.get(i);
}
return ts;
}
public static int[] listToArray(List list, int[] ts) {
for (int i = 0; i < list.size(); i++) {
ts[0] = (int) list.get(i);
}
return ts;
}
/**
* 判断对象是否为空
*
* @param obj 待判断的对象
* @return
*/
public static boolean isEmpty(Object obj) {
if (obj == null) {
return true;
} else if (obj instanceof String) {
return ((String) obj).trim().isEmpty();
} else if (obj instanceof Collection) {
return ((Collection) obj).isEmpty();
} else if (obj instanceof Map) {
return ((Map) obj).isEmpty();
} else if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
return true;
}
return false;
}
private static Map<String, Reproduce> reproduceMap = new HashMap<>();
/**
* @param d 目标对象
* @param s 源对象
* @param <D> 目标对象的数据类型
* @param <S> 源对象的数据类型
* @return
*/
public static <D, S> D copy(D d, S s) {
String reproductKey = d.getClass().getName() + "_" + s.getClass().getName();
Reproduce<D, S> reproduce = reproduceMap.get(reproductKey);
if (reproduce == null) {
if (reproduce == null) {
reproduceMap.put(reproductKey, reproduce = (Reproduce<D, S>) Reproduce.create(d.getClass(), s.getClass()));
}
}
return reproduce.apply(d, s);
}
public static List<String> parseHtmlImage(String html) {
Pattern pattern = Pattern.compile("(?<=(<img\\s?src\\s?=\\s?\"))\\S+\\.[A-Za-z]+");
Matcher match = pattern.matcher(html);
List<String> ls = new ArrayList<>();
while (match.find()) {
ls.add(match.group());
}
return ls;
}
/**
* @param rs
* @param type
* @param <T>
* @return
*/
public static <T> List<T> queryList(ResultSet rs, Class<T> type) {
try {
List list = new ArrayList();
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
while (rs.next()) {
Kv row = Kv.of();
for (int i = 1; i <= count; i++) {
String columnTypeName = metaData.getColumnTypeName(i);
String columnLabel = metaData.getColumnLabel(i);
row.put(columnLabel, null);
if (rs.getObject(i) != null) {
switch (columnTypeName) {
case "DATETIME", "TIMESTAMP", "DATE" -> row.put(columnLabel, rs.getTimestamp(i).getTime());
default -> row.put(columnLabel, rs.getObject(i));
}
}
}
list.add((Map.class == type || Kv.class == type) ? row : Kv.toBean(row, type));
}
return list;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 查询 第一条的 第一列数据 值
*
* @param rs
* @param type
* @param <T>
* @return
*/
public static <T> T findColumn(ResultSet rs, Class<T> type) {
try {
Object v = null;
while (rs.next()) {
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
for (int i = 1; i <= count; i++) {
String columnTypeName = metaData.getColumnTypeName(i);
if (rs.getObject(i) != null) {
switch (columnTypeName) {
case "DATETIME", "TIMESTAMP", "DATE" -> v = rs.getTimestamp(i).getTime();
default -> v = rs.getObject(i);
}
}
break;
}
}
return Kv.toAs(v, type);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* List 混排
*
* @param list
* @return
*/
public static <T> List<T> mix(List<T> list) {
int len = list.size();
Random random = new Random();
for (int i = 0; i < len; i++) {
int r = random.nextInt(len);
if (i == r) continue;
T x = list.get(i);
list.set(i, list.get(r));
list.set(r, x);
}
return list;
}
@Comment("获取集合随机元素")
public static <T> List<T> randomItems(List<T> list, int len) {
List<Integer> randoms = getRandoms(list.size(), len);
List<T> items = new ArrayList<>(randoms.size());
randoms.forEach(x -> items.add(list.get(x)));
return items;
}
@Comment("获取随机数字符")
public static String randomNumber(int len) {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < len; i++) {
sb.append(random.nextInt(9));
}
return sb.toString();
}
@Comment("获取随机数集合")
private static List<Integer> getRandoms(int max, int len) {
Set<Integer> randoms = new HashSet<>();
Random random = new Random();
while (randoms.size() < len && randoms.size() < max) {
randoms.add(random.nextInt(max));
}
List<Integer> list = randoms.stream().collect(Collectors.toList());
return mix(list);
}
/**
* unicode转中文
*
* @param str
* @return
*/
public static String unicodeToCn(String str) {
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
Matcher matcher = pattern.matcher(str);
char ch;
while (matcher.find()) {
ch = (char) Integer.parseInt(matcher.group(2), 16);
str = str.replace(matcher.group(1), ch + "");
}
return str;
}
/**
* 计算字符串的字符长度
*
* @param value
* @return
*/
public static int strLength(String value) {
int valueLength = 0;
String chinese = "[\u4e00-\u9fa5]";
for (int i = 0; i < value.length(); i++) {
String temp = value.substring(i, i + 1);
if (temp.matches(chinese)) {
valueLength += 2;
} else {
valueLength += 1;
}
}
return valueLength;
}
public static String randomIP() {
// aaa.aaa.aaa.aaa
StringBuilder buf = new StringBuilder();
Random r = new Random();
buf.append("x").append(".");
buf.append(r.nextInt(255)).append(".");
buf.append(r.nextInt(255)).append(".");
buf.append(r.nextInt(255));
return buf.toString();
}
public static String fmt36(int n) {
return Integer.toString(n, 36);
}
public static String fmt36(long n) {
return Long.toString(n, 36);
}
public static <T, V> Map<T, V> toMap(Collection<V> list, Function<V, T> fun) {
Map<T, V> map = new HashMap<>(list.size());
for (V v : list) {
if (v == null) {
continue;
}
map.put(fun.apply(v), v);
}
return map;
}
public static <T, V, T2> Map<T, T2> toMap(Collection<V> list, Function<V, T> fun, Function<V, T2> fun2) {
Map<T, T2> map = new HashMap<>(list.size());
for (V v : list) {
if (v == null) {
continue;
}
map.put(fun.apply(v), fun2.apply(v));
}
return map;
}
public static <T, V> List<V> toList(Collection<T> list, Function<T, V> fun) {
if (list == null || list.isEmpty()) {
return new ArrayList<>();
}
List<V> list1 = new ArrayList<>();
list.forEach(x -> list1.add(fun.apply(x)));
return list1;
}
public static <T, V> List<V> toList(Sheet<T> sheet, Function<T, V> fun) {
List<V> list = new ArrayList<>();
sheet.forEach(x -> list.add(fun.apply(x)));
return list;
}
public static <T, V> Set<V> toSet(Collection<T> list, Function<T, V> fun) {
if (list == null || list.isEmpty()) {
return new HashSet<>();
}
Set<V> set = new HashSet<>(list.size());
list.forEach(x -> set.add(fun.apply(x)));
return set;
}
public static <T, V> Set<V> toSet(Sheet<T> sheet, Function<T, V> fun) {
Set<V> set = new HashSet<>();
sheet.forEach(x -> set.add(fun.apply(x)));
return set;
}
public static <T> List<T> filter(Collection<T> list, Predicate<T> predicate) {
if (list == null || list.isEmpty()) {
return new ArrayList<>();
}
List<T> list1 = new ArrayList<>(list.size());
list.forEach(x -> {
if (!predicate.test(x)) {
return;
}
list1.add(x);
});
return list1;
}
public static <T, V> List<V> filterToList(Collection<T> list, Predicate<T> predicate, Function<T, V> fun) {
if (list == null || list.isEmpty()) {
return new ArrayList<>();
}
List<V> list1 = new ArrayList<>(list.size());
list.forEach(x -> {
if (!predicate.test(x)) {
return;
}
list1.add(fun.apply(x));
});
return list1;
}
public static <T, V> Map<V, List<T>> group(Collection<T> list, Function<T, V> fun) {
if (list == null || list.isEmpty()) {
return new HashMap<>();
}
return list.stream().collect(Collectors.groupingBy(fun));
}
public static <T, V, K> Map<V, List<K>> group(Collection<T> list, Function<T, V> fun, Function<T, K> fun2) {
if (list == null || list.isEmpty()) {
return new HashMap<>();
}
Map<V, List<T>> group = group(list, fun);
Map<V, List<K>> _group = new HashMap<>();
group.forEach((k, v) -> _group.put(k, toList(v, fun2)));
return _group;
}
public static String getHtmlBody(String html) {
String s = html.replaceAll("\n", "");
int bodyIndex = s.indexOf("<body>");
if (bodyIndex > -1) {
bodyIndex = bodyIndex + 6;
int lastIndexOf = s.lastIndexOf("</body>");
if (lastIndexOf < bodyIndex) lastIndexOf = s.length();
s = s.substring(bodyIndex, lastIndexOf);
}
return s;
}
public static String getHtmlText(String html) {
return html.replaceAll("<([^ \\f\\n\\r\\t\\v<]| )+>", "");
}
//获取指定日期的 前/后 几天日期
public static long plusDays(long datetime, int daynum) {
if (daynum == 0 || datetime == 0) {
return datetime;
}
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime time = LocalDateTime.ofInstant(Instant.ofEpochMilli(datetime), zoneId);
time = time.plusDays(daynum);
return time.toInstant(ZoneOffset.of("+8")).toEpochMilli();
}
// -----------------
private static final MessageDigest sha1;
private static final MessageDigest md5;
private static final String AES_KEY = "HAOGAME_20200721";
private static final Cipher aesEncrypter; //加密
private static final Cipher aesDecrypter; //解密
static {
MessageDigest d = null;
try {
d = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException ex) {
throw new Error(ex);
}
sha1 = d;
try {
d = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
throw new Error(ex);
}
md5 = d;
Cipher cipher = null;
final SecretKeySpec aesKey = new SecretKeySpec(AES_KEY.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
} catch (Exception e) {
throw new Error(e);
}
aesEncrypter = cipher; //加密
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
} catch (Exception e) {
throw new Error(e);
}
aesDecrypter = cipher; //解密
}
//AES加密
public static String encryptAES(String value) {
if (value == null || value.isEmpty()) {
return value;
}
try {
synchronized (aesEncrypter) {
return Utility.binToHexString(aesEncrypter.doFinal(value.getBytes()));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//AES解密
public static String decryptAES(String value) {
if (value == null || value.isEmpty()) {
return value;
}
byte[] hex = Utility.hexToBin(value);
try {
synchronized (aesEncrypter) {
return new String(aesDecrypter.doFinal(hex));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Comment("GET请求参数转换为字符结果p1=v1&p2=v2&p3=v3")
public static String convertHttpParams(Map map, boolean encode) {
if (map == null || map.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
map.forEach((k, v) -> {
if (Utils.isEmpty(k) || Utils.isEmpty(v)) {
return;
}
String value = String.valueOf(v);
if (encode) {
value = URLEncoder.encode(String.valueOf(v), StandardCharsets.UTF_8);
}
sb.append("&").append(k).append("=").append(value);
});
return sb.length() > 0 ? sb.substring(1) : "";
}
@Comment("对象转GET请求参数转换为字符结果p1=v1&p2=v2&p3=v3")
public static String convertHttpParams(Object o, List<String> removeFields, boolean encode) {
Class<? extends Object> c = o.getClass();
Field[] fields = c.getDeclaredFields();
Map<String, Object> map = new TreeMap<String, Object>();
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
if (!Utils.isEmpty(removeFields) && removeFields.contains(name)) {
continue;
}
Object value = null;
try {
value = field.get(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (value != null) {
map.put(name, value);
}
}
return convertHttpParams(map, encode);
}
@Comment("GET请求参数转换为字符结果p1=v1&p2=v2&p3=v3")
public static String convertHttpParams(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return "";
}
Set<String> sortSet = new TreeSet<String>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
sortSet.add(entry.getKey());
}
// 参数名按ASCII码从小到大排序字典序,然后使用( & )连接排好序的key=value集合
StringBuffer sb = new StringBuffer();
boolean isFirst = true;
for (String key : sortSet) {
if (isFirst) {
sb.append(key + "=" + URLEncoder.encode(String.valueOf(map.get(key)), StandardCharsets.UTF_8));
isFirst = false;
} else {
sb.append("&" + key + "=" + URLEncoder.encode(String.valueOf(map.get(key)), StandardCharsets.UTF_8));
}
}
return sb.toString();
}
@Comment("对象转map")
public static Map<String, Object> convertToMap(Object o, List<String> removeFields) {
Class<? extends Object> c = o.getClass();
List<Field> fields = Stream.of(c.getDeclaredFields()).collect(Collectors.toList());
if (c.getSuperclass() != null) {
Field[] superFields = c.getSuperclass().getDeclaredFields();
if (superFields.length > 0) {
fields.addAll(Arrays.asList(superFields));
}
}
Map<String, Object> map = new TreeMap<>();
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
if (!Utils.isEmpty(removeFields) && removeFields.contains(name)) {
continue;
}
Object value = null;
try {
value = field.get(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (value != null) {
map.put(name, value);
}
}
return map;
}
@Comment("key字典排序")
public static LinkedHashMap sortedMap(Map<String, ?> map, String... excludeKeys) {
List<String> excludeList = List.of(excludeKeys);
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
map.entrySet().stream()
.filter(f -> !excludeList.contains(f.getKey()))
.sorted(Map.Entry.comparingByKey())
.forEach(x -> linkedHashMap.put(x.getKey(), x.getValue()));
return linkedHashMap;
}
@Comment(" string转化为jsonstring")
public static String convertParamStrToJsonStr(String paramStr) {
StringBuilder builder = new StringBuilder();
Arrays.stream(paramStr.split("&")).forEach(x -> {
//防止有地址传参时造成的错误解析
x = URLDecoder.decode(x, StandardCharsets.UTF_8);
int index = x.indexOf("=");
char c = x.charAt(index + 1);
builder.append(String.format("\"%s\":\"%s\",", x.substring(0, index), c == '[' || c == '{' ? x.substring(index + 1).replaceAll("\"", "\\\\\"") : x.substring(index + 1)));
});
return String.format("{%s}", builder.deleteCharAt(builder.length() - 1).toString());
}
public static <T> Sheet<T> querySheetBySql(DataSource dataSource, String sql, Flipper flipper, Class<T> type) {
DataJdbcSource jdbcSource = (DataJdbcSource) dataSource;
//总条数
int total = jdbcSource.directQuery("select count(0) c from (" + sql + ") c", rs -> {
int result = 0;
try {
while (rs.next()) {
result = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return result;
});
if (total == 0) {
return new Sheet<>(0, new ArrayList<>());
}
if (flipper != null) {
sql = String.format("%s %s limit %s,%s ", sql, Utils.isEmpty(flipper.getSort()) ? "" : "order by " + flipper.getSort(), flipper.getOffset(), flipper.getLimit());
}
List<T> dataList = jdbcSource.directQuery(sql, rs -> Utils.queryList(rs, type));
return new Sheet<>(total, dataList);
}
@Comment("获取次日0点0分0秒时间戳")
public static long getNextDayZero() {
LocalDate localDate = LocalDate.now();
localDate = localDate.plusDays(1);
LocalDateTime dateTime = LocalDateTime.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth(), 0, 0, 0);
return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
public static String formatTime(long time, String pattern) {
if (Utils.isEmpty(pattern)) pattern = "yyyy-MM-dd";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(new Date(time));
}
@Comment("获取字符串中某个字符的数量")
public static int strCountOfChar(String str, String code) {
int fromIndex = 0;
int count = 0;
while (true) {
int index = str.indexOf(code, fromIndex);
if (-1 != index) {
fromIndex = index + 1;
count++;
} else {
break;
}
}
return count;
}
private static Random random = new Random();
public static int randomNum(int len) {
int rs = random.nextInt(9);
if (rs == 0) rs = 1;
for (int i = 0; i < len - 1; i++) { //总长度为6
rs = rs * 10 + random.nextInt(9);
}
return rs;
}
public static String genMd5(String info) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] infoBytes = info.getBytes();
md5.update(infoBytes);
byte[] sign = md5.digest();
return byteArrayToHex(sign);
}
public static String byteArrayToHex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (byte aByte : bytes) {
String hex = Integer.toHexString(aByte & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toLowerCase());
}
return sign.toString();
}
}