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 _dateFmt = SMTStatic.newSimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 生成线程安全的SimpleDateFormat对象 * * @param fmt - date格式 * @return - 返回SimpleDateFormat对象 */ public static ThreadLocal newSimpleDateFormat(final String fmt) { return new ThreadLocal (){ @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 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(); // 如果最后一个参数是名称数组,则只解析名称数组 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 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 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 list = new ArrayList(); 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>> getDictionaryMapList(List recs, String typeKey, String nameKey) { Map>> mapList = new HashMap>>(); for(Object rec : recs) { Map orec = (Map)rec; // 获取类型map表 String type = ((String)orec.get(typeKey)).toUpperCase(); Map> mapType = mapList.get(type); if(mapType == null) { mapType = new LinkedHashMap>(); 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 createMap(Object...args) { Map map = new LinkedHashMap(); 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 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( "\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("" + xmlStr + ""); 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 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 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(); } }