package com.smtservlet.util;
|
|
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayOutputStream;
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.FileOutputStream;
|
import java.io.FilenameFilter;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.InputStreamReader;
|
import java.io.OutputStream;
|
import java.io.OutputStreamWriter;
|
import java.io.PrintStream;
|
import java.lang.reflect.Method;
|
import java.math.BigDecimal;
|
import java.math.BigInteger;
|
import java.net.URL;
|
import java.net.URLClassLoader;
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.security.SecureRandom;
|
import java.text.SimpleDateFormat;
|
import java.util.ArrayList;
|
import java.util.Calendar;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.UUID;
|
import java.util.Map.Entry;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import org.dom4j.Attribute;
|
import org.dom4j.Document;
|
import org.dom4j.Element;
|
import org.dom4j.io.SAXReader;
|
|
import com.fasterxml.uuid.Generators;
|
|
|
public final class SMTStatic
|
{
|
/**
|
* 数据转换类型
|
*/
|
public enum SMTConvType
|
{
|
Integer,
|
Long,
|
Float,
|
Double,
|
Date,
|
String,
|
MergeDate,
|
MD5,
|
}
|
|
/**
|
* 数据转换对于空字符串的处理
|
*/
|
public enum SMTConvEmpty
|
{
|
SkipEmpty,
|
KeepEmpty,
|
ErrorEmpty,
|
}
|
|
/**
|
* 计算时间用枚举
|
*/
|
public enum SMTCalcTime
|
{
|
SET_MILLISECOND,
|
ADD_SECOND,
|
ADD_MINUTE,
|
ADD_HOUR,
|
ADD_DATE,
|
ADD_MONTH,
|
ADD_YEAR,
|
SET_SECOND,
|
SET_MINUTE,
|
SET_HOUR,
|
SET_DATE,
|
SET_MONTH,
|
SET_YEAR,
|
ZERO_TIME,
|
}
|
|
/**
|
* stringFormat使用的格式化类
|
*/
|
public static class StringNamedFormat
|
{
|
/**
|
* 参数名
|
*/
|
public String _name;
|
|
/**
|
* 参数索引
|
*/
|
public int _index;
|
|
/**
|
* 构造函数
|
*
|
* @param name - 参数名
|
* @param index - 参数索引
|
*/
|
public StringNamedFormat(String name, int index)
|
{
|
_name = name;
|
_index = index;
|
}
|
|
}
|
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
private static final String LOWER = UPPER.toLowerCase();
|
private static final String DIGITS = "0123456789";
|
private static final String SPECIAL = "!@#$%^&*()-_=+";
|
|
private static final String ALL_CHARACTERS = UPPER + LOWER + DIGITS + SPECIAL;
|
|
/**
|
* stringFormat使用的参数通知函数
|
*/
|
public static interface StringNamedNotify
|
{
|
/**
|
* 通过命名参数获取值
|
*
|
* @param name - 参数名
|
* @param args - 输入的参数列表
|
* @return - 转换后的字符串
|
*/
|
Object getNamedValue(String name, Object[] args) throws Exception;
|
}
|
|
/**
|
* 空json对象
|
*/
|
public static Json emptyObject = Json.object();
|
|
/**
|
* stringFormat使用的正则匹配
|
*/
|
private static final Pattern _patStringFormat = Pattern.compile("^\\{(\\d+|[#_A-Za-z\\$][^\\{%\\}]+)(\\%[^\\}]+)?\\}", 0);
|
|
/**
|
* 分析日期格式用的正则匹配
|
*/
|
private static final Pattern _patDateFormat = Pattern.compile("^(\\d+)-(\\d+)-(\\d+)(?: (\\d+):(\\d+)(?::(\\d+))?)?$", 0);
|
|
/**
|
* html转换使用的映射表
|
*/
|
private static final String[] _convCharToHtml = new String[]{"<", "<", ">", ">"};
|
|
private static final Pattern _patTimeSpanFormat = Pattern.compile("(\\d+)([smhd])");
|
|
private static final char[] _charSeqList = 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 final ThreadLocal <SimpleDateFormat> _dateFmt = SMTStatic.newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
/**
|
* 生成线程安全的SimpleDateFormat对象
|
*
|
* @param fmt - date格式
|
* @return - 返回SimpleDateFormat对象
|
*/
|
public static ThreadLocal <SimpleDateFormat> newSimpleDateFormat(final String fmt)
|
{
|
return new ThreadLocal <SimpleDateFormat>(){
|
@Override
|
protected SimpleDateFormat initialValue() {
|
return new SimpleDateFormat(fmt);
|
}
|
};
|
}
|
|
|
|
/**
|
* 判断字符串是否为空或null
|
*
|
* @param str - 要判断的字符串
|
* @return - 判断结果
|
*/
|
public static boolean isNullOrEmpty(String str)
|
{
|
return (str == null || str.length() == 0);
|
}
|
|
/**
|
* 格式化字符串
|
*
|
* @param format - 要格式化的内容,可以用'{名称}'或'{索引}'来表示
|
* @param args - 要格式化的参数,最后的参数可以跟StringNamedFormat或StringNamedNotify
|
* @return - 返回格式化后的字符串
|
*/
|
public static String stringFormat(String format, Object...args)
|
{
|
try
|
{
|
StringBuilder sbOut = new StringBuilder();
|
Map<String, Integer> mapName2Index = null;
|
StringNamedNotify notify = null;
|
|
// 如果最后一个参数是StringNamedNotify,则按照这个设置
|
if(args.length > 0 && args[args.length - 1] instanceof StringNamedNotify)
|
notify = (StringNamedNotify)args[args.length - 1];
|
|
for(int i = 0; i < format.length(); i ++)
|
{
|
char ch = format.charAt(i);
|
if(ch == '\\')
|
{
|
i++;
|
ch = format.charAt(i);
|
switch(ch)
|
{
|
case 'r':ch = '\r';break;
|
case 'n':ch = '\n';break;
|
case 'b':ch = '\b';break;
|
case 't':ch = '\t';break;
|
}
|
sbOut.append(ch);
|
}
|
else if(ch == '{')
|
{
|
Matcher mat = _patStringFormat.matcher(format.substring(i));
|
if(!mat.find())
|
throw new RuntimeException(String.format("unknow format match for [%s] at [%d]", format.substring(i), i));
|
String fullFmt = mat.group();
|
String dataName = mat.group(1);
|
String dataFmt = mat.group(2);
|
Object value = null;
|
|
// 如果当前是通知类型,则调用通知函数获得值
|
if(notify != null)
|
{
|
value = notify.getNamedValue(dataName, args);
|
}
|
// 如果参数第一个符号不是数字,则解析名称
|
else if(dataName.charAt(0) < '0' || dataName.charAt(0) > '9')
|
{
|
if(mapName2Index == null)
|
{
|
mapName2Index = new HashMap<String, Integer>();
|
|
// 如果最后一个参数是名称数组,则只解析名称数组
|
if(args[args.length - 1] instanceof StringNamedFormat[])
|
{
|
for(StringNamedFormat named : (StringNamedFormat[])args[args.length - 1])
|
{
|
mapName2Index.put(named._name, named._index);
|
}
|
}
|
// 最后一个参数不是名称数组,则解析每一个名称对象
|
else
|
{
|
for(int j = 0; j < args.length; j ++)
|
{
|
if(args[j] instanceof StringNamedFormat)
|
{
|
StringNamedFormat named = (StringNamedFormat)args[j];
|
mapName2Index.put(named._name, named._index);
|
}
|
}
|
}
|
|
if(!mapName2Index.containsKey(dataName))
|
throw new RuntimeException(String.format("format name [%s] is not found for string [%s]", dataName, format));
|
int dataIndex = mapName2Index.get(dataName);
|
if(dataIndex >= args.length)
|
throw new RuntimeException(String.format("format argument name [%s] index [%d] is out of range for string [%s]", dataName, dataIndex, format));
|
value = args[dataIndex];
|
}
|
}
|
// 如果第一个字符是数字,则解析索引
|
else
|
{
|
int dataIndex = Integer.parseInt(dataName);
|
if(dataIndex >= args.length)
|
throw new RuntimeException(String.format("format argument index [%d] is out of range for string [%s]", dataIndex, format));
|
value = args[dataIndex];
|
}
|
|
|
if(dataFmt == null)
|
{
|
sbOut.append(value == null ? "" : value.toString());
|
}
|
else
|
{
|
sbOut.append(String.format(dataFmt, value));
|
}
|
|
i += fullFmt.length() - 1;
|
}
|
else
|
{
|
sbOut.append(ch);
|
}
|
}
|
|
return sbOut.toString();
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException(String.format("stringFormat [%s] exception", format), ex);
|
}
|
}
|
|
/**
|
* 转换字符串成html格式
|
*
|
* @param text - 要转换的字符串
|
* @return - 返回转换后的html内容
|
*/
|
public static String convStringToHtmlBody(String text)
|
{
|
for(int i = 0; i < _convCharToHtml.length; i += 2)
|
{
|
text = text.replace(_convCharToHtml[i + 0], _convCharToHtml[i + 1]);
|
}
|
return text;
|
}
|
|
public static String convHtmlBodyToString(String text)
|
{
|
for(int i = 0; i < _convCharToHtml.length; i += 2)
|
{
|
text = text.replace(_convCharToHtml[i + 1], _convCharToHtml[i + 0]);
|
}
|
return text;
|
}
|
|
/**
|
* 读取UTF-8文本流的内容
|
*
|
* @param inputStream - 要读取的文本流
|
* @return - 返回读取的内容
|
*/
|
public static String readTextStream(InputStream inputStream)
|
{
|
InputStreamReader rd = null;
|
|
try
|
{
|
StringBuilder sb = new StringBuilder();
|
int size = 0;
|
char[] data = new char[10240];
|
rd=new InputStreamReader(inputStream, "UTF-8");
|
while((size = rd.read(data)) > 0)
|
{
|
sb.append(data, 0, size);
|
}
|
return sb.toString();
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException(ex);
|
}
|
finally
|
{
|
if(rd != null)
|
try {
|
rd.close();
|
} catch (IOException e) {
|
}
|
}
|
}
|
|
/**
|
* 从文本文件中读取UTF-8的文本
|
*
|
* @param fileName - 文件名
|
* @return - 返回文件内容
|
*/
|
public static String readAllText(String fileName)
|
{
|
return readAllText(new File(fileName));
|
}
|
|
|
/**
|
* 从文本文件中读取UTF-8的文本
|
*
|
* @param fileName - 文件名
|
* @return - 返回文件内容
|
*/
|
public static String readAllText(File file)
|
{
|
FileInputStream fi = null;
|
try
|
{
|
fi = new FileInputStream(file);
|
return readTextStream(fi);
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException(String.format("read file [%s] error", file.getAbsolutePath()), ex);
|
}
|
finally
|
{
|
if(fi != null)
|
{
|
try {
|
fi.close();
|
} catch (IOException e) {
|
}
|
}
|
}
|
}
|
|
/**
|
* 将文本数据以UTF-8格式写入文件
|
*
|
* @param file - 要写入的文件名
|
* @param text - 要写入的内容
|
*/
|
public static void saveTextFile(File file, String text) throws Exception
|
{
|
OutputStreamWriter wr = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
|
|
try
|
{
|
wr.write(text);
|
}
|
finally
|
{
|
wr.close();
|
}
|
}
|
|
/**
|
* 将文本数据以UTF-8格式写入文件
|
*
|
* @param file - 要写入的文件名
|
* @param text - 要写入的内容
|
* @param append-是否要追加
|
*/
|
public static void saveTextFile(File file, String text, boolean append) throws Exception
|
{
|
OutputStreamWriter wr = new OutputStreamWriter(new FileOutputStream(file, append), "UTF-8");
|
|
try
|
{
|
wr.write(text);
|
}
|
finally
|
{
|
wr.close();
|
}
|
}
|
|
|
/**
|
* 将字符串或日期类型转换成日期类型
|
*
|
* @param value - 要转换的内容
|
* @return - 返回转换后的日期
|
*/
|
public static Date toDate(Object value)
|
{
|
if(value instanceof String)
|
{
|
Matcher m = _patDateFormat.matcher(value.toString());
|
if(!m.find())
|
throw new RuntimeException("parse time error");
|
int year = Integer.parseInt(m.group(1));
|
int month = Integer.parseInt(m.group(2));
|
int day = Integer.parseInt(m.group(3));
|
int hour = (m.group(4) != null) ? Integer.parseInt(m.group(4)) : 0;
|
int minute = (m.group(5) != null) ? Integer.parseInt(m.group(5)) : 0;
|
int second = (m.group(6) != null) ? Integer.parseInt(m.group(6)) : 0;
|
//objValue = new Date(year - 1900, month, day, hour, minute, second);
|
Calendar cal = Calendar.getInstance();
|
cal.set(year, month - 1, day, hour, minute, second);
|
cal.set(Calendar.MILLISECOND, 0);
|
return cal.getTime();
|
}
|
|
if(value instanceof Date)
|
return (Date)value;
|
|
throw new RuntimeException("unknow date type");
|
}
|
|
/**
|
* 通过json配置,将字符串转换成值,并保存在map中
|
*
|
* @param jsonParams - json配置列表
|
* @param mapName2Value - 返回的映射数据
|
* @param skipEmpty - 对于空白的缺省处理
|
* @param throwError - 出错是否抛异常
|
* @return - true:全部成功,false:有错
|
*/
|
public static boolean convStrByJson(String value, Json jsonParam, Map<String, Object> mapName2Value, SMTConvEmpty skipEmpty, boolean throwError) throws Exception
|
{
|
if(!jsonParam.isObject())
|
throw new Exception("current is not map json:" + jsonParam.toString());
|
|
// 如果没有field或ctrl属性,则直接忽略
|
if(!jsonParam.has("field") || !jsonParam.has("ctrl") || !jsonParam.has("type"))
|
return true;
|
|
try
|
{
|
// 获取字段名
|
boolean ret = true;
|
String field = jsonParam.at("field").asString();
|
SMTConvType type = Enum.valueOf(SMTConvType.class, jsonParam.at("type").asString());
|
String mode = jsonParam.safeGetStr("mode", "only");
|
if(jsonParam.has("empty"))
|
skipEmpty = Enum.valueOf(SMTConvEmpty.class, jsonParam.at("empty").asString());
|
|
// 取值
|
if(mode.equals("array"))
|
{
|
String split = jsonParam.safeGetStr("split", ",");
|
ret = insertValueToMap(field, convStrToArray(value, type, skipEmpty, split), mapName2Value, ret);
|
}
|
else if(mode.equals("only"))
|
{
|
ret = insertValueToMap(field, convStrToValue(value, type, skipEmpty), mapName2Value, ret);
|
}
|
else
|
throw new Exception(String.format("mode [%s] is not 'between' or 'array' or 'only'", mode));
|
|
return ret;
|
}
|
catch(Exception ex)
|
{
|
if(throwError)
|
throw ex;
|
|
return false;
|
}
|
}
|
|
/**
|
* 如果value是有效输入则插入map,否则返回false
|
* @param key - 要插入的key
|
* @param value - 要插入的值
|
* @param mapName2Value - 返回插入的map
|
* @param prevStat - 前一次的状态
|
* @return - 如果失败则返回false, 如果成功则返回prevStat
|
*/
|
protected static boolean insertValueToMap(String key, Object value, Map<String, Object> mapName2Value, boolean prevStat)
|
{
|
if(value == null)
|
return true;
|
if(value instanceof Exception)
|
return false;
|
|
mapName2Value.put(key, value);
|
return prevStat;
|
}
|
|
/**
|
* 将字符串转换成对应的数组类型
|
*
|
* @param str - 字符串
|
* @param type - 要转换的类型
|
* @param skipEmpty - 是否跳过空字串
|
* @param split - 数据切分
|
* @return - null:无数据,Exception:有错误,其他:数组类型数据
|
*/
|
public static Object convStrToArray(String str, SMTConvType type, SMTConvEmpty skipEmpty, String split)
|
{
|
if(str == null)
|
return null;
|
|
List<Object> list = new ArrayList<Object>();
|
for(String value : str.split(split, -1))
|
{
|
Object ovalue = convStrToValue(value, type, skipEmpty);
|
if(ovalue == null)
|
continue;
|
if(ovalue instanceof Throwable)
|
return ovalue;
|
list.add(ovalue);
|
}
|
|
if(list.size() == 0)
|
return null;
|
|
Object[] ret = new Object[list.size()];
|
list.toArray(ret);
|
return ret;
|
|
}
|
|
/**
|
* 将字符串转换成指定的类型数据
|
*
|
* @param str - 要转换的字符串
|
* @param type - 要转换的类型
|
* @param skipEmpty - 如果str为空是否返回null
|
* @return - null:不需要转换,Throwable:转换出错,其他:正确的数据
|
*/
|
public static Object convStrToValue(String str, SMTConvType type, SMTConvEmpty convEmpty)
|
{
|
try
|
{
|
if(str == null)
|
return null;
|
|
if(str.length() == 0)
|
{
|
if(convEmpty == SMTConvEmpty.SkipEmpty)
|
return null;
|
|
if(convEmpty == SMTConvEmpty.ErrorEmpty)
|
throw new Exception("value is empty");
|
}
|
|
if(type == SMTConvType.String)
|
{
|
return str;
|
}
|
else if(type == SMTConvType.MD5)
|
{
|
return SMTStatic.convStrToMD5(str);
|
}
|
|
if(str.length() == 0)
|
{
|
if(convEmpty == SMTConvEmpty.KeepEmpty)
|
return null;
|
throw new Exception("value is empty");
|
}
|
|
if(type == SMTConvType.Integer)
|
{
|
return Integer.parseInt(str, 10);
|
}
|
else if(type == SMTConvType.Long)
|
{
|
return Long.parseLong(str, 10);
|
}
|
else if(type == SMTConvType.Float)
|
{
|
return Float.parseFloat(str);
|
}
|
else if(type == SMTConvType.Double)
|
{
|
return Double.parseDouble(str);
|
}
|
else if(type == SMTConvType.Date)
|
{
|
return SMTStatic.toDate(str);
|
}
|
else if(type == SMTConvType.MergeDate)
|
{
|
// 将当前字符串转换成日期
|
Date date = SMTStatic.toDate(str);
|
|
// 如果当前字符串未设定时间,则将当前时间加入
|
if(str.indexOf(":") < 0)
|
{
|
Date now = new Date();
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(now);
|
date = SMTStatic.calculateTime(date,
|
SMTCalcTime.SET_HOUR, cal.get(Calendar.HOUR_OF_DAY),
|
SMTCalcTime.SET_MINUTE, cal.get(Calendar.MINUTE),
|
SMTCalcTime.SET_SECOND, cal.get(Calendar.SECOND));
|
}
|
return date;
|
}
|
throw new Exception("unsupport convert type:" + type.toString());
|
}
|
catch(Exception ex)
|
{
|
return new Exception(String.format("convert [%s] to [%s] error:[%s]", str, type, ex.getMessage()), ex);
|
}
|
}
|
|
/**
|
* 将任意类型转换成int
|
*
|
* @param value - 要转换的类型
|
* @return - 转换后的结果
|
*/
|
public static int toInt(Object value)
|
{
|
try
|
{
|
if(value instanceof Integer)
|
return (Integer)value;
|
|
if(value instanceof Long)
|
return (int)(long)(Long)value;
|
|
if(value instanceof String)
|
return Integer.parseInt((String)value);
|
|
return (Integer)(value.getClass().getMethod("intValue").invoke(value));
|
}
|
catch(Exception ex)
|
{
|
return Integer.parseInt(value.toString());
|
}
|
}
|
|
/**
|
* 将任意类型转换成int
|
*
|
* @param value - 要转换的类型
|
* @return - 转换后的结果
|
*/
|
public static long toLong(Object value)
|
{
|
try
|
{
|
if(value instanceof Long)
|
return (Long)value;
|
|
if(value instanceof Integer)
|
return (long)(Integer)value;
|
|
if(value instanceof String)
|
return Long.parseLong((String)value);
|
|
return (Long)(value.getClass().getMethod("longValue").invoke(value));
|
}
|
catch(Exception ex)
|
{
|
return Long.parseLong(value.toString());
|
}
|
}
|
|
|
/**
|
* 将任意类型转换成double
|
*
|
* @param value - 要转换的类型
|
* @return - 转换后的结果
|
*/
|
public static double toDouble(Object value)
|
{
|
try
|
{
|
if(value instanceof Double)
|
return (Double)value;
|
|
if(value instanceof String)
|
return Double.parseDouble((String)value);
|
|
return (Double)(value.getClass().getMethod("doubleValue").invoke(value));
|
}
|
catch(Exception ex)
|
{
|
return Double.parseDouble(value.toString());
|
}
|
}
|
|
|
/**
|
* 将字符串转换成MD5模式
|
*
|
* @param text - 原始字符串
|
* @return - 转换后的MD5字符串
|
*/
|
public static String convStrToMD5(String text)
|
{
|
try
|
{
|
StringBuilder sb = new StringBuilder();
|
sb.append("PA");
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
md.update(text.getBytes("UTF8"));
|
byte b[] = md.digest();
|
for(int i = 0; i < b.length; i ++)
|
{
|
sb.append(((int)b[i]) & 0xFF);
|
}
|
sb.append("SS");
|
return sb.toString();
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException(ex);
|
}
|
}
|
|
/**
|
* 生成唯一序列号
|
*
|
* @return - 返回唯一序列号
|
*/
|
public static String newSequence()
|
{
|
//String time = _GuidFmtTime.get().format(new Date());
|
//return time + UUID.randomUUID().toString().replace("-", "").substring(15);
|
StringBuilder sb = new StringBuilder();
|
Date date = new Date();
|
encodeSeqValue(date.getYear(), sb); //2
|
encodeSeqValue(date.getMonth(), sb); // 1
|
encodeSeqValue(date.getDate(), sb);// 1
|
encodeSeqValue(date.getHours(), sb); //1
|
encodeSeqValue(date.getMinutes(), sb);//1
|
encodeSeqValue(date.getSeconds(), sb);//1
|
encodeSeqValue((int)(date.getTime() % 1000), sb); //2
|
sb.append(UUID.randomUUID().toString().replace("-", "").substring(9));
|
return sb.toString();
|
}
|
|
private static void encodeSeqValue(int value, StringBuilder sb)
|
{
|
if(value < 60)
|
{
|
sb.append(_charSeqList[value]);
|
}
|
else
|
{
|
sb.append(_charSeqList[value / 60]);
|
sb.append(_charSeqList[value % 60]);
|
}
|
}
|
|
|
/**
|
* 生成uuid序列号
|
*
|
* @return - uuid序列号
|
*/
|
public static String newUUID()
|
{
|
return Generators.timeBasedEpochRandomGenerator().generate().toString().replace("-", "");
|
//return UUID.randomUUID().toString().replace("-", "");
|
}
|
|
/**
|
* 转换成C语言类型的字符串
|
*
|
* @param str - 原始字符串
|
* @return - C语言类型字符串
|
*/
|
public static String toCStr(String str)
|
{
|
return str.replace("\\", "\\\\").replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t").replace("\"", "\\\"");
|
}
|
|
/**
|
* 从json中获取字段名
|
*
|
* @param jsonField - 要获取的json对象
|
* @param subKey - != null:子对象的路径,==null:获取当前对象
|
* @param defField - 缺省字段值
|
* @return - 返回取到的字段名或缺省字段名
|
*/
|
public static String getFieldByJson(Json jsonField, String subKey, String defField)
|
{
|
if(subKey != null)
|
{
|
if(jsonField.has(subKey))
|
jsonField = jsonField.getJson(subKey);
|
else
|
return defField;
|
}
|
|
if(jsonField.isString())
|
return jsonField.asString();
|
|
if(jsonField.isObject() && jsonField.has("field"))
|
return jsonField.getJson("field").asString();
|
|
return defField;
|
}
|
|
/**
|
* 生成字典表的map list
|
*
|
* @param recs - 字典表对应的记录集
|
* @param typeKey - 类型字段名
|
* @param nameKey - 名称字段名
|
* @return - 返回创建后的列表
|
*/
|
@SuppressWarnings("unchecked")
|
public static Map<String, Map<Object, Map<String, Object>>> getDictionaryMapList(List<Object> recs, String typeKey, String nameKey)
|
{
|
Map<String, Map<Object, Map<String, Object>>> mapList = new HashMap<String, Map<Object, Map<String, Object>>>();
|
|
for(Object rec : recs)
|
{
|
Map<String, Object> orec = (Map<String, Object>)rec;
|
|
// 获取类型map表
|
String type = ((String)orec.get(typeKey)).toUpperCase();
|
Map<Object, Map<String, Object>> mapType = mapList.get(type);
|
if(mapType == null)
|
{
|
mapType = new LinkedHashMap<Object, Map<String, Object>>();
|
mapList.put(type, mapType);
|
}
|
|
// 保存当前记录
|
Object key = orec.get(nameKey);
|
orec.remove(typeKey);
|
mapType.put(key, orec);
|
}
|
return mapList;
|
}
|
|
/**
|
* 将字符串转换成值
|
*
|
* @param value - 字符串表现的值
|
* @param type - 数据类型
|
* @param skipEmpty - 空值是否返回null
|
* @param throwError - 出错是否抛异常
|
* @return - Exception:错误,null:忽略, 其他:返回转换后的值,
|
*/
|
public static Object convStringToValue(String value, SMTConvType type, SMTConvEmpty skipEmpty, boolean throwError) throws Exception
|
{
|
Object ret = convStrToValue(value == null ? "" : value, type, skipEmpty);
|
if(throwError && ret instanceof Exception)
|
throw (Exception)ret;
|
|
return ret;
|
}
|
|
/**
|
* 将字符串转换成数组
|
*
|
* @param value - 字符串表现的值
|
* @param type - 数据类型
|
* @param split - 切分字符串
|
* @param skipEmpty - 空值是否返回null
|
* @param throwError - 出错是否抛异常
|
* @return - Exception:错误,null:忽略, 其他:返回转换后的值,
|
*/
|
public static Object convStringToArray(String value, SMTConvType type, SMTConvEmpty skipEmpty, String split, boolean throwError) throws Exception
|
{
|
Object ret = convStrToArray(value == null ? "" : value, type, skipEmpty, split);
|
if(throwError && ret instanceof Exception)
|
throw (Exception)ret;
|
|
return ret;
|
}
|
|
/**
|
* 计算时间
|
*
|
* @param date - 原始时间
|
* @param args - SMTCalcTime计算类型,要计算的值。。。
|
* @return - 计算后的时间
|
*/
|
public static Date calculateTime(Date date, Object...args)
|
{
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(date);
|
for(int i = 0; i < args.length; i += 2)
|
{
|
SMTCalcTime type = (SMTCalcTime) args[i + 0];
|
int value = SMTStatic.toInt( args[i + 1]);
|
|
switch(type)
|
{
|
case ADD_SECOND:
|
cal.add(Calendar.SECOND, value);
|
break;
|
|
case ADD_MINUTE:
|
cal.add(Calendar.MINUTE, value);
|
break;
|
|
case ADD_HOUR:
|
cal.add(Calendar.HOUR_OF_DAY, value);
|
break;
|
|
case ADD_DATE:
|
cal.add(Calendar.DATE, value);
|
break;
|
|
case ADD_MONTH:
|
cal.add(Calendar.MONTH, value);
|
break;
|
|
case ADD_YEAR:
|
cal.add(Calendar.YEAR, value);
|
break;
|
|
case SET_SECOND:
|
cal.set(Calendar.SECOND, value);
|
break;
|
|
case SET_MINUTE:
|
cal.set(Calendar.MINUTE, value);
|
break;
|
|
case SET_HOUR:
|
cal.set(Calendar.HOUR_OF_DAY, value);
|
break;
|
|
case SET_DATE:
|
cal.set(Calendar.DATE, value);
|
break;
|
|
case SET_MONTH:
|
cal.set(Calendar.MONTH, value);
|
break;
|
|
case SET_YEAR:
|
cal.set(Calendar.YEAR, value);
|
break;
|
|
case SET_MILLISECOND:
|
cal.set(Calendar.MILLISECOND, value);
|
break;
|
|
case ZERO_TIME:
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
cal.set(Calendar.MINUTE, 0);
|
cal.set(Calendar.SECOND, 0);
|
cal.set(Calendar.MILLISECOND, 0);
|
break;
|
}
|
}
|
return cal.getTime();
|
}
|
|
/**
|
* 将时间间隔字符串转换成对应的秒值
|
* 时间格式: [数字][单位].....
|
* 单位格式: d:天,h:小时,m:分钟,s:秒
|
*
|
* @param timeSpan
|
* @return
|
* @throws Exception
|
*/
|
public static long convTimeSpanToSecond(String timeSpan) throws Exception
|
{
|
Matcher m = _patTimeSpanFormat.matcher(timeSpan);
|
int pos = 0;
|
long retSecond = 0;
|
while(m.find())
|
{
|
if(pos != m.start())
|
throw new Exception("time span format is error");
|
|
pos += m.group().length();
|
long value = Integer.parseInt(m.group(1));
|
|
switch(m.group(2).charAt(0))
|
{
|
case 'd':
|
retSecond += value * 60 * 60 * 24;
|
break;
|
|
case 'h':
|
retSecond += value * 60 * 60;
|
break;
|
|
case 'm':
|
retSecond += value * 60;
|
break;
|
|
case 's':
|
retSecond += value;
|
break;
|
}
|
}
|
return retSecond;
|
}
|
|
public static void loadJarPath(String filePath)
|
{
|
loadJarPath(filePath, null);
|
}
|
/**
|
* 读取jar包的路径
|
*
|
* @param filePath - 要读取的路径名
|
*/
|
public static void loadJarPath(String filePath, URLClassLoader classLoader)
|
{
|
// 系统类库路径
|
File libPath = new File(filePath);
|
|
// 获取所有的.jar和.zip文件
|
File[] jarFiles = libPath.listFiles(new FilenameFilter() {
|
public boolean accept(File dir, String name) {
|
return name.endsWith(".jar") || name.endsWith(".zip");
|
}
|
});
|
loadJarFiles(jarFiles, classLoader);
|
}
|
|
/**
|
* 将jar包文件列表读入系统
|
* @param jarFiles - 要读入的文件列表
|
*/
|
public static void loadJarFiles(File[] jarFiles, URLClassLoader classLoader)
|
{
|
try
|
{
|
if(classLoader == null)
|
classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
|
|
if (jarFiles != null) {
|
// 从URLClassLoader类中获取类所在文件夹的方法
|
// 对于jar文件,可以理解为一个存放class文件的文件夹
|
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
boolean accessible = method.isAccessible(); // 获取方法的访问权限
|
try {
|
if (accessible == false) {
|
method.setAccessible(true); // 设置方法的访问权限
|
}
|
// 获取系统类加载器
|
for (File file : jarFiles) {
|
URL url = file.toURI().toURL();
|
try {
|
method.invoke(classLoader, url);
|
//LOG.debug("读取jar文件[name={}]", file.getName());
|
} catch (Exception e) {
|
//LOG.error("读取jar文件[name={}]失败", file.getName());
|
}
|
}
|
} finally {
|
method.setAccessible(accessible);
|
}
|
}
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException(ex);
|
}
|
}
|
|
public static String toString(Object value)
|
{
|
if(value == null)
|
return "";
|
if(value instanceof Date)
|
return _dateFmt.get().format(value);
|
else if((value instanceof Float) || (value instanceof Double) || (value instanceof BigDecimal))
|
{
|
String ret = String.format("%f", value);
|
if(ret.indexOf('.') > 0)
|
{
|
for(int i = ret.length() - 1; i >= 0; i --)
|
{
|
char ch = ret.charAt(i);
|
if(ch == '.')
|
{
|
return ret.substring(0, i);
|
}
|
else if(ch != '0')
|
return ret.substring(0, i + 1);
|
}
|
}
|
|
return ret;
|
}
|
else if(value instanceof Integer || value instanceof Long || value instanceof Short || value instanceof BigInteger)
|
{
|
String ret = String.format("%d", value);
|
return ret;
|
}
|
else if(value instanceof Throwable)
|
{
|
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
|
PrintStream ps = new PrintStream(byteOS);
|
((Throwable)value).printStackTrace(ps);
|
String errMsg = new String(byteOS.toByteArray());
|
return errMsg;
|
}
|
else
|
return value.toString();
|
}
|
|
public static boolean checkFileName(String fileName, boolean incSubPath, boolean throwError) throws Exception
|
{
|
boolean check = fileName.indexOf("..") < 0;
|
if(!incSubPath)
|
check &= (fileName.indexOf("/") < 0 && fileName.indexOf("\\") < 0);
|
if(!check && throwError)
|
throw new Exception("file name include '..' : " + fileName);
|
|
return check;
|
}
|
|
public static boolean moveFile(File fileSrc, File fileTag, boolean throwError)
|
{
|
// 如果文件名相同,则直接返回
|
if(fileSrc.toString().equals(fileTag.toString()))
|
return true;
|
|
// 删除目标文件
|
if(fileTag.exists())
|
fileTag.delete();
|
if(fileTag.exists())
|
{
|
if(throwError)
|
throw new RuntimeException("delete move tag file error");
|
return false;
|
}
|
|
// 尝试移动目标文件
|
fileSrc.renameTo(fileTag);
|
|
// 如果移动成功,则返回成功
|
if(fileTag.exists())
|
return true;
|
|
// 将文件复制到目标目录
|
File tempFile = new File(fileTag.getAbsolutePath() + ".temp");
|
byte[] data = new byte[1024 * 100];
|
int size;
|
InputStream is = null;
|
OutputStream os = null;
|
try
|
{
|
// 复制文件
|
is = new FileInputStream(fileSrc);
|
os = new FileOutputStream(tempFile);
|
while((size = is.read(data)) > 0)
|
{
|
os.write(data, 0, size);
|
}
|
|
// 关闭文件
|
os.close();
|
os = null;
|
|
is.close();
|
is = null;
|
|
// 将临时文件改名
|
tempFile.renameTo(fileTag);
|
if(!fileTag.exists())
|
{
|
if(throwError)
|
throw new RuntimeException("temp file can't not rename to tag file");
|
return false;
|
}
|
return true;
|
}
|
catch(Exception ex)
|
{
|
if(throwError)
|
throw new RuntimeException("copy file error", ex);
|
return false;
|
}
|
finally
|
{
|
try
|
{
|
if(is != null)
|
is.close();
|
if(os != null)
|
os.close();
|
}
|
catch(Exception ex)
|
{
|
throw new RuntimeException("close file error", ex);
|
}
|
}
|
}
|
|
public static Map<String, Object> createMap(Object...args)
|
{
|
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
for(int i = 0; i < args.length; i += 2)
|
{
|
if(args[i + 1] != null)
|
map.put(args[i].toString(), args[i + 1]);
|
}
|
|
return map;
|
}
|
|
public static String throwToString(Throwable ex)
|
{
|
ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
|
PrintStream ps = new PrintStream(byteOS);
|
ex.printStackTrace(ps);
|
String errMsg = new String(byteOS.toByteArray());
|
return errMsg;
|
}
|
|
public static String getStdoutEncode()
|
{
|
String encoding = System.getProperty("sun.stdout.encoding");
|
if(!SMTStatic.isNullOrEmpty(encoding))
|
return encoding;
|
|
String os = System.getProperty("os.name").toLowerCase();
|
if (os.contains("win"))
|
return "GB2312";
|
else
|
return "UTF-8";
|
}
|
|
public static String getJavaExe()
|
{
|
String os = System.getProperty("os.name").toLowerCase();
|
|
if (os.contains("win"))
|
return "java.exe";
|
else
|
return "java";
|
}
|
|
|
public static String getClientAddr(HttpServletRequest request)
|
{
|
String clientAddr = null;
|
|
clientAddr = request.getHeader("x-real-ip");
|
if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
|
return clientAddr;
|
|
clientAddr = request.getHeader("x-forwarded-for");
|
if(!SMTStatic.isNullOrEmpty(clientAddr))
|
clientAddr = clientAddr.split(",")[0];
|
if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
|
return clientAddr;
|
|
clientAddr = request.getHeader("Proxy-client-IP");
|
if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
|
return clientAddr;
|
|
clientAddr = request.getHeader("WL-Proxy-client-IP");
|
if(!SMTStatic.isNullOrEmpty(clientAddr) && !"unknown".equalsIgnoreCase(clientAddr))
|
return clientAddr;
|
|
clientAddr = request.getRemoteAddr();
|
return clientAddr;
|
}
|
|
public static String[] convProcessArg(List<String> args)
|
{
|
return convProcessArg(args.toArray(new String[args.size()]));
|
}
|
public static String[] convProcessArg(String[] args)
|
{
|
String os = System.getProperty("os.name").toLowerCase();
|
if (os.contains("win"))
|
{
|
for(int i = 0; i < args.length; i ++)
|
{
|
args[i] = args[i].replace("\"", "\\\"");
|
}
|
}
|
|
return args;
|
}
|
|
public static String generatePassword(int length) {
|
SecureRandom random = new SecureRandom();
|
StringBuilder password = new StringBuilder();
|
|
// 至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符
|
password.append(UPPER.charAt(random.nextInt(UPPER.length())));
|
password.append(LOWER.charAt(random.nextInt(LOWER.length())));
|
password.append(DIGITS.charAt(random.nextInt(DIGITS.length())));
|
password.append(SPECIAL.charAt(random.nextInt(SPECIAL.length())));
|
|
// 生成剩余的字符
|
for (int i = 4; i < length; i++) {
|
int index = random.nextInt(ALL_CHARACTERS.length());
|
password.append(ALL_CHARACTERS.charAt(index));
|
}
|
|
// 将密码随机打乱顺序
|
for (int i = 0; i < length; i++) {
|
int randomIndex = random.nextInt(length);
|
char temp = password.charAt(i);
|
password.setCharAt(i, password.charAt(randomIndex));
|
password.setCharAt(randomIndex, temp);
|
}
|
|
return password.toString();
|
}
|
|
public static Document convStrToXmlDoc(String xmlStr) throws Exception
|
{
|
try
|
{
|
String xml = String.format(
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n%s",
|
xmlStr);
|
ByteArrayInputStream sqlXmlStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
|
SAXReader reader=new SAXReader();
|
Document doc=reader.read(sqlXmlStream);
|
|
return doc;
|
}
|
catch(Exception ex)
|
{
|
throw new Exception("parse xml error : \n" + xmlStr, ex);
|
}
|
}
|
|
public static void setInnerXml(Element xmlRoot, String xmlStr) throws Exception
|
{
|
xmlRoot.clearContent();
|
Document doc = SMTStatic.convStrToXmlDoc("<ROOT>" + xmlStr + "</ROOT>");
|
Element xmlSubRoot = (Element)doc.selectSingleNode("ROOT");
|
xmlSubRoot.setParent(null);
|
xmlRoot.add(doc.getRootElement());
|
}
|
|
public static Element getOrCreateXmlNode(Element xmlRoot, String tag) throws Exception
|
{
|
Element xmlNode = (Element) xmlRoot.selectSingleNode(tag);
|
if(xmlNode == null)
|
xmlNode = xmlRoot.addElement(tag);
|
|
return xmlNode;
|
}
|
|
|
public static String getXmlAttr(Element xmlNode, String key) throws Exception
|
{
|
Attribute attr = xmlNode.attribute(key);
|
if(attr == null)
|
throw new Exception("can't find xml attr : " + key);
|
|
return attr.getValue();
|
}
|
|
public static String getXmlAttr(Element xmlNode, String key, String defValue)
|
{
|
Attribute attr = xmlNode.attribute(key);
|
if(attr == null)
|
return defValue;
|
|
return attr.getValue();
|
}
|
|
public static String formatJson(Json json)
|
{
|
StringBuilder sb = new StringBuilder();
|
convJsonToString(0, json, "", sb);
|
return sb.toString();
|
}
|
|
private static void convJsonToString(int level, Json json, String tailStr, StringBuilder sbRet)
|
{
|
String space = " ";
|
String perfix = "";
|
for(int i = 0; i < level; i ++)
|
{
|
perfix += space;
|
}
|
if(json == null)
|
{
|
sbRet.append(perfix);
|
sbRet.append("null" + tailStr + "\n");
|
}
|
else if(json.isObject())
|
{
|
//sbRet.append(perfix);
|
if(sbRet.length() > 0)
|
{
|
char lastChar = sbRet.charAt(sbRet.length() - 1);
|
if(lastChar == '\n')
|
sbRet.append(perfix);
|
}
|
sbRet.append("{\n");
|
int curCount = 0;
|
int totalCount = json.asJsonMap().size();
|
for(Entry<String, Json> entry : json.asJsonMap().entrySet())
|
{
|
String curTailStr = (curCount < (totalCount - 1)) ? "," : "";
|
sbRet.append(perfix + space);
|
sbRet.append("\"" + SMTStatic.toCStr(entry.getKey().toString()) + "\":");
|
Json value = entry.getValue();
|
if(value.isObject() || value.isArray())
|
{
|
convJsonToString(level + 1, value, curTailStr, sbRet);
|
|
}
|
else
|
{
|
convJsonToString(0, value, curTailStr, sbRet);
|
|
}
|
|
if(curTailStr.length() == 0)
|
curTailStr = ",";
|
curCount ++;
|
}
|
sbRet.append(perfix);
|
sbRet.append("}" + tailStr + "\n");
|
}
|
else if(json.isArray())
|
{
|
List<Json> naJson = json.asJsonList();
|
if(sbRet.length() > 0)
|
{
|
char lastChar = sbRet.charAt(sbRet.length() - 1);
|
if(lastChar == '\n')
|
sbRet.append(perfix);
|
}
|
sbRet.append("[\n");
|
for(int i = 0; i < naJson.size(); i ++)
|
{
|
String curTailStr = (i < (naJson.size() - 1)) ? "," : "";
|
Json value = naJson.get(i);
|
if(value.isObject() || value.isArray())
|
{
|
convJsonToString(level + 1, value, curTailStr, sbRet);
|
}
|
else
|
{
|
convJsonToString(level + 1, value, curTailStr, sbRet);
|
}
|
|
}
|
sbRet.append(perfix);
|
sbRet.append("]" + tailStr + "\n");
|
}
|
else if(json.isString())
|
{
|
sbRet.append(perfix);
|
sbRet.append(json.toString() + tailStr + "\n");
|
}
|
else
|
{
|
sbRet.append(perfix);
|
sbRet.append(json.toString() + tailStr + "\n");
|
}
|
}
|
|
public static Json convLLMAnswerToJson(String answer, boolean toArray)
|
{
|
String perfixJson = "```json\n";
|
int pos = answer.indexOf(perfixJson);
|
if(pos >= 0)
|
{
|
answer = answer.substring(pos + perfixJson.length());
|
pos = answer.lastIndexOf("\n```");
|
if(pos >= 0)
|
answer = answer.substring(0, pos);
|
}
|
|
if(toArray)
|
{
|
if(answer.charAt(0) != '[')
|
{
|
answer = "[" + answer + "]";
|
}
|
}
|
|
try
|
{
|
return Json.read(answer);
|
}
|
catch(Exception ex)
|
{
|
return Json.object("error", answer);
|
}
|
}
|
|
public static String convLLMAnswerToJavascript(String answer)
|
{
|
String perfixJson = "```javascript\n";
|
int pos = answer.indexOf(perfixJson);
|
if(pos >= 0)
|
{
|
answer = answer.substring(pos + perfixJson.length());
|
pos = answer.lastIndexOf("\n```");
|
if(pos >= 0)
|
answer = answer.substring(0, pos);
|
}
|
|
return answer;
|
}
|
|
private static Pattern _patTrimStrLineS = Pattern.compile("^[\\r\\n\\t ]+");
|
private static Pattern _patTrimStrLineE = Pattern.compile("[\\r\\n\\t ]+$");
|
|
public static String trimStrLines(String value)
|
{
|
Matcher m;
|
m = _patTrimStrLineS.matcher(value);
|
if(m.find())
|
value = m.replaceAll("");
|
m = _patTrimStrLineE.matcher(value);
|
if(m.find())
|
value = m.replaceAll("");
|
|
return value;
|
}
|
|
public static String indentStrLines(String value, String perfix)
|
{
|
return value.replace("\r\n", "\n").replace("\n", "\n" + perfix);
|
}
|
|
public interface SMTReplaceTextNotify {
|
String replace(String match);
|
}
|
|
public static String replaceRegexText(String text, Pattern pattern, SMTReplaceTextNotify callback)
|
{
|
Matcher matcher = pattern.matcher(text);
|
StringBuffer result = new StringBuffer();
|
while (matcher.find()) {
|
String match = matcher.group();
|
String replacement = callback.replace(match);
|
matcher.appendReplacement(result, replacement);
|
}
|
matcher.appendTail(result);
|
return result.toString();
|
}
|
}
|