修改系统
This commit is contained in:
		
							
								
								
									
										114
									
								
								stdiet-common/src/main/java/com/stdiet/common/utils/Arith.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								stdiet-common/src/main/java/com/stdiet/common/utils/Arith.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.math.RoundingMode; | ||||
|  | ||||
| /** | ||||
|  * 精确的浮点数运算 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class Arith | ||||
| { | ||||
|  | ||||
|     /** 默认除法运算精度 */ | ||||
|     private static final int DEF_DIV_SCALE = 10; | ||||
|  | ||||
|     /** 这个类不能实例化 */ | ||||
|     private Arith() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供精确的加法运算。 | ||||
|      * @param v1 被加数 | ||||
|      * @param v2 加数 | ||||
|      * @return 两个参数的和 | ||||
|      */ | ||||
|     public static double add(double v1, double v2) | ||||
|     { | ||||
|         BigDecimal b1 = new BigDecimal(Double.toString(v1)); | ||||
|         BigDecimal b2 = new BigDecimal(Double.toString(v2)); | ||||
|         return b1.add(b2).doubleValue(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供精确的减法运算。 | ||||
|      * @param v1 被减数 | ||||
|      * @param v2 减数 | ||||
|      * @return 两个参数的差 | ||||
|      */ | ||||
|     public static double sub(double v1, double v2) | ||||
|     { | ||||
|         BigDecimal b1 = new BigDecimal(Double.toString(v1)); | ||||
|         BigDecimal b2 = new BigDecimal(Double.toString(v2)); | ||||
|         return b1.subtract(b2).doubleValue(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供精确的乘法运算。 | ||||
|      * @param v1 被乘数 | ||||
|      * @param v2 乘数 | ||||
|      * @return 两个参数的积 | ||||
|      */ | ||||
|     public static double mul(double v1, double v2) | ||||
|     { | ||||
|         BigDecimal b1 = new BigDecimal(Double.toString(v1)); | ||||
|         BigDecimal b2 = new BigDecimal(Double.toString(v2)); | ||||
|         return b1.multiply(b2).doubleValue(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 | ||||
|      * 小数点以后10位,以后的数字四舍五入。 | ||||
|      * @param v1 被除数 | ||||
|      * @param v2 除数 | ||||
|      * @return 两个参数的商 | ||||
|      */ | ||||
|     public static double div(double v1, double v2) | ||||
|     { | ||||
|         return div(v1, v2, DEF_DIV_SCALE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 | ||||
|      * 定精度,以后的数字四舍五入。 | ||||
|      * @param v1 被除数 | ||||
|      * @param v2 除数 | ||||
|      * @param scale 表示表示需要精确到小数点以后几位。 | ||||
|      * @return 两个参数的商 | ||||
|      */ | ||||
|     public static double div(double v1, double v2, int scale) | ||||
|     { | ||||
|         if (scale < 0) | ||||
|         { | ||||
|             throw new IllegalArgumentException( | ||||
|                     "The scale must be a positive integer or zero"); | ||||
|         } | ||||
|         BigDecimal b1 = new BigDecimal(Double.toString(v1)); | ||||
|         BigDecimal b2 = new BigDecimal(Double.toString(v2)); | ||||
|         if (b1.compareTo(BigDecimal.ZERO) == 0) | ||||
|         { | ||||
|             return BigDecimal.ZERO.doubleValue(); | ||||
|         } | ||||
|         return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 提供精确的小数位四舍五入处理。 | ||||
|      * @param v 需要四舍五入的数字 | ||||
|      * @param scale 小数点后保留几位 | ||||
|      * @return 四舍五入后的结果 | ||||
|      */ | ||||
|     public static double round(double v, int scale) | ||||
|     { | ||||
|         if (scale < 0) | ||||
|         { | ||||
|             throw new IllegalArgumentException( | ||||
|                     "The scale must be a positive integer or zero"); | ||||
|         } | ||||
|         BigDecimal b = new BigDecimal(Double.toString(v)); | ||||
|         BigDecimal one = new BigDecimal("1"); | ||||
|         return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,155 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.lang.management.ManagementFactory; | ||||
| import java.text.ParseException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | ||||
| import org.apache.commons.lang3.time.DateFormatUtils; | ||||
|  | ||||
| /** | ||||
|  * 时间工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class DateUtils extends org.apache.commons.lang3.time.DateUtils | ||||
| { | ||||
|     public static String YYYY = "yyyy"; | ||||
|  | ||||
|     public static String YYYY_MM = "yyyy-MM"; | ||||
|  | ||||
|     public static String YYYY_MM_DD = "yyyy-MM-dd"; | ||||
|  | ||||
|     public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; | ||||
|  | ||||
|     public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; | ||||
|      | ||||
|     private static String[] parsePatterns = { | ||||
|             "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",  | ||||
|             "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", | ||||
|             "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; | ||||
|  | ||||
|     /** | ||||
|      * 获取当前Date型日期 | ||||
|      *  | ||||
|      * @return Date() 当前日期 | ||||
|      */ | ||||
|     public static Date getNowDate() | ||||
|     { | ||||
|         return new Date(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取当前日期, 默认格式为yyyy-MM-dd | ||||
|      *  | ||||
|      * @return String | ||||
|      */ | ||||
|     public static String getDate() | ||||
|     { | ||||
|         return dateTimeNow(YYYY_MM_DD); | ||||
|     } | ||||
|  | ||||
|     public static final String getTime() | ||||
|     { | ||||
|         return dateTimeNow(YYYY_MM_DD_HH_MM_SS); | ||||
|     } | ||||
|  | ||||
|     public static final String dateTimeNow() | ||||
|     { | ||||
|         return dateTimeNow(YYYYMMDDHHMMSS); | ||||
|     } | ||||
|  | ||||
|     public static final String dateTimeNow(final String format) | ||||
|     { | ||||
|         return parseDateToStr(format, new Date()); | ||||
|     } | ||||
|  | ||||
|     public static final String dateTime(final Date date) | ||||
|     { | ||||
|         return parseDateToStr(YYYY_MM_DD, date); | ||||
|     } | ||||
|  | ||||
|     public static final String parseDateToStr(final String format, final Date date) | ||||
|     { | ||||
|         return new SimpleDateFormat(format).format(date); | ||||
|     } | ||||
|  | ||||
|     public static final Date dateTime(final String format, final String ts) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return new SimpleDateFormat(format).parse(ts); | ||||
|         } | ||||
|         catch (ParseException e) | ||||
|         { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 日期路径 即年/月/日 如2018/08/08 | ||||
|      */ | ||||
|     public static final String datePath() | ||||
|     { | ||||
|         Date now = new Date(); | ||||
|         return DateFormatUtils.format(now, "yyyy/MM/dd"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 日期路径 即年/月/日 如20180808 | ||||
|      */ | ||||
|     public static final String dateTime() | ||||
|     { | ||||
|         Date now = new Date(); | ||||
|         return DateFormatUtils.format(now, "yyyyMMdd"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 日期型字符串转化为日期 格式 | ||||
|      */ | ||||
|     public static Date parseDate(Object str) | ||||
|     { | ||||
|         if (str == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             return parseDate(str.toString(), parsePatterns); | ||||
|         } | ||||
|         catch (ParseException e) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * 获取服务器启动时间 | ||||
|      */ | ||||
|     public static Date getServerStartDate() | ||||
|     { | ||||
|         long time = ManagementFactory.getRuntimeMXBean().getStartTime(); | ||||
|         return new Date(time); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 计算两个时间差 | ||||
|      */ | ||||
|     public static String getDatePoor(Date endDate, Date nowDate) | ||||
|     { | ||||
|         long nd = 1000 * 24 * 60 * 60; | ||||
|         long nh = 1000 * 60 * 60; | ||||
|         long nm = 1000 * 60; | ||||
|         // long ns = 1000; | ||||
|         // 获得两个时间的毫秒时间差异 | ||||
|         long diff = endDate.getTime() - nowDate.getTime(); | ||||
|         // 计算差多少天 | ||||
|         long day = diff / nd; | ||||
|         // 计算差多少小时 | ||||
|         long hour = diff % nd / nh; | ||||
|         // 计算差多少分钟 | ||||
|         long min = diff % nd % nh / nm; | ||||
|         // 计算差多少秒//输出结果 | ||||
|         // long sec = diff % nd % nh % nm / ns; | ||||
|         return day + "天" + hour + "小时" + min + "分钟"; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,173 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import com.stdiet.common.constant.Constants; | ||||
| import com.stdiet.common.core.domain.entity.SysDictData; | ||||
| import com.stdiet.common.core.redis.RedisCache; | ||||
| import com.stdiet.common.utils.spring.SpringUtils; | ||||
|  | ||||
| /** | ||||
|  * 字典工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class DictUtils | ||||
| { | ||||
|     /** | ||||
|      * 分隔符 | ||||
|      */ | ||||
|     public static final String SEPARATOR = ","; | ||||
|  | ||||
|     /** | ||||
|      * 设置字典缓存 | ||||
|      *  | ||||
|      * @param key 参数键 | ||||
|      * @param dictDatas 字典数据列表 | ||||
|      */ | ||||
|     public static void setDictCache(String key, List<SysDictData> dictDatas) | ||||
|     { | ||||
|         SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取字典缓存 | ||||
|      *  | ||||
|      * @param key 参数键 | ||||
|      * @return dictDatas 字典数据列表 | ||||
|      */ | ||||
|     public static List<SysDictData> getDictCache(String key) | ||||
|     { | ||||
|         Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); | ||||
|         if (StringUtils.isNotNull(cacheObj)) | ||||
|         { | ||||
|             List<SysDictData> dictDatas = StringUtils.cast(cacheObj); | ||||
|             return dictDatas; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据字典类型和字典值获取字典标签 | ||||
|      *  | ||||
|      * @param dictType 字典类型 | ||||
|      * @param dictValue 字典值 | ||||
|      * @return 字典标签 | ||||
|      */ | ||||
|     public static String getDictLabel(String dictType, String dictValue) | ||||
|     { | ||||
|         return getDictLabel(dictType, dictValue, SEPARATOR); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据字典类型和字典标签获取字典值 | ||||
|      *  | ||||
|      * @param dictType 字典类型 | ||||
|      * @param dictLabel 字典标签 | ||||
|      * @return 字典值 | ||||
|      */ | ||||
|     public static String getDictValue(String dictType, String dictLabel) | ||||
|     { | ||||
|         return getDictValue(dictType, dictLabel, SEPARATOR); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据字典类型和字典值获取字典标签 | ||||
|      *  | ||||
|      * @param dictType 字典类型 | ||||
|      * @param dictValue 字典值 | ||||
|      * @param separator 分隔符 | ||||
|      * @return 字典标签 | ||||
|      */ | ||||
|     public static String getDictLabel(String dictType, String dictValue, String separator) | ||||
|     { | ||||
|         StringBuilder propertyString = new StringBuilder(); | ||||
|         List<SysDictData> datas = getDictCache(dictType); | ||||
|  | ||||
|         if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas)) | ||||
|         { | ||||
|             for (SysDictData dict : datas) | ||||
|             { | ||||
|                 for (String value : dictValue.split(separator)) | ||||
|                 { | ||||
|                     if (value.equals(dict.getDictValue())) | ||||
|                     { | ||||
|                         propertyString.append(dict.getDictLabel() + separator); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             for (SysDictData dict : datas) | ||||
|             { | ||||
|                 if (dictValue.equals(dict.getDictValue())) | ||||
|                 { | ||||
|                     return dict.getDictLabel(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return StringUtils.stripEnd(propertyString.toString(), separator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据字典类型和字典标签获取字典值 | ||||
|      *  | ||||
|      * @param dictType 字典类型 | ||||
|      * @param dictLabel 字典标签 | ||||
|      * @param separator 分隔符 | ||||
|      * @return 字典值 | ||||
|      */ | ||||
|     public static String getDictValue(String dictType, String dictLabel, String separator) | ||||
|     { | ||||
|         StringBuilder propertyString = new StringBuilder(); | ||||
|         List<SysDictData> datas = getDictCache(dictType); | ||||
|  | ||||
|         if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) | ||||
|         { | ||||
|             for (SysDictData dict : datas) | ||||
|             { | ||||
|                 for (String label : dictLabel.split(separator)) | ||||
|                 { | ||||
|                     if (label.equals(dict.getDictLabel())) | ||||
|                     { | ||||
|                         propertyString.append(dict.getDictValue() + separator); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             for (SysDictData dict : datas) | ||||
|             { | ||||
|                 if (dictLabel.equals(dict.getDictLabel())) | ||||
|                 { | ||||
|                     return dict.getDictValue(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return StringUtils.stripEnd(propertyString.toString(), separator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 清空字典缓存 | ||||
|      */ | ||||
|     public static void clearDictCache() | ||||
|     { | ||||
|         Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*"); | ||||
|         SpringUtils.getBean(RedisCache.class).deleteObject(keys); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 设置cache key | ||||
|      *  | ||||
|      * @param configKey 参数键 | ||||
|      * @return 缓存键key | ||||
|      */ | ||||
|     public static String getCacheKey(String configKey) | ||||
|     { | ||||
|         return Constants.SYS_DICT_KEY + configKey; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.io.PrintWriter; | ||||
| import java.io.StringWriter; | ||||
| import org.apache.commons.lang3.exception.ExceptionUtils; | ||||
|  | ||||
| /** | ||||
|  * 错误信息处理类。 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class ExceptionUtil | ||||
| { | ||||
|     /** | ||||
|      * 获取exception的详细错误信息。 | ||||
|      */ | ||||
|     public static String getExceptionMessage(Throwable e) | ||||
|     { | ||||
|         StringWriter sw = new StringWriter(); | ||||
|         e.printStackTrace(new PrintWriter(sw, true)); | ||||
|         String str = sw.toString(); | ||||
|         return str; | ||||
|     } | ||||
|  | ||||
|     public static String getRootErrorMseeage(Exception e) | ||||
|     { | ||||
|         Throwable root = ExceptionUtils.getRootCause(e); | ||||
|         root = (root == null ? e : root); | ||||
|         if (root == null) | ||||
|         { | ||||
|             return ""; | ||||
|         } | ||||
|         String msg = root.getMessage(); | ||||
|         if (msg == null) | ||||
|         { | ||||
|             return "null"; | ||||
|         } | ||||
|         return StringUtils.defaultString(msg); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,18 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| /** | ||||
|  * 处理并记录日志文件 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class LogUtils | ||||
| { | ||||
|     public static String getBlock(Object msg) | ||||
|     { | ||||
|         if (msg == null) | ||||
|         { | ||||
|             msg = ""; | ||||
|         } | ||||
|         return "[" + msg.toString() + "]"; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,26 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import org.springframework.context.MessageSource; | ||||
| import org.springframework.context.i18n.LocaleContextHolder; | ||||
| import com.stdiet.common.utils.spring.SpringUtils; | ||||
|  | ||||
| /** | ||||
|  * 获取i18n资源文件 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class MessageUtils | ||||
| { | ||||
|     /** | ||||
|      * 根据消息键和参数 获取消息 委托给spring messageSource | ||||
|      * | ||||
|      * @param code 消息键 | ||||
|      * @param args 参数 | ||||
|      * @return 获取国际化翻译值 | ||||
|      */ | ||||
|     public static String message(String code, Object... args) | ||||
|     { | ||||
|         MessageSource messageSource = SpringUtils.getBean(MessageSource.class); | ||||
|         return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,90 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import org.springframework.security.core.Authentication; | ||||
| import org.springframework.security.core.context.SecurityContextHolder; | ||||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||||
| import com.stdiet.common.constant.HttpStatus; | ||||
| import com.stdiet.common.core.domain.model.LoginUser; | ||||
| import com.stdiet.common.exception.CustomException; | ||||
|  | ||||
| /** | ||||
|  * 安全服务工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class SecurityUtils | ||||
| { | ||||
|     /** | ||||
|      * 获取用户账户 | ||||
|      **/ | ||||
|     public static String getUsername() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return getLoginUser().getUsername(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取用户 | ||||
|      **/ | ||||
|     public static LoginUser getLoginUser() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return (LoginUser) getAuthentication().getPrincipal(); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             throw new CustomException("获取用户信息异常", HttpStatus.UNAUTHORIZED); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取Authentication | ||||
|      */ | ||||
|     public static Authentication getAuthentication() | ||||
|     { | ||||
|         return SecurityContextHolder.getContext().getAuthentication(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成BCryptPasswordEncoder密码 | ||||
|      * | ||||
|      * @param password 密码 | ||||
|      * @return 加密字符串 | ||||
|      */ | ||||
|     public static String encryptPassword(String password) | ||||
|     { | ||||
|         BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); | ||||
|         return passwordEncoder.encode(password); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断密码是否相同 | ||||
|      * | ||||
|      * @param rawPassword 真实密码 | ||||
|      * @param encodedPassword 加密后字符 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public static boolean matchesPassword(String rawPassword, String encodedPassword) | ||||
|     { | ||||
|         BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); | ||||
|         return passwordEncoder.matches(rawPassword, encodedPassword); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为管理员 | ||||
|      *  | ||||
|      * @param userId 用户ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public static boolean isAdmin(Long userId) | ||||
|     { | ||||
|         return userId != null && 1L == userId; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,136 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import javax.servlet.http.HttpSession; | ||||
| import org.springframework.web.context.request.RequestAttributes; | ||||
| import org.springframework.web.context.request.RequestContextHolder; | ||||
| import org.springframework.web.context.request.ServletRequestAttributes; | ||||
| import com.stdiet.common.core.text.Convert; | ||||
|  | ||||
| /** | ||||
|  * 客户端工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class ServletUtils | ||||
| { | ||||
|     /** | ||||
|      * 获取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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取request | ||||
|      */ | ||||
|     public static HttpServletRequest getRequest() | ||||
|     { | ||||
|         return getRequestAttributes().getRequest(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取response | ||||
|      */ | ||||
|     public static HttpServletResponse getResponse() | ||||
|     { | ||||
|         return getRequestAttributes().getResponse(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取session | ||||
|      */ | ||||
|     public static HttpSession getSession() | ||||
|     { | ||||
|         return getRequest().getSession(); | ||||
|     } | ||||
|  | ||||
|     public static ServletRequestAttributes getRequestAttributes() | ||||
|     { | ||||
|         RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); | ||||
|         return (ServletRequestAttributes) attributes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将字符串渲染到客户端 | ||||
|      *  | ||||
|      * @param response 渲染对象 | ||||
|      * @param string 待渲染的字符串 | ||||
|      * @return null | ||||
|      */ | ||||
|     public static String 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(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否是Ajax异步请求 | ||||
|      *  | ||||
|      * @param request | ||||
|      */ | ||||
|     public static boolean isAjaxRequest(HttpServletRequest request) | ||||
|     { | ||||
|         String accept = request.getHeader("accept"); | ||||
|         if (accept != null && accept.indexOf("application/json") != -1) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         String xRequestedWith = request.getHeader("X-Requested-With"); | ||||
|         if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         String uri = request.getRequestURI(); | ||||
|         if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         String ajax = request.getParameter("__ajax"); | ||||
|         if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,459 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import com.stdiet.common.core.text.StrFormatter; | ||||
|  | ||||
| /** | ||||
|  * 字符串工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| 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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * * 判断一个对象是否是数组类型(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 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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 格式化文本, {} 表示占位符<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 StrFormatter.format(template, params); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 字符串转set | ||||
|      *  | ||||
|      * @param str 字符串 | ||||
|      * @param sep 分隔符 | ||||
|      * @return set集合 | ||||
|      */ | ||||
|     public static final Set<String> str2Set(String str, String sep) | ||||
|     { | ||||
|         return new HashSet<String>(str2List(str, sep, true, false)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 字符串转list | ||||
|      *  | ||||
|      * @param str 字符串 | ||||
|      * @param sep 分隔符 | ||||
|      * @param filterBlank 过滤纯空白 | ||||
|      * @param trim 去掉首尾空白 | ||||
|      * @return list集合 | ||||
|      */ | ||||
|     public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) | ||||
|     { | ||||
|         List<String> list = new ArrayList<String>(); | ||||
|         if (StringUtils.isEmpty(str)) | ||||
|         { | ||||
|             return list; | ||||
|         } | ||||
|  | ||||
|         // 过滤空白字符串 | ||||
|         if (filterBlank && StringUtils.isBlank(str)) | ||||
|         { | ||||
|             return list; | ||||
|         } | ||||
|         String[] split = str.split(sep); | ||||
|         for (String string : split) | ||||
|         { | ||||
|             if (filterBlank && StringUtils.isBlank(string)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             if (trim) | ||||
|             { | ||||
|                 string = string.trim(); | ||||
|             } | ||||
|             list.add(string); | ||||
|         } | ||||
|  | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 下划线转驼峰命名 | ||||
|      */ | ||||
|     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); | ||||
|         } | ||||
|         // 用下划线将原始字符串分割 | ||||
|         String[] camels = name.split("_"); | ||||
|         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(); | ||||
|     } | ||||
|  | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <T> T cast(Object obj) | ||||
|     { | ||||
|         return (T) obj; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,99 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.util.concurrent.CancellationException; | ||||
| import java.util.concurrent.ExecutionException; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Future; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * 线程相关工具类. | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class Threads | ||||
| { | ||||
|     private static final Logger logger = LoggerFactory.getLogger(Threads.class); | ||||
|  | ||||
|     /** | ||||
|      * sleep等待,单位为毫秒 | ||||
|      */ | ||||
|     public static void sleep(long milliseconds) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Thread.sleep(milliseconds); | ||||
|         } | ||||
|         catch (InterruptedException e) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 停止线程池 | ||||
|      * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. | ||||
|      * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. | ||||
|      * 如果仍人超時,則強制退出. | ||||
|      * 另对在shutdown时线程本身被调用中断做了处理. | ||||
|      */ | ||||
|     public static void shutdownAndAwaitTermination(ExecutorService pool) | ||||
|     { | ||||
|         if (pool != null && !pool.isShutdown()) | ||||
|         { | ||||
|             pool.shutdown(); | ||||
|             try | ||||
|             { | ||||
|                 if (!pool.awaitTermination(120, TimeUnit.SECONDS)) | ||||
|                 { | ||||
|                     pool.shutdownNow(); | ||||
|                     if (!pool.awaitTermination(120, TimeUnit.SECONDS)) | ||||
|                     { | ||||
|                         logger.info("Pool did not terminate"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             catch (InterruptedException ie) | ||||
|             { | ||||
|                 pool.shutdownNow(); | ||||
|                 Thread.currentThread().interrupt(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 打印线程异常信息 | ||||
|      */ | ||||
|     public static void printException(Runnable r, Throwable t) | ||||
|     { | ||||
|         if (t == null && r instanceof Future<?>) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Future<?> future = (Future<?>) r; | ||||
|                 if (future.isDone()) | ||||
|                 { | ||||
|                     future.get(); | ||||
|                 } | ||||
|             } | ||||
|             catch (CancellationException ce) | ||||
|             { | ||||
|                 t = ce; | ||||
|             } | ||||
|             catch (ExecutionException ee) | ||||
|             { | ||||
|                 t = ee.getCause(); | ||||
|             } | ||||
|             catch (InterruptedException ie) | ||||
|             { | ||||
|                 Thread.currentThread().interrupt(); | ||||
|             } | ||||
|         } | ||||
|         if (t != null) | ||||
|         { | ||||
|             logger.error(t.getMessage(), t); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,228 @@ | ||||
| package com.stdiet.common.utils; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import java.awt.Font; | ||||
| import java.awt.Graphics; | ||||
| import java.awt.Graphics2D; | ||||
| import java.awt.RenderingHints; | ||||
| import java.awt.geom.AffineTransform; | ||||
| import java.awt.image.BufferedImage; | ||||
| import java.io.IOException; | ||||
| import java.io.OutputStream; | ||||
| import java.security.SecureRandom; | ||||
| import java.util.Arrays; | ||||
| import java.util.Random; | ||||
| import javax.imageio.ImageIO; | ||||
|  | ||||
| /** | ||||
|  * 验证码工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class VerifyCodeUtils | ||||
| { | ||||
|     // 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 | ||||
|     public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ"; | ||||
|  | ||||
|     private static Random random = new SecureRandom(); | ||||
|  | ||||
|     /** | ||||
|      * 使用系统默认字符源生成验证码 | ||||
|      *  | ||||
|      * @param verifySize 验证码长度 | ||||
|      * @return | ||||
|      */ | ||||
|     public static String generateVerifyCode(int verifySize) | ||||
|     { | ||||
|         return generateVerifyCode(verifySize, VERIFY_CODES); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 使用指定源生成验证码 | ||||
|      *  | ||||
|      * @param verifySize 验证码长度 | ||||
|      * @param sources 验证码字符源 | ||||
|      * @return | ||||
|      */ | ||||
|     public static String generateVerifyCode(int verifySize, String sources) | ||||
|     { | ||||
|         if (sources == null || sources.length() == 0) | ||||
|         { | ||||
|             sources = VERIFY_CODES; | ||||
|         } | ||||
|         int codesLen = sources.length(); | ||||
|         Random rand = new Random(System.currentTimeMillis()); | ||||
|         StringBuilder verifyCode = new StringBuilder(verifySize); | ||||
|         for (int i = 0; i < verifySize; i++) | ||||
|         { | ||||
|             verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1))); | ||||
|         } | ||||
|         return verifyCode.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 输出指定验证码图片流 | ||||
|      *  | ||||
|      * @param w | ||||
|      * @param h | ||||
|      * @param os | ||||
|      * @param code | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     public static void outputImage(int w, int h, OutputStream os, String code) throws IOException | ||||
|     { | ||||
|         int verifySize = code.length(); | ||||
|         BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); | ||||
|         Random rand = new Random(); | ||||
|         Graphics2D g2 = image.createGraphics(); | ||||
|         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||||
|         Color[] colors = new Color[5]; | ||||
|         Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, | ||||
|                 Color.ORANGE, Color.PINK, Color.YELLOW }; | ||||
|         float[] fractions = new float[colors.length]; | ||||
|         for (int i = 0; i < colors.length; i++) | ||||
|         { | ||||
|             colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; | ||||
|             fractions[i] = rand.nextFloat(); | ||||
|         } | ||||
|         Arrays.sort(fractions); | ||||
|  | ||||
|         g2.setColor(Color.GRAY);// 设置边框色 | ||||
|         g2.fillRect(0, 0, w, h); | ||||
|  | ||||
|         Color c = getRandColor(200, 250); | ||||
|         g2.setColor(c);// 设置背景色 | ||||
|         g2.fillRect(0, 2, w, h - 4); | ||||
|  | ||||
|         // 绘制干扰线 | ||||
|         Random random = new Random(); | ||||
|         g2.setColor(getRandColor(160, 200));// 设置线条的颜色 | ||||
|         for (int i = 0; i < 20; i++) | ||||
|         { | ||||
|             int x = random.nextInt(w - 1); | ||||
|             int y = random.nextInt(h - 1); | ||||
|             int xl = random.nextInt(6) + 1; | ||||
|             int yl = random.nextInt(12) + 1; | ||||
|             g2.drawLine(x, y, x + xl + 40, y + yl + 20); | ||||
|         } | ||||
|  | ||||
|         // 添加噪点 | ||||
|         float yawpRate = 0.05f;// 噪声率 | ||||
|         int area = (int) (yawpRate * w * h); | ||||
|         for (int i = 0; i < area; i++) | ||||
|         { | ||||
|             int x = random.nextInt(w); | ||||
|             int y = random.nextInt(h); | ||||
|             int rgb = getRandomIntColor(); | ||||
|             image.setRGB(x, y, rgb); | ||||
|         } | ||||
|  | ||||
|         shear(g2, w, h, c);// 使图片扭曲 | ||||
|  | ||||
|         g2.setColor(getRandColor(100, 160)); | ||||
|         int fontSize = h - 4; | ||||
|         Font font = new Font("Algerian", Font.ITALIC, fontSize); | ||||
|         g2.setFont(font); | ||||
|         char[] chars = code.toCharArray(); | ||||
|         for (int i = 0; i < verifySize; i++) | ||||
|         { | ||||
|             AffineTransform affine = new AffineTransform(); | ||||
|             affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), | ||||
|                     (w / verifySize) * i + fontSize / 2, h / 2); | ||||
|             g2.setTransform(affine); | ||||
|             g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10); | ||||
|         } | ||||
|  | ||||
|         g2.dispose(); | ||||
|         ImageIO.write(image, "jpg", os); | ||||
|     } | ||||
|  | ||||
|     private static Color getRandColor(int fc, int bc) | ||||
|     { | ||||
|         if (fc > 255) { | ||||
|             fc = 255; | ||||
|         } | ||||
|         if (bc > 255) { | ||||
|             bc = 255; | ||||
|         } | ||||
|         int r = fc + random.nextInt(bc - fc); | ||||
|         int g = fc + random.nextInt(bc - fc); | ||||
|         int b = fc + random.nextInt(bc - fc); | ||||
|         return new Color(r, g, b); | ||||
|     } | ||||
|  | ||||
|     private static int getRandomIntColor() | ||||
|     { | ||||
|         int[] rgb = getRandomRgb(); | ||||
|         int color = 0; | ||||
|         for (int c : rgb) | ||||
|         { | ||||
|             color = color << 8; | ||||
|             color = color | c; | ||||
|         } | ||||
|         return color; | ||||
|     } | ||||
|  | ||||
|     private static int[] getRandomRgb() | ||||
|     { | ||||
|         int[] rgb = new int[3]; | ||||
|         for (int i = 0; i < 3; i++) | ||||
|         { | ||||
|             rgb[i] = random.nextInt(255); | ||||
|         } | ||||
|         return rgb; | ||||
|     } | ||||
|  | ||||
|     private static void shear(Graphics g, int w1, int h1, Color color) | ||||
|     { | ||||
|         shearX(g, w1, h1, color); | ||||
|         shearY(g, w1, h1, color); | ||||
|     } | ||||
|  | ||||
|     private static void shearX(Graphics g, int w1, int h1, Color color) | ||||
|     { | ||||
|  | ||||
|         int period = random.nextInt(2); | ||||
|  | ||||
|         boolean borderGap = true; | ||||
|         int frames = 1; | ||||
|         int phase = random.nextInt(2); | ||||
|  | ||||
|         for (int i = 0; i < h1; i++) | ||||
|         { | ||||
|             double d = (double) (period >> 1) | ||||
|                     * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); | ||||
|             g.copyArea(0, i, w1, 1, (int) d, 0); | ||||
|             if (borderGap) | ||||
|             { | ||||
|                 g.setColor(color); | ||||
|                 g.drawLine((int) d, i, 0, i); | ||||
|                 g.drawLine((int) d + w1, i, w1, i); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private static void shearY(Graphics g, int w1, int h1, Color color) | ||||
|     { | ||||
|  | ||||
|         int period = random.nextInt(40) + 10; // 50; | ||||
|  | ||||
|         boolean borderGap = true; | ||||
|         int frames = 20; | ||||
|         int phase = 7; | ||||
|         for (int i = 0; i < w1; i++) | ||||
|         { | ||||
|             double d = (double) (period >> 1) | ||||
|                     * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); | ||||
|             g.copyArea(i, 0, 1, h1, 0, (int) d); | ||||
|             if (borderGap) | ||||
|             { | ||||
|                 g.setColor(color); | ||||
|                 g.drawLine(i, (int) d, i, 0); | ||||
|                 g.drawLine(i, (int) d + h1, i, h1); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,110 @@ | ||||
| package com.stdiet.common.utils.bean; | ||||
|  | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * Bean 工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class BeanUtils extends org.springframework.beans.BeanUtils | ||||
| { | ||||
|     /** Bean方法名中属性名开始的下标 */ | ||||
|     private static final int BEAN_METHOD_PROP_INDEX = 3; | ||||
|  | ||||
|     /** * 匹配getter方法的正则表达式 */ | ||||
|     private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)"); | ||||
|  | ||||
|     /** * 匹配setter方法的正则表达式 */ | ||||
|     private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)"); | ||||
|  | ||||
|     /** | ||||
|      * Bean属性复制工具方法。 | ||||
|      *  | ||||
|      * @param dest 目标对象 | ||||
|      * @param src 源对象 | ||||
|      */ | ||||
|     public static void copyBeanProp(Object dest, Object src) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             copyProperties(src, dest); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取对象的setter方法。 | ||||
|      *  | ||||
|      * @param obj 对象 | ||||
|      * @return 对象的setter方法列表 | ||||
|      */ | ||||
|     public static List<Method> getSetterMethods(Object obj) | ||||
|     { | ||||
|         // setter方法列表 | ||||
|         List<Method> setterMethods = new ArrayList<Method>(); | ||||
|  | ||||
|         // 获取所有方法 | ||||
|         Method[] methods = obj.getClass().getMethods(); | ||||
|  | ||||
|         // 查找setter方法 | ||||
|  | ||||
|         for (Method method : methods) | ||||
|         { | ||||
|             Matcher m = SET_PATTERN.matcher(method.getName()); | ||||
|             if (m.matches() && (method.getParameterTypes().length == 1)) | ||||
|             { | ||||
|                 setterMethods.add(method); | ||||
|             } | ||||
|         } | ||||
|         // 返回setter方法列表 | ||||
|         return setterMethods; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取对象的getter方法。 | ||||
|      *  | ||||
|      * @param obj 对象 | ||||
|      * @return 对象的getter方法列表 | ||||
|      */ | ||||
|  | ||||
|     public static List<Method> getGetterMethods(Object obj) | ||||
|     { | ||||
|         // getter方法列表 | ||||
|         List<Method> getterMethods = new ArrayList<Method>(); | ||||
|         // 获取所有方法 | ||||
|         Method[] methods = obj.getClass().getMethods(); | ||||
|         // 查找getter方法 | ||||
|         for (Method method : methods) | ||||
|         { | ||||
|             Matcher m = GET_PATTERN.matcher(method.getName()); | ||||
|             if (m.matches() && (method.getParameterTypes().length == 0)) | ||||
|             { | ||||
|                 getterMethods.add(method); | ||||
|             } | ||||
|         } | ||||
|         // 返回getter方法列表 | ||||
|         return getterMethods; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 检查Bean方法名中的属性名是否相等。<br> | ||||
|      * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 | ||||
|      *  | ||||
|      * @param m1 方法名1 | ||||
|      * @param m2 方法名2 | ||||
|      * @return 属性名一样返回true,否则返回false | ||||
|      */ | ||||
|  | ||||
|     public static boolean isMethodPropEquals(String m1, String m2) | ||||
|     { | ||||
|         return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,231 @@ | ||||
| package com.stdiet.common.utils.file; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import org.apache.commons.io.FilenameUtils; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
| import com.stdiet.common.config.RuoYiConfig; | ||||
| import com.stdiet.common.constant.Constants; | ||||
| import com.stdiet.common.exception.file.FileNameLengthLimitExceededException; | ||||
| import com.stdiet.common.exception.file.FileSizeLimitExceededException; | ||||
| import com.stdiet.common.exception.file.InvalidExtensionException; | ||||
| import com.stdiet.common.utils.DateUtils; | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
| import com.stdiet.common.utils.uuid.IdUtils; | ||||
|  | ||||
| /** | ||||
|  * 文件上传工具类 | ||||
|  * | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class FileUploadUtils | ||||
| { | ||||
|     /** | ||||
|      * 默认大小 50M | ||||
|      */ | ||||
|     public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; | ||||
|  | ||||
|     /** | ||||
|      * 默认的文件名最大长度 100 | ||||
|      */ | ||||
|     public static final int DEFAULT_FILE_NAME_LENGTH = 100; | ||||
|  | ||||
|     /** | ||||
|      * 默认上传的地址 | ||||
|      */ | ||||
|     private static String defaultBaseDir = RuoYiConfig.getProfile(); | ||||
|  | ||||
|     public static void setDefaultBaseDir(String defaultBaseDir) | ||||
|     { | ||||
|         FileUploadUtils.defaultBaseDir = defaultBaseDir; | ||||
|     } | ||||
|  | ||||
|     public static String getDefaultBaseDir() | ||||
|     { | ||||
|         return defaultBaseDir; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 以默认配置进行文件上传 | ||||
|      * | ||||
|      * @param file 上传的文件 | ||||
|      * @return 文件名称 | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     public static final String upload(MultipartFile file) throws IOException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             throw new IOException(e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据文件路径上传 | ||||
|      * | ||||
|      * @param baseDir 相对应用的基目录 | ||||
|      * @param file 上传的文件 | ||||
|      * @return 文件名称 | ||||
|      * @throws IOException | ||||
|      */ | ||||
|     public static final String upload(String baseDir, MultipartFile file) throws IOException | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             throw new IOException(e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 文件上传 | ||||
|      * | ||||
|      * @param baseDir 相对应用的基目录 | ||||
|      * @param file 上传的文件 | ||||
|      * @param allowedExtension 上传文件类型 | ||||
|      * @return 返回上传成功的文件名 | ||||
|      * @throws FileSizeLimitExceededException 如果超出最大大小 | ||||
|      * @throws FileNameLengthLimitExceededException 文件名太长 | ||||
|      * @throws IOException 比如读写文件出错时 | ||||
|      * @throws InvalidExtensionException 文件校验异常 | ||||
|      */ | ||||
|     public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) | ||||
|             throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, | ||||
|             InvalidExtensionException | ||||
|     { | ||||
|         int fileNamelength = file.getOriginalFilename().length(); | ||||
|         if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) | ||||
|         { | ||||
|             throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); | ||||
|         } | ||||
|  | ||||
|         assertAllowed(file, allowedExtension); | ||||
|  | ||||
|         String fileName = extractFilename(file); | ||||
|  | ||||
|         File desc = getAbsoluteFile(baseDir, fileName); | ||||
|         file.transferTo(desc); | ||||
|         String pathFileName = getPathFileName(baseDir, fileName); | ||||
|         return pathFileName; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 编码文件名 | ||||
|      */ | ||||
|     public static final String extractFilename(MultipartFile file) | ||||
|     { | ||||
|         String fileName = file.getOriginalFilename(); | ||||
|         String extension = getExtension(file); | ||||
|         fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; | ||||
|         return fileName; | ||||
|     } | ||||
|  | ||||
|     private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException | ||||
|     { | ||||
|         File desc = new File(uploadDir + File.separator + fileName); | ||||
|  | ||||
|         if (!desc.getParentFile().exists()) | ||||
|         { | ||||
|             desc.getParentFile().mkdirs(); | ||||
|         } | ||||
|         if (!desc.exists()) | ||||
|         { | ||||
|             desc.createNewFile(); | ||||
|         } | ||||
|         return desc; | ||||
|     } | ||||
|  | ||||
|     private static final String getPathFileName(String uploadDir, String fileName) throws IOException | ||||
|     { | ||||
|         int dirLastIndex = RuoYiConfig.getProfile().length() + 1; | ||||
|         String currentDir = StringUtils.substring(uploadDir, dirLastIndex); | ||||
|         String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; | ||||
|         return pathFileName; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 文件大小校验 | ||||
|      * | ||||
|      * @param file 上传的文件 | ||||
|      * @return | ||||
|      * @throws FileSizeLimitExceededException 如果超出最大大小 | ||||
|      * @throws InvalidExtensionException | ||||
|      */ | ||||
|     public static final void assertAllowed(MultipartFile file, String[] allowedExtension) | ||||
|             throws FileSizeLimitExceededException, InvalidExtensionException | ||||
|     { | ||||
|         long size = file.getSize(); | ||||
|         if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) | ||||
|         { | ||||
|             throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); | ||||
|         } | ||||
|  | ||||
|         String fileName = file.getOriginalFilename(); | ||||
|         String extension = getExtension(file); | ||||
|         if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) | ||||
|         { | ||||
|             if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) | ||||
|             { | ||||
|                 throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, | ||||
|                         fileName); | ||||
|             } | ||||
|             else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) | ||||
|             { | ||||
|                 throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, | ||||
|                         fileName); | ||||
|             } | ||||
|             else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) | ||||
|             { | ||||
|                 throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, | ||||
|                         fileName); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 throw new InvalidExtensionException(allowedExtension, extension, fileName); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断MIME类型是否是允许的MIME类型 | ||||
|      * | ||||
|      * @param extension | ||||
|      * @param allowedExtension | ||||
|      * @return | ||||
|      */ | ||||
|     public static final boolean isAllowedExtension(String extension, String[] allowedExtension) | ||||
|     { | ||||
|         for (String str : allowedExtension) | ||||
|         { | ||||
|             if (str.equalsIgnoreCase(extension)) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取文件名的后缀 | ||||
|      * | ||||
|      * @param file 表单文件 | ||||
|      * @return 后缀名 | ||||
|      */ | ||||
|     public static final String getExtension(MultipartFile file) | ||||
|     { | ||||
|         String extension = FilenameUtils.getExtension(file.getOriginalFilename()); | ||||
|         if (StringUtils.isEmpty(extension)) | ||||
|         { | ||||
|             extension = MimeTypeUtils.getExtension(file.getContentType()); | ||||
|         } | ||||
|         return extension; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,142 @@ | ||||
| package com.stdiet.common.utils.file; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.OutputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.net.URLEncoder; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
|  | ||||
| /** | ||||
|  * 文件处理工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class FileUtils extends org.apache.commons.io.FileUtils | ||||
| { | ||||
|     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(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除文件 | ||||
|      *  | ||||
|      * @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 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| package com.stdiet.common.utils.file; | ||||
|  | ||||
| /** | ||||
|  * 媒体类型工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class MimeTypeUtils | ||||
| { | ||||
|     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[] DEFAULT_ALLOWED_EXTENSION = { | ||||
|             // 图片 | ||||
|             "bmp", "gif", "jpg", "jpeg", "png", | ||||
|             // word excel powerpoint | ||||
|             "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", | ||||
|             // 压缩文件 | ||||
|             "rar", "zip", "gz", "bz2", | ||||
|             // 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 ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,155 @@ | ||||
| package com.stdiet.common.utils.html; | ||||
|  | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * 转义和反转义工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class EscapeUtil | ||||
| { | ||||
|     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['\''] = "'".toCharArray(); // 单引号 | ||||
|         TEXT['"'] = """.toCharArray(); // 单引号 | ||||
|         TEXT['&'] = "&".toCharArray(); // &符 | ||||
|         TEXT['<'] = "<".toCharArray(); // 小于号 | ||||
|         TEXT['>'] = ">".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) | ||||
|     { | ||||
|         int len; | ||||
|         if ((text == null) || ((len = text.length()) == 0)) | ||||
|         { | ||||
|             return StringUtils.EMPTY; | ||||
|         } | ||||
|         StringBuilder buffer = new StringBuilder(len + (len >> 2)); | ||||
|         char c; | ||||
|         for (int i = 0; i < len; i++) | ||||
|         { | ||||
|             c = text.charAt(i); | ||||
|             if (c < 64) | ||||
|             { | ||||
|                 buffer.append(TEXT[c]); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 buffer.append(c); | ||||
|             } | ||||
|         } | ||||
|         return buffer.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 html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>"; | ||||
|         // String html = "<123"; | ||||
|         // String html = "123>"; | ||||
|         System.out.println(EscapeUtil.clean(html)); | ||||
|         System.out.println(EscapeUtil.escape(html)); | ||||
|         System.out.println(EscapeUtil.unescape(html)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,570 @@ | ||||
| package com.stdiet.common.utils.html; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.ConcurrentMap; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * HTML过滤器,用于去除XSS漏洞隐患。 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| 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, "&", result); | ||||
|         result = regexReplace(P_QUOTE, """, result); | ||||
|         result = regexReplace(P_LEFT_ARROW, "<", result); | ||||
|         result = regexReplace(P_RIGHT_ARROW, ">", 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, "<$1", s); | ||||
|             s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", 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 (false == 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); // (<|$) | ||||
|                 // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, 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 : "&" + 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)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| package com.stdiet.common.utils.http; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.nio.charset.Charset; | ||||
| import javax.servlet.ServletRequest; | ||||
| import org.apache.commons.lang3.exception.ExceptionUtils; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * 通用http工具封装 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class HttpHelper | ||||
| { | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class); | ||||
|  | ||||
|     public static String getBodyString(ServletRequest request) | ||||
|     { | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         BufferedReader reader = null; | ||||
|         try (InputStream inputStream = request.getInputStream()) | ||||
|         { | ||||
|             reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); | ||||
|             String line = ""; | ||||
|             while ((line = reader.readLine()) != null) | ||||
|             { | ||||
|                 sb.append(line); | ||||
|             } | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             LOGGER.warn("getBodyString出现问题!"); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             if (reader != null) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     reader.close(); | ||||
|                 } | ||||
|                 catch (IOException e) | ||||
|                 { | ||||
|                     LOGGER.error(ExceptionUtils.getMessage(e)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,262 @@ | ||||
| package com.stdiet.common.utils.http; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.PrintWriter; | ||||
| import java.net.ConnectException; | ||||
| import java.net.SocketTimeoutException; | ||||
| import java.net.URL; | ||||
| import java.net.URLConnection; | ||||
| import java.security.cert.X509Certificate; | ||||
| import javax.net.ssl.HostnameVerifier; | ||||
| import javax.net.ssl.HttpsURLConnection; | ||||
| import javax.net.ssl.SSLContext; | ||||
| import javax.net.ssl.SSLSession; | ||||
| import javax.net.ssl.TrustManager; | ||||
| import javax.net.ssl.X509TrustManager; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import com.stdiet.common.constant.Constants; | ||||
|  | ||||
| /** | ||||
|  * 通用http发送方法 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class HttpUtils | ||||
| { | ||||
|     private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); | ||||
|  | ||||
|     /** | ||||
|      * 向指定 URL 发送GET方法的请求 | ||||
|      * | ||||
|      * @param url 发送请求的 URL | ||||
|      * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | ||||
|      * @return 所代表远程资源的响应结果 | ||||
|      */ | ||||
|     public static String sendGet(String url, String param) | ||||
|     { | ||||
|         return sendGet(url, param, Constants.UTF8); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 向指定 URL 发送GET方法的请求 | ||||
|      * | ||||
|      * @param url 发送请求的 URL | ||||
|      * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | ||||
|      * @param contentType 编码类型 | ||||
|      * @return 所代表远程资源的响应结果 | ||||
|      */ | ||||
|     public static String sendGet(String url, String param, String contentType) | ||||
|     { | ||||
|         StringBuilder result = new StringBuilder(); | ||||
|         BufferedReader in = null; | ||||
|         try | ||||
|         { | ||||
|             String urlNameString = url + "?" + param; | ||||
|             log.info("sendGet - {}", urlNameString); | ||||
|             URL realUrl = new URL(urlNameString); | ||||
|             URLConnection connection = realUrl.openConnection(); | ||||
|             connection.setRequestProperty("accept", "*/*"); | ||||
|             connection.setRequestProperty("connection", "Keep-Alive"); | ||||
|             connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | ||||
|             connection.connect(); | ||||
|             in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); | ||||
|             String line; | ||||
|             while ((line = in.readLine()) != null) | ||||
|             { | ||||
|                 result.append(line); | ||||
|             } | ||||
|             log.info("recv - {}", result); | ||||
|         } | ||||
|         catch (ConnectException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (SocketTimeoutException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (in != null) | ||||
|                 { | ||||
|                     in.close(); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); | ||||
|             } | ||||
|         } | ||||
|         return result.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 向指定 URL 发送POST方法的请求 | ||||
|      * | ||||
|      * @param url 发送请求的 URL | ||||
|      * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | ||||
|      * @return 所代表远程资源的响应结果 | ||||
|      */ | ||||
|     public static String sendPost(String url, String param) | ||||
|     { | ||||
|         PrintWriter out = null; | ||||
|         BufferedReader in = null; | ||||
|         StringBuilder result = new StringBuilder(); | ||||
|         try | ||||
|         { | ||||
|             String urlNameString = url; | ||||
|             log.info("sendPost - {}", urlNameString); | ||||
|             URL realUrl = new URL(urlNameString); | ||||
|             URLConnection conn = realUrl.openConnection(); | ||||
|             conn.setRequestProperty("accept", "*/*"); | ||||
|             conn.setRequestProperty("connection", "Keep-Alive"); | ||||
|             conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | ||||
|             conn.setRequestProperty("Accept-Charset", "utf-8"); | ||||
|             conn.setRequestProperty("contentType", "utf-8"); | ||||
|             conn.setDoOutput(true); | ||||
|             conn.setDoInput(true); | ||||
|             out = new PrintWriter(conn.getOutputStream()); | ||||
|             out.print(param); | ||||
|             out.flush(); | ||||
|             in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); | ||||
|             String line; | ||||
|             while ((line = in.readLine()) != null) | ||||
|             { | ||||
|                 result.append(line); | ||||
|             } | ||||
|             log.info("recv - {}", result); | ||||
|         } | ||||
|         catch (ConnectException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (SocketTimeoutException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (out != null) | ||||
|                 { | ||||
|                     out.close(); | ||||
|                 } | ||||
|                 if (in != null) | ||||
|                 { | ||||
|                     in.close(); | ||||
|                 } | ||||
|             } | ||||
|             catch (IOException ex) | ||||
|             { | ||||
|                 log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); | ||||
|             } | ||||
|         } | ||||
|         return result.toString(); | ||||
|     } | ||||
|  | ||||
|     public static String sendSSLPost(String url, String param) | ||||
|     { | ||||
|         StringBuilder result = new StringBuilder(); | ||||
|         String urlNameString = url + "?" + param; | ||||
|         try | ||||
|         { | ||||
|             log.info("sendSSLPost - {}", urlNameString); | ||||
|             SSLContext sc = SSLContext.getInstance("SSL"); | ||||
|             sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); | ||||
|             URL console = new URL(urlNameString); | ||||
|             HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); | ||||
|             conn.setRequestProperty("accept", "*/*"); | ||||
|             conn.setRequestProperty("connection", "Keep-Alive"); | ||||
|             conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | ||||
|             conn.setRequestProperty("Accept-Charset", "utf-8"); | ||||
|             conn.setRequestProperty("contentType", "utf-8"); | ||||
|             conn.setDoOutput(true); | ||||
|             conn.setDoInput(true); | ||||
|  | ||||
|             conn.setSSLSocketFactory(sc.getSocketFactory()); | ||||
|             conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); | ||||
|             conn.connect(); | ||||
|             InputStream is = conn.getInputStream(); | ||||
|             BufferedReader br = new BufferedReader(new InputStreamReader(is)); | ||||
|             String ret = ""; | ||||
|             while ((ret = br.readLine()) != null) | ||||
|             { | ||||
|                 if (ret != null && !"".equals(ret.trim())) | ||||
|                 { | ||||
|                     result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); | ||||
|                 } | ||||
|             } | ||||
|             log.info("recv - {}", result); | ||||
|             conn.disconnect(); | ||||
|             br.close(); | ||||
|         } | ||||
|         catch (ConnectException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (SocketTimeoutException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); | ||||
|         } | ||||
|         return result.toString(); | ||||
|     } | ||||
|  | ||||
|     private static class TrustAnyTrustManager implements X509TrustManager | ||||
|     { | ||||
|         @Override | ||||
|         public void checkClientTrusted(X509Certificate[] chain, String authType) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void checkServerTrusted(X509Certificate[] chain, String authType) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public X509Certificate[] getAcceptedIssuers() | ||||
|         { | ||||
|             return new X509Certificate[] {}; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class TrustAnyHostnameVerifier implements HostnameVerifier | ||||
|     { | ||||
|         @Override | ||||
|         public boolean verify(String hostname, SSLSession session) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,56 @@ | ||||
| package com.stdiet.common.utils.ip; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import com.alibaba.fastjson.JSONObject; | ||||
| import com.stdiet.common.config.RuoYiConfig; | ||||
| import com.stdiet.common.constant.Constants; | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
| import com.stdiet.common.utils.http.HttpUtils; | ||||
|  | ||||
| /** | ||||
|  * 获取地址类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class AddressUtils | ||||
| { | ||||
|     private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); | ||||
|  | ||||
|     // IP地址查询 | ||||
|     public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; | ||||
|  | ||||
|     // 未知地址 | ||||
|     public static final String UNKNOWN = "XX XX"; | ||||
|  | ||||
|     public static String getRealAddressByIP(String ip) | ||||
|     { | ||||
|         String address = UNKNOWN; | ||||
|         // 内网不查询 | ||||
|         if (IpUtils.internalIp(ip)) | ||||
|         { | ||||
|             return "内网IP"; | ||||
|         } | ||||
|         if (RuoYiConfig.isAddressEnabled()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK); | ||||
|                 if (StringUtils.isEmpty(rspStr)) | ||||
|                 { | ||||
|                     log.error("获取地理位置异常 {}", ip); | ||||
|                     return UNKNOWN; | ||||
|                 } | ||||
|                 JSONObject obj = JSONObject.parseObject(rspStr); | ||||
|                 String region = obj.getString("pro"); | ||||
|                 String city = obj.getString("city"); | ||||
|                 return String.format("%s %s", region, city); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 log.error("获取地理位置异常 {}", ip); | ||||
|             } | ||||
|         } | ||||
|         return address; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,195 @@ | ||||
| package com.stdiet.common.utils.ip; | ||||
|  | ||||
| import java.net.InetAddress; | ||||
| import java.net.UnknownHostException; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
| import com.stdiet.common.utils.html.EscapeUtil; | ||||
|  | ||||
| /** | ||||
|  * 获取IP方法 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class IpUtils | ||||
| { | ||||
|     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" : EscapeUtil.clean(ip); | ||||
|     } | ||||
|  | ||||
|     public static boolean internalIp(String ip) | ||||
|     { | ||||
|         byte[] addr = textToNumericFormatV4(ip); | ||||
|         return internalIp(addr) || "127.0.0.1".equals(ip); | ||||
|     } | ||||
|  | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|     public static String getHostIp() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return InetAddress.getLocalHost().getHostAddress(); | ||||
|         } | ||||
|         catch (UnknownHostException e) | ||||
|         { | ||||
|         } | ||||
|         return "127.0.0.1"; | ||||
|     } | ||||
|  | ||||
|     public static String getHostName() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return InetAddress.getLocalHost().getHostName(); | ||||
|         } | ||||
|         catch (UnknownHostException e) | ||||
|         { | ||||
|         } | ||||
|         return "未知"; | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,406 @@ | ||||
| package com.stdiet.common.utils.reflect; | ||||
|  | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.lang.reflect.ParameterizedType; | ||||
| import java.lang.reflect.Type; | ||||
| import java.util.Date; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.apache.commons.lang3.Validate; | ||||
| import org.apache.poi.ss.usermodel.DateUtil; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import com.stdiet.common.core.text.Convert; | ||||
| import com.stdiet.common.utils.DateUtils; | ||||
|  | ||||
| /** | ||||
|  * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| @SuppressWarnings("rawtypes") | ||||
| public class ReflectUtils | ||||
| { | ||||
|     private static final String SETTER_PREFIX = "set"; | ||||
|  | ||||
|     private static final String GETTER_PREFIX = "get"; | ||||
|  | ||||
|     private static final String CGLIB_CLASS_SEPARATOR = "$$"; | ||||
|  | ||||
|     private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); | ||||
|  | ||||
|     /** | ||||
|      * 调用Getter方法. | ||||
|      * 支持多级,如:对象名.对象名.方法 | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <E> E invokeGetter(Object obj, String propertyName) | ||||
|     { | ||||
|         Object object = obj; | ||||
|         for (String name : StringUtils.split(propertyName, ".")) | ||||
|         { | ||||
|             String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); | ||||
|             object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); | ||||
|         } | ||||
|         return (E) object; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 调用Setter方法, 仅匹配方法名。 | ||||
|      * 支持多级,如:对象名.对象名.方法 | ||||
|      */ | ||||
|     public static <E> void invokeSetter(Object obj, String propertyName, E value) | ||||
|     { | ||||
|         Object object = obj; | ||||
|         String[] names = StringUtils.split(propertyName, "."); | ||||
|         for (int i = 0; i < names.length; i++) | ||||
|         { | ||||
|             if (i < names.length - 1) | ||||
|             { | ||||
|                 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); | ||||
|                 object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); | ||||
|                 invokeMethodByName(object, setterMethodName, new Object[] { value }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <E> E getFieldValue(final Object obj, final String fieldName) | ||||
|     { | ||||
|         Field field = getAccessibleField(obj, fieldName); | ||||
|         if (field == null) | ||||
|         { | ||||
|             logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); | ||||
|             return null; | ||||
|         } | ||||
|         E result = null; | ||||
|         try | ||||
|         { | ||||
|             result = (E) field.get(obj); | ||||
|         } | ||||
|         catch (IllegalAccessException e) | ||||
|         { | ||||
|             logger.error("不可能抛出的异常{}", e.getMessage()); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. | ||||
|      */ | ||||
|     public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) | ||||
|     { | ||||
|         Field field = getAccessibleField(obj, fieldName); | ||||
|         if (field == null) | ||||
|         { | ||||
|             // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); | ||||
|             logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); | ||||
|             return; | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             field.set(obj, value); | ||||
|         } | ||||
|         catch (IllegalAccessException e) | ||||
|         { | ||||
|             logger.error("不可能抛出的异常: {}", e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 直接调用对象方法, 无视private/protected修饰符. | ||||
|      * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. | ||||
|      * 同时匹配方法名+参数类型, | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, | ||||
|             final Object[] args) | ||||
|     { | ||||
|         if (obj == null || methodName == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         Method method = getAccessibleMethod(obj, methodName, parameterTypes); | ||||
|         if (method == null) | ||||
|         { | ||||
|             logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); | ||||
|             return null; | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             return (E) method.invoke(obj, args); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; | ||||
|             throw convertReflectionExceptionToUnchecked(msg, e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 直接调用对象方法, 无视private/protected修饰符, | ||||
|      * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. | ||||
|      * 只匹配函数名,如果有多个同名函数调用第一个。 | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) | ||||
|     { | ||||
|         Method method = getAccessibleMethodByName(obj, methodName, args.length); | ||||
|         if (method == null) | ||||
|         { | ||||
|             // 如果为空不报错,直接返回空。 | ||||
|             logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); | ||||
|             return null; | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             // 类型转换(将参数数据类型转换为目标方法参数类型) | ||||
|             Class<?>[] cs = method.getParameterTypes(); | ||||
|             for (int i = 0; i < cs.length; i++) | ||||
|             { | ||||
|                 if (args[i] != null && !args[i].getClass().equals(cs[i])) | ||||
|                 { | ||||
|                     if (cs[i] == String.class) | ||||
|                     { | ||||
|                         args[i] = Convert.toStr(args[i]); | ||||
|                         if (StringUtils.endsWith((String) args[i], ".0")) | ||||
|                         { | ||||
|                             args[i] = StringUtils.substringBefore((String) args[i], ".0"); | ||||
|                         } | ||||
|                     } | ||||
|                     else if (cs[i] == Integer.class) | ||||
|                     { | ||||
|                         args[i] = Convert.toInt(args[i]); | ||||
|                     } | ||||
|                     else if (cs[i] == Long.class) | ||||
|                     { | ||||
|                         args[i] = Convert.toLong(args[i]); | ||||
|                     } | ||||
|                     else if (cs[i] == Double.class) | ||||
|                     { | ||||
|                         args[i] = Convert.toDouble(args[i]); | ||||
|                     } | ||||
|                     else if (cs[i] == Float.class) | ||||
|                     { | ||||
|                         args[i] = Convert.toFloat(args[i]); | ||||
|                     } | ||||
|                     else if (cs[i] == Date.class) | ||||
|                     { | ||||
|                         if (args[i] instanceof String) | ||||
|                         { | ||||
|                             args[i] = DateUtils.parseDate(args[i]); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             args[i] = DateUtil.getJavaDate((Double) args[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return (E) method.invoke(obj, args); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; | ||||
|             throw convertReflectionExceptionToUnchecked(msg, e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. | ||||
|      * 如向上转型到Object仍无法找到, 返回null. | ||||
|      */ | ||||
|     public static Field getAccessibleField(final Object obj, final String fieldName) | ||||
|     { | ||||
|         // 为空不报错。直接返回 null | ||||
|         if (obj == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         Validate.notBlank(fieldName, "fieldName can't be blank"); | ||||
|         for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Field field = superClass.getDeclaredField(fieldName); | ||||
|                 makeAccessible(field); | ||||
|                 return field; | ||||
|             } | ||||
|             catch (NoSuchFieldException e) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. | ||||
|      * 如向上转型到Object仍无法找到, 返回null. | ||||
|      * 匹配函数名+参数类型。 | ||||
|      * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) | ||||
|      */ | ||||
|     public static Method getAccessibleMethod(final Object obj, final String methodName, | ||||
|             final Class<?>... parameterTypes) | ||||
|     { | ||||
|         // 为空不报错。直接返回 null | ||||
|         if (obj == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         Validate.notBlank(methodName, "methodName can't be blank"); | ||||
|         for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Method method = searchType.getDeclaredMethod(methodName, parameterTypes); | ||||
|                 makeAccessible(method); | ||||
|                 return method; | ||||
|             } | ||||
|             catch (NoSuchMethodException e) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. | ||||
|      * 如向上转型到Object仍无法找到, 返回null. | ||||
|      * 只匹配函数名。 | ||||
|      * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) | ||||
|      */ | ||||
|     public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) | ||||
|     { | ||||
|         // 为空不报错。直接返回 null | ||||
|         if (obj == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         Validate.notBlank(methodName, "methodName can't be blank"); | ||||
|         for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) | ||||
|         { | ||||
|             Method[] methods = searchType.getDeclaredMethods(); | ||||
|             for (Method method : methods) | ||||
|             { | ||||
|                 if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) | ||||
|                 { | ||||
|                     makeAccessible(method); | ||||
|                     return method; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 | ||||
|      */ | ||||
|     public static void makeAccessible(Method method) | ||||
|     { | ||||
|         if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) | ||||
|                 && !method.isAccessible()) | ||||
|         { | ||||
|             method.setAccessible(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 | ||||
|      */ | ||||
|     public static void makeAccessible(Field field) | ||||
|     { | ||||
|         if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) | ||||
|                 || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) | ||||
|         { | ||||
|             field.setAccessible(true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 | ||||
|      * 如无法找到, 返回Object.class. | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <T> Class<T> getClassGenricType(final Class clazz) | ||||
|     { | ||||
|         return getClassGenricType(clazz, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. | ||||
|      * 如无法找到, 返回Object.class. | ||||
|      */ | ||||
|     public static Class getClassGenricType(final Class clazz, final int index) | ||||
|     { | ||||
|         Type genType = clazz.getGenericSuperclass(); | ||||
|  | ||||
|         if (!(genType instanceof ParameterizedType)) | ||||
|         { | ||||
|             logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); | ||||
|             return Object.class; | ||||
|         } | ||||
|  | ||||
|         Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); | ||||
|  | ||||
|         if (index >= params.length || index < 0) | ||||
|         { | ||||
|             logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " | ||||
|                     + params.length); | ||||
|             return Object.class; | ||||
|         } | ||||
|         if (!(params[index] instanceof Class)) | ||||
|         { | ||||
|             logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); | ||||
|             return Object.class; | ||||
|         } | ||||
|  | ||||
|         return (Class) params[index]; | ||||
|     } | ||||
|  | ||||
|     public static Class<?> getUserClass(Object instance) | ||||
|     { | ||||
|         if (instance == null) | ||||
|         { | ||||
|             throw new RuntimeException("Instance must not be null"); | ||||
|         } | ||||
|         Class clazz = instance.getClass(); | ||||
|         if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) | ||||
|         { | ||||
|             Class<?> superClass = clazz.getSuperclass(); | ||||
|             if (superClass != null && !Object.class.equals(superClass)) | ||||
|             { | ||||
|                 return superClass; | ||||
|             } | ||||
|         } | ||||
|         return clazz; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将反射时的checked exception转换为unchecked exception. | ||||
|      */ | ||||
|     public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) | ||||
|     { | ||||
|         if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException | ||||
|                 || e instanceof NoSuchMethodException) | ||||
|         { | ||||
|             return new IllegalArgumentException(msg, e); | ||||
|         } | ||||
|         else if (e instanceof InvocationTargetException) | ||||
|         { | ||||
|             return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); | ||||
|         } | ||||
|         return new RuntimeException(msg, e); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,291 @@ | ||||
| package com.stdiet.common.utils.sign; | ||||
|  | ||||
| /** | ||||
|  * Base64工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public final class Base64 | ||||
| { | ||||
|     static private final int     BASELENGTH           = 128; | ||||
|     static private final int     LOOKUPLENGTH         = 64; | ||||
|     static private final int     TWENTYFOURBITGROUP   = 24; | ||||
|     static private final int     EIGHTBIT             = 8; | ||||
|     static private final int     SIXTEENBIT           = 16; | ||||
|     static private final int     FOURBYTE             = 4; | ||||
|     static private final int     SIGN                 = -128; | ||||
|     static private final char    PAD                  = '='; | ||||
|     static final private byte[]  base64Alphabet       = new byte[BASELENGTH]; | ||||
|     static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH]; | ||||
|  | ||||
|     static | ||||
|     { | ||||
|         for (int i = 0; i < BASELENGTH; ++i) | ||||
|         { | ||||
|             base64Alphabet[i] = -1; | ||||
|         } | ||||
|         for (int i = 'Z'; i >= 'A'; i--) | ||||
|         { | ||||
|             base64Alphabet[i] = (byte) (i - 'A'); | ||||
|         } | ||||
|         for (int i = 'z'; i >= 'a'; i--) | ||||
|         { | ||||
|             base64Alphabet[i] = (byte) (i - 'a' + 26); | ||||
|         } | ||||
|  | ||||
|         for (int i = '9'; i >= '0'; i--) | ||||
|         { | ||||
|             base64Alphabet[i] = (byte) (i - '0' + 52); | ||||
|         } | ||||
|  | ||||
|         base64Alphabet['+'] = 62; | ||||
|         base64Alphabet['/'] = 63; | ||||
|  | ||||
|         for (int i = 0; i <= 25; i++) | ||||
|         { | ||||
|             lookUpBase64Alphabet[i] = (char) ('A' + i); | ||||
|         } | ||||
|  | ||||
|         for (int i = 26, j = 0; i <= 51; i++, j++) | ||||
|         { | ||||
|             lookUpBase64Alphabet[i] = (char) ('a' + j); | ||||
|         } | ||||
|  | ||||
|         for (int i = 52, j = 0; i <= 61; i++, j++) | ||||
|         { | ||||
|             lookUpBase64Alphabet[i] = (char) ('0' + j); | ||||
|         } | ||||
|         lookUpBase64Alphabet[62] = (char) '+'; | ||||
|         lookUpBase64Alphabet[63] = (char) '/'; | ||||
|     } | ||||
|  | ||||
|     private static boolean isWhiteSpace(char octect) | ||||
|     { | ||||
|         return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); | ||||
|     } | ||||
|  | ||||
|     private static boolean isPad(char octect) | ||||
|     { | ||||
|         return (octect == PAD); | ||||
|     } | ||||
|  | ||||
|     private static boolean isData(char octect) | ||||
|     { | ||||
|         return (octect < BASELENGTH && base64Alphabet[octect] != -1); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Encodes hex octects into Base64 | ||||
|      * | ||||
|      * @param binaryData Array containing binaryData | ||||
|      * @return Encoded Base64 array | ||||
|      */ | ||||
|     public static String encode(byte[] binaryData) | ||||
|     { | ||||
|         if (binaryData == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         int lengthDataBits = binaryData.length * EIGHTBIT; | ||||
|         if (lengthDataBits == 0) | ||||
|         { | ||||
|             return ""; | ||||
|         } | ||||
|  | ||||
|         int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; | ||||
|         int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; | ||||
|         int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; | ||||
|         char encodedData[] = null; | ||||
|  | ||||
|         encodedData = new char[numberQuartet * 4]; | ||||
|  | ||||
|         byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; | ||||
|  | ||||
|         int encodedIndex = 0; | ||||
|         int dataIndex = 0; | ||||
|  | ||||
|         for (int i = 0; i < numberTriplets; i++) | ||||
|         { | ||||
|             b1 = binaryData[dataIndex++]; | ||||
|             b2 = binaryData[dataIndex++]; | ||||
|             b3 = binaryData[dataIndex++]; | ||||
|  | ||||
|             l = (byte) (b2 & 0x0f); | ||||
|             k = (byte) (b1 & 0x03); | ||||
|  | ||||
|             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); | ||||
|             byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); | ||||
|             byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); | ||||
|  | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; | ||||
|         } | ||||
|  | ||||
|         // form integral number of 6-bit groups | ||||
|         if (fewerThan24bits == EIGHTBIT) | ||||
|         { | ||||
|             b1 = binaryData[dataIndex]; | ||||
|             k = (byte) (b1 & 0x03); | ||||
|             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; | ||||
|             encodedData[encodedIndex++] = PAD; | ||||
|             encodedData[encodedIndex++] = PAD; | ||||
|         } | ||||
|         else if (fewerThan24bits == SIXTEENBIT) | ||||
|         { | ||||
|             b1 = binaryData[dataIndex]; | ||||
|             b2 = binaryData[dataIndex + 1]; | ||||
|             l = (byte) (b2 & 0x0f); | ||||
|             k = (byte) (b1 & 0x03); | ||||
|  | ||||
|             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); | ||||
|             byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); | ||||
|  | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; | ||||
|             encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; | ||||
|             encodedData[encodedIndex++] = PAD; | ||||
|         } | ||||
|         return new String(encodedData); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Decodes Base64 data into octects | ||||
|      * | ||||
|      * @param encoded string containing Base64 data | ||||
|      * @return Array containind decoded data. | ||||
|      */ | ||||
|     public static byte[] decode(String encoded) | ||||
|     { | ||||
|         if (encoded == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         char[] base64Data = encoded.toCharArray(); | ||||
|         // remove white spaces | ||||
|         int len = removeWhiteSpace(base64Data); | ||||
|  | ||||
|         if (len % FOURBYTE != 0) | ||||
|         { | ||||
|             return null;// should be divisible by four | ||||
|         } | ||||
|  | ||||
|         int numberQuadruple = (len / FOURBYTE); | ||||
|  | ||||
|         if (numberQuadruple == 0) | ||||
|         { | ||||
|             return new byte[0]; | ||||
|         } | ||||
|  | ||||
|         byte decodedData[] = null; | ||||
|         byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; | ||||
|         char d1 = 0, d2 = 0, d3 = 0, d4 = 0; | ||||
|  | ||||
|         int i = 0; | ||||
|         int encodedIndex = 0; | ||||
|         int dataIndex = 0; | ||||
|         decodedData = new byte[(numberQuadruple) * 3]; | ||||
|  | ||||
|         for (; i < numberQuadruple - 1; i++) | ||||
|         { | ||||
|  | ||||
|             if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) | ||||
|                     || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) | ||||
|             { | ||||
|                 return null; | ||||
|             } // if found "no data" just return null | ||||
|  | ||||
|             b1 = base64Alphabet[d1]; | ||||
|             b2 = base64Alphabet[d2]; | ||||
|             b3 = base64Alphabet[d3]; | ||||
|             b4 = base64Alphabet[d4]; | ||||
|  | ||||
|             decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); | ||||
|             decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); | ||||
|             decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); | ||||
|         } | ||||
|  | ||||
|         if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) | ||||
|         { | ||||
|             return null;// if found "no data" just return null | ||||
|         } | ||||
|  | ||||
|         b1 = base64Alphabet[d1]; | ||||
|         b2 = base64Alphabet[d2]; | ||||
|  | ||||
|         d3 = base64Data[dataIndex++]; | ||||
|         d4 = base64Data[dataIndex++]; | ||||
|         if (!isData((d3)) || !isData((d4))) | ||||
|         {// Check if they are PAD characters | ||||
|             if (isPad(d3) && isPad(d4)) | ||||
|             { | ||||
|                 if ((b2 & 0xf) != 0)// last 4 bits should be zero | ||||
|                 { | ||||
|                     return null; | ||||
|                 } | ||||
|                 byte[] tmp = new byte[i * 3 + 1]; | ||||
|                 System.arraycopy(decodedData, 0, tmp, 0, i * 3); | ||||
|                 tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); | ||||
|                 return tmp; | ||||
|             } | ||||
|             else if (!isPad(d3) && isPad(d4)) | ||||
|             { | ||||
|                 b3 = base64Alphabet[d3]; | ||||
|                 if ((b3 & 0x3) != 0)// last 2 bits should be zero | ||||
|                 { | ||||
|                     return null; | ||||
|                 } | ||||
|                 byte[] tmp = new byte[i * 3 + 2]; | ||||
|                 System.arraycopy(decodedData, 0, tmp, 0, i * 3); | ||||
|                 tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); | ||||
|                 tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); | ||||
|                 return tmp; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { // No PAD e.g 3cQl | ||||
|             b3 = base64Alphabet[d3]; | ||||
|             b4 = base64Alphabet[d4]; | ||||
|             decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); | ||||
|             decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); | ||||
|             decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); | ||||
|  | ||||
|         } | ||||
|         return decodedData; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * remove WhiteSpace from MIME containing encoded Base64 data. | ||||
|      * | ||||
|      * @param data the byte array of base64 data (with WS) | ||||
|      * @return the new length | ||||
|      */ | ||||
|     private static int removeWhiteSpace(char[] data) | ||||
|     { | ||||
|         if (data == null) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         // count characters that's not whitespace | ||||
|         int newSize = 0; | ||||
|         int len = data.length; | ||||
|         for (int i = 0; i < len; i++) | ||||
|         { | ||||
|             if (!isWhiteSpace(data[i])) | ||||
|             { | ||||
|                 data[newSize++] = data[i]; | ||||
|             } | ||||
|         } | ||||
|         return newSize; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package com.stdiet.common.utils.sign; | ||||
|  | ||||
| import java.security.MessageDigest; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * Md5加密方法 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class Md5Utils | ||||
| { | ||||
|     private static final Logger log = LoggerFactory.getLogger(Md5Utils.class); | ||||
|  | ||||
|     private static byte[] md5(String s) | ||||
|     { | ||||
|         MessageDigest algorithm; | ||||
|         try | ||||
|         { | ||||
|             algorithm = MessageDigest.getInstance("MD5"); | ||||
|             algorithm.reset(); | ||||
|             algorithm.update(s.getBytes("UTF-8")); | ||||
|             byte[] messageDigest = algorithm.digest(); | ||||
|             return messageDigest; | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("MD5 Error...", e); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     private static final String toHex(byte hash[]) | ||||
|     { | ||||
|         if (hash == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         StringBuffer buf = new StringBuffer(hash.length * 2); | ||||
|         int i; | ||||
|  | ||||
|         for (i = 0; i < hash.length; i++) | ||||
|         { | ||||
|             if ((hash[i] & 0xff) < 0x10) | ||||
|             { | ||||
|                 buf.append("0"); | ||||
|             } | ||||
|             buf.append(Long.toString(hash[i] & 0xff, 16)); | ||||
|         } | ||||
|         return buf.toString(); | ||||
|     } | ||||
|  | ||||
|     public static String hash(String s) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8"); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("not supported charset...{}", e); | ||||
|             return s; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,146 @@ | ||||
| package com.stdiet.common.utils.spring; | ||||
|  | ||||
| import org.springframework.aop.framework.AopContext; | ||||
| import org.springframework.beans.BeansException; | ||||
| import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||||
| import org.springframework.beans.factory.config.BeanFactoryPostProcessor; | ||||
| import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||||
| import org.springframework.context.ApplicationContext; | ||||
| import org.springframework.context.ApplicationContextAware; | ||||
| import org.springframework.stereotype.Component; | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * spring工具类 方便在非spring管理环境中获取bean | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| @Component | ||||
| public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware  | ||||
| { | ||||
|     /** Spring应用上下文环境 */ | ||||
|     private static ConfigurableListableBeanFactory beanFactory; | ||||
|  | ||||
|     private static ApplicationContext applicationContext; | ||||
|  | ||||
|     @Override | ||||
|     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException  | ||||
|     { | ||||
|         SpringUtils.beanFactory = beanFactory; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException  | ||||
|     { | ||||
|         SpringUtils.applicationContext = applicationContext; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取对象 | ||||
|      * | ||||
|      * @param name | ||||
|      * @return Object 一个以所给名字注册的bean的实例 | ||||
|      * @throws org.springframework.beans.BeansException | ||||
|      * | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <T> T getBean(String name) throws BeansException | ||||
|     { | ||||
|         return (T) beanFactory.getBean(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取类型为requiredType的对象 | ||||
|      * | ||||
|      * @param clz | ||||
|      * @return | ||||
|      * @throws org.springframework.beans.BeansException | ||||
|      * | ||||
|      */ | ||||
|     public static <T> T getBean(Class<T> clz) throws BeansException | ||||
|     { | ||||
|         T result = (T) beanFactory.getBean(clz); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true | ||||
|      * | ||||
|      * @param name | ||||
|      * @return boolean | ||||
|      */ | ||||
|     public static boolean containsBean(String name) | ||||
|     { | ||||
|         return beanFactory.containsBean(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) | ||||
|      * | ||||
|      * @param name | ||||
|      * @return boolean | ||||
|      * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException | ||||
|      * | ||||
|      */ | ||||
|     public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException | ||||
|     { | ||||
|         return beanFactory.isSingleton(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param name | ||||
|      * @return Class 注册对象的类型 | ||||
|      * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException | ||||
|      * | ||||
|      */ | ||||
|     public static Class<?> getType(String name) throws NoSuchBeanDefinitionException | ||||
|     { | ||||
|         return beanFactory.getType(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 如果给定的bean名字在bean定义中有别名,则返回这些别名 | ||||
|      * | ||||
|      * @param name | ||||
|      * @return | ||||
|      * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException | ||||
|      * | ||||
|      */ | ||||
|     public static String[] getAliases(String name) throws NoSuchBeanDefinitionException | ||||
|     { | ||||
|         return beanFactory.getAliases(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取aop代理对象 | ||||
|      *  | ||||
|      * @param invoker | ||||
|      * @return | ||||
|      */ | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <T> T getAopProxy(T invoker) | ||||
|     { | ||||
|         return (T) AopContext.currentProxy(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取当前的环境配置,无配置返回null | ||||
|      * | ||||
|      * @return 当前的环境配置 | ||||
|      */ | ||||
|     public static String[] getActiveProfiles() | ||||
|     { | ||||
|         return applicationContext.getEnvironment().getActiveProfiles(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取当前的环境配置,当有多个环境配置时,只获取第一个 | ||||
|      * | ||||
|      * @return 当前的环境配置 | ||||
|      */ | ||||
|     public static String getActiveProfile() | ||||
|     { | ||||
|         final String[] activeProfiles = getActiveProfiles(); | ||||
|         return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,37 @@ | ||||
| package com.stdiet.common.utils.sql; | ||||
|  | ||||
| import com.stdiet.common.exception.BaseException; | ||||
| import com.stdiet.common.utils.StringUtils; | ||||
|  | ||||
| /** | ||||
|  * sql操作工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class SqlUtil | ||||
| { | ||||
|     /** | ||||
|      * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) | ||||
|      */ | ||||
|     public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; | ||||
|  | ||||
|     /** | ||||
|      * 检查字符,防止注入绕过 | ||||
|      */ | ||||
|     public static String escapeOrderBySql(String value) | ||||
|     { | ||||
|         if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) | ||||
|         { | ||||
|             throw new BaseException("参数不符合规范,不能进行查询"); | ||||
|         } | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 验证 order by 语法是否符合规范 | ||||
|      */ | ||||
|     public static boolean isValidOrderBySql(String value) | ||||
|     { | ||||
|         return value.matches(SQL_PATTERN); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,51 @@ | ||||
| package com.stdiet.common.utils.uuid; | ||||
|  | ||||
| import com.stdiet.common.utils.uuid.UUID; | ||||
|  | ||||
| /** | ||||
|  * ID生成器工具类 | ||||
|  *  | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public class IdUtils | ||||
| { | ||||
|     /** | ||||
|      * 获取随机UUID | ||||
|      *  | ||||
|      * @return 随机UUID | ||||
|      */ | ||||
|     public static String randomUUID() | ||||
|     { | ||||
|         return UUID.randomUUID().toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 简化的UUID,去掉了横线 | ||||
|      *  | ||||
|      * @return 简化的UUID,去掉了横线 | ||||
|      */ | ||||
|     public static String simpleUUID() | ||||
|     { | ||||
|         return UUID.randomUUID().toString(true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID | ||||
|      *  | ||||
|      * @return 随机UUID | ||||
|      */ | ||||
|     public static String fastUUID() | ||||
|     { | ||||
|         return UUID.fastUUID().toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID | ||||
|      *  | ||||
|      * @return 简化的UUID,去掉了横线 | ||||
|      */ | ||||
|     public static String fastSimpleUUID() | ||||
|     { | ||||
|         return UUID.fastUUID().toString(true); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,484 @@ | ||||
| package com.stdiet.common.utils.uuid; | ||||
|  | ||||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.security.SecureRandom; | ||||
| import java.util.Random; | ||||
| import java.util.concurrent.ThreadLocalRandom; | ||||
| import com.stdiet.common.exception.UtilException; | ||||
|  | ||||
| /** | ||||
|  * 提供通用唯一识别码(universally unique identifier)(UUID)实现 | ||||
|  * | ||||
|  * @author stdiet | ||||
|  */ | ||||
| public final class UUID implements java.io.Serializable, Comparable<UUID> | ||||
| { | ||||
|     private static final long serialVersionUID = -1185015143654744140L; | ||||
|  | ||||
|     /** | ||||
|      * SecureRandom 的单例 | ||||
|      * | ||||
|      */ | ||||
|     private static class Holder | ||||
|     { | ||||
|         static final SecureRandom numberGenerator = getSecureRandom(); | ||||
|     } | ||||
|  | ||||
|     /** 此UUID的最高64有效位 */ | ||||
|     private final long mostSigBits; | ||||
|  | ||||
|     /** 此UUID的最低64有效位 */ | ||||
|     private final long leastSigBits; | ||||
|  | ||||
|     /** | ||||
|      * 私有构造 | ||||
|      *  | ||||
|      * @param data 数据 | ||||
|      */ | ||||
|     private UUID(byte[] data) | ||||
|     { | ||||
|         long msb = 0; | ||||
|         long lsb = 0; | ||||
|         assert data.length == 16 : "data must be 16 bytes in length"; | ||||
|         for (int i = 0; i < 8; i++) | ||||
|         { | ||||
|             msb = (msb << 8) | (data[i] & 0xff); | ||||
|         } | ||||
|         for (int i = 8; i < 16; i++) | ||||
|         { | ||||
|             lsb = (lsb << 8) | (data[i] & 0xff); | ||||
|         } | ||||
|         this.mostSigBits = msb; | ||||
|         this.leastSigBits = lsb; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 使用指定的数据构造新的 UUID。 | ||||
|      * | ||||
|      * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 | ||||
|      * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 | ||||
|      */ | ||||
|     public UUID(long mostSigBits, long leastSigBits) | ||||
|     { | ||||
|         this.mostSigBits = mostSigBits; | ||||
|         this.leastSigBits = leastSigBits; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。 | ||||
|      *  | ||||
|      * @return 随机生成的 {@code UUID} | ||||
|      */ | ||||
|     public static UUID fastUUID() | ||||
|     { | ||||
|         return randomUUID(false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 | ||||
|      *  | ||||
|      * @return 随机生成的 {@code UUID} | ||||
|      */ | ||||
|     public static UUID randomUUID() | ||||
|     { | ||||
|         return randomUUID(true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 | ||||
|      *  | ||||
|      * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 | ||||
|      * @return 随机生成的 {@code UUID} | ||||
|      */ | ||||
|     public static UUID randomUUID(boolean isSecure) | ||||
|     { | ||||
|         final Random ng = isSecure ? Holder.numberGenerator : getRandom(); | ||||
|  | ||||
|         byte[] randomBytes = new byte[16]; | ||||
|         ng.nextBytes(randomBytes); | ||||
|         randomBytes[6] &= 0x0f; /* clear version */ | ||||
|         randomBytes[6] |= 0x40; /* set to version 4 */ | ||||
|         randomBytes[8] &= 0x3f; /* clear variant */ | ||||
|         randomBytes[8] |= 0x80; /* set to IETF variant */ | ||||
|         return new UUID(randomBytes); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 | ||||
|      * | ||||
|      * @param name 用于构造 UUID 的字节数组。 | ||||
|      * | ||||
|      * @return 根据指定数组生成的 {@code UUID} | ||||
|      */ | ||||
|     public static UUID nameUUIDFromBytes(byte[] name) | ||||
|     { | ||||
|         MessageDigest md; | ||||
|         try | ||||
|         { | ||||
|             md = MessageDigest.getInstance("MD5"); | ||||
|         } | ||||
|         catch (NoSuchAlgorithmException nsae) | ||||
|         { | ||||
|             throw new InternalError("MD5 not supported"); | ||||
|         } | ||||
|         byte[] md5Bytes = md.digest(name); | ||||
|         md5Bytes[6] &= 0x0f; /* clear version */ | ||||
|         md5Bytes[6] |= 0x30; /* set to version 3 */ | ||||
|         md5Bytes[8] &= 0x3f; /* clear variant */ | ||||
|         md5Bytes[8] |= 0x80; /* set to IETF variant */ | ||||
|         return new UUID(md5Bytes); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 | ||||
|      * | ||||
|      * @param name 指定 {@code UUID} 字符串 | ||||
|      * @return 具有指定值的 {@code UUID} | ||||
|      * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 | ||||
|      * | ||||
|      */ | ||||
|     public static UUID fromString(String name) | ||||
|     { | ||||
|         String[] components = name.split("-"); | ||||
|         if (components.length != 5) | ||||
|         { | ||||
|             throw new IllegalArgumentException("Invalid UUID string: " + name); | ||||
|         } | ||||
|         for (int i = 0; i < 5; i++) | ||||
|         { | ||||
|             components[i] = "0x" + components[i]; | ||||
|         } | ||||
|  | ||||
|         long mostSigBits = Long.decode(components[0]).longValue(); | ||||
|         mostSigBits <<= 16; | ||||
|         mostSigBits |= Long.decode(components[1]).longValue(); | ||||
|         mostSigBits <<= 16; | ||||
|         mostSigBits |= Long.decode(components[2]).longValue(); | ||||
|  | ||||
|         long leastSigBits = Long.decode(components[3]).longValue(); | ||||
|         leastSigBits <<= 48; | ||||
|         leastSigBits |= Long.decode(components[4]).longValue(); | ||||
|  | ||||
|         return new UUID(mostSigBits, leastSigBits); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回此 UUID 的 128 位值中的最低有效 64 位。 | ||||
|      * | ||||
|      * @return 此 UUID 的 128 位值中的最低有效 64 位。 | ||||
|      */ | ||||
|     public long getLeastSignificantBits() | ||||
|     { | ||||
|         return leastSigBits; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回此 UUID 的 128 位值中的最高有效 64 位。 | ||||
|      * | ||||
|      * @return 此 UUID 的 128 位值中最高有效 64 位。 | ||||
|      */ | ||||
|     public long getMostSignificantBits() | ||||
|     { | ||||
|         return mostSigBits; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 | ||||
|      * <p> | ||||
|      * 版本号具有以下含意: | ||||
|      * <ul> | ||||
|      * <li>1 基于时间的 UUID | ||||
|      * <li>2 DCE 安全 UUID | ||||
|      * <li>3 基于名称的 UUID | ||||
|      * <li>4 随机生成的 UUID | ||||
|      * </ul> | ||||
|      * | ||||
|      * @return 此 {@code UUID} 的版本号 | ||||
|      */ | ||||
|     public int version() | ||||
|     { | ||||
|         // Version is bits masked by 0x000000000000F000 in MS long | ||||
|         return (int) ((mostSigBits >> 12) & 0x0f); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 | ||||
|      * <p> | ||||
|      * 变体号具有以下含意: | ||||
|      * <ul> | ||||
|      * <li>0 为 NCS 向后兼容保留 | ||||
|      * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类 | ||||
|      * <li>6 保留,微软向后兼容 | ||||
|      * <li>7 保留供以后定义使用 | ||||
|      * </ul> | ||||
|      * | ||||
|      * @return 此 {@code UUID} 相关联的变体号 | ||||
|      */ | ||||
|     public int variant() | ||||
|     { | ||||
|         // This field is composed of a varying number of bits. | ||||
|         // 0 - - Reserved for NCS backward compatibility | ||||
|         // 1 0 - The IETF aka Leach-Salz variant (used by this class) | ||||
|         // 1 1 0 Reserved, Microsoft backward compatibility | ||||
|         // 1 1 1 Reserved for future definition. | ||||
|         return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 与此 UUID 相关联的时间戳值。 | ||||
|      * | ||||
|      * <p> | ||||
|      * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br> | ||||
|      * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 | ||||
|      * | ||||
|      * <p> | ||||
|      * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br> | ||||
|      * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 | ||||
|      * | ||||
|      * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 | ||||
|      */ | ||||
|     public long timestamp() throws UnsupportedOperationException | ||||
|     { | ||||
|         checkTimeBase(); | ||||
|         return (mostSigBits & 0x0FFFL) << 48// | ||||
|                 | ((mostSigBits >> 16) & 0x0FFFFL) << 32// | ||||
|                 | mostSigBits >>> 32; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 与此 UUID 相关联的时钟序列值。 | ||||
|      * | ||||
|      * <p> | ||||
|      * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 | ||||
|      * <p> | ||||
|      * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 | ||||
|      * UnsupportedOperationException。 | ||||
|      * | ||||
|      * @return 此 {@code UUID} 的时钟序列 | ||||
|      * | ||||
|      * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 | ||||
|      */ | ||||
|     public int clockSequence() throws UnsupportedOperationException | ||||
|     { | ||||
|         checkTimeBase(); | ||||
|         return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 与此 UUID 相关的节点值。 | ||||
|      * | ||||
|      * <p> | ||||
|      * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 | ||||
|      * <p> | ||||
|      * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br> | ||||
|      * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 | ||||
|      * | ||||
|      * @return 此 {@code UUID} 的节点值 | ||||
|      * | ||||
|      * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 | ||||
|      */ | ||||
|     public long node() throws UnsupportedOperationException | ||||
|     { | ||||
|         checkTimeBase(); | ||||
|         return leastSigBits & 0x0000FFFFFFFFFFFFL; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回此{@code UUID} 的字符串表现形式。 | ||||
|      * | ||||
|      * <p> | ||||
|      * UUID 的字符串表示形式由此 BNF 描述: | ||||
|      *  | ||||
|      * <pre> | ||||
|      * {@code | ||||
|      * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node> | ||||
|      * time_low               = 4*<hexOctet> | ||||
|      * time_mid               = 2*<hexOctet> | ||||
|      * time_high_and_version  = 2*<hexOctet> | ||||
|      * variant_and_sequence   = 2*<hexOctet> | ||||
|      * node                   = 6*<hexOctet> | ||||
|      * hexOctet               = <hexDigit><hexDigit> | ||||
|      * hexDigit               = [0-9a-fA-F] | ||||
|      * } | ||||
|      * </pre> | ||||
|      *  | ||||
|      * </blockquote> | ||||
|      * | ||||
|      * @return 此{@code UUID} 的字符串表现形式 | ||||
|      * @see #toString(boolean) | ||||
|      */ | ||||
|     @Override | ||||
|     public String toString() | ||||
|     { | ||||
|         return toString(false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回此{@code UUID} 的字符串表现形式。 | ||||
|      * | ||||
|      * <p> | ||||
|      * UUID 的字符串表示形式由此 BNF 描述: | ||||
|      *  | ||||
|      * <pre> | ||||
|      * {@code | ||||
|      * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node> | ||||
|      * time_low               = 4*<hexOctet> | ||||
|      * time_mid               = 2*<hexOctet> | ||||
|      * time_high_and_version  = 2*<hexOctet> | ||||
|      * variant_and_sequence   = 2*<hexOctet> | ||||
|      * node                   = 6*<hexOctet> | ||||
|      * hexOctet               = <hexDigit><hexDigit> | ||||
|      * hexDigit               = [0-9a-fA-F] | ||||
|      * } | ||||
|      * </pre> | ||||
|      *  | ||||
|      * </blockquote> | ||||
|      * | ||||
|      * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 | ||||
|      * @return 此{@code UUID} 的字符串表现形式 | ||||
|      */ | ||||
|     public String toString(boolean isSimple) | ||||
|     { | ||||
|         final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); | ||||
|         // time_low | ||||
|         builder.append(digits(mostSigBits >> 32, 8)); | ||||
|         if (false == isSimple) | ||||
|         { | ||||
|             builder.append('-'); | ||||
|         } | ||||
|         // time_mid | ||||
|         builder.append(digits(mostSigBits >> 16, 4)); | ||||
|         if (false == isSimple) | ||||
|         { | ||||
|             builder.append('-'); | ||||
|         } | ||||
|         // time_high_and_version | ||||
|         builder.append(digits(mostSigBits, 4)); | ||||
|         if (false == isSimple) | ||||
|         { | ||||
|             builder.append('-'); | ||||
|         } | ||||
|         // variant_and_sequence | ||||
|         builder.append(digits(leastSigBits >> 48, 4)); | ||||
|         if (false == isSimple) | ||||
|         { | ||||
|             builder.append('-'); | ||||
|         } | ||||
|         // node | ||||
|         builder.append(digits(leastSigBits, 12)); | ||||
|  | ||||
|         return builder.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回此 UUID 的哈希码。 | ||||
|      * | ||||
|      * @return UUID 的哈希码值。 | ||||
|      */ | ||||
|     @Override | ||||
|     public int hashCode() | ||||
|     { | ||||
|         long hilo = mostSigBits ^ leastSigBits; | ||||
|         return ((int) (hilo >> 32)) ^ (int) hilo; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将此对象与指定对象比较。 | ||||
|      * <p> | ||||
|      * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 | ||||
|      * | ||||
|      * @param obj 要与之比较的对象 | ||||
|      * | ||||
|      * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean equals(Object obj) | ||||
|     { | ||||
|         if ((null == obj) || (obj.getClass() != UUID.class)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         UUID id = (UUID) obj; | ||||
|         return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); | ||||
|     } | ||||
|  | ||||
|     // Comparison Operations | ||||
|  | ||||
|     /** | ||||
|      * 将此 UUID 与指定的 UUID 比较。 | ||||
|      * | ||||
|      * <p> | ||||
|      * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 | ||||
|      * | ||||
|      * @param val 与此 UUID 比较的 UUID | ||||
|      * | ||||
|      * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 | ||||
|      * | ||||
|      */ | ||||
|     @Override | ||||
|     public int compareTo(UUID val) | ||||
|     { | ||||
|         // The ordering is intentionally set up so that the UUIDs | ||||
|         // can simply be numerically compared as two numbers | ||||
|         return (this.mostSigBits < val.mostSigBits ? -1 : // | ||||
|                 (this.mostSigBits > val.mostSigBits ? 1 : // | ||||
|                         (this.leastSigBits < val.leastSigBits ? -1 : // | ||||
|                                 (this.leastSigBits > val.leastSigBits ? 1 : // | ||||
|                                         0)))); | ||||
|     } | ||||
|  | ||||
|     // ------------------------------------------------------------------------------------------------------------------- | ||||
|     // Private method start | ||||
|     /** | ||||
|      * 返回指定数字对应的hex值 | ||||
|      *  | ||||
|      * @param val 值 | ||||
|      * @param digits 位 | ||||
|      * @return 值 | ||||
|      */ | ||||
|     private static String digits(long val, int digits) | ||||
|     { | ||||
|         long hi = 1L << (digits * 4); | ||||
|         return Long.toHexString(hi | (val & (hi - 1))).substring(1); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 检查是否为time-based版本UUID | ||||
|      */ | ||||
|     private void checkTimeBase() | ||||
|     { | ||||
|         if (version() != 1) | ||||
|         { | ||||
|             throw new UnsupportedOperationException("Not a time-based UUID"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) | ||||
|      *  | ||||
|      * @return {@link SecureRandom} | ||||
|      */ | ||||
|     public static SecureRandom getSecureRandom() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return SecureRandom.getInstance("SHA1PRNG"); | ||||
|         } | ||||
|         catch (NoSuchAlgorithmException e) | ||||
|         { | ||||
|             throw new UtilException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取随机数生成器对象<br> | ||||
|      * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 | ||||
|      *  | ||||
|      * @return {@link ThreadLocalRandom} | ||||
|      */ | ||||
|     public static ThreadLocalRandom getRandom() | ||||
|     { | ||||
|         return ThreadLocalRandom.current(); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user