├── .gitignore ├── README.md ├── pom.xml └── src ├── main └── java │ └── org │ └── hswebframework │ └── utils │ ├── ClassUtils.java │ ├── DateTimeUtils.java │ ├── ListUtils.java │ ├── MapUtils.java │ ├── PinyinUtils.java │ ├── RandomUtil.java │ ├── StringUtils.java │ ├── file │ ├── BytesEncodingDetect.java │ ├── ClassLoaderWrapper.java │ ├── Encoding.java │ ├── EncodingDetect.java │ ├── FileUtils.java │ ├── Resources.java │ └── callback │ │ ├── AbstractScanCallBack.java │ │ ├── CanExitCallBack.java │ │ ├── ReadCallBack.java │ │ ├── ReadStringCallBack.java │ │ └── ScanCallBack.java │ └── time │ ├── DateFormatter.java │ ├── SmartDateFormatter.java │ └── Utils.java └── test └── java └── org └── hswebframework └── utils └── time ├── TimeTests.java └── UtilsTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /upload 2 | **/target/ 3 | **/out/ 4 | bin/ 5 | *.class 6 | # Mobile Tools for Java (J2ME) 7 | .mtj.tmp/ 8 | .idea/ 9 | /nbproject 10 | *.ipr 11 | *.iws 12 | *.iml 13 | *.db 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | 19 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 20 | hs_err_pid* 21 | pom.xml.versionsBackup -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hsweb-utils 2 | 常用工具类 3 | 4 | [![Maven Central](https://img.shields.io/maven-central/v/org.hswebframework/hsweb-utils.svg?style=plastic)](http://search.maven.org/#search%7Cga%7C1%7Chsweb-utils) 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.hswebframework 8 | hsweb-utils 9 | 3.0.5-SNAPSHOT 10 | 11 | ${project.groupId}:${project.artifactId} 12 | hsweb utils 13 | https://github.com/hs-web/hsweb-utils 14 | 15 | 16 | 17 | The Apache License, Version 2.0 18 | https://www.apache.org/licenses/LICENSE-2.0.txt 19 | 20 | 21 | 22 | 23 | 24 | zhouhao 25 | i@hsweb.me 26 | 27 | Owner 28 | 29 | +8 30 | https://github.com/zhou-hao 31 | 32 | 33 | 34 | 35 | scm:git:https://github.com/hs-web/hsweb-utils.git 36 | scm:git:https://github.com/hs-web/hsweb-utils.git 37 | https://github.com/hs-web/hsweb-utils 38 | ${project.version} 39 | 40 | 41 | 42 | 43 | UTF-8 44 | zh_CN 45 | 1.8 46 | 4.11 47 | 48 | 49 | 50 | 51 | release 52 | 53 | 54 | 55 | org.sonatype.plugins 56 | nexus-staging-maven-plugin 57 | 1.6.3 58 | true 59 | 60 | sonatype-releases 61 | https://oss.sonatype.org/ 62 | true 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-release-plugin 68 | 69 | true 70 | false 71 | release 72 | deploy 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-gpg-plugin 78 | 1.5 79 | 80 | 81 | sign-artifacts 82 | verify 83 | 84 | sign 85 | 86 | 87 | 88 | 89 | 90 | org.apache.maven.plugins 91 | maven-javadoc-plugin 92 | 2.9.1 93 | 94 | -Xdoclint:none 95 | 96 | 97 | 98 | attach-javadocs 99 | 100 | jar 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | org.apache.maven.plugins 114 | maven-scm-plugin 115 | 1.8.1 116 | 117 | connection 118 | 119 | 120 | 121 | 122 | maven-source-plugin 123 | 2.4 124 | 125 | true 126 | 127 | 128 | 129 | compile 130 | 131 | jar 132 | 133 | 134 | 135 | 136 | 137 | 138 | org.apache.maven.plugins 139 | maven-compiler-plugin 140 | 3.1 141 | 142 | ${project.build.jdk} 143 | ${project.build.jdk} 144 | ${project.build.sourceEncoding} 145 | 146 | 147 | 148 | 149 | org.apache.maven.plugins 150 | maven-surefire-plugin 151 | 2.17 152 | 153 | 154 | 155 | **/org/hswebframework/**/*Tests.java 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | junit 166 | junit 167 | 4.13.2 168 | test 169 | 170 | 171 | 172 | joda-time 173 | joda-time 174 | 2.7 175 | 176 | 177 | 178 | 179 | com.belerweb 180 | pinyin4j 181 | 2.5.0 182 | true 183 | 184 | 185 | 186 | 187 | hsweb-nexus 188 | Nexus Release Repository 189 | https://nexus.jetlinks.cn/content/groups/public/ 190 | 191 | true 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | sonatype-releases 211 | sonatype repository 212 | https://oss.sonatype.org/service/local/staging/deploy/maven2 213 | 214 | 215 | sonatype-snapshots 216 | Nexus Snapshot Repository 217 | https://oss.sonatype.org/content/repositories/snapshots 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.ParameterizedType; 6 | import java.lang.reflect.Type; 7 | import java.util.*; 8 | 9 | public class ClassUtils { 10 | 11 | /** 12 | * 获取一个类的注解,如果未获取到则获取父类 13 | * 14 | * @param clazz 要获取的类 15 | * @param annotation 注解类型 16 | * @param 注解类型泛型 17 | * @return 注解 18 | */ 19 | public static T getAnnotation(Class clazz, Class annotation) { 20 | T ann = clazz.getAnnotation(annotation); 21 | if (ann != null) { 22 | return ann; 23 | } else { 24 | if (clazz.getSuperclass() != Object.class) { 25 | //尝试获取父类 26 | return getAnnotation(clazz.getSuperclass(), annotation); 27 | } 28 | } 29 | return ann; 30 | } 31 | 32 | /** 33 | * 获取一个方法的注解,如果未获取则获取父类方法 34 | * 35 | * @param method 要获取的方法 36 | * @param annotation 注解类型 37 | * @param 注解类型泛型 38 | * @return 39 | */ 40 | public static T getAnnotation(Method method, Class annotation) { 41 | T ann = method.getAnnotation(annotation); 42 | if (ann != null) { 43 | return ann; 44 | } else { 45 | Class clazz = method.getDeclaringClass(); 46 | Class superClass = clazz.getSuperclass(); 47 | if (superClass != Object.class) { 48 | try { 49 | //父类方法 50 | Method suMethod = superClass.getMethod(method.getName(), method.getParameterTypes()); 51 | return getAnnotation(suMethod, annotation); 52 | } catch (NoSuchMethodException e) { 53 | return null; 54 | } 55 | } 56 | } 57 | return ann; 58 | } 59 | 60 | public static Class getGenericTypeByType(ParameterizedType genType, int index) { 61 | Type[] params = genType.getActualTypeArguments(); 62 | if (index >= params.length || index < 0) { 63 | return null; 64 | } 65 | Object res = params[index]; 66 | if (res instanceof Class) { 67 | return ((Class) res); 68 | } 69 | if (res instanceof ParameterizedType) { 70 | return (Class) ((ParameterizedType) res).getRawType(); 71 | } 72 | return null; 73 | } 74 | 75 | /** 76 | * 获取一个类的泛型类型,如果未获取到返回Object.class 77 | * 78 | * @param clazz 要获取的类 79 | * @param index 泛型索引 80 | * @return 泛型 81 | */ 82 | public static Class getGenericType(Class clazz, int index) { 83 | List arrys = new ArrayList<>(); 84 | arrys.add(clazz.getGenericSuperclass()); 85 | arrys.addAll(Arrays.asList(clazz.getGenericInterfaces())); 86 | return arrys.stream() 87 | .filter(Objects::nonNull) 88 | .map(type -> { 89 | if (clazz != Object.class && !(type instanceof ParameterizedType)) { 90 | return getGenericType(clazz.getSuperclass(), index); 91 | } 92 | return getGenericTypeByType(((ParameterizedType) type), index); 93 | }) 94 | .filter(Objects::nonNull) 95 | .filter(res -> res != Object.class) 96 | .findFirst() 97 | .orElse((Class) Object.class); 98 | } 99 | 100 | /** 101 | * 获取一个类的第一个泛型的类型 102 | * 103 | * @param clazz 要获取的类 104 | * @return 泛型 105 | */ 106 | public static Class getGenericType(Class clazz) { 107 | return getGenericType(clazz, 0); 108 | } 109 | 110 | 111 | public static boolean instanceOf(Class clazz, Class target) { 112 | if (clazz == null) return false; 113 | if (clazz == target) return true; 114 | if (target.isInterface()) { 115 | for (Class aClass : clazz.getInterfaces()) { 116 | if (aClass == target) return true; 117 | } 118 | } 119 | if (clazz.getSuperclass() == target) return true; 120 | else { 121 | if (clazz.isInterface()) { 122 | for (Class aClass : clazz.getInterfaces()) { 123 | if (instanceOf(aClass, target)) return true; 124 | } 125 | } 126 | return instanceOf(clazz.getSuperclass(), target); 127 | } 128 | } 129 | 130 | /** 131 | * 将对象转为指定的类型 132 | *
133 | * 支持日期,数字,boolean类型转换 134 | * 135 | * @param value 需要转换的值 136 | * @param type 目标类型 137 | * @return 转换后的值 138 | */ 139 | public static final T cast(Object value, Class type) { 140 | if (value == null) return null; 141 | Object newVal = null; 142 | if (ClassUtils.instanceOf(value.getClass(), type)) { 143 | newVal = value; 144 | } else if (type == Integer.class || type == int.class) { 145 | newVal = StringUtils.toInt(value); 146 | } else if (type == Double.class || type == double.class || type == Float.class || type == float.class) { 147 | newVal = StringUtils.toDouble(value); 148 | } else if (type == Long.class || type == long.class) { 149 | newVal = StringUtils.toLong(value); 150 | } else if (type == Boolean.class || type == boolean.class) { 151 | newVal = StringUtils.isTrue(value); 152 | } else if (type == Date.class) { 153 | newVal = DateTimeUtils.formatUnknownString2Date(value.toString()); 154 | } else if (type == String.class) { 155 | if (value instanceof Date) { 156 | newVal = DateTimeUtils.format(((Date) value), DateTimeUtils.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); 157 | } else 158 | newVal = String.valueOf(value); 159 | } 160 | return (T) newVal; 161 | } 162 | 163 | public static final Set basicClass = new HashSet<>(); 164 | 165 | static { 166 | basicClass.add(int.class); 167 | basicClass.add(double.class); 168 | basicClass.add(float.class); 169 | basicClass.add(byte.class); 170 | basicClass.add(short.class); 171 | basicClass.add(char.class); 172 | basicClass.add(String.class); 173 | } 174 | 175 | public static boolean isBasicClass(Class clazz) { 176 | return basicClass.contains(clazz); 177 | } 178 | 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/DateTimeUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | import org.joda.time.DateTime; 4 | import org.joda.time.Days; 5 | import org.joda.time.format.DateTimeFormat; 6 | import org.joda.time.format.DateTimeFormatter; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * 日期时间工具类 12 | */ 13 | @Deprecated 14 | public final class DateTimeUtils { 15 | 16 | /** 17 | * 年(yyyy) 18 | */ 19 | public static final String YEAR = "yyyy"; 20 | 21 | /** 22 | * 年-月(yyyy-MM) 23 | */ 24 | public static final String YEAR_MONTH = "yyyy-MM"; 25 | 26 | /** 27 | * 年-月-日(yyyy-MM-dd) 28 | */ 29 | public static final String YEAR_MONTH_DAY = "yyyy-MM-dd"; 30 | 31 | /** 32 | * 年月日(yyyyMMdd) 33 | */ 34 | public static final String YEAR_MONTH_DAY_SIMPLE = "yyyyMMdd"; 35 | 36 | /** 37 | * 年-月-日 小时(yyyy-MM-dd HH) 38 | */ 39 | public static final String YEAR_MONTH_DAY_HOUR = "yyyy-MM-dd HH"; 40 | 41 | /** 42 | * 年-月-日 小时(yyyy-MM-dd HH)中文输出 43 | */ 44 | public static final String YEAR_MONTH_DAY_HOUR_CN = "yyyy年MM月dd日HH时"; 45 | 46 | /** 47 | * 年-月-日 小时:分钟(yyyy-MM-dd HH:mm) 48 | */ 49 | public static final String YEAR_MONTH_DAY_HOUR_MINUTE = "yyyy-MM-dd HH:mm"; 50 | 51 | /** 52 | * 年-月-日 小时:分钟:秒钟(yyyy-MM-dd HH:mm:ss) 53 | */ 54 | public static final String YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; 55 | 56 | /** 57 | * 年月日小时分钟秒钟(yyyyMMddHHmmss) 58 | */ 59 | public static final String YEAR_MONTH_DAY_HOUR_MINUTE_SECOND_SIMPLE = "yyyyMMddHHmmss"; 60 | 61 | /** 62 | * 小时:分钟:秒钟(HH:mm:ss) 63 | */ 64 | public static final String HOUR_MINUTE_SECOND = "HH:mm:ss"; 65 | 66 | /** 67 | * 小时:分钟(HH:mm) 68 | */ 69 | public static final String HOUR_MINUTE = "HH:mm"; 70 | 71 | /** 72 | * 月.日(M.d) 73 | */ 74 | public static final String MONTH_DAY = "M.d"; 75 | 76 | /** 77 | * 一天的秒数 78 | */ 79 | private static final int DAY_SECOND = 24 * 60 * 60; 80 | 81 | /** 82 | * 一小时的秒数 83 | */ 84 | private static final int HOUR_SECOND = 60 * 60; 85 | 86 | /** 87 | * 一分钟的秒数 88 | */ 89 | private static final int MINUTE_SECOND = 60; 90 | 91 | /** 92 | * 格式化日期时间 93 | * 94 | * @param date Date对象 95 | * @param pattern 模式 96 | * @return 格式化后的日期时间字符串 97 | */ 98 | public static String format(Date date, String pattern) { 99 | if (date == null) 100 | return ""; 101 | return new DateTime(date).toString(pattern); 102 | } 103 | 104 | /** 105 | * 格式化日期时间字符串 106 | * 107 | * @param dateString 日期时间字符串 108 | * @param pattern 模式 109 | * @return Date对象 110 | */ 111 | public static Date formatDateString(String dateString, String pattern) { 112 | try { 113 | DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(pattern); 114 | return dateTimeFormatter.parseDateTime(dateString).toDate(); 115 | } catch (Exception e) { 116 | return null; 117 | } 118 | } 119 | 120 | /** 121 | * 根据秒数获得x天x小时x分钟x秒字符串 122 | * 123 | * @param second 秒数 124 | * @return x天x小时x分钟x秒字符串 125 | */ 126 | public static String getDayHourMinuteSecond(int second) { 127 | if (second == 0) { 128 | return "0秒"; 129 | } 130 | StringBuilder sb = new StringBuilder(); 131 | int days = second / DAY_SECOND; 132 | if (days > 0) { 133 | sb.append(days); 134 | sb.append("天"); 135 | second -= days * DAY_SECOND; 136 | } 137 | 138 | int hours = second / HOUR_SECOND; 139 | if (hours > 0) { 140 | sb.append(hours); 141 | sb.append("小时"); 142 | second -= hours * HOUR_SECOND; 143 | } 144 | 145 | int minutes = second / MINUTE_SECOND; 146 | if (minutes > 0) { 147 | sb.append(minutes); 148 | sb.append("分钟"); 149 | second -= minutes * MINUTE_SECOND; 150 | } 151 | if (second > 0) { 152 | sb.append(second); 153 | sb.append("秒"); 154 | } 155 | return sb.toString(); 156 | } 157 | 158 | 159 | /** 160 | * 根据秒数获得x天x小时x分钟字符串 161 | * 162 | * @param second 秒数 163 | * @return x天x小时x分钟字符串 164 | */ 165 | public static String getDayHourMinute(int second) { 166 | if (second == 0) { 167 | return "0分钟"; 168 | } 169 | StringBuilder sb = new StringBuilder(); 170 | int days = second / DAY_SECOND; 171 | if (days > 0) { 172 | sb.append(days); 173 | sb.append("天"); 174 | second -= days * DAY_SECOND; 175 | } 176 | 177 | int hours = second / HOUR_SECOND; 178 | if (hours > 0) { 179 | sb.append(hours); 180 | sb.append("小时"); 181 | second -= hours * HOUR_SECOND; 182 | } 183 | int minutes = second / MINUTE_SECOND; 184 | if (minutes > 0) { 185 | sb.append(minutes); 186 | sb.append("分钟"); 187 | } 188 | return sb.toString(); 189 | } 190 | 191 | /** 192 | * 获取只含有年月日的DateTime对象 193 | * 194 | * @param dateTime DateTime对象 195 | * @return 只含有年月日的DateTime对象 196 | */ 197 | public static DateTime getDateOnly(DateTime dateTime) { 198 | return new DateTime(dateTime.toString(YEAR_MONTH_DAY)); 199 | } 200 | 201 | /** 202 | * 获取当前周的周一和下周一 203 | * 204 | * @return 日期数组(索引0为周一,索引1为下周一) 205 | */ 206 | public static Date[] getMondayAndNextMonday() { 207 | DateTime dateTime = getDateOnly(new DateTime()); 208 | DateTime monday = dateTime.dayOfWeek().withMinimumValue(); 209 | DateTime nextMonday = monday.plusDays(7); 210 | return new Date[]{monday.toDate(), nextMonday.toDate()}; 211 | } 212 | 213 | /** 214 | * 获取指定时间的周一和周日 215 | * 216 | * @param dateTime DateTime对象 217 | * @return 日期数组(索引0为周一,索引1为周日) 218 | */ 219 | public static Date[] getMondayAndSunday(DateTime dateTime) { 220 | dateTime = getDateOnly(dateTime); 221 | DateTime monday = dateTime.dayOfWeek().withMinimumValue(); 222 | DateTime sunday = monday.plusDays(6); 223 | return new Date[]{monday.toDate(), sunday.toDate()}; 224 | } 225 | 226 | /** 227 | * 和当前时间相比的天数差(正数为大于天数,负数为小于天数,零为同一天) 228 | * 229 | * @param date Date对象 230 | * @return 和当前时间相比的天数差 231 | */ 232 | public static int compareDaysWithNow(Date date) { 233 | return Days.daysBetween(new DateTime(), new DateTime(date)).getDays(); 234 | } 235 | 236 | /** 237 | * 和今天相比的天数差(正数为大于天数,负数为小于天数,零为同一天) 238 | * 239 | * @param date Date对象 240 | * @return 和今天相比的天数差 241 | */ 242 | public static int compareDaysWithToday(Date date) { 243 | DateTime today = new DateTime(); 244 | today = new DateTime(today.getYear(), today.getMonthOfYear(), today.getDayOfMonth(), 0, 0, 0, 0); 245 | DateTime compareDay = new DateTime(date); 246 | compareDay = new DateTime(compareDay.getYear(), compareDay.getMonthOfYear(), compareDay.getDayOfMonth(), 0, 0, 0, 0); 247 | return Days.daysBetween(today, compareDay).getDays(); 248 | } 249 | 250 | /** 251 | * 比较时间a到时间b的天数差 252 | * 253 | * @param a 时间a 254 | * @param b 时间b 255 | * @return 相差天数 256 | */ 257 | public static int compareDaysWithDay(Date a, Date b) { 258 | DateTime today = new DateTime(b); 259 | today = new DateTime(today.getYear(), today.getMonthOfYear(), today.getDayOfMonth(), 0, 0, 0, 0); 260 | DateTime compareDay = new DateTime(a); 261 | compareDay = new DateTime(compareDay.getYear(), compareDay.getMonthOfYear(), compareDay.getDayOfMonth(), 0, 0, 0, 0); 262 | return Days.daysBetween(today, compareDay).getDays(); 263 | } 264 | 265 | /** 266 | * 比较两个时间是否相等(省略毫秒) 267 | * 268 | * @param date Date对象 269 | * @param compareDate 比较Date对象 270 | * @return 是否相等 271 | */ 272 | public static boolean compareDateIgnoreMillisecond(Date date, Date compareDate) { 273 | if (date == null && compareDate == null) { 274 | return true; 275 | } else if (date == null && compareDate != null) { 276 | return false; 277 | } else if (date != null && compareDate == null) { 278 | return false; 279 | } 280 | 281 | return (date.getTime() / 1000 == compareDate.getTime() / 1000); 282 | } 283 | 284 | /** 285 | * 根据秒数获取天数 286 | * 287 | * @param second 秒数 288 | * @return 天数 289 | */ 290 | public static int getDay(int second) { 291 | return second / DAY_SECOND; 292 | } 293 | 294 | /** 295 | * 获取和今天相比的日期字符串 296 | * 297 | * @param date Date对象 298 | * @return 和今天相比的日期字符串 299 | */ 300 | public static String getCompareWithTodayDateString(Date date) { 301 | int days = Math.abs(DateTimeUtils.compareDaysWithToday(date)); 302 | String dateString = ""; 303 | if (days == 0) { 304 | dateString = "今天"; 305 | } else if (days == 1) { 306 | dateString = "昨天"; 307 | } else if (days == 2) { 308 | dateString = "2天前"; 309 | } else if (days == 3) { 310 | dateString = "3天前"; 311 | } else if (days == 4) { 312 | dateString = "4天前"; 313 | } else if (days == 5) { 314 | dateString = "5天前"; 315 | } else if (days == 6) { 316 | dateString = "6天前"; 317 | } else if (days > 6 && days <= 14) { 318 | dateString = "1周前"; 319 | } else if (days > 14 && days <= 21) { 320 | dateString = "2周前"; 321 | } else if (days > 21 && days <= 30) { 322 | dateString = "3周前"; 323 | } else if (days > 30) { 324 | dateString = "1月前"; 325 | } else if (days > 365) { 326 | dateString = "1年前"; 327 | } else if (days > 365 * 3) { 328 | dateString = "3年前"; 329 | } 330 | return dateString; 331 | } 332 | 333 | /** 334 | * 比较两个时间相差分钟数 335 | * 336 | * @param now 当前时间 337 | * @param compareDate 比较时间 338 | * @return 相差分钟数 339 | */ 340 | public static int compareMinutes(Date now, Date compareDate) { 341 | return (int) (now.getTime() - compareDate.getTime()) / 60000; 342 | } 343 | 344 | /** 345 | * 比较时间是本月的第几天 346 | * 347 | * @param date 348 | * @return 349 | */ 350 | public static int getDayOfMonth(Date date) { 351 | DateTime dateTime = new DateTime(date); 352 | return dateTime.getDayOfMonth(); 353 | } 354 | 355 | /** 356 | * 计算当月有几天 357 | * 358 | * @param date 359 | * @return 360 | */ 361 | public static int getDateOfMonth(Date date) { 362 | DateTime dateTime = new DateTime(date); 363 | return dateTime.dayOfMonth().getMaximumValue(); 364 | } 365 | 366 | /** 367 | * 指定时间,判断该时间到现在时间的年数 368 | * 369 | * @param date 指定时间 370 | * @return 到现在时间的年数 371 | */ 372 | public static int compareYear(Date date) { 373 | DateTime btd = new DateTime(date); 374 | DateTime nowDate = new DateTime(); 375 | int year = 0; 376 | if (nowDate.getMonthOfYear() > btd.getMonthOfYear()) { 377 | year = nowDate.getYear() - btd.getYear(); 378 | } else if (nowDate.getMonthOfYear() < btd.getMonthOfYear()) { 379 | year = nowDate.getYear() - btd.getYear() - 1; 380 | } else if (nowDate.getMonthOfYear() == btd.getMonthOfYear()) { 381 | if (nowDate.getDayOfMonth() >= btd.getDayOfMonth()) { 382 | year = nowDate.getYear() - btd.getYear(); 383 | } else { 384 | year = nowDate.getYear() - btd.getYear() - 1; 385 | } 386 | } 387 | return year; 388 | } 389 | 390 | /** 391 | * 判断2个时间的时间差 返回字符串形式 392 | * 393 | * @param date 要对比的字符串 394 | * @param date2 要对比的字符串 395 | * @return 字符串形式 如1小时 ,2天2小时 396 | */ 397 | public static String compareDaysWithDate(Date date, Date date2) { 398 | StringBuilder msg = new StringBuilder(); 399 | int minutes = (int) Math.abs((date.getTime() - date2.getTime()) / 60000); 400 | if (minutes / 60 > 0 && minutes / 60 / 24 <= 0) { 401 | msg.append(minutes / 60 + "小时"); 402 | } 403 | if (minutes / 60 / 24 > 0) { 404 | msg.append(minutes / 60 / 24 + "天"); 405 | msg.append(minutes / 60 % 24 + "小时"); 406 | } 407 | return msg.toString(); 408 | } 409 | 410 | public static final String REG_EXP_DATE = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"; 411 | 412 | /** 413 | * 自动解析多种格式的时间字符串为时间对象
414 | * 支持格式为:yyyy-MM-dd HH:mm:ss 支持多种分隔符,以及多种日期精度。 如yyyy年MM月。 HH时mm分ss秒 415 | * 416 | * @param dateString 时间字符串
417 | * @return 格式正确则返回对应的java.util.Date对象 格式错误返回null 418 | */ 419 | public static Date formatUnknownString2Date(String dateString) { 420 | try { 421 | if (StringUtils.isNullOrEmpty(dateString)) { 422 | return null; 423 | } 424 | dateString = dateString.replace("T", " "); 425 | String hms = "00:00:00"; 426 | dateString = dateString.trim(); 427 | if (dateString.contains(" ")) { 428 | // 截取时分秒 429 | hms = dateString.substring(dateString.indexOf(" ") + 1, dateString.length()); 430 | // 重置日期 431 | dateString = dateString.substring(0, dateString.indexOf(" ")); 432 | // 多中分隔符的支持 433 | hms = hms.replace(":", ":"); 434 | hms = hms.replace("时", ":"); 435 | hms = hms.replace("分", ":"); 436 | hms = hms.replace("秒", ":"); 437 | hms = hms.replace("-", ":"); 438 | hms = hms.replace("-", ":"); 439 | // 时间不同精确度的支持 440 | if (hms.endsWith(":")) { 441 | hms = hms.substring(0, hms.length() - 1); 442 | } 443 | if (hms.split(":").length == 1) { 444 | hms += ":00:00"; 445 | } 446 | if (hms.split(":").length == 2) { 447 | hms += ":00"; 448 | } 449 | } 450 | String[] hmsarr = hms.split(":"); 451 | // 不同日期分隔符的支持 452 | dateString = dateString.replace(".", "-"); 453 | dateString = dateString.replace("/", "-"); 454 | dateString = dateString.replace("-", "-"); 455 | dateString = dateString.replace("年", "-"); 456 | dateString = dateString.replace("月", "-"); 457 | dateString = dateString.replace("日", ""); 458 | // 切割年月日 459 | String yearStr, monthStr, dateStr; 460 | // 截取日期 461 | String[] ymd = dateString.split("-"); 462 | // 判断日期精确度 463 | yearStr = ymd[0]; 464 | monthStr = ymd.length > 1 ? ymd[1] : ""; 465 | dateStr = ymd.length > 2 ? ymd[2] : ""; 466 | monthStr = monthStr == "" ? Integer.toString(1) : monthStr; 467 | dateStr = dateStr == "" ? Integer.toString(1) : dateStr; 468 | String dtr = (yearStr + "-" + monthStr + "-" + dateStr + " " + hms); 469 | if (!dtr.matches(REG_EXP_DATE)) 470 | return null; 471 | // 返回日期 472 | return new DateTime(Integer.parseInt(yearStr.trim()), Integer.parseInt(monthStr.trim()), Integer.parseInt(dateStr.trim()), Integer.parseInt(hmsarr[0].trim()), Integer.parseInt(hmsarr[1].trim()), Integer.parseInt(hmsarr[2].trim()), 0).toDate(); 473 | } catch (Exception e) { 474 | return null; 475 | } 476 | } 477 | 478 | /** 479 | * 解析多个时间,指定时间之间的分隔符和时间的格式符 分隔符不能与格式符相同 480 | * 481 | * @param dateString 传入一个时间段字符串 482 | * @param spaceChar 指定格式符 483 | * @param splitChar 指定分隔符 484 | * @return 格式正确返回分割后的时间对象数组 格式错误返回null
485 | * 指定了格式符为. 分隔符为- 返回值为 时间长度为2的Date类型数组
486 | * 时间转换的方式详见 {@link DateTimeUtils#formatUnknownString2Date(String dateString)} 487 | */ 488 | public static Date[] formatDatesByString(String dateString, String spaceChar, String splitChar) { 489 | if (spaceChar.equals(splitChar)) { 490 | return null; 491 | } 492 | String[] dateStrs = dateString.split(splitChar); 493 | Date[] dates = new Date[dateStrs.length]; 494 | for (int i = 0, size = dateStrs.length; i < size; i++) { 495 | dates[i] = formatUnknownString2Date(dateStrs[i]); 496 | } 497 | return dates; 498 | } 499 | 500 | /** 501 | * 身份证号转生日 502 | * 503 | * @param identityCard 身份证 504 | * @return 生日 505 | */ 506 | public static Date identityCard2Date(String identityCard) { 507 | try { 508 | String dateStr; 509 | if (identityCard.length() == 18) { 510 | dateStr = identityCard.substring(6, 14);// 截取18位身份证身份证中生日部分 511 | return formatDateString(dateStr, "yyyyMMdd"); 512 | } 513 | if (identityCard.length() == 15) { 514 | dateStr = identityCard.substring(6, 12);// 截取15位身份证中生日部分 515 | return formatDateString(dateStr, "yyMMdd"); 516 | } 517 | return null; 518 | } catch (Exception e) { 519 | return null; 520 | } 521 | } 522 | 523 | public static boolean validDate(String str) { 524 | try { 525 | Date date = formatUnknownString2Date(str); 526 | return date != null; 527 | } catch (Exception e) { 528 | return false; 529 | } 530 | } 531 | } 532 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/ListUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.function.Supplier; 7 | 8 | @Deprecated 9 | public class ListUtils { 10 | public static boolean isNullOrEmpty(List list) { 11 | return list == null || list.isEmpty(); 12 | } 13 | 14 | public static String toString(Object... objs) { 15 | StringBuffer buffer = new StringBuffer(); 16 | for (int i = 0; i < objs.length; i++) { 17 | if (i != 0) 18 | buffer.append(","); 19 | buffer.append(objs[i]); 20 | } 21 | return buffer.toString(); 22 | } 23 | 24 | public static Integer[] stringArr2intArr(String[] arr) { 25 | Integer[] i = new Integer[arr.length]; 26 | int index = 0; 27 | for (String str : arr) { 28 | if (StringUtils.isInt(str)) { 29 | i[index++] = Integer.parseInt(str); 30 | } 31 | } 32 | return i; 33 | } 34 | 35 | public static List merge(List list, List... lists) { 36 | return merge(new ArrayList<>(), list, lists); 37 | } 38 | 39 | public static List merge(List target, List list, List... lists) { 40 | target.addAll(list); 41 | for (int i = 0; i < lists.length; i++) { 42 | target.addAll(lists[i]); 43 | } 44 | return target; 45 | } 46 | 47 | public static List merge(Supplier> supplier, List list, List... lists) { 48 | return merge(supplier.get(), list, lists); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/MapUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | 4 | import java.util.*; 5 | import java.util.function.Supplier; 6 | 7 | @Deprecated 8 | public class MapUtils { 9 | 10 | public static boolean isNullOrEmpty(Map map) { 11 | return map == null || map.isEmpty(); 12 | } 13 | 14 | public static Map removeEmptyValue(Map map) { 15 | Map newMap = new HashMap<>(); 16 | if (map == null) 17 | return newMap; 18 | map.entrySet().stream().filter(entry -> !StringUtils.isNullOrEmpty(entry.getValue())).forEach(entry -> { 19 | newMap.put(entry.getKey(), entry.getValue()); 20 | }); 21 | return newMap; 22 | } 23 | 24 | public static Map sortMapByKey(Map data) { 25 | Map data_ = new LinkedHashMap<>(); 26 | List list = new LinkedList<>(data.keySet()); 27 | Collections.sort(list); 28 | for (K k : list) { 29 | data_.put(k, data.get(k)); 30 | } 31 | return data_; 32 | } 33 | 34 | public static Map merge(Map map, Map maps) { 35 | return merge(new HashMap<>(), map, maps); 36 | } 37 | 38 | public static Map merge(Map target, Map map, Map... maps) { 39 | target.putAll(map); 40 | for (int i = 0; i < maps.length; i++) { 41 | target.putAll(maps[i]); 42 | } 43 | return target; 44 | } 45 | 46 | public static Map merge(Supplier> supplier, Map map, Map... maps) { 47 | return merge(supplier.get(), map, maps); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/PinyinUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | import net.sourceforge.pinyin4j.PinyinHelper; 4 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 5 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 6 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 7 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; 8 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 9 | 10 | public class PinyinUtils { 11 | /** 12 | * 获取汉字全拼 13 | * 14 | * @param str 汉字字符串 15 | * @return 汉字字符串全拼 16 | */ 17 | public static String toPingYin(String str) { 18 | char[] t1 = str.toCharArray(); 19 | String[] t2; 20 | HanyuPinyinOutputFormat t3 = new HanyuPinyinOutputFormat(); 21 | t3.setCaseType(HanyuPinyinCaseType.LOWERCASE); 22 | t3.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 23 | t3.setVCharType(HanyuPinyinVCharType.WITH_V); 24 | StringBuilder t4 = new StringBuilder(); 25 | try { 26 | for (char c : t1) { 27 | // 判断是否为汉字字符 28 | if (StringUtils.containsChineseChar(Character.toString(c))) { 29 | t2 = PinyinHelper.toHanyuPinyinStringArray(c, t3); 30 | t4.append(t2[0]); 31 | } else { 32 | t4.append(c); 33 | } 34 | } 35 | return t4.toString(); 36 | } catch (BadHanyuPinyinOutputFormatCombination ignore) { 37 | } 38 | return t4.toString(); 39 | } 40 | 41 | /** 42 | * 获取中文字符串首字母 43 | * 44 | * @param str 字符串 45 | * @return 字符串首字母 46 | */ 47 | public static String toPinYinHeadChar(String str) { 48 | StringBuilder convert = new StringBuilder(); 49 | for (int j = 0; j < str.length(); j++) { 50 | char word = str.charAt(j); 51 | String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word); 52 | if (pinyinArray != null) { 53 | convert.append(pinyinArray[0].charAt(0)); 54 | } else { 55 | convert.append(word); 56 | } 57 | } 58 | return convert.toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | import java.util.Random; 4 | import java.util.concurrent.ThreadLocalRandom; 5 | 6 | /** 7 | * 随机数工具,用于产生随机数,随机密码等 8 | */ 9 | public class RandomUtil { 10 | 11 | public static Random getRandom() { 12 | return ThreadLocalRandom.current(); 13 | } 14 | 15 | private static final char[] chars = { 16 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 17 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 18 | 'o', 'p', 'q', 'r', 's', 't', 'u', 19 | 'v', 'w', 'x', 'y', 'z', 20 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 21 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 22 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 23 | 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 24 | 'V', 'W', 'X', 'Y', 'Z' 25 | }; 26 | 27 | /** 28 | * 随机生成由0-9a-zA-Z组合而成的字符串 29 | * 30 | * @param len 字符串长度 31 | * @return 生成结果 32 | */ 33 | public static String randomChar(int len) { 34 | StringBuilder sb = new StringBuilder(); 35 | for (int i = 0; i < len; i++) { 36 | sb.append(chars[ThreadLocalRandom.current().nextInt(chars.length)]); 37 | } 38 | return sb.toString(); 39 | } 40 | 41 | public static String randomChar() { 42 | return randomChar(8); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils; 2 | 3 | import java.io.PrintWriter; 4 | import java.io.StringWriter; 5 | import java.util.Arrays; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * 字符操作常用方法集 13 | * Created by zhouhao on 16-6-6. 14 | */ 15 | public class StringUtils { 16 | /** 17 | * 编译后的正则表达式缓存 18 | */ 19 | private static final Map PATTERN_CACHE = new ConcurrentHashMap<>(); 20 | 21 | /** 22 | * 编译一个正则表达式,并且进行缓存,如果换成已存在则使用缓存 23 | * 24 | * @param regex 表达式 25 | * @return 编译后的Pattern 26 | */ 27 | public static final Pattern compileRegex(String regex) { 28 | Pattern pattern = PATTERN_CACHE.get(regex); 29 | if (pattern == null) { 30 | pattern = Pattern.compile(regex); 31 | PATTERN_CACHE.put(regex, pattern); 32 | } 33 | return pattern; 34 | } 35 | 36 | /** 37 | * 将字符串的第一位转为小写 38 | * 39 | * @param str 需要转换的字符串 40 | * @return 转换后的字符串 41 | */ 42 | public static String toLowerCaseFirstOne(String str) { 43 | if (Character.isLowerCase(str.charAt(0))) 44 | return str; 45 | else { 46 | char[] chars = str.toCharArray(); 47 | chars[0] = Character.toLowerCase(chars[0]); 48 | return new String(chars); 49 | } 50 | } 51 | 52 | /** 53 | * 将字符串的第一位转为大写 54 | * 55 | * @param str 需要转换的字符串 56 | * @return 转换后的字符串 57 | */ 58 | public static String toUpperCaseFirstOne(String str) { 59 | if (Character.isUpperCase(str.charAt(0))) 60 | return str; 61 | else { 62 | char[] chars = str.toCharArray(); 63 | chars[0] = Character.toUpperCase(chars[0]); 64 | return new String(chars); 65 | } 66 | } 67 | 68 | /** 69 | * 下划线命名转为驼峰命名 70 | * 71 | * @param str 下划线命名格式 72 | * @return 驼峰命名格式 73 | */ 74 | public static final String underScoreCase2CamelCase(String str) { 75 | if (!str.contains("_")) return str; 76 | StringBuilder sb = new StringBuilder(); 77 | char[] chars = str.toCharArray(); 78 | boolean hitUnderScore = false; 79 | sb.append(chars[0]); 80 | for (int i = 1; i < chars.length; i++) { 81 | char c = chars[i]; 82 | if (c == '_') { 83 | hitUnderScore = true; 84 | } else { 85 | if (hitUnderScore) { 86 | sb.append(Character.toUpperCase(c)); 87 | hitUnderScore = false; 88 | } else { 89 | sb.append(c); 90 | } 91 | } 92 | } 93 | return sb.toString(); 94 | } 95 | 96 | /** 97 | * 驼峰命名法转为下划线命名 98 | * 99 | * @param str 驼峰命名格式 100 | * @return 下划线命名格式 101 | */ 102 | public static final String camelCase2UnderScoreCase(String str) { 103 | StringBuilder sb = new StringBuilder(); 104 | char[] chars = str.toCharArray(); 105 | for (int i = 0; i < chars.length; i++) { 106 | char c = chars[i]; 107 | if (Character.isUpperCase(c)) { 108 | sb.append("_").append(Character.toLowerCase(c)); 109 | } else { 110 | sb.append(c); 111 | } 112 | } 113 | return sb.toString(); 114 | } 115 | 116 | /** 117 | * 将异常栈信息转为字符串 118 | * 119 | * @param e 字符串 120 | * @return 异常栈 121 | */ 122 | public static String throwable2String(Throwable e) { 123 | StringWriter writer = new StringWriter(); 124 | e.printStackTrace(new PrintWriter(writer)); 125 | return writer.toString(); 126 | } 127 | 128 | /** 129 | * 字符串连接,将参数列表拼接为一个字符串 130 | * 131 | * @param more 追加 132 | * @return 返回拼接后的字符串 133 | */ 134 | public static String concat(Object... more) { 135 | return concatSpiltWith("", more); 136 | } 137 | 138 | public static String concatSpiltWith(String split, Object... more) { 139 | StringBuilder buf = new StringBuilder(); 140 | for (int i = 0; i < more.length; i++) { 141 | if (i != 0) buf.append(split); 142 | buf.append(more[i]); 143 | } 144 | return buf.toString(); 145 | } 146 | 147 | /** 148 | * 将字符串转移为ASCII码 149 | * 150 | * @param str 字符串 151 | * @return 字符串ASCII码 152 | */ 153 | public static String toASCII(String str) { 154 | StringBuffer strBuf = new StringBuffer(); 155 | byte[] bGBK = str.getBytes(); 156 | for (int i = 0; i < bGBK.length; i++) { 157 | strBuf.append(Integer.toHexString(bGBK[i] & 0xff)); 158 | } 159 | return strBuf.toString(); 160 | } 161 | 162 | public static String toUnicode(String str) { 163 | StringBuffer strBuf = new StringBuffer(); 164 | char[] chars = str.toCharArray(); 165 | for (int i = 0; i < chars.length; i++) { 166 | strBuf.append("\\u").append(Integer.toHexString(chars[i])); 167 | } 168 | return strBuf.toString(); 169 | } 170 | 171 | public static String toUnicodeString(char[] chars) { 172 | StringBuffer strBuf = new StringBuffer(); 173 | for (int i = 0; i < chars.length; i++) { 174 | strBuf.append("\\u").append(Integer.toHexString(chars[i])); 175 | } 176 | return strBuf.toString(); 177 | } 178 | 179 | static final char CN_CHAR_START = '\u4e00'; 180 | static final char CN_CHAR_END = '\u9fa5'; 181 | 182 | /** 183 | * 是否包含中文字符 184 | * 185 | * @param str 要判断的字符串 186 | * @return 是否包含中文字符 187 | */ 188 | public static boolean containsChineseChar(String str) { 189 | char[] chars = str.toCharArray(); 190 | for (int i = 0; i < chars.length; i++) { 191 | if (chars[i] >= CN_CHAR_START && chars[i] <= CN_CHAR_END) return true; 192 | } 193 | return false; 194 | } 195 | 196 | /** 197 | * 对象是否为无效值 198 | * 199 | * @param obj 要判断的对象 200 | * @return 是否为有效值(不为null 和 "" 字符串) 201 | */ 202 | public static boolean isNullOrEmpty(Object obj) { 203 | return obj == null || "".equals(obj.toString()); 204 | } 205 | 206 | /** 207 | * 参数是否是有效数字 (整数或者小数) 208 | * 209 | * @param obj 参数(对象将被调用string()转为字符串类型) 210 | * @return 是否是数字 211 | */ 212 | public static boolean isNumber(Object obj) { 213 | if (obj instanceof Number) return true; 214 | return isInt(obj) || isDouble(obj); 215 | } 216 | 217 | public static String matcherFirst(String patternStr, String text) { 218 | Pattern pattern = compileRegex(patternStr); 219 | Matcher matcher = pattern.matcher(text); 220 | String group = null; 221 | if (matcher.find()) { 222 | group = matcher.group(); 223 | } 224 | return group; 225 | } 226 | 227 | /** 228 | * 参数是否是有效整数 229 | * 230 | * @param obj 参数(对象将被调用string()转为字符串类型) 231 | * @return 是否是整数 232 | */ 233 | public static boolean isInt(Object obj) { 234 | if (isNullOrEmpty(obj)) 235 | return false; 236 | if (obj instanceof Integer) 237 | return true; 238 | return obj.toString().matches("[-+]?\\d+"); 239 | } 240 | 241 | /** 242 | * 字符串参数是否是double 243 | * 244 | * @param obj 参数(对象将被调用string()转为字符串类型) 245 | * @return 是否是double 246 | */ 247 | public static boolean isDouble(Object obj) { 248 | if (isNullOrEmpty(obj)) 249 | return false; 250 | if (obj instanceof Double || obj instanceof Float) 251 | return true; 252 | return compileRegex("[-+]?\\d+\\.\\d+").matcher(obj.toString()).matches(); 253 | } 254 | 255 | /** 256 | * 判断一个对象是否为boolean类型,包括字符串中的true和false 257 | * 258 | * @param obj 要判断的对象 259 | * @return 是否是一个boolean类型 260 | */ 261 | public static boolean isBoolean(Object obj) { 262 | if (obj instanceof Boolean) return true; 263 | String strVal = String.valueOf(obj); 264 | return "true".equalsIgnoreCase(strVal) || "false".equalsIgnoreCase(strVal); 265 | } 266 | 267 | /** 268 | * 对象是否为true 269 | * 270 | * @param obj 271 | * @return 272 | */ 273 | public static boolean isTrue(Object obj) { 274 | return "true".equals(String.valueOf(obj)); 275 | } 276 | 277 | /** 278 | * 判断一个数组里是否包含指定对象 279 | * 280 | * @param arr 对象数组 281 | * @param obj 要判断的对象 282 | * @return 是否包含 283 | */ 284 | public static boolean contains(Object arr[], Object... obj) { 285 | if (arr == null || obj == null || arr.length == 0) return false; 286 | return Arrays.asList(arr).containsAll(Arrays.asList(obj)); 287 | } 288 | 289 | /** 290 | * 将对象转为int值,如果对象无法进行转换,则使用默认值 291 | * 292 | * @param object 要转换的对象 293 | * @param defaultValue 默认值 294 | * @return 转换后的值 295 | */ 296 | public static int toInt(Object object, int defaultValue) { 297 | if (object instanceof Number) 298 | return ((Number) object).intValue(); 299 | if (isInt(object)) { 300 | return Integer.parseInt(object.toString()); 301 | } 302 | if (isDouble(object)) { 303 | return (int) Double.parseDouble(object.toString()); 304 | } 305 | return defaultValue; 306 | } 307 | 308 | /** 309 | * 将对象转为int值,如果对象不能转为,将返回0 310 | * 311 | * @param object 要转换的对象 312 | * @return 转换后的值 313 | */ 314 | public static int toInt(Object object) { 315 | return toInt(object, 0); 316 | } 317 | 318 | /** 319 | * 将对象转为long类型,如果对象无法转换,将返回默认值 320 | * 321 | * @param object 要转换的对象 322 | * @param defaultValue 默认值 323 | * @return 转换后的值 324 | */ 325 | public static long toLong(Object object, long defaultValue) { 326 | if (object instanceof Number) 327 | return ((Number) object).longValue(); 328 | if (isInt(object)) { 329 | return Long.parseLong(object.toString()); 330 | } 331 | if (isDouble(object)) { 332 | return (long) Double.parseDouble(object.toString()); 333 | } 334 | return defaultValue; 335 | } 336 | 337 | /** 338 | * 将对象转为 long值,如果无法转换,则转为0 339 | * 340 | * @param object 要转换的对象 341 | * @return 转换后的值 342 | */ 343 | public static long toLong(Object object) { 344 | return toLong(object, 0); 345 | } 346 | 347 | /** 348 | * 将对象转为Double,如果对象无法转换,将使用默认值 349 | * 350 | * @param object 要转换的对象 351 | * @param defaultValue 默认值 352 | * @return 转换后的值 353 | */ 354 | public static double toDouble(Object object, double defaultValue) { 355 | if (object instanceof Number) 356 | return ((Number) object).doubleValue(); 357 | if (isNumber(object)) { 358 | return Double.parseDouble(object.toString()); 359 | } 360 | if (null == object) return defaultValue; 361 | return 0; 362 | } 363 | 364 | /** 365 | * 将对象转为Double,如果对象无法转换,将使用默认值0 366 | * 367 | * @param object 要转换的对象 368 | * @return 转换后的值 369 | */ 370 | public static double toDouble(Object object) { 371 | return toDouble(object, 0); 372 | } 373 | 374 | /** 375 | * 分隔字符串,根据正则表达式分隔字符串,只分隔首个,剩下的的不进行分隔,如: 1,2,3,4 将分隔为 ['1','2,3,4'] 376 | * 377 | * @param str 要分隔的字符串 378 | * @param regex 分隔表达式 379 | * @return 分隔后的数组 380 | */ 381 | public static String[] splitFirst(String str, String regex) { 382 | return str.split(regex, 2); 383 | } 384 | 385 | /** 386 | * 将对象转为字符串,如果对象为null,则返回null,而不是"null" 387 | * 388 | * @param object 要转换的对象 389 | * @return 转换后的对象 390 | */ 391 | public static String toString(Object object) { 392 | return toString(object, null); 393 | } 394 | 395 | /** 396 | * 将对象转为字符串,如果对象为null,则使用默认值 397 | * 398 | * @param object 要转换的对象 399 | * @param defaultValue 默认值 400 | * @return 转换后的字符串 401 | */ 402 | public static String toString(Object object, String defaultValue) { 403 | if (object == null) return defaultValue; 404 | return String.valueOf(object); 405 | } 406 | 407 | /** 408 | * 将对象转为String后进行分割,如果为对象为空或者空字符,则返回null 409 | * 410 | * @param object 要分隔的对象 411 | * @param regex 分隔规则 412 | * @return 分隔后的对象 413 | */ 414 | public static final String[] toStringAndSplit(Object object, String regex) { 415 | if (isNullOrEmpty(object)) return null; 416 | return String.valueOf(object).split(regex); 417 | } 418 | 419 | private static boolean isChinese(char c) { 420 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); 421 | if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS 422 | || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS 423 | || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A 424 | || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION 425 | || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION 426 | || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { 427 | return true; 428 | } 429 | return false; 430 | } 431 | 432 | public static boolean isMessyCode(String strName) { 433 | Pattern p = Pattern.compile("\\s*|\t*|\r*|\n*"); 434 | Matcher m = p.matcher(strName); 435 | String after = m.replaceAll(""); 436 | String temp = after.replaceAll("\\p{P}", ""); 437 | char[] ch = temp.trim().toCharArray(); 438 | float chLength = 0; 439 | float count = 0; 440 | for (int i = 0; i < ch.length; i++) { 441 | char c = ch[i]; 442 | if (!Character.isLetterOrDigit(c)) { 443 | if (!isChinese(c)) { 444 | count = count + 1; 445 | } 446 | chLength++; 447 | } 448 | } 449 | float result = count / chLength; 450 | if (result > 0.4) { 451 | return true; 452 | } else { 453 | return false; 454 | } 455 | } 456 | 457 | } 458 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/ClassLoaderWrapper.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file; 2 | 3 | import java.io.InputStream; 4 | import java.net.URL; 5 | 6 | /** 7 | * A class to wrap access to multiple class loaders making them work as one 8 | */ 9 | public class ClassLoaderWrapper { 10 | 11 | ClassLoader defaultClassLoader; 12 | 13 | ClassLoaderWrapper() { 14 | } 15 | 16 | /** 17 | * Get a resource as a URL using the current class path 18 | * 19 | * @param resource - the resource to locate 20 | * @return the resource or null 21 | */ 22 | public URL getResourceAsURL(String resource) { 23 | return getResourceAsURL(resource, new ClassLoader[]{ 24 | defaultClassLoader, 25 | Thread.currentThread().getContextClassLoader(), 26 | getClass().getClassLoader(), 27 | ClassLoader.getSystemClassLoader() 28 | }); 29 | } 30 | 31 | /** 32 | * Get a resource from the classpath, starting with a specific class loader 33 | * 34 | * @param resource - the resource to find 35 | * @param classLoader - the first classloader to try 36 | * @return the stream or null 37 | */ 38 | public URL getResourceAsURL(String resource, ClassLoader classLoader) { 39 | return getResourceAsURL(resource, new ClassLoader[]{ 40 | classLoader, 41 | defaultClassLoader, 42 | Thread.currentThread().getContextClassLoader(), 43 | getClass().getClassLoader(), 44 | ClassLoader.getSystemClassLoader() 45 | }); 46 | } 47 | 48 | /** 49 | * Get a resource from the classpath 50 | * 51 | * @param resource - the resource to find 52 | * @return the stream or null 53 | */ 54 | public InputStream getResourceAsStream(String resource) { 55 | return getResourceAsStream(resource, new ClassLoader[]{ 56 | defaultClassLoader, 57 | Thread.currentThread().getContextClassLoader(), 58 | getClass().getClassLoader(), 59 | ClassLoader.getSystemClassLoader() 60 | }); 61 | } 62 | 63 | /** 64 | * Get a resource from the classpath, starting with a specific class loader 65 | * 66 | * @param resource - the resource to find 67 | * @param classLoader - the first class loader to try 68 | * @return the stream or null 69 | */ 70 | public InputStream getResourceAsStream(String resource, ClassLoader classLoader) { 71 | return getResourceAsStream(resource, new ClassLoader[]{ 72 | classLoader, 73 | defaultClassLoader, 74 | Thread.currentThread().getContextClassLoader(), 75 | getClass().getClassLoader(), 76 | ClassLoader.getSystemClassLoader() 77 | }); 78 | } 79 | 80 | /** 81 | * Find a class on the classpath (or die trying) 82 | * 83 | * @param name - the class to look for 84 | * @return - the class 85 | * @throws ClassNotFoundException Duh. 86 | */ 87 | public Class classForName(String name) throws ClassNotFoundException { 88 | return classForName(name, new ClassLoader[]{ 89 | defaultClassLoader, 90 | Thread.currentThread().getContextClassLoader(), 91 | getClass().getClassLoader(), 92 | ClassLoader.getSystemClassLoader() 93 | }); 94 | } 95 | 96 | /** 97 | * Find a class on the classpath, starting with a specific classloader (or die trying) 98 | * 99 | * @param name - the class to look for 100 | * @param classLoader - the first classloader to try 101 | * @return - the class 102 | * @throws ClassNotFoundException Duh. 103 | */ 104 | public Class classForName(String name, ClassLoader classLoader) throws ClassNotFoundException { 105 | return classForName(name, new ClassLoader[]{ 106 | classLoader, 107 | defaultClassLoader, 108 | Thread.currentThread().getContextClassLoader(), 109 | getClass().getClassLoader(), 110 | ClassLoader.getSystemClassLoader() 111 | }); 112 | } 113 | 114 | /** 115 | * Try to get a resource from a group of classloaders 116 | * 117 | * @param resource - the resource to get 118 | * @param classLoader - the classloaders to examine 119 | * @return the resource or null 120 | */ 121 | InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) { 122 | for (ClassLoader cl : classLoader) { 123 | if (null != cl) { 124 | 125 | // try to find the resource as passed 126 | InputStream returnValue = cl.getResourceAsStream(resource); 127 | 128 | // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource 129 | if (null == returnValue) returnValue = cl.getResourceAsStream("/" + resource); 130 | 131 | if (null != returnValue) return returnValue; 132 | } 133 | } 134 | return null; 135 | } 136 | 137 | /** 138 | * Get a resource as a URL using the current class path 139 | * 140 | * @param resource - the resource to locate 141 | * @param classLoader - the class loaders to examine 142 | * @return the resource or null 143 | */ 144 | URL getResourceAsURL(String resource, ClassLoader[] classLoader) { 145 | 146 | URL url; 147 | 148 | for (ClassLoader cl : classLoader) { 149 | 150 | if (null != cl) { 151 | 152 | // look for the resource as passed in... 153 | url = cl.getResource(resource); 154 | 155 | // ...but some class loaders want this leading "/", so we'll add it 156 | // and try again if we didn't find the resource 157 | if (null == url) url = cl.getResource("/" + resource); 158 | 159 | // "It's always in the last place I look for it!" 160 | // ... because only an idiot would keep looking for it after finding it, so stop looking already. 161 | if (null != url) return url; 162 | 163 | } 164 | 165 | } 166 | 167 | // didn't find it anywhere. 168 | return null; 169 | 170 | } 171 | 172 | /** 173 | * Attempt to load a class from a group of classloaders 174 | * 175 | * @param name - the class to load 176 | * @param classLoader - the group of classloaders to examine 177 | * @return the class 178 | * @throws ClassNotFoundException - Remember the wisdom of Judge Smails: Well, the world needs ditch diggers, too. 179 | */ 180 | Class classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException { 181 | 182 | for (ClassLoader cl : classLoader) { 183 | 184 | if (null != cl) { 185 | 186 | try { 187 | 188 | Class c = cl.loadClass(name); 189 | 190 | if (null != c) return c; 191 | 192 | } catch (ClassNotFoundException e) { 193 | // we'll ignore this until all classloaders fail to locate the class 194 | } 195 | 196 | } 197 | 198 | } 199 | 200 | throw new ClassNotFoundException("Cannot find class: " + name); 201 | 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/Encoding.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file; 2 | 3 | class Encoding { 4 | // Supported Encoding Types 5 | public static int GB2312 = 0; 6 | 7 | public static int GBK = 1; 8 | 9 | public static int GB18030 = 2; 10 | 11 | public static int HZ = 3; 12 | 13 | public static int BIG5 = 4; 14 | 15 | public static int CNS11643 = 5; 16 | 17 | public static int UTF8 = 6; 18 | 19 | public static int UTF8T = 7; 20 | 21 | public static int UTF8S = 8; 22 | 23 | public static int UNICODE = 9; 24 | 25 | public static int UNICODET = 10; 26 | 27 | public static int UNICODES = 11; 28 | 29 | public static int ISO2022CN = 12; 30 | 31 | public static int ISO2022CN_CNS = 13; 32 | 33 | public static int ISO2022CN_GB = 14; 34 | 35 | public static int EUC_KR = 15; 36 | 37 | public static int CP949 = 16; 38 | 39 | public static int ISO2022KR = 17; 40 | 41 | public static int JOHAB = 18; 42 | 43 | public static int SJIS = 19; 44 | 45 | public static int EUC_JP = 20; 46 | 47 | public static int ISO2022JP = 21; 48 | 49 | public static int ASCII = 22; 50 | 51 | public static int OTHER = 23; 52 | 53 | public static int TOTALTYPES = 24; 54 | 55 | public final static int SIMP = 0; 56 | 57 | public final static int TRAD = 1; 58 | 59 | // Names of the encodings as understood by Java 60 | public static String[] javaname; 61 | 62 | // Names of the encodings for human viewing 63 | public static String[] nicename; 64 | 65 | // Names of charsets as used in charset parameter of HTML Meta tag 66 | public static String[] htmlname; 67 | 68 | // Constructor 69 | public Encoding() { 70 | javaname = new String[TOTALTYPES]; 71 | nicename = new String[TOTALTYPES]; 72 | htmlname = new String[TOTALTYPES]; 73 | // Assign encoding names 74 | javaname[GB2312] = "GB2312"; 75 | javaname[GBK] = "GBK"; 76 | javaname[GB18030] = "GB18030"; 77 | javaname[HZ] = "ASCII"; // What to put here? Sun doesn't support HZ 78 | javaname[ISO2022CN_GB] = "ISO2022CN_GB"; 79 | javaname[BIG5] = "BIG5"; 80 | javaname[CNS11643] = "EUC-TW"; 81 | javaname[ISO2022CN_CNS] = "ISO2022CN_CNS"; 82 | javaname[ISO2022CN] = "ISO2022CN"; 83 | javaname[UTF8] = "UTF-8"; 84 | javaname[UTF8T] = "UTF-8"; 85 | javaname[UTF8S] = "UTF-8"; 86 | javaname[UNICODE] = "Unicode"; 87 | javaname[UNICODET] = "Unicode"; 88 | javaname[UNICODES] = "Unicode"; 89 | javaname[EUC_KR] = "EUC_KR"; 90 | javaname[CP949] = "MS949"; 91 | javaname[ISO2022KR] = "ISO2022KR"; 92 | javaname[JOHAB] = "Johab"; 93 | javaname[SJIS] = "SJIS"; 94 | javaname[EUC_JP] = "EUC_JP"; 95 | javaname[ISO2022JP] = "ISO2022JP"; 96 | javaname[ASCII] = "ASCII"; 97 | javaname[OTHER] = "ISO8859_1"; 98 | // Assign encoding names 99 | htmlname[GB2312] = "GB2312"; 100 | htmlname[GBK] = "GBK"; 101 | htmlname[GB18030] = "GB18030"; 102 | htmlname[HZ] = "HZ-GB-2312"; 103 | htmlname[ISO2022CN_GB] = "ISO-2022-CN-EXT"; 104 | htmlname[BIG5] = "BIG5"; 105 | htmlname[CNS11643] = "EUC-TW"; 106 | htmlname[ISO2022CN_CNS] = "ISO-2022-CN-EXT"; 107 | htmlname[ISO2022CN] = "ISO-2022-CN"; 108 | htmlname[UTF8] = "UTF-8"; 109 | htmlname[UTF8T] = "UTF-8"; 110 | htmlname[UTF8S] = "UTF-8"; 111 | htmlname[UNICODE] = "UTF-16"; 112 | htmlname[UNICODET] = "UTF-16"; 113 | htmlname[UNICODES] = "UTF-16"; 114 | htmlname[EUC_KR] = "EUC-KR"; 115 | htmlname[CP949] = "x-windows-949"; 116 | htmlname[ISO2022KR] = "ISO-2022-KR"; 117 | htmlname[JOHAB] = "x-Johab"; 118 | htmlname[SJIS] = "Shift_JIS"; 119 | htmlname[EUC_JP] = "EUC-JP"; 120 | htmlname[ISO2022JP] = "ISO-2022-JP"; 121 | htmlname[ASCII] = "ASCII"; 122 | htmlname[OTHER] = "ISO8859-1"; 123 | // Assign Human readable names 124 | nicename[GB2312] = "GB-2312"; 125 | nicename[GBK] = "GBK"; 126 | nicename[GB18030] = "GB18030"; 127 | nicename[HZ] = "HZ"; 128 | nicename[ISO2022CN_GB] = "ISO2022CN-GB"; 129 | nicename[BIG5] = "Big5"; 130 | nicename[CNS11643] = "CNS11643"; 131 | nicename[ISO2022CN_CNS] = "ISO2022CN-CNS"; 132 | nicename[ISO2022CN] = "ISO2022 CN"; 133 | nicename[UTF8] = "UTF-8"; 134 | nicename[UTF8T] = "UTF-8 (Trad)"; 135 | nicename[UTF8S] = "UTF-8 (Simp)"; 136 | nicename[UNICODE] = "Unicode"; 137 | nicename[UNICODET] = "Unicode (Trad)"; 138 | nicename[UNICODES] = "Unicode (Simp)"; 139 | nicename[EUC_KR] = "EUC-KR"; 140 | nicename[CP949] = "CP949"; 141 | nicename[ISO2022KR] = "ISO 2022 KR"; 142 | nicename[JOHAB] = "Johab"; 143 | nicename[SJIS] = "Shift-JIS"; 144 | nicename[EUC_JP] = "EUC-JP"; 145 | nicename[ISO2022JP] = "ISO 2022 JP"; 146 | nicename[ASCII] = "ASCII"; 147 | nicename[OTHER] = "OTHER"; 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/EncodingDetect.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 自动获取文件的编码 7 | */ 8 | public class EncodingDetect { 9 | static BytesEncodingDetect s = new BytesEncodingDetect(); 10 | 11 | /** 12 | * 得到文件的编码 13 | * 14 | * @param filePath 文件路径 15 | * @return 文件的编码 16 | */ 17 | public static String getJavaEncode(String filePath) { 18 | 19 | return BytesEncodingDetect.javaname[s.detectEncoding(new File(filePath))]; 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/FileUtils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file; 2 | 3 | 4 | import org.hswebframework.utils.StringUtils; 5 | import org.hswebframework.utils.file.callback.ReadCallBack; 6 | import org.hswebframework.utils.file.callback.ReadStringCallBack; 7 | import org.hswebframework.utils.file.callback.ScanCallBack; 8 | 9 | import java.io.*; 10 | 11 | /** 12 | * Created by 浩 on 2015-12-09 0009. 13 | */ 14 | public class FileUtils extends Resources { 15 | 16 | /** 17 | * 指定目录,扫描文件.可指定最大扫描深度 18 | * 19 | * @param path 要扫描的目录 20 | * @param maxDeep 最大扫描深度 21 | * @param callBack 扫描回掉 22 | */ 23 | public static void scanFile(String path, int maxDeep, ScanCallBack callBack) { 24 | scanFile(path, true, maxDeep, 0, callBack); 25 | } 26 | 27 | /** 28 | * 指定目录,扫描文件.可指定是否递归往下扫描 29 | * 30 | * @param path 指定要扫描的目录 31 | * @param depth 是否递归往下 32 | * @param callBack 扫描回掉 33 | */ 34 | public static void scanFile(String path, boolean depth, ScanCallBack callBack) { 35 | scanFile(path, depth, -1, 0, callBack); 36 | } 37 | 38 | /** 39 | * 指定目录,扫描文件.只扫描指定一层 40 | * 41 | * @param path 指定要扫描的目录 42 | * @param callBack 扫描回掉 43 | */ 44 | public static void scanFile(String path, ScanCallBack callBack) { 45 | scanFile(path, false, callBack); 46 | } 47 | 48 | /** 49 | * 深度优先,扫描文件 50 | * 51 | * @param path 扫描目录 52 | * @param depth 是否往下递归 53 | * @param maxDeep 扫描最大深度 54 | * @param deep 当前深度 55 | * @param callBack 扫描回掉 56 | */ 57 | private static void scanFile(String path, boolean depth, int maxDeep, int deep, ScanCallBack callBack) { 58 | if ((maxDeep != -1 && deep > maxDeep) || callBack.isExit()) { 59 | return; 60 | } 61 | File file = new File(path); 62 | try { 63 | if (file.isFile()) { 64 | callBack.accept(deep, file); 65 | } else { 66 | deep++; 67 | callBack.accept(deep, file); 68 | File[] files = file.listFiles(); 69 | for (File file2 : files) { 70 | if (callBack.isExit()) return; 71 | // 递归 72 | if (depth) 73 | scanFile(file2.getAbsolutePath(), depth, maxDeep, deep, callBack); 74 | // 调用回调 75 | else if (file2.isFile()) 76 | callBack.accept(deep, file2); 77 | else if (file2.isDirectory()) 78 | callBack.accept(deep, file2); 79 | } 80 | } 81 | } catch (Throwable e) { 82 | callBack.error(deep, file, e); 83 | } 84 | } 85 | 86 | /** 87 | * 获取文件编码,如果获取失败,使用默认编码utf8 88 | * 89 | * @param fileName 文件名 90 | * @return 文件编码 91 | */ 92 | public static final String getFileEncode(String fileName) { 93 | String encode = EncodingDetect.getJavaEncode(fileName); 94 | if (StringUtils.isNullOrEmpty(encode)) { 95 | encode = "utf8"; 96 | } 97 | return encode; 98 | } 99 | 100 | /** 101 | * 回掉方式按行读取文件 102 | * 103 | * @param callBack 读取回掉 104 | * @throws Exception 读取异常 105 | */ 106 | public static final void readFile(Reader reader, ReadCallBack callBack) throws IOException { 107 | // 指定文件编码读取 108 | BufferedReader bufferedReader = new BufferedReader(reader); 109 | int number = 0; 110 | try { 111 | while (bufferedReader.ready()) { 112 | if (callBack.isExit()) break; 113 | // 读取一行 回掉 114 | callBack.readLine(number++, bufferedReader.readLine()); 115 | } 116 | } catch (Throwable e) { 117 | callBack.error(e); 118 | } finally { 119 | bufferedReader.close(); 120 | } 121 | callBack.done(number); 122 | } 123 | 124 | /** 125 | * 读取文件为字符串,将自动获取文件编码 126 | * 127 | * @return 读取结果 128 | * @throws Exception 读取异常 129 | */ 130 | public static final String reader2String(String fileName) throws IOException { 131 | ReadStringCallBack callBack = new ReadStringCallBack(); 132 | Reader reader; 133 | try { 134 | reader = getResourceAsReader(fileName); 135 | } catch (Exception e) { 136 | reader = new InputStreamReader(new FileInputStream(fileName)); 137 | } 138 | readFile(reader, callBack); 139 | return callBack.toString(); 140 | } 141 | 142 | public static final void readerFile(String fileName, ReadCallBack callBack) throws Exception { 143 | readFile(getResourceAsReader(fileName), callBack); 144 | } 145 | 146 | 147 | /** 148 | * 读取文件为字符串,将自动获取文件编码 149 | * 150 | * @return 读取结果 151 | * @throws Exception 读取异常 152 | */ 153 | public static final String reader2String(Reader reader) throws Exception { 154 | ReadStringCallBack callBack = new ReadStringCallBack(); 155 | readFile(reader, callBack); 156 | return callBack.toString(); 157 | } 158 | 159 | 160 | /** 161 | * 读取文件为对象 162 | * 163 | * @param fileName 文件名 164 | * @param 对象泛型 165 | * @return 读取结果 166 | * @throws Exception 读取异常 167 | */ 168 | public static final T readFile2Obj(String fileName) throws Exception { 169 | try (InputStream input = new FileInputStream(fileName)) { 170 | return readStream2Obj(input); 171 | } 172 | } 173 | 174 | /** 175 | * 读取输入流为对象 176 | * 177 | * @param inputStream 输入流 178 | * @param 对象泛型 179 | * @return 读取结果 180 | * @throws Exception 读取异常 181 | */ 182 | public static final T readStream2Obj(InputStream inputStream) throws Exception { 183 | ObjectInputStream stream = null; 184 | try { 185 | stream = new ObjectInputStream(inputStream); 186 | return (T) stream.readObject(); 187 | } finally { 188 | if (stream != null) 189 | stream.close(); 190 | } 191 | } 192 | 193 | /** 194 | * 写出对象到文件(序列化) 195 | * 196 | * @param obj 需要写出的对象 197 | * @param fileName 文件名称 198 | * @throws Exception 写出异常 199 | */ 200 | public static final void writeObj2File(Serializable obj, String fileName) throws Exception { 201 | try (OutputStream out = new FileOutputStream(fileName)) { 202 | writeObj2Steam(obj, out); 203 | } 204 | } 205 | 206 | public static final void writeString2File(String str, String fileName, String encode) throws Exception { 207 | File file = new File(fileName); 208 | if (!file.getParentFile().exists()) { 209 | file.getParentFile().mkdirs(); 210 | } 211 | try (Writer out = new OutputStreamWriter(new FileOutputStream(fileName), encode)) { 212 | out.write(str); 213 | out.flush(); 214 | } 215 | } 216 | 217 | /** 218 | * 写出对象到输出流 219 | * 220 | * @param obj 需要写出的对象 221 | * @param outputStream 输出流 222 | * @throws Exception 写出异常 223 | */ 224 | public static final void writeObj2Steam(Serializable obj, OutputStream outputStream) throws Exception { 225 | ObjectOutputStream stream = new ObjectOutputStream(outputStream); 226 | stream.writeObject(obj); 227 | stream.flush(); 228 | } 229 | 230 | /** 231 | * 获取文件后缀名 232 | * 233 | * @param file 文件对象 234 | * @return 文件后缀名 235 | */ 236 | public static String getSuffix(File file) { 237 | return getSuffix(file.getName()); 238 | } 239 | 240 | /** 241 | * 获取文件后缀名 242 | * 243 | * @param fileName 文件名 244 | * @return 文件后缀名 245 | */ 246 | public static String getSuffix(String fileName) { 247 | if (fileName == null) 248 | return ""; 249 | if (fileName.contains(".")) { 250 | return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()); 251 | } 252 | return ""; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/Resources.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file; 2 | 3 | 4 | import java.io.*; 5 | import java.net.URL; 6 | import java.net.URLConnection; 7 | import java.nio.charset.Charset; 8 | import java.util.Properties; 9 | 10 | /** 11 | * A class to simplify access to resources through the classloader. 12 | */ 13 | public class Resources { 14 | 15 | private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper(); 16 | 17 | /** 18 | * Charset to use when calling getResourceAsReader. 19 | * null means use the system default. 20 | */ 21 | private static Charset charset; 22 | 23 | Resources() { 24 | } 25 | 26 | /** 27 | * Returns the default classloader (may be null). 28 | * 29 | * @return The default classloader 30 | */ 31 | public static ClassLoader getDefaultClassLoader() { 32 | return classLoaderWrapper.defaultClassLoader; 33 | } 34 | 35 | /** 36 | * Sets the default classloader 37 | * 38 | * @param defaultClassLoader - the new default ClassLoader 39 | */ 40 | public static void setDefaultClassLoader(ClassLoader defaultClassLoader) { 41 | classLoaderWrapper.defaultClassLoader = defaultClassLoader; 42 | } 43 | 44 | /** 45 | * Returns the URL of the resource on the classpath 46 | * 47 | * @param resource The resource to find 48 | * @return The resource 49 | * @throws IOException If the resource cannot be found or read 50 | */ 51 | public static URL getResourceURL(String resource) throws IOException { 52 | return classLoaderWrapper.getResourceAsURL(resource); 53 | } 54 | 55 | /** 56 | * Returns the URL of the resource on the classpath 57 | * 58 | * @param loader The classloader used to fetch the resource 59 | * @param resource The resource to find 60 | * @return The resource 61 | * @throws IOException If the resource cannot be found or read 62 | */ 63 | public static URL getResourceURL(ClassLoader loader, String resource) throws IOException { 64 | URL url = classLoaderWrapper.getResourceAsURL(resource, loader); 65 | if (url == null) throw new IOException("Could not find resource " + resource); 66 | return url; 67 | } 68 | 69 | /** 70 | * Returns a resource on the classpath as a Stream object 71 | * 72 | * @param resource The resource to find 73 | * @return The resource 74 | * @throws IOException If the resource cannot be found or read 75 | */ 76 | public static InputStream getResourceAsStream(String resource) throws IOException { 77 | return getResourceAsStream(null, resource); 78 | } 79 | 80 | /** 81 | * Returns a resource on the classpath as a Stream object 82 | * 83 | * @param loader The classloader used to fetch the resource 84 | * @param resource The resource to find 85 | * @return The resource 86 | * @throws IOException If the resource cannot be found or read 87 | */ 88 | public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { 89 | InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader); 90 | if (in == null) throw new IOException("Could not find resource " + resource); 91 | return in; 92 | } 93 | 94 | /** 95 | * Returns a resource on the classpath as a Properties object 96 | * 97 | * @param resource The resource to find 98 | * @return The resource 99 | * @throws IOException If the resource cannot be found or read 100 | */ 101 | public static Properties getResourceAsProperties(String resource) throws IOException { 102 | Properties props = new Properties(); 103 | InputStream in = getResourceAsStream(resource); 104 | props.load(in); 105 | in.close(); 106 | return props; 107 | } 108 | 109 | /** 110 | * Returns a resource on the classpath as a Properties object 111 | * 112 | * @param loader The classloader used to fetch the resource 113 | * @param resource The resource to find 114 | * @return The resource 115 | * @throws IOException If the resource cannot be found or read 116 | */ 117 | public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException { 118 | Properties props = new Properties(); 119 | InputStream in = getResourceAsStream(loader, resource); 120 | props.load(in); 121 | in.close(); 122 | return props; 123 | } 124 | 125 | /** 126 | * Returns a resource on the classpath as a Reader object 127 | * 128 | * @param resource The resource to find 129 | * @return The resource 130 | * @throws IOException If the resource cannot be found or read 131 | */ 132 | public static Reader getResourceAsReader(String resource) throws IOException { 133 | Reader reader; 134 | if (charset == null) { 135 | reader = new InputStreamReader(getResourceAsStream(resource)); 136 | } else { 137 | reader = new InputStreamReader(getResourceAsStream(resource), charset); 138 | } 139 | return reader; 140 | } 141 | 142 | /** 143 | * Returns a resource on the classpath as a Reader object 144 | * 145 | * @param loader The classloader used to fetch the resource 146 | * @param resource The resource to find 147 | * @return The resource 148 | * @throws IOException If the resource cannot be found or read 149 | */ 150 | public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException { 151 | Reader reader; 152 | if (charset == null) { 153 | reader = new InputStreamReader(getResourceAsStream(loader, resource)); 154 | } else { 155 | reader = new InputStreamReader(getResourceAsStream(loader, resource), charset); 156 | } 157 | return reader; 158 | } 159 | 160 | /** 161 | * Returns a resource on the classpath as a File object 162 | * 163 | * @param resource The resource to find 164 | * @return The resource 165 | * @throws IOException If the resource cannot be found or read 166 | */ 167 | public static File getResourceAsFile(String resource) throws IOException { 168 | return new File(getResourceURL(resource).getFile()); 169 | } 170 | 171 | /** 172 | * Returns a resource on the classpath as a File object 173 | * 174 | * @param loader - the classloader used to fetch the resource 175 | * @param resource - the resource to find 176 | * @return The resource 177 | * @throws IOException If the resource cannot be found or read 178 | */ 179 | public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException { 180 | return new File(getResourceURL(loader, resource).getFile()); 181 | } 182 | 183 | /** 184 | * Gets a URL as an input stream 185 | * 186 | * @param urlString - the URL to get 187 | * @return An input stream with the data from the URL 188 | * @throws IOException If the resource cannot be found or read 189 | */ 190 | public static InputStream getUrlAsStream(String urlString) throws IOException { 191 | URL url = new URL(urlString); 192 | URLConnection conn = url.openConnection(); 193 | return conn.getInputStream(); 194 | } 195 | 196 | /** 197 | * Gets a URL as a Reader 198 | * 199 | * @param urlString - the URL to get 200 | * @return A Reader with the data from the URL 201 | * @throws IOException If the resource cannot be found or read 202 | */ 203 | public static Reader getUrlAsReader(String urlString) throws IOException { 204 | return new InputStreamReader(getUrlAsStream(urlString)); 205 | } 206 | 207 | /** 208 | * Gets a URL as a Properties object 209 | * 210 | * @param urlString - the URL to get 211 | * @return A Properties object with the data from the URL 212 | * @throws IOException If the resource cannot be found or read 213 | */ 214 | public static Properties getUrlAsProperties(String urlString) throws IOException { 215 | Properties props = new Properties(); 216 | InputStream in = getUrlAsStream(urlString); 217 | props.load(in); 218 | in.close(); 219 | return props; 220 | } 221 | 222 | /** 223 | * Loads a class 224 | * 225 | * @param className - the class to fetch 226 | * @return The loaded class 227 | * @throws ClassNotFoundException If the class cannot be found (duh!) 228 | */ 229 | public static Class classForName(String className) throws ClassNotFoundException { 230 | return classLoaderWrapper.classForName(className); 231 | } 232 | 233 | public static Charset getCharset() { 234 | return charset; 235 | } 236 | 237 | public static void setCharset(Charset charset) { 238 | Resources.charset = charset; 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/callback/AbstractScanCallBack.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file.callback; 2 | 3 | /** 4 | * Created by 浩 on 2015-12-09 0009. 5 | */ 6 | public abstract class AbstractScanCallBack implements ScanCallBack { 7 | 8 | private boolean exit = false; 9 | 10 | @Override 11 | public void exit() { 12 | exit=true; 13 | } 14 | 15 | @Override 16 | public boolean isExit() { 17 | return exit; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/callback/CanExitCallBack.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file.callback; 2 | 3 | /** 4 | * Created by 浩 on 2015-12-09 0009. 5 | */ 6 | public interface CanExitCallBack { 7 | 8 | default void exit() { 9 | } 10 | 11 | default boolean isExit() { 12 | return false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/callback/ReadCallBack.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file.callback; 2 | 3 | /** 4 | * Created by 浩 on 2015-12-09 0009. 5 | */ 6 | public interface ReadCallBack extends CanExitCallBack { 7 | 8 | void readLine(int lineNumber, String line); 9 | 10 | default void error(Throwable e) { 11 | e.printStackTrace(); 12 | } 13 | 14 | default void done(int total) { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/callback/ReadStringCallBack.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file.callback; 2 | 3 | /** 4 | * Created by 浩 on 2015-12-09 0009. 5 | */ 6 | public class ReadStringCallBack implements ReadCallBack { 7 | 8 | protected StringBuilder builder = new StringBuilder(); 9 | 10 | @Override 11 | public String toString() { 12 | return builder.toString(); 13 | } 14 | 15 | @Override 16 | public void readLine(int lineNumber, String line) { 17 | builder.append(line).append("\n"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/file/callback/ScanCallBack.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.file.callback; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Created by 浩 on 2015-12-09 0009. 7 | */ 8 | public interface ScanCallBack extends CanExitCallBack { 9 | 10 | void accept(int deep, File file); 11 | 12 | default void error(int deep, File file, Throwable e) { 13 | e.printStackTrace(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/time/DateFormatter.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.time; 2 | 3 | import org.joda.time.DateTime; 4 | import org.joda.time.format.DateTimeFormat; 5 | 6 | import java.time.LocalDateTime; 7 | import java.time.format.DateTimeFormatter; 8 | import java.util.*; 9 | 10 | import static org.hswebframework.utils.time.SmartDateFormatter.*; 11 | 12 | /** 13 | * 日期格式化工具 14 | * 15 | * @author zhouhao 16 | */ 17 | public interface DateFormatter { 18 | 19 | List supportFormatter = new ArrayList<>(Arrays.asList( 20 | /* 21 | *常见格式 22 | * */ 23 | // yyyyMMdd 24 | of(yyyy, MM, dd) 25 | // yyyy-MM-dd 26 | , of(yyyy, strike, MM, strike, dd) 27 | // yyyy/MM/dd 28 | , of(yyyy, slash, MM, slash, dd) 29 | //yyyy年MM月dd日 30 | , of(yyyy, year_cn, MM, month_cn, dd, day_cn) 31 | // yyyy-MM-dd HH:mm:ss 32 | , of(yyyy, strike, MM, strike, dd, blankSpace, HH, colon, mm, colon, ss) 33 | , of(yyyy, strike, MM, strike, dd, blankSpace, HH, colon, mm, colon, ss, str("."), SSS) 34 | // yyyy/MM/dd HH:mm:ss 35 | , of(yyyy, slash, MM, slash, dd, blankSpace, HH, colon, mm, colon, ss) 36 | // yyyyMMddHHmmss 37 | , of(yyyy, MM, dd, HH, mm, ss) 38 | //yyyy年M月d日 39 | , of(yyyy, year_cn, M, month_cn, d, day_cn) 40 | //yyyy年MM月d日 41 | , of(yyyy, year_cn, MM, month_cn, d, day_cn) 42 | //yyyy年M月dd日 43 | , of(yyyy, year_cn, M, month_cn, dd, day_cn) 44 | 45 | // yyyy-M-d 46 | , of(yyyy, strike, M, strike, d) 47 | // yyyy-MM-d 48 | , of(yyyy, strike, MM, strike, d) 49 | // yyyy-M-dd 50 | , of(yyyy, strike, M, strike, dd) 51 | 52 | // yyyy/M/d 53 | , of(yyyy, slash, M, slash, d) 54 | // yyyy/MM/d 55 | , of(yyyy, slash, MM, slash, d) 56 | // yyyy/M/dd 57 | , of(yyyy, slash, M, slash, dd) 58 | 59 | 60 | // yyyy-MM-dd HH:mm:ssZ 61 | , of("yyyy-MM-dd HH:mm:ssZ", yyyy, strike, MM, strike, dd, blankSpace, HH, colon, mm, colon, ss, plus, Z) 62 | , of("yyyy-MM-dd HH:mm:ss.SSSZ", yyyy, strike, MM, strike, dd, blankSpace, HH, colon, mm, colon, ss, str("."), SSS, plus, Z) 63 | , of("yyyy-MM-dd HH:mm:ss.SSSXXX", yyyy, strike, MM, strike, dd, blankSpace, HH, colon, mm, colon, ss, str("."), SSS, XXX) 64 | //yyyy-MM-dd'T'HH:mm:ss 65 | , of("yyyy-MM-dd'T'HH:mm:ss", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss) 66 | //yyyy-MM-dd'T'HH:mm:ssZ 67 | , of("yyyy-MM-dd'T'HH:mm:ssZ", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, plus, Z) 68 | , of("yyyy-MM-dd'T'HH:mm:ssXXX", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, plus, XXX) 69 | //yyyy-MM-dd'T'HH:mm:ss.SSS 70 | , of("yyyy-MM-dd'T'HH:mm:ss.SSS", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, str("."), SSS) 71 | , of("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, str("."), SSS, SSS) 72 | , of("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, str("."), SSS, SSS, SSS) 73 | 74 | //yyyy-MM-dd'T'HH:mm:ss.SSSz 75 | , of("yyyy-MM-dd'T'HH:mm:ss.SSSZ", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, str("."), SSS, plus, Z) 76 | , of("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", yyyy, strike, MM, strike, dd, T, HH, colon, mm, colon, ss, str("."), SSS, XXX) 77 | //yyyy年MM月dd日HH时mm分ss秒 78 | , of(yyyy, year_cn, MM, month_cn, dd, day_cn, HH, hour_cn, mm, minute_cn, ss, second_cn) 79 | //yyyy年MM月dd日 HH时mm分ss秒 80 | , of(yyyy, year_cn, MM, month_cn, dd, day_cn, blankSpace, HH, hour_cn, mm, minute_cn, ss, second_cn) 81 | // HH:mm:ss 82 | , of(HH, colon, mm, colon, ss) 83 | 84 | // yyyy-M-dd HH:mm:ss 85 | , of(yyyy, strike, M, strike, dd, blankSpace, HH, colon, mm, colon, ss) 86 | // yyyy-M-d HH:mm:ss 87 | , of(yyyy, strike, M, strike, d, blankSpace, HH, colon, mm, colon, ss) 88 | // yyyy-MM-d HH:mm:ss 89 | , of(yyyy, strike, MM, strike, d, blankSpace, HH, colon, mm, colon, ss) 90 | // yyyy-M-dd H:m:s 91 | , of(yyyy, strike, M, strike, dd, blankSpace, H, colon, m, colon, s) 92 | // yyyy-M-d H:m:s 93 | , of(yyyy, strike, M, strike, d, blankSpace, H, colon, m, colon, s) 94 | // yyyy-MM-d H:m:s 95 | , of(yyyy, strike, MM, strike, d, blankSpace, H, colon, m, colon, s) 96 | 97 | // yyyy/M/dd HH:mm:ss 98 | , of(yyyy, slash, M, slash, dd, blankSpace, HH, colon, mm, colon, ss) 99 | // yyyy/M/d HH:mm:ss 100 | , of(yyyy, slash, M, slash, d, blankSpace, HH, colon, mm, colon, ss) 101 | // yyyy/MM/d HH:mm:ss 102 | , of(yyyy, slash, MM, slash, d, blankSpace, HH, colon, mm, colon, ss) 103 | // yyyy/M/dd H:m:s 104 | , of(yyyy, slash, M, slash, dd, blankSpace, H, colon, m, colon, s) 105 | // yyyy/M/d H:m:s 106 | , of(yyyy, slash, M, slash, d, blankSpace, H, colon, m, colon, s) 107 | // yyyy/MM/d H:m:s 108 | , of(yyyy, slash, MM, slash, d, blankSpace, H, colon, m, colon, s) 109 | 110 | /* 111 | * 奇奇怪怪的格式 112 | * */ 113 | // yyyyMMdd HH:mm:ss 114 | , 115 | of(yyyy, MM, dd, blankSpace, HH, colon, mm, colon, ss) 116 | // yyyyMMdd HHmmss 117 | , 118 | of(yyyy, MM, dd, blankSpace, HH, mm, ss) 119 | //yyyy年 MM月 dd日 EEE HH:mm:ss 'CST' 120 | , 121 | of("yyyy年 MM月 dd日 EEE HH:mm:ss zzz", 122 | yyyy, year_cn, blankSpace, 123 | MM, month_cn, blankSpace, 124 | dd, day_cn, blankSpace, 125 | weeks3, blankSpace, 126 | HH, colon, mm, colon, ss, blankSpace, 127 | zzz).withLocal(Locale.CHINA) 128 | 129 | //EEE MMM dd HH:mm:ss 'CST' yyyy 130 | , of("EEE MMM dd HH:mm:ss zzz yyyy", 131 | weeks3, blankSpace, 132 | month3, blankSpace, 133 | dd, blankSpace, 134 | HH, colon, mm, colon, ss, blankSpace, 135 | zzz, blankSpace, yyyy) 136 | .withLocal(Locale.ENGLISH) 137 | //MMM dd, yyyy K:mm:ss a 138 | , of("MMM dd, yyyy K:mm:ss a", 139 | month3, blankSpace, 140 | dd, str(","), blankSpace, 141 | yyyy, blankSpace, 142 | K, colon, mm, colon, ss, blankSpace, a) 143 | .withLocal(Locale.ENGLISH) 144 | )); 145 | 146 | boolean support(String str); 147 | 148 | Date format(String str); 149 | 150 | LocalDateTime parse(String str); 151 | 152 | String toString(Date date); 153 | 154 | String toString(LocalDateTime dateTime); 155 | 156 | String getPattern(); 157 | 158 | static Date fromString(String dateString) { 159 | DateFormatter formatter = getFormatter(dateString); 160 | if (formatter != null) { 161 | return formatter.format(dateString); 162 | } 163 | 164 | return null; 165 | } 166 | 167 | static Date fromString(String dateString, String pattern) { 168 | DateFormatter formatter = getFormatter(dateString); 169 | if (formatter != null) { 170 | return formatter.format(dateString); 171 | } 172 | return DateTimeFormat 173 | .forPattern(pattern) 174 | .parseDateTime(dateString) 175 | .toDate(); 176 | } 177 | 178 | static String toString(LocalDateTime date, String format) { 179 | if (null == date) return null; 180 | for (DateFormatter formatter : supportFormatter) { 181 | if (formatter.getPattern().equals(format)) 182 | return formatter.toString(date); 183 | } 184 | return DateTimeFormatter.ofPattern(format).format(date); 185 | } 186 | 187 | static String toString(Date date, String format) { 188 | if (null == date) return null; 189 | for (DateFormatter formatter : supportFormatter) { 190 | if (formatter.getPattern().equals(format)) 191 | return formatter.toString(date); 192 | } 193 | return new DateTime(date).toString(format); 194 | } 195 | 196 | static boolean isSupport(String dateString) { 197 | return getFormatter(dateString) != null; 198 | } 199 | 200 | static DateFormatter getFormatter(String dateString) { 201 | if (dateString == null || dateString.length() < 4) return null; 202 | for (DateFormatter formatter : supportFormatter) { 203 | if (formatter.support(dateString)) 204 | return formatter; 205 | } 206 | return null; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/time/SmartDateFormatter.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.time; 2 | 3 | 4 | import java.time.*; 5 | import java.time.format.DateTimeFormatter; 6 | import java.time.temporal.TemporalAccessor; 7 | import java.time.temporal.TemporalQueries; 8 | import java.util.*; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.Stream; 11 | 12 | 13 | class SmartDateFormatter implements DateFormatter { 14 | static Part year_cn = str("年"); 15 | static Part month_cn = str("月"); 16 | static Part day_cn = str("日"); 17 | static Part hour_cn = str("时"); 18 | static Part minute_cn = str("分"); 19 | static Part second_cn = str("秒"); 20 | static Part weeks3 = new Week("EEE", 3); 21 | static Part month3 = new Month("MMM", 3); 22 | 23 | static Part zzz = new TimezonePart("zzz", 3); 24 | 25 | static Part strike = str("-"); 26 | static Part slash = str("/"); 27 | static Part plus = str("+"); 28 | 29 | static Part blankSpace = str(" "); 30 | 31 | static Part colon = str(":"); 32 | 33 | static Part yyyy = new NumberPart("yyyy", 1900, 2999); 34 | static Part MM = new NumberPart("MM", 1, 12); 35 | static Part M = new NumberPart("M", 1, 12); 36 | 37 | static Part dd = new NumberPart("dd", 1, 31); 38 | static Part d = new NumberPart("d", 1, 31); 39 | static Part HH = new NumberPart("HH", 0, 23); 40 | static Part k = new NumberPart("k", 1, 24); 41 | static Part K = new NumberPart("K", 0, 11); 42 | 43 | static Part a = new MatchPart("a", 2, new HashSet<>(Arrays.asList("AM", "PM"))); 44 | 45 | static Part h = new NumberPart("h", 1, 12); 46 | static Part H = new NumberPart("H", 0, 24); 47 | static Part mm = new NumberPart("mm", 0, 60); 48 | static Part m = new NumberPart("m", 0, 60); 49 | static Part ss = new NumberPart("ss", 0, 60); 50 | static Part SSS = new NumberPart("SSS", 3, 0, 999); 51 | 52 | static Part s = new NumberPart("s", 0, 60); 53 | static Part Z = new NumberPart("Z", 4, 0, 9999); 54 | static Part XXX = new ZoneOffsetPart(); 55 | 56 | static Part T = str("T"); 57 | 58 | 59 | DateTimeFormatter pattern; 60 | final String patternString; 61 | 62 | private final Part[] parts; 63 | 64 | private final int max, min; 65 | 66 | public SmartDateFormatter withLocal(Locale locale) { 67 | pattern = pattern.withLocale(locale); 68 | return this; 69 | } 70 | 71 | SmartDateFormatter(String pattern, int max, int min, Part[] parts) { 72 | this.parts = parts; 73 | this.max = max; 74 | this.min = min; 75 | this.patternString = pattern; 76 | this.pattern = DateTimeFormatter.ofPattern(patternString); 77 | } 78 | 79 | SmartDateFormatter(String pattern, Part[] parts) { 80 | this.parts = parts; 81 | this.max = Stream.of(this.parts).mapToInt(Part::length).sum(); 82 | this.min = max; 83 | this.patternString = pattern; 84 | this.pattern = DateTimeFormatter.ofPattern(patternString); 85 | } 86 | 87 | SmartDateFormatter(Part[] parts) { 88 | this.parts = parts; 89 | this.max = Stream.of(this.parts).mapToInt(Part::length).sum(); 90 | this.min = max; 91 | this.patternString = Stream.of(this.parts).map(Part::pattern).collect(Collectors.joining()); 92 | this.pattern = DateTimeFormatter.ofPattern(patternString); 93 | } 94 | 95 | public static SmartDateFormatter of(String pattern, Part... parts) { 96 | return new SmartDateFormatter(pattern, parts); 97 | } 98 | 99 | public static SmartDateFormatter of(String pattern, int min, int max, Part... parts) { 100 | return new SmartDateFormatter(pattern, max, min, parts); 101 | } 102 | 103 | public static SmartDateFormatter of(Part... parts) { 104 | return new SmartDateFormatter(parts); 105 | } 106 | 107 | @Override 108 | public boolean support(String str) { 109 | int len = str.length(); 110 | if (len < min || len > max) { 111 | return false; 112 | } 113 | int temp = 0; 114 | for (Part part : parts) { 115 | if (!part.test(str, temp)) { 116 | return false; 117 | } 118 | temp += part.length(); 119 | } 120 | return true; 121 | } 122 | 123 | @Override 124 | public Date format(String str) { 125 | return Date.from(parse(str).atZone(ZoneId.systemDefault()).toInstant()); 126 | } 127 | 128 | @Override 129 | public LocalDateTime parse(String str) { 130 | TemporalAccessor accessor = pattern.parse(str); 131 | 132 | LocalDate date = accessor.query(TemporalQueries.localDate()); 133 | LocalTime time = accessor.query(TemporalQueries.localTime()); 134 | ZoneId zoneId = accessor.query(TemporalQueries.zone()); 135 | ZoneOffset offset = accessor.query(TemporalQueries.offset()); 136 | LocalDateTime dateTime; 137 | 138 | if (date != null) { 139 | if (time != null) { 140 | dateTime = LocalDateTime.of(date, time); 141 | } else { 142 | dateTime = LocalDateTime.of(date, LocalTime.of(0, 0, 0, 0)); 143 | } 144 | } else { 145 | dateTime = LocalDateTime.of(LocalDate.now(), time); 146 | } 147 | if (offset != null) { 148 | return dateTime.atOffset(offset).toLocalDateTime(); 149 | } 150 | if (zoneId != null) { 151 | return dateTime 152 | .atZone(zoneId) 153 | .withZoneSameInstant(ZoneId.systemDefault()) 154 | .toLocalDateTime(); 155 | } 156 | return dateTime.atZone(ZoneId.systemDefault()).toLocalDateTime(); 157 | } 158 | 159 | @Override 160 | public String toString(Date date) { 161 | 162 | return pattern.format( 163 | ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()) 164 | ); 165 | } 166 | 167 | @Override 168 | public String toString(LocalDateTime dateTime) { 169 | return pattern.format(dateTime.atZone(ZoneId.systemDefault())); 170 | } 171 | 172 | @Override 173 | public String getPattern() { 174 | return patternString; 175 | } 176 | 177 | 178 | public static SmartDateFormatter.Part str(String str) { 179 | return new StringPart(str); 180 | } 181 | 182 | static class StringPart implements Part { 183 | private final String pattern; 184 | private final int length; 185 | 186 | StringPart(String pattern) { 187 | this(pattern, pattern.length()); 188 | } 189 | 190 | StringPart(String pattern, int length) { 191 | this.pattern = pattern; 192 | this.length = length; 193 | } 194 | 195 | @Override 196 | public int length() { 197 | return length; 198 | } 199 | 200 | @Override 201 | public String pattern() { 202 | return pattern; 203 | } 204 | 205 | @Override 206 | public boolean test(String str, int offset) { 207 | for (int i = 0; i < pattern.length(); i++) { 208 | if (str.charAt(offset + i) != pattern.charAt(i)) { 209 | return false; 210 | } 211 | } 212 | return true; 213 | } 214 | } 215 | 216 | static class TimezonePart extends MatchPart { 217 | static Set TZ = new HashSet<>(Arrays.asList( 218 | "CST", "GMT", "UTC" 219 | )); 220 | 221 | TimezonePart(String pattern, int length) { 222 | super(pattern, length, TZ); 223 | } 224 | } 225 | 226 | static class ZoneOffsetPart implements Part { 227 | 228 | @Override 229 | public int length() { 230 | return 6; 231 | } 232 | 233 | @Override 234 | public String pattern() { 235 | return "Z"; 236 | } 237 | 238 | @Override 239 | public boolean test(String str, int offset) { 240 | if (str.charAt(offset) != '+' || 241 | str.charAt(offset + 3) != ':') { 242 | return false; 243 | } 244 | int hour = Utils.toNumber(str, offset + 1, 2); 245 | 246 | if (hour < 0 || hour > 12) { 247 | return false; 248 | } 249 | int minute = Utils.toNumber(str, offset + 4, 2); 250 | 251 | return minute >= 0; 252 | } 253 | } 254 | 255 | static class NumberPart implements Part { 256 | private final String pattern; 257 | private final int length; 258 | private final int min; 259 | private final int max; 260 | 261 | NumberPart(String pattern, int length, int min, int max) { 262 | this.pattern = pattern; 263 | this.min = min; 264 | this.max = max; 265 | this.length = length; 266 | } 267 | 268 | NumberPart(String pattern, int min, int max) { 269 | this(pattern, pattern.length(), min, max); 270 | } 271 | 272 | @Override 273 | public int length() { 274 | return length; 275 | } 276 | 277 | @Override 278 | public String pattern() { 279 | return pattern; 280 | } 281 | 282 | @Override 283 | public boolean test(String str, int offset) { 284 | int val = Utils.toNumber(str, offset, length); 285 | return val >= min && val <= max; 286 | } 287 | } 288 | 289 | static class Month extends MatchPart { 290 | static Set MONTHS = new HashSet<>(Arrays.asList( 291 | "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月", 292 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 293 | "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" 294 | )); 295 | 296 | Month(String pattern, int length) { 297 | super(pattern, length, MONTHS); 298 | } 299 | 300 | } 301 | 302 | static class Week extends MatchPart { 303 | static Set WEEKS = new HashSet<>(Arrays.asList( 304 | "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日", 305 | "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", 306 | "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", 307 | "周一", "周二", "周三", "周四", "周五", "周六", "周日" 308 | )); 309 | 310 | Week(String pattern, int length) { 311 | super(pattern, length, WEEKS); 312 | } 313 | 314 | } 315 | 316 | static class MatchPart implements Part { 317 | private final Set matched; 318 | private final String pattern; 319 | private final int length; 320 | 321 | MatchPart(String pattern, int length, Set matched) { 322 | this.pattern = pattern; 323 | this.length = length; 324 | this.matched = matched; 325 | } 326 | 327 | @Override 328 | public int length() { 329 | return length; 330 | } 331 | 332 | @Override 333 | public String pattern() { 334 | return pattern; 335 | } 336 | 337 | @Override 338 | public boolean test(String str, int offset) { 339 | return matched.contains(str.substring(offset, offset + length)); 340 | } 341 | } 342 | 343 | 344 | interface Part { 345 | int length(); 346 | 347 | String pattern(); 348 | 349 | boolean test(String str, int offset); 350 | } 351 | 352 | } 353 | -------------------------------------------------------------------------------- /src/main/java/org/hswebframework/utils/time/Utils.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.time; 2 | 3 | class Utils { 4 | 5 | static int toNumber(String str, int index, int length) { 6 | int result = 0; 7 | for (int i = length, x = 0; i > 0; i--, x++) { 8 | char c = str.charAt(index + x); 9 | if (c < '0' || c > '9') { 10 | return -1; 11 | } 12 | int val = c - 48; 13 | result = result + (int) (Math.pow(10, i - 1)) * val; 14 | } 15 | return result; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/org/hswebframework/utils/time/TimeTests.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.time; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | import java.time.ZoneId; 9 | import java.util.Date; 10 | import java.util.function.BiFunction; 11 | import java.util.function.Predicate; 12 | 13 | /** 14 | * TODO 完成注释 15 | * 16 | * @author zhouhao 17 | */ 18 | public class TimeTests { 19 | @Test 20 | public void testFormat() { 21 | String[] tests = { 22 | new Date().toString(), 23 | LocalDateTime.now().toString(), 24 | LocalDateTime.now().atZone(ZoneId.systemDefault()).toOffsetDateTime().toString(), 25 | "20151101", 26 | "2015-11-01", 27 | "2015/11/02", 28 | "2015年11月01日", 29 | "2015年5月1日", 30 | "2015年5月12日", 31 | "2015年12月1日", 32 | "2017年 04月 27日 星期四 00:00:00 CST", 33 | "2017年 04月 21日 星期五 00:00:00 GMT", 34 | "2017年 04月 21日 星期五 00:00:00 UTC", 35 | "2015年11月01日 13时12分01秒", 36 | "20151101131201", 37 | "20151101 13:12:01", 38 | "20151101 131201", 39 | "2015-11-01 13:12:01", 40 | "2015-11-01 13:12:01.666", 41 | 42 | "2015-1-1 13:12:01", 43 | "2015-9-1 1:2:1", 44 | 45 | "2015/1/1 13:12:01", 46 | "2015/9/1 1:2:1", 47 | 48 | 49 | "2015-11-01 13:12:01+0100", 50 | "2015-11-01T13:12:01", 51 | "2015-11-01T13:12:01.777", 52 | "2015-11-01T13:12:01.777666", 53 | "2015-11-01T13:12:01.777666555", 54 | "2015-11-01T13:12:01+0100", 55 | "2015-11-01T13:12:01.888+0100", 56 | "Sep 29, 2012 1:00:01 AM", 57 | "Sep 29, 2012 1:00:01 PM", 58 | "07:13:12", 59 | "2017-4-5", 60 | "2017/4/5", 61 | "2017/10/5", 62 | "2017/4/12" 63 | }; 64 | for (String test : tests) { 65 | DateFormatter formatter = DateFormatter.getFormatter(test); 66 | Assert.assertNotNull("format not supported :" + test, formatter); 67 | try { 68 | LocalDateTime date = formatter.parse(test); 69 | System.out.println(formatter.getPattern() + "=>:\t\t" + test + " = " + DateFormatter.toString(date, formatter.getPattern())); 70 | } catch (Throwable e) { 71 | System.err.println(formatter.getPattern()+"=>"+test); 72 | throw e; 73 | } 74 | } 75 | 76 | 77 | BiFunction> compareBuilder = (str1, str2) -> { 78 | long from = DateFormatter.fromString(str1).getTime(); 79 | long to = DateFormatter.fromString(str2).getTime(); 80 | return (compare) -> { 81 | long target = DateFormatter.fromString(compare).getTime(); 82 | return from >= to ? target >= from || target <= to : target >= from && target <= to; 83 | }; 84 | }; 85 | 86 | boolean timeInScope = compareBuilder.apply("20:12:00", "06:00:00") 87 | .and(compareBuilder.apply("18:00:00", "22:00:00")) 88 | .and(compareBuilder.apply("02:00:00", "22:00:00")) 89 | .test("21:59:00"); 90 | 91 | boolean timeNotInScope = !compareBuilder.apply("08:12:02", "21:12:21") 92 | .test("21:59:00"); 93 | 94 | boolean dateInScope = compareBuilder.apply("2012/12/12 11:11:11", "2012/12/15 23:11:11") 95 | .test("2012/12/13 00:00:00"); 96 | 97 | boolean dateNotInScope = !compareBuilder.apply("2012/12/12 11:11:11", "2012/12/15 23:11:11") 98 | .test("2012/12/12 10:00:00"); 99 | 100 | Assert.assertTrue(timeInScope && timeNotInScope && dateInScope && dateNotInScope); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/org/hswebframework/utils/time/UtilsTest.java: -------------------------------------------------------------------------------- 1 | package org.hswebframework.utils.time; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class UtilsTest { 8 | 9 | 10 | @Test 11 | public void testToInt(){ 12 | assertEquals(1991,Utils.toNumber("1991",0,4)); 13 | 14 | assertEquals(2008,Utils.toNumber("2008",0,4)); 15 | 16 | assertEquals(31,Utils.toNumber("31",0,2)); 17 | } 18 | 19 | } --------------------------------------------------------------------------------