├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── xcbeyond
│ └── common
│ ├── DateUtils.java
│ ├── StringUtils.java
│ ├── communication
│ ├── http
│ │ └── HttpClient.java
│ └── socket
│ │ ├── SocketClient.java
│ │ └── SocketServer.java
│ ├── data
│ └── redis
│ │ └── RedisUtils.java
│ ├── file
│ └── chunk
│ │ ├── controller
│ │ └── FileController.java
│ │ └── service
│ │ ├── FileService.java
│ │ └── impl
│ │ └── FileServiceImpl.java
│ └── security
│ └── JwtToken.java
└── test
└── java
├── com
└── xcbeyond
│ └── common
│ ├── DateUtilsTest.java
│ ├── StartApplication.java
│ ├── communication
│ └── socket
│ │ ├── SocketClientTest.java
│ │ └── SocketServerTest.java
│ └── security
│ └── JwtTokenTest.java
└── resources
└── application.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | /target/
4 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # common-utils
2 | 通用Java基础库,汇聚常用工具类
3 |
4 | # 手册
5 | 详细手册文档同步在[CSDN博客](https://blog.csdn.net/xcbeyond)、微信公众号("程序猿技术大咖(cxyjsdk)")更新。
6 | * [HTTP方式文件分片断点下载](https://mp.weixin.qq.com/s?__biz=MzA5MzUwOTY4NQ==&mid=2247484537&idx=1&sn=557a97d9abddc30164a416c7af72fd56&chksm=905d8523a72a0c357bcb453d256fcd5ba14f842d4ac472ec35ebe1268bf778301b05fbbca284&token=1646810344&lang=zh_CN#rd)
7 |
8 | # 微信公众号:
9 | 欢迎微信扫码下面二维码,关注微信公众号【程序猿技术大咖】,进行更多交流学习!
10 |
11 | 
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.xcbeyond.common
8 | common-utils
9 | 1.0
10 |
11 | 通用java基础库
12 |
13 |
14 | UTF-8
15 | UTF-8
16 | 1.8
17 | 2.0.7.RELEASE
18 | 1.2.47
19 |
20 |
21 |
22 |
23 |
24 | junit
25 | junit
26 | RELEASE
27 | test
28 |
29 |
30 |
31 |
32 | org.jsoup
33 | jsoup
34 | 1.11.3
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-data-redis
45 |
46 |
47 |
48 | com.alibaba
49 | fastjson
50 | ${fastjson.version}
51 |
52 |
53 |
54 |
55 | io.jsonwebtoken
56 | jjwt
57 | 0.9.0
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-dependencies
67 | ${spring-boot.version}
68 | pom
69 | import
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | org.apache.maven.plugins
78 | maven-compiler-plugin
79 | 3.6.0
80 |
81 | 1.8
82 | 1.8
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common;
2 |
3 | import java.text.ParseException;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 |
8 | /**
9 | * 日期工具类
10 | * @Auther: xcbeyond
11 | * @Date: 2019/4/30 15:17
12 | */
13 | public class DateUtils {
14 |
15 | /**
16 | * 获取当前时间,yyyy-MM-dd HH:mm:ss
17 | * @return
18 | */
19 | public static String getCurrentDate() {
20 | //设置日期格式
21 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
22 | // new Date()为获取当前系统时间
23 | return df.format(new Date());
24 | }
25 |
26 | /**
27 | * 根据输入的日期格式获得系统当前日期
28 | * @param format
29 | * 时间格式化,如:"yyyy-MM-dd","yyyy/MM/dd","yyyyMMdd"
30 | * @return
31 | */
32 | public static String getCurrentDate(String format) {
33 | String date;
34 | try {
35 | SimpleDateFormat sdf = new SimpleDateFormat(format);
36 | date = sdf.format(new Date());
37 | } catch (Exception e) {
38 | // 默认格式
39 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
40 | date = sdf.format(new Date());
41 | }
42 | return date;
43 | }
44 |
45 | /**
46 | * 获取当前时间(yyyy年MM月dd日)
47 | * @return
48 | */
49 | public static String getYYYYMMDDCHN() {
50 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
51 | return sdf.format(new Date());
52 | }
53 |
54 | /**
55 | * 获取当前时间(yyyyMMdd)
56 | * @return
57 | */
58 | public static String getYYYYMMDD() {
59 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
60 | return sdf.format(new Date());
61 | }
62 |
63 | /**
64 | * 获取当前时间(格式自定义)
65 | * @param type 时间格式化字符串,如:"yyyy-MM-dd"
66 | * @return
67 | */
68 | public static String getYYYYMMDD(String type) {
69 | SimpleDateFormat sdf = new SimpleDateFormat(type);
70 | return sdf.format(new Date());
71 | }
72 |
73 | /**
74 | * 获取当前时间(yyyyMMddHHmmssSSS)
75 | * @return
76 | */
77 | public static String getYYYYMMDDHHMMssSSS() {
78 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
79 | return sdf.format(new Date());
80 | }
81 |
82 | /**
83 | * 获取当前时间 hh24mmss
84 | * @return
85 | */
86 | public static String getHMS() {
87 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
88 | return sdf.format(new Date());
89 | }
90 |
91 |
92 | /**
93 | * 取得当天之后几个月的天数
94 | * @param yyyyMM
95 | * @return
96 | */
97 | public static int getDaysOfMonthNext(String yyyyMM, int months) {
98 | Calendar rightNow = Calendar.getInstance();
99 | SimpleDateFormat simpleDate = new SimpleDateFormat("yyyyMM");
100 | int retValue = 0;
101 | for (int i = 0; i <= months; i++) {
102 | rightNow.add(rightNow.MONTH, i);
103 | yyyyMM = simpleDate.format(rightNow.getTime());
104 | String now = getYYYYMMDD("yyyyMMdd");
105 | if (i == 0) {
106 | int dd = Integer.parseInt(now.substring(6));
107 | retValue += (getDaysOfMonth(yyyyMM) - dd + 1);
108 | } else if (i == months) {
109 | int dd = Integer.parseInt(now.substring(6));
110 | retValue += dd - 1;
111 | } else {
112 | retValue += getDaysOfMonth(yyyyMM);
113 | }
114 | }
115 | return retValue;
116 | }
117 |
118 | /**
119 | * 取得某年某月有多少天
120 | * @param yyyyMM
121 | * 年月,注意时间格式 yyyyMM
122 | * @return
123 | */
124 | public static int getDaysOfMonth(String yyyyMM) {
125 | Calendar rightNow = Calendar.getInstance();
126 | SimpleDateFormat simpleDate = new SimpleDateFormat("yyyyMM"); // 如果写成年月日的形式的话,要写小d,如:"yyyy/MM/dd"
127 | try {
128 | rightNow.setTime(simpleDate.parse(yyyyMM)); // 要计算你想要的月份,改变这里即可
129 | } catch (ParseException e) {
130 | e.printStackTrace();
131 | }
132 | int days = rightNow.getActualMaximum(Calendar.DAY_OF_MONTH);
133 | return days;
134 | }
135 |
136 | /**
137 | * 两时间相差的天数 注:日期格式yyyyMMdd
138 | * @param startDay
139 | * @param endDay
140 | * @return
141 | */
142 | public static long getDiffDays(String startDay, String endDay) {
143 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
144 | long days = 0;
145 | try {
146 | Date s = sdf.parse(startDay);
147 | Date e = sdf.parse(endDay);
148 | long sd = s.getTime();
149 | long ed = e.getTime();
150 | long diff;
151 | if (ed > sd) {
152 | diff = ed - sd;
153 | } else {
154 | diff = sd - ed;
155 | }
156 | days = diff / (1000 * 60 * 60 * 24);
157 | } catch (ParseException e) {
158 | e.printStackTrace();
159 | }
160 | return days + 1;
161 | }
162 |
163 | /**
164 | * 比较两个日期是否在一个月内
165 | * @param beginDate
166 | * 开始日期
167 | * @param endDate
168 | * 结束日期
169 | * @return true说明超过一个月
170 | */
171 | public static boolean compareDateInMonth(String beginDate, String endDate) {
172 | boolean bool = false;
173 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
174 | Calendar c = Calendar.getInstance();
175 | try {
176 | c.setTime(sdf.parse(beginDate));
177 | int syear = c.get(Calendar.YEAR);
178 | int smonth = c.get(Calendar.MONTH);
179 | int sday = c.get(Calendar.DATE);
180 | c.setTime(sdf.parse(endDate));
181 | int eyear = c.get(Calendar.YEAR);
182 | int emonth = c.get(Calendar.MONTH);
183 | int eday = c.get(Calendar.DATE);
184 | if (syear != eyear) {
185 | if (eyear - syear == 1) {
186 | if (smonth - emonth == 11 && eday < sday) {
187 | bool = false;
188 | } else {
189 | bool = true;
190 | }
191 | } else {
192 | bool = true;
193 | }
194 | } else {
195 | if (emonth - smonth > 1) {
196 | bool = true;
197 | } else if (emonth - smonth == 1) {
198 | if (eday >= sday) {
199 | bool = true;
200 | }
201 | }
202 | }
203 | } catch (ParseException e) {
204 | e.printStackTrace();
205 | }
206 | return bool;
207 | }
208 |
209 | /**
210 | * 取到某个日期months个月之后日期
211 | *
212 | * @param date
213 | * 格式yyyyMMdd
214 | * @param months
215 | * 月数
216 | * @return
217 | */
218 | public static String getDateOfMonth(String date, int months) {
219 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
220 | try {
221 | Date toDate = sdf.parse(date);
222 | Calendar c = Calendar.getInstance();
223 | c.setTime(toDate);
224 | c.add(Calendar.MONTH, months);
225 | date = sdf.format(c.getTime());
226 | } catch (ParseException e) {
227 | e.printStackTrace();
228 | }
229 | return date;
230 | }
231 |
232 | /**
233 | * 格式化日期为YYYY年MM月DD日 例如 20130805格式化为2013年08月04日
234 | * @param str
235 | * 格式YYYYMMDD
236 | * @return date 格式YYYY年MM月DD日
237 | */
238 | public static String formatDateCHN(String str) {
239 | String format = "yyyyMMdd";
240 | if (str.contains("-")) {
241 | format = "yyyy-MM-dd";
242 | }
243 | SimpleDateFormat sdf = new SimpleDateFormat(format);
244 | Date date = new Date();
245 | try {
246 | date = sdf.parse(str);
247 | } catch (ParseException e) {
248 | e.printStackTrace();
249 | }
250 | SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
251 | return sdf1.format(date);
252 | }
253 |
254 | /**
255 | * 格式化时间为HH:MM:SS,如果数据不为6位,前补0 例如 091516格式化为09:15:16
256 | * @param str
257 | * 格式HHMMSS
258 | * @return time 格式HH:MM:SS
259 | */
260 | public static String formatTime(String str) {
261 | String format = "HHmmss";
262 | if (str.length() == 5) {
263 | str = "0" + str;
264 | }
265 | if (str.length() == 9) {
266 | format = "HHmmssSSS";
267 | }
268 | SimpleDateFormat sdf = new SimpleDateFormat(format);
269 | SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");
270 | try {
271 | str = sdf1.format(sdf.parse(str));
272 | } catch (ParseException e) {
273 | e.printStackTrace();
274 | }
275 | return str;
276 | }
277 |
278 | /**
279 | * 计算两个日期相隔天数
280 | * @param smdate
281 | * 小日期
282 | * @param bdate
283 | * 大日期
284 | * @return int
285 | * @throws ParseException
286 | */
287 | public static int getDaysBetween(String smdate, String bdate) {
288 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
289 | Calendar cal = Calendar.getInstance();
290 | long time1 = 0;
291 | long time2 = 0;
292 | try {
293 | cal.setTime(sdf.parse(smdate));
294 | time1 = cal.getTimeInMillis();
295 | cal.setTime(sdf.parse(bdate));
296 | time2 = cal.getTimeInMillis();
297 | } catch (ParseException e) {
298 | e.printStackTrace();
299 | }
300 | long between_days = (time2 - time1) / (1000 * 3600 * 24);
301 | return Integer.parseInt(String.valueOf(between_days));
302 | }
303 |
304 | /**
305 | * 比较两个日期
306 | * @param startDate
307 | * 开始日期
308 | * @param endDate
309 | * 结束日期
310 | * 结束日期 > 开始日期 返回大于0
311 | * 结束日期 < 开始日期 返回小于0
312 | * @return int
313 | * @throws ParseException
314 | */
315 | public static long compareDate(String startDate, String endDate) {
316 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
317 | Calendar cal = Calendar.getInstance();
318 | long time1 = 0;
319 | long time2 = 0;
320 | try {
321 | cal.setTime(sdf.parse(startDate));
322 | time1 = cal.getTimeInMillis();
323 | cal.setTime(sdf.parse(endDate));
324 | time2 = cal.getTimeInMillis();
325 | } catch (ParseException e) {
326 | e.printStackTrace();
327 | }
328 | return time2 - time1;
329 | }
330 |
331 | /**
332 | * 计算两个日期相隔月数
333 | * @param smdate
334 | * 小日期
335 | * @param bdate
336 | * 大日期
337 | * @return int
338 | * @throws ParseException
339 | */
340 | public static int getMonthsBetween(String smdate, String bdate) {
341 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
342 | Calendar calStart = Calendar.getInstance();
343 | Calendar calEnd = Calendar.getInstance();
344 | int compMonth = 0, compYear = 0;
345 | try {
346 | calStart.setTime(sdf.parse(smdate));
347 | calEnd.setTime(sdf.parse(bdate));
348 | compMonth = calEnd.get(Calendar.MONTH)
349 | - calStart.get(Calendar.MONTH);
350 | compYear = calEnd.get(Calendar.YEAR) - calStart.get(Calendar.YEAR);
351 | } catch (ParseException e) {
352 | e.printStackTrace();
353 | }
354 | compMonth = compYear * 12 + compMonth;
355 | return compMonth;
356 | }
357 |
358 | /**
359 | * 格式化日期 传入19900101 返回 1990-01-01 传入为空或null 返回空
360 | * @param str
361 | * @return
362 | */
363 | public static String formatDate(String str) {
364 | String format = "yyyyMMdd";
365 | if (null == str) {
366 | return "";
367 | } else if (str.equals("")) {
368 | return "";
369 | } else if (str.contains("-")) {
370 | return str;
371 | } else {
372 | SimpleDateFormat sdf = new SimpleDateFormat(format);
373 | Date date = new Date();
374 | try {
375 | date = sdf.parse(str);
376 | } catch (ParseException e) {
377 | return "";
378 | }
379 | SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
380 | return sdf1.format(date);
381 | }
382 | }
383 |
384 | /**
385 | * 格式化日期型字符串
386 | * @param date
387 | * @param dateFormatFrom
388 | * @param dateFormatTo
389 | * @return
390 | */
391 | public static String formatDate(String date, String dateFormatFrom,
392 | String dateFormatTo) {
393 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormatFrom);
394 | Date temp = new Date();
395 | try {
396 | temp = sdf.parse(date);
397 | } catch (ParseException e) {
398 | return date;
399 | }
400 | SimpleDateFormat sdf1 = new SimpleDateFormat(dateFormatTo);
401 | return sdf1.format(temp);
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common;
2 |
3 | import org.springframework.lang.Nullable;
4 | import org.springframework.util.Assert;
5 | import org.springframework.util.CollectionUtils;
6 | import org.springframework.util.ObjectUtils;
7 |
8 | import java.io.ByteArrayOutputStream;
9 | import java.nio.charset.Charset;
10 | import java.util.*;
11 |
12 | /**
13 | * 字符串工具类
14 | * @Auther: xcbeyond
15 | * @Date: 2019/1/29 17:04
16 | */
17 | public class StringUtils {
18 | private static final String FOLDER_SEPARATOR = "/";
19 | private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
20 | private static final String TOP_PATH = "..";
21 | private static final String CURRENT_PATH = ".";
22 | private static final char EXTENSION_SEPARATOR = '.';
23 |
24 | public StringUtils() {
25 | }
26 |
27 | public static boolean isEmpty(@Nullable Object str) {
28 | return str == null || "".equals(str);
29 | }
30 |
31 | public static boolean isNotEmpty(@Nullable Object str) {
32 | return str != null && !"".equals(str);
33 | }
34 |
35 | public static boolean hasLength(@Nullable CharSequence str) {
36 | return str != null && str.length() > 0;
37 | }
38 |
39 | public static boolean hasLength(@Nullable String str) {
40 | return str != null && !str.isEmpty();
41 | }
42 |
43 | public static boolean hasText(@Nullable CharSequence str) {
44 | return str != null && str.length() > 0 && containsText(str);
45 | }
46 |
47 | public static boolean hasText(@Nullable String str) {
48 | return str != null && !str.isEmpty() && containsText(str);
49 | }
50 |
51 | private static boolean containsText(CharSequence str) {
52 | int strLen = str.length();
53 |
54 | for(int i = 0; i < strLen; ++i) {
55 | if (!Character.isWhitespace(str.charAt(i))) {
56 | return true;
57 | }
58 | }
59 |
60 | return false;
61 | }
62 |
63 | public static boolean containsWhitespace(@Nullable CharSequence str) {
64 | if (!hasLength(str)) {
65 | return false;
66 | } else {
67 | int strLen = str.length();
68 |
69 | for(int i = 0; i < strLen; ++i) {
70 | if (Character.isWhitespace(str.charAt(i))) {
71 | return true;
72 | }
73 | }
74 |
75 | return false;
76 | }
77 | }
78 |
79 | public static boolean containsWhitespace(@Nullable String str) {
80 | return containsWhitespace((CharSequence)str);
81 | }
82 |
83 | public static String trimWhitespace(String str) {
84 | if (!hasLength(str)) {
85 | return str;
86 | } else {
87 | int beginIndex = 0;
88 |
89 | int endIndex;
90 | for(endIndex = str.length() - 1; beginIndex <= endIndex && Character.isWhitespace(str.charAt(beginIndex)); ++beginIndex) {
91 | }
92 |
93 | while(endIndex > beginIndex && Character.isWhitespace(str.charAt(endIndex))) {
94 | --endIndex;
95 | }
96 |
97 | return str.substring(beginIndex, endIndex + 1);
98 | }
99 | }
100 |
101 | public static String trimAllWhitespace(String str) {
102 | if (!hasLength(str)) {
103 | return str;
104 | } else {
105 | int len = str.length();
106 | StringBuilder sb = new StringBuilder(str.length());
107 |
108 | for(int i = 0; i < len; ++i) {
109 | char c = str.charAt(i);
110 | if (!Character.isWhitespace(c)) {
111 | sb.append(c);
112 | }
113 | }
114 |
115 | return sb.toString();
116 | }
117 | }
118 |
119 | public static String trimLeadingWhitespace(String str) {
120 | if (!hasLength(str)) {
121 | return str;
122 | } else {
123 | StringBuilder sb = new StringBuilder(str);
124 |
125 | while(sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) {
126 | sb.deleteCharAt(0);
127 | }
128 |
129 | return sb.toString();
130 | }
131 | }
132 |
133 | public static String trimTrailingWhitespace(String str) {
134 | if (!hasLength(str)) {
135 | return str;
136 | } else {
137 | StringBuilder sb = new StringBuilder(str);
138 |
139 | while(sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {
140 | sb.deleteCharAt(sb.length() - 1);
141 | }
142 |
143 | return sb.toString();
144 | }
145 | }
146 |
147 | public static String trimLeadingCharacter(String str, char leadingCharacter) {
148 | if (!hasLength(str)) {
149 | return str;
150 | } else {
151 | StringBuilder sb = new StringBuilder(str);
152 |
153 | while(sb.length() > 0 && sb.charAt(0) == leadingCharacter) {
154 | sb.deleteCharAt(0);
155 | }
156 |
157 | return sb.toString();
158 | }
159 | }
160 |
161 | public static String trimTrailingCharacter(String str, char trailingCharacter) {
162 | if (!hasLength(str)) {
163 | return str;
164 | } else {
165 | StringBuilder sb = new StringBuilder(str);
166 |
167 | while(sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) {
168 | sb.deleteCharAt(sb.length() - 1);
169 | }
170 |
171 | return sb.toString();
172 | }
173 | }
174 |
175 | public static boolean startsWithIgnoreCase(@Nullable String str, @Nullable String prefix) {
176 | return str != null && prefix != null && str.length() >= prefix.length() && str.regionMatches(true, 0, prefix, 0, prefix.length());
177 | }
178 |
179 | public static boolean endsWithIgnoreCase(@Nullable String str, @Nullable String suffix) {
180 | return str != null && suffix != null && str.length() >= suffix.length() && str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length());
181 | }
182 |
183 | public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
184 | if (index + substring.length() > str.length()) {
185 | return false;
186 | } else {
187 | for(int i = 0; i < substring.length(); ++i) {
188 | if (str.charAt(index + i) != substring.charAt(i)) {
189 | return false;
190 | }
191 | }
192 |
193 | return true;
194 | }
195 | }
196 |
197 | public static int countOccurrencesOf(String str, String sub) {
198 | if (hasLength(str) && hasLength(sub)) {
199 | int count = 0;
200 |
201 | int idx;
202 | for(int pos = 0; (idx = str.indexOf(sub, pos)) != -1; pos = idx + sub.length()) {
203 | ++count;
204 | }
205 |
206 | return count;
207 | } else {
208 | return 0;
209 | }
210 | }
211 |
212 | public static String replace(String inString, String oldPattern, @Nullable String newPattern) {
213 | if (hasLength(inString) && hasLength(oldPattern) && newPattern != null) {
214 | int index = inString.indexOf(oldPattern);
215 | if (index == -1) {
216 | return inString;
217 | } else {
218 | int capacity = inString.length();
219 | if (newPattern.length() > oldPattern.length()) {
220 | capacity += 16;
221 | }
222 |
223 | StringBuilder sb = new StringBuilder(capacity);
224 | int pos = 0;
225 |
226 | for(int patLen = oldPattern.length(); index >= 0; index = inString.indexOf(oldPattern, pos)) {
227 | sb.append(inString.substring(pos, index));
228 | sb.append(newPattern);
229 | pos = index + patLen;
230 | }
231 |
232 | sb.append(inString.substring(pos));
233 | return sb.toString();
234 | }
235 | } else {
236 | return inString;
237 | }
238 | }
239 |
240 | public static String delete(String inString, String pattern) {
241 | return replace(inString, pattern, "");
242 | }
243 |
244 | public static String deleteAny(String inString, @Nullable String charsToDelete) {
245 | if (hasLength(inString) && hasLength(charsToDelete)) {
246 | StringBuilder sb = new StringBuilder(inString.length());
247 |
248 | for(int i = 0; i < inString.length(); ++i) {
249 | char c = inString.charAt(i);
250 | if (charsToDelete.indexOf(c) == -1) {
251 | sb.append(c);
252 | }
253 | }
254 |
255 | return sb.toString();
256 | } else {
257 | return inString;
258 | }
259 | }
260 |
261 | @Nullable
262 | public static String quote(@Nullable String str) {
263 | return str != null ? "'" + str + "'" : null;
264 | }
265 |
266 | @Nullable
267 | public static Object quoteIfString(@Nullable Object obj) {
268 | return obj instanceof String ? quote((String)obj) : obj;
269 | }
270 |
271 | public static String unqualify(String qualifiedName) {
272 | return unqualify(qualifiedName, '.');
273 | }
274 |
275 | public static String unqualify(String qualifiedName, char separator) {
276 | return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1);
277 | }
278 |
279 | public static String capitalize(String str) {
280 | return changeFirstCharacterCase(str, true);
281 | }
282 |
283 | public static String uncapitalize(String str) {
284 | return changeFirstCharacterCase(str, false);
285 | }
286 |
287 | private static String changeFirstCharacterCase(String str, boolean capitalize) {
288 | if (!hasLength(str)) {
289 | return str;
290 | } else {
291 | char baseChar = str.charAt(0);
292 | char updatedChar;
293 | if (capitalize) {
294 | updatedChar = Character.toUpperCase(baseChar);
295 | } else {
296 | updatedChar = Character.toLowerCase(baseChar);
297 | }
298 |
299 | if (baseChar == updatedChar) {
300 | return str;
301 | } else {
302 | char[] chars = str.toCharArray();
303 | chars[0] = updatedChar;
304 | return new String(chars, 0, chars.length);
305 | }
306 | }
307 | }
308 |
309 | @Nullable
310 | public static String getFilename(@Nullable String path) {
311 | if (path == null) {
312 | return null;
313 | } else {
314 | int separatorIndex = path.lastIndexOf("/");
315 | return separatorIndex != -1 ? path.substring(separatorIndex + 1) : path;
316 | }
317 | }
318 |
319 | @Nullable
320 | public static String getFilenameExtension(@Nullable String path) {
321 | if (path == null) {
322 | return null;
323 | } else {
324 | int extIndex = path.lastIndexOf(46);
325 | if (extIndex == -1) {
326 | return null;
327 | } else {
328 | int folderIndex = path.lastIndexOf("/");
329 | return folderIndex > extIndex ? null : path.substring(extIndex + 1);
330 | }
331 | }
332 | }
333 |
334 | public static String stripFilenameExtension(String path) {
335 | int extIndex = path.lastIndexOf(46);
336 | if (extIndex == -1) {
337 | return path;
338 | } else {
339 | int folderIndex = path.lastIndexOf("/");
340 | return folderIndex > extIndex ? path : path.substring(0, extIndex);
341 | }
342 | }
343 |
344 | public static String applyRelativePath(String path, String relativePath) {
345 | int separatorIndex = path.lastIndexOf("/");
346 | if (separatorIndex != -1) {
347 | String newPath = path.substring(0, separatorIndex);
348 | if (!relativePath.startsWith("/")) {
349 | newPath = newPath + "/";
350 | }
351 |
352 | return newPath + relativePath;
353 | } else {
354 | return relativePath;
355 | }
356 | }
357 |
358 | public static String cleanPath(String path) {
359 | if (!hasLength(path)) {
360 | return path;
361 | } else {
362 | String pathToUse = replace(path, "\\", "/");
363 | int prefixIndex = pathToUse.indexOf(58);
364 | String prefix = "";
365 | if (prefixIndex != -1) {
366 | prefix = pathToUse.substring(0, prefixIndex + 1);
367 | if (prefix.contains("/")) {
368 | prefix = "";
369 | } else {
370 | pathToUse = pathToUse.substring(prefixIndex + 1);
371 | }
372 | }
373 |
374 | if (pathToUse.startsWith("/")) {
375 | prefix = prefix + "/";
376 | pathToUse = pathToUse.substring(1);
377 | }
378 |
379 | String[] pathArray = delimitedListToStringArray(pathToUse, "/");
380 | LinkedList pathElements = new LinkedList();
381 | int tops = 0;
382 |
383 | int i;
384 | for(i = pathArray.length - 1; i >= 0; --i) {
385 | String element = pathArray[i];
386 | if (!".".equals(element)) {
387 | if ("..".equals(element)) {
388 | ++tops;
389 | } else if (tops > 0) {
390 | --tops;
391 | } else {
392 | pathElements.add(0, element);
393 | }
394 | }
395 | }
396 |
397 | for(i = 0; i < tops; ++i) {
398 | pathElements.add(0, "..");
399 | }
400 |
401 | if (pathElements.size() == 1 && "".equals(pathElements.getLast()) && !prefix.endsWith("/")) {
402 | pathElements.add(0, ".");
403 | }
404 |
405 | return prefix + collectionToDelimitedString(pathElements, "/");
406 | }
407 | }
408 |
409 | public static boolean pathEquals(String path1, String path2) {
410 | return cleanPath(path1).equals(cleanPath(path2));
411 | }
412 |
413 | public static String uriDecode(String source, Charset charset) {
414 | int length = source.length();
415 | if (length == 0) {
416 | return source;
417 | } else {
418 | Assert.notNull(charset, "Charset must not be null");
419 | ByteArrayOutputStream bos = new ByteArrayOutputStream(length);
420 | boolean changed = false;
421 |
422 | for(int i = 0; i < length; ++i) {
423 | int ch = source.charAt(i);
424 | if (ch == '%') {
425 | if (i + 2 >= length) {
426 | throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
427 | }
428 |
429 | char hex1 = source.charAt(i + 1);
430 | char hex2 = source.charAt(i + 2);
431 | int u = Character.digit(hex1, 16);
432 | int l = Character.digit(hex2, 16);
433 | if (u == -1 || l == -1) {
434 | throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
435 | }
436 |
437 | bos.write((char)((u << 4) + l));
438 | i += 2;
439 | changed = true;
440 | } else {
441 | bos.write(ch);
442 | }
443 | }
444 |
445 | return changed ? new String(bos.toByteArray(), charset) : source;
446 | }
447 | }
448 |
449 | @Nullable
450 | public static Locale parseLocale(String localeValue) {
451 | String[] tokens = tokenizeLocaleSource(localeValue);
452 | if (tokens.length == 1) {
453 | Locale resolved = Locale.forLanguageTag(localeValue);
454 | return resolved.getLanguage().length() > 0 ? resolved : null;
455 | } else {
456 | return parseLocaleTokens(localeValue, tokens);
457 | }
458 | }
459 |
460 | @Nullable
461 | public static Locale parseLocaleString(String localeString) {
462 | return parseLocaleTokens(localeString, tokenizeLocaleSource(localeString));
463 | }
464 |
465 | private static String[] tokenizeLocaleSource(String localeSource) {
466 | return tokenizeToStringArray(localeSource, "_ ", false, false);
467 | }
468 |
469 | @Nullable
470 | private static Locale parseLocaleTokens(String localeString, String[] tokens) {
471 | String language = tokens.length > 0 ? tokens[0] : "";
472 | String country = tokens.length > 1 ? tokens[1] : "";
473 | validateLocalePart(language);
474 | validateLocalePart(country);
475 | String variant = "";
476 | if (tokens.length > 2) {
477 | int endIndexOfCountryCode = localeString.indexOf(country, language.length()) + country.length();
478 | variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode));
479 | if (variant.startsWith("_")) {
480 | variant = trimLeadingCharacter(variant, '_');
481 | }
482 | }
483 |
484 | if ("".equals(variant) && country.startsWith("#")) {
485 | variant = country;
486 | country = "";
487 | }
488 |
489 | return language.length() > 0 ? new Locale(language, country, variant) : null;
490 | }
491 |
492 | private static void validateLocalePart(String localePart) {
493 | for(int i = 0; i < localePart.length(); ++i) {
494 | char ch = localePart.charAt(i);
495 | if (ch != ' ' && ch != '_' && ch != '#' && !Character.isLetterOrDigit(ch)) {
496 | throw new IllegalArgumentException("Locale part \"" + localePart + "\" contains invalid characters");
497 | }
498 | }
499 |
500 | }
501 |
502 | /** @deprecated */
503 | @Deprecated
504 | public static String toLanguageTag(Locale locale) {
505 | return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : "");
506 | }
507 |
508 | public static TimeZone parseTimeZoneString(String timeZoneString) {
509 | TimeZone timeZone = TimeZone.getTimeZone(timeZoneString);
510 | if ("GMT".equals(timeZone.getID()) && !timeZoneString.startsWith("GMT")) {
511 | throw new IllegalArgumentException("Invalid time zone specification '" + timeZoneString + "'");
512 | } else {
513 | return timeZone;
514 | }
515 | }
516 |
517 | public static String[] addStringToArray(@Nullable String[] array, String str) {
518 | if (ObjectUtils.isEmpty(array)) {
519 | return new String[]{str};
520 | } else {
521 | String[] newArr = new String[array.length + 1];
522 | System.arraycopy(array, 0, newArr, 0, array.length);
523 | newArr[array.length] = str;
524 | return newArr;
525 | }
526 | }
527 |
528 | @Nullable
529 | public static String[] concatenateStringArrays(@Nullable String[] array1, @Nullable String[] array2) {
530 | if (ObjectUtils.isEmpty(array1)) {
531 | return array2;
532 | } else if (ObjectUtils.isEmpty(array2)) {
533 | return array1;
534 | } else {
535 | String[] newArr = new String[array1.length + array2.length];
536 | System.arraycopy(array1, 0, newArr, 0, array1.length);
537 | System.arraycopy(array2, 0, newArr, array1.length, array2.length);
538 | return newArr;
539 | }
540 | }
541 |
542 | /** @deprecated */
543 | @Deprecated
544 | @Nullable
545 | public static String[] mergeStringArrays(@Nullable String[] array1, @Nullable String[] array2) {
546 | if (ObjectUtils.isEmpty(array1)) {
547 | return array2;
548 | } else if (ObjectUtils.isEmpty(array2)) {
549 | return array1;
550 | } else {
551 | List result = new ArrayList();
552 | result.addAll(Arrays.asList(array1));
553 | String[] var3 = array2;
554 | int var4 = array2.length;
555 |
556 | for(int var5 = 0; var5 < var4; ++var5) {
557 | String str = var3[var5];
558 | if (!result.contains(str)) {
559 | result.add(str);
560 | }
561 | }
562 |
563 | return toStringArray((Collection)result);
564 | }
565 | }
566 |
567 | public static String[] sortStringArray(String[] array) {
568 | if (ObjectUtils.isEmpty(array)) {
569 | return new String[0];
570 | } else {
571 | Arrays.sort(array);
572 | return array;
573 | }
574 | }
575 |
576 | public static String[] toStringArray(Collection collection) {
577 | return (String[])collection.toArray(new String[0]);
578 | }
579 |
580 | public static String[] toStringArray(Enumeration enumeration) {
581 | return toStringArray((Collection)Collections.list(enumeration));
582 | }
583 |
584 | public static String[] trimArrayElements(@Nullable String[] array) {
585 | if (ObjectUtils.isEmpty(array)) {
586 | return new String[0];
587 | } else {
588 | String[] result = new String[array.length];
589 |
590 | for(int i = 0; i < array.length; ++i) {
591 | String element = array[i];
592 | result[i] = element != null ? element.trim() : null;
593 | }
594 |
595 | return result;
596 | }
597 | }
598 |
599 | public static String[] removeDuplicateStrings(String[] array) {
600 | if (ObjectUtils.isEmpty(array)) {
601 | return array;
602 | } else {
603 | Set set = new LinkedHashSet(Arrays.asList(array));
604 | return toStringArray((Collection)set);
605 | }
606 | }
607 |
608 | @Nullable
609 | public static String[] split(@Nullable String toSplit, @Nullable String delimiter) {
610 | if (hasLength(toSplit) && hasLength(delimiter)) {
611 | int offset = toSplit.indexOf(delimiter);
612 | if (offset < 0) {
613 | return null;
614 | } else {
615 | String beforeDelimiter = toSplit.substring(0, offset);
616 | String afterDelimiter = toSplit.substring(offset + delimiter.length());
617 | return new String[]{beforeDelimiter, afterDelimiter};
618 | }
619 | } else {
620 | return null;
621 | }
622 | }
623 |
624 | @Nullable
625 | public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) {
626 | return splitArrayElementsIntoProperties(array, delimiter, (String)null);
627 | }
628 |
629 | @Nullable
630 | public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter, @Nullable String charsToDelete) {
631 | if (ObjectUtils.isEmpty(array)) {
632 | return null;
633 | } else {
634 | Properties result = new Properties();
635 | String[] var4 = array;
636 | int var5 = array.length;
637 |
638 | for(int var6 = 0; var6 < var5; ++var6) {
639 | String element = var4[var6];
640 | if (charsToDelete != null) {
641 | element = deleteAny(element, charsToDelete);
642 | }
643 |
644 | String[] splittedElement = split(element, delimiter);
645 | if (splittedElement != null) {
646 | result.setProperty(splittedElement[0].trim(), splittedElement[1].trim());
647 | }
648 | }
649 |
650 | return result;
651 | }
652 | }
653 |
654 | public static String[] tokenizeToStringArray(@Nullable String str, String delimiters) {
655 | return tokenizeToStringArray(str, delimiters, true, true);
656 | }
657 |
658 | public static String[] tokenizeToStringArray(@Nullable String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
659 | if (str == null) {
660 | return new String[0];
661 | } else {
662 | StringTokenizer st = new StringTokenizer(str, delimiters);
663 | ArrayList tokens = new ArrayList();
664 |
665 | while(true) {
666 | String token;
667 | do {
668 | if (!st.hasMoreTokens()) {
669 | return toStringArray((Collection)tokens);
670 | }
671 |
672 | token = st.nextToken();
673 | if (trimTokens) {
674 | token = token.trim();
675 | }
676 | } while(ignoreEmptyTokens && token.length() <= 0);
677 |
678 | tokens.add(token);
679 | }
680 | }
681 | }
682 |
683 | public static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter) {
684 | return delimitedListToStringArray(str, delimiter, (String)null);
685 | }
686 |
687 | public static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter, @Nullable String charsToDelete) {
688 | if (str == null) {
689 | return new String[0];
690 | } else if (delimiter == null) {
691 | return new String[]{str};
692 | } else {
693 | List result = new ArrayList();
694 | int pos;
695 | if ("".equals(delimiter)) {
696 | for(pos = 0; pos < str.length(); ++pos) {
697 | result.add(deleteAny(str.substring(pos, pos + 1), charsToDelete));
698 | }
699 | } else {
700 | int delPos;
701 | for(pos = 0; (delPos = str.indexOf(delimiter, pos)) != -1; pos = delPos + delimiter.length()) {
702 | result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
703 | }
704 |
705 | if (str.length() > 0 && pos <= str.length()) {
706 | result.add(deleteAny(str.substring(pos), charsToDelete));
707 | }
708 | }
709 |
710 | return toStringArray((Collection)result);
711 | }
712 | }
713 |
714 | public static String[] commaDelimitedListToStringArray(@Nullable String str) {
715 | return delimitedListToStringArray(str, ",");
716 | }
717 |
718 | public static Set commaDelimitedListToSet(@Nullable String str) {
719 | String[] tokens = commaDelimitedListToStringArray(str);
720 | return new LinkedHashSet(Arrays.asList(tokens));
721 | }
722 |
723 | public static String collectionToDelimitedString(@Nullable Collection> coll, String delim, String prefix, String suffix) {
724 | if (CollectionUtils.isEmpty(coll)) {
725 | return "";
726 | } else {
727 | StringBuilder sb = new StringBuilder();
728 | Iterator it = coll.iterator();
729 |
730 | while(it.hasNext()) {
731 | sb.append(prefix).append(it.next()).append(suffix);
732 | if (it.hasNext()) {
733 | sb.append(delim);
734 | }
735 | }
736 |
737 | return sb.toString();
738 | }
739 | }
740 |
741 | public static String collectionToDelimitedString(@Nullable Collection> coll, String delim) {
742 | return collectionToDelimitedString(coll, delim, "", "");
743 | }
744 |
745 | public static String collectionToCommaDelimitedString(@Nullable Collection> coll) {
746 | return collectionToDelimitedString(coll, ",");
747 | }
748 |
749 | public static String arrayToDelimitedString(@Nullable Object[] arr, String delim) {
750 | if (ObjectUtils.isEmpty(arr)) {
751 | return "";
752 | } else if (arr.length == 1) {
753 | return ObjectUtils.nullSafeToString(arr[0]);
754 | } else {
755 | StringBuilder sb = new StringBuilder();
756 |
757 | for(int i = 0; i < arr.length; ++i) {
758 | if (i > 0) {
759 | sb.append(delim);
760 | }
761 |
762 | sb.append(arr[i]);
763 | }
764 |
765 | return sb.toString();
766 | }
767 | }
768 |
769 | public static String arrayToCommaDelimitedString(@Nullable Object[] arr) {
770 | return arrayToDelimitedString(arr, ",");
771 | }
772 | }
773 |
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/communication/http/HttpClient.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common.communication.http;
2 |
3 | import org.jsoup.Connection;
4 | import org.jsoup.Connection.Response;
5 | import org.jsoup.Jsoup;
6 |
7 | import javax.net.ssl.*;
8 | import java.io.*;
9 | import java.net.URLEncoder;
10 | import java.security.SecureRandom;
11 | import java.security.cert.CertificateException;
12 | import java.security.cert.X509Certificate;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.Map;
16 | import java.util.Map.Entry;
17 | import java.util.Set;
18 |
19 | /**
20 | * Http、Https客户端
21 | * @Auther: xcbeyond
22 | * @Date: 2019/1/17 18:03
23 | */
24 | public class HttpClient {
25 |
26 | /**
27 | * 请求超时时间
28 | */
29 | private static final int TIME_OUT = 120000;
30 |
31 | /**
32 | * Https请求
33 | */
34 | private static final String HTTPS = "https";
35 |
36 | /**
37 | * 发送JSON格式参数POST请求
38 | * @param url 请求路径
39 | * @param params JSON格式请求参数
40 | * @return 服务器响应对象
41 | * @throws IOException
42 | */
43 | public static Response post(String url, String params) throws IOException {
44 | return doPostRequest(url, null, null, params);
45 | }
46 |
47 | /**
48 | * 字符串参数post请求
49 | * @param url 请求URL地址
50 | * @param param 请求参数Map
51 | * @return 服务器响应对象
52 | * @throws IOException
53 | */
54 | public static Response post(String url, Map param) throws IOException {
55 | return doPostRequest(url, param, null, null);
56 | }
57 |
58 | /**
59 | * 带上传文件的post请求
60 | * @param url 请求URL地址
61 | * @param param 请求字符串参数集合
62 | * @param fileMap 请求文件参数集合
63 | * @return 服务器响应对象
64 | * @throws IOException
65 | */
66 | public static Response post(String url, Map param, Map fileMap) throws IOException {
67 | return doPostRequest(url, param, fileMap, null);
68 | }
69 |
70 | /**
71 | * 执行post请求
72 | * @param url 请求URL地址
73 | * @param paramMap 请求字符串参数Map
74 | * @param fileMap 请求文件参数集合
75 | * @return 服务器响应对象
76 | * @throws IOException
77 | */
78 | private static Response doPostRequest(String url, Map paramMap, Map fileMap, String jsonParams) throws IOException {
79 | if (null == url || url.isEmpty()) {
80 | throw new RuntimeException("The request URL is blank.");
81 | }
82 |
83 | Connection connection = initConn(url, Connection.Method.POST);
84 |
85 | // 收集上传文件输入流,最终全部关闭
86 | List inputStreamList = null;
87 | try {
88 | // 添加文件参数
89 | if (null != fileMap && !fileMap.isEmpty()) {
90 | inputStreamList = new ArrayList();
91 | InputStream in = null;
92 | File file = null;
93 | Set> set = fileMap.entrySet();
94 | for (Entry e : set) {
95 | file = e.getValue();
96 | in = new FileInputStream(file);
97 | inputStreamList.add(in);
98 | connection.data(e.getKey(), file.getName(), in);
99 | }
100 | }
101 |
102 | // 设置请求体为JSON格式内容
103 | else if (null != jsonParams && !jsonParams.isEmpty()) {
104 | connection.header("Content-Type", "application/json;charset=UTF-8");
105 | connection.requestBody(jsonParams);
106 | }
107 |
108 | // 普通表单提交方式
109 | else {
110 | connection.header("Content-Type", "application/x-www-form-urlencoded");
111 | }
112 |
113 | // 添加字符串类参数
114 | if (null != paramMap && !paramMap.isEmpty()) {
115 | connection.data(paramMap);
116 | }
117 |
118 | Response response = connection.execute();
119 | return response;
120 | } catch (FileNotFoundException e) {
121 | throw e;
122 | } catch (IOException e) {
123 | throw e;
124 | } finally {// 关闭上传文件的输入流
125 | if (null != inputStreamList) {
126 | for (InputStream in : inputStreamList) {
127 | try {
128 | in.close();
129 | } catch (IOException e) {
130 | e.printStackTrace();
131 | }
132 | }
133 | }
134 | }
135 | }
136 |
137 | /**
138 | * Get请求
139 | * @param url 请求URL
140 | * @param param 请求参数Map
141 | * @return 服务器响应对象
142 | * @throws IOException
143 | */
144 | public static Response get(String url, Map param) throws IOException {
145 | if (null == url || url.isEmpty()) {
146 | throw new RuntimeException("The request URL is blank.");
147 | }
148 |
149 | if (null != param && !param.isEmpty()) {
150 | StringBuilder sb = new StringBuilder(url);
151 | if (url.indexOf("?") == -1) {
152 | sb.append("?");
153 | }
154 | sb.append(map2UrlParam(param));
155 |
156 | url = sb.toString();
157 | }
158 |
159 | Connection connection = initConn(url, Connection.Method.GET);
160 | Response response = connection.execute();
161 |
162 | return response;
163 | }
164 |
165 | /**
166 | * Put请求
167 | * @param url 请求URL
168 | * @param param 请求参数Map
169 | * @return 服务器响应对象
170 | * @throws Exception
171 | */
172 | public static Response put(String url, Map param) throws Exception {
173 | if (null == url || url.isEmpty()) {
174 | throw new RuntimeException("The request URL is blank.");
175 | }
176 |
177 | Connection connection = initConn(url, Connection.Method.PUT);
178 | connection.data(param);
179 |
180 | Response response = connection.execute();
181 | return response;
182 | }
183 |
184 | /**
185 | * 将请求参数map转换为Url参数字符串
186 | * @param param 请求参数map
187 | * @return Url参数字符串 格式为:key1=value1&key2=value2
188 | * @throws UnsupportedEncodingException
189 | */
190 | private static String map2UrlParam(Map param) throws UnsupportedEncodingException {
191 | if (null == param || param.isEmpty()) {
192 | return null;
193 | }
194 | StringBuffer url = new StringBuffer();
195 | boolean isfist = true;
196 | for (Entry entry : param.entrySet()) {
197 | if (isfist) {
198 | isfist = false;
199 | } else {
200 | url.append("&");
201 | }
202 | url.append(entry.getKey()).append("=");
203 | String value = entry.getValue();
204 | if (null != value && !"".equals(value)) {
205 | url.append(URLEncoder.encode(value, "UTF-8"));
206 | }
207 | }
208 | return url.toString();
209 |
210 | }
211 |
212 | /**
213 | * 初始化请求连接
214 | * @param url
215 | * @param requestMethod
216 | * @return
217 | */
218 | private static Connection initConn(String url, Connection.Method requestMethod) {
219 | // 如果是Https请求
220 | if (url.startsWith(HTTPS)) {
221 | getTrust();
222 | }
223 |
224 | Connection connection = Jsoup.connect(url);
225 | connection.method(requestMethod);
226 | connection.timeout(TIME_OUT);
227 | connection.ignoreHttpErrors(true);
228 | connection.ignoreContentType(true);
229 |
230 | return connection;
231 | }
232 |
233 | /**
234 | * 获取服务器信任
235 | */
236 | private static void getTrust() {
237 | try {
238 | HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
239 |
240 | public boolean verify(String hostname, SSLSession session) {
241 | return true;
242 | }
243 | });
244 | SSLContext context = SSLContext.getInstance("TLS");
245 | context.init(null, new X509TrustManager[] { new X509TrustManager() {
246 |
247 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
248 | }
249 |
250 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
251 | }
252 |
253 | public X509Certificate[] getAcceptedIssuers() {
254 | return new X509Certificate[0];
255 | }
256 | } }, new SecureRandom());
257 | HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
258 | } catch (Exception e) {
259 | e.printStackTrace();
260 | }
261 | }
262 | }
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/communication/socket/SocketClient.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common.communication.socket;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.BufferedInputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.OutputStream;
10 | import java.net.ConnectException;
11 | import java.net.Socket;
12 | import java.net.UnknownHostException;
13 | import java.nio.ByteBuffer;
14 | import java.nio.channels.UnresolvedAddressException;
15 | import java.nio.charset.Charset;
16 |
17 | /**
18 | * socket客户端
19 | * @Auther: xcbeyond
20 | * @Date: 2019/4/22 15:45
21 | */
22 | public class SocketClient {
23 | // 日志记录类
24 | private static Logger logger = LoggerFactory.getLogger(SocketClient.class);
25 |
26 | // 字符集编码
27 | private static final Charset UTF8 = Charset.forName("UTF-8");
28 |
29 | // Socket链接地址
30 | private String ip = null;
31 | // Socket链接端口
32 | private int port = 0;
33 | // 消息长度
34 | private int msglen = 8;
35 | // Socket链接超时时间(默认值为30秒)
36 | private int timeout = 30000;
37 | // 读取缓冲区(默认1024字节)
38 | private int bufferCapacity = 1024;
39 | // 字符集
40 | private String charset = "UTF-8";
41 |
42 |
43 | public SocketClient(String ip, int port) {
44 | this.ip = ip;
45 | this.port = port;
46 | }
47 |
48 | public String sendMessage(String msg) {
49 | logger.debug("通讯开始处理请求!");
50 |
51 | Socket client = null;
52 | //输入流
53 | InputStream is = null;
54 | //输出流
55 | OutputStream os = null;
56 | //返回报文
57 | byte[] result = null;
58 | try {
59 | // 创建Socket链接
60 | client = new Socket(ip, port);
61 |
62 | // 定义用来存储发送数据的byte缓冲区
63 | byte[] sendContent = msg.getBytes(charset);
64 | int contentLength = sendContent.length;
65 | ByteBuffer sendbuffer = ByteBuffer.allocate(contentLength + 8);
66 |
67 | // 添加报文头
68 | String header = getWriteHead(contentLength);
69 | sendbuffer.put(header.getBytes(charset));
70 |
71 | sendbuffer.put(msg.getBytes(charset));
72 |
73 | // 将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
74 | sendbuffer.flip();
75 |
76 | // 向服务器发送数据
77 | this.sendMsg(sendbuffer.array(), client, os);
78 | // 读取对方返回数据
79 | result = this.readMsg(client, is);
80 |
81 | if (null == result) {
82 | logger.error("收到应答报文为空");
83 | }
84 |
85 | } catch (UnresolvedAddressException ue) {
86 | logger.error("远程服务配置的地址格式不正确:[" + ip + "]", ue);
87 | } catch (UnknownHostException e) {
88 | logger.error("无法建立到远程服务器地址的链接[" + ip + ":" + port
89 | + "]", e);
90 | } catch (ConnectException ce) {
91 | logger.error("无法连接到远程服务器[" + ip + ":" + port
92 | + "]", ce);
93 | } catch (IOException e) {
94 | logger.error("通讯接出捕获IO错误", e);
95 | } catch (Exception e) {
96 | logger.error("连接到远程服务器执行服务时发生未知异常", e);
97 | } finally {
98 | try {
99 | // 关闭输出流
100 | if (null != os) {
101 | os.close();
102 | }
103 | // 关闭输入流
104 | if (null != is) {
105 | is.close();
106 | }
107 | // 关闭链接
108 | if (null != client) {
109 | client.close();
110 | }
111 | } catch (IOException e) {
112 | logger.error("关闭链接时捕获IO错误,抛出通讯接出异常!", e);
113 | }
114 | }
115 |
116 | return new String(result,UTF8);
117 | }
118 |
119 |
120 | /**
121 | * 读取返回数据
122 | * @param client
123 | * @param is
124 | * @return
125 | * @throws IOException
126 | */
127 | private byte[] readMsg(Socket client, InputStream is) throws IOException {
128 | // 记录等待起始时间
129 | long startTime = System.currentTimeMillis();
130 |
131 | //设置超时时间
132 | client.setSoTimeout(timeout);
133 | is = client.getInputStream();
134 | BufferedInputStream bis = new BufferedInputStream(is);
135 | //首先读取报文头长度
136 | byte[] head = new byte[msglen];
137 | bis.read(head, 0, head.length);
138 | int length = 0;
139 | try {
140 | length = Integer.parseInt(new String(head));
141 | } catch (NumberFormatException nfe) {
142 | logger.error("报文格式有误,[报文长度]域包含无效数字!");
143 | nfe.printStackTrace();
144 | }
145 |
146 | logger.debug("读取报文头,获得报文内容的大小为:[" + length + "]");
147 |
148 | //定义用于存放整个报文体的缓冲区数组
149 | byte[] request = new byte[length];
150 | //已读取到的数据
151 | int bufferSize = 0;
152 | // 每次读取的数据的值
153 | int numberRead = 0;
154 | while (true) {
155 | if(bufferCapacity + bufferSize > length) {
156 | numberRead = bis.read(request, bufferSize, length - bufferSize);
157 | } else {
158 | numberRead = bis.read(request, bufferSize ,bufferCapacity);
159 | }
160 | bufferSize += numberRead;
161 | if (bufferSize == length) {
162 | break;
163 | }
164 | }
165 |
166 | logger.debug("读取报文完成,获取报文内容为:[" + new String(request,UTF8) + "]");
167 |
168 | // 记录当前时间并计算已等待时间
169 | long currentTime = System.currentTimeMillis();
170 | long waitTime = currentTime - startTime;
171 |
172 | logger.debug("当前时间:" + currentTime
173 | + ",开始等待读的时间:" + startTime + ",已等待时间:"
174 | + waitTime + "毫秒");
175 | return request;
176 | }
177 |
178 | /**
179 | * 发送消息
180 | * @param buff
181 | * @return
182 | * @throws IOException
183 | */
184 | private void sendMsg(byte[] buff, Socket client, OutputStream os) throws IOException {
185 | logger.debug("开始发送数据...\r\n"+ new String(buff, UTF8));
186 |
187 | os = client.getOutputStream();
188 | os.write(buff);
189 | os.flush();
190 |
191 | logger.debug("数据发送完毕,发送数据的长度为:[" + buff.length + "]");
192 | }
193 |
194 | /**
195 | * 拼发送8位报文长度
196 | * @param length
197 | * @return
198 | */
199 | private String getWriteHead(long length) {
200 | StringBuilder result = new StringBuilder();
201 | String res = String.valueOf(length);
202 | if (res.length() == 8) {
203 | result.append(res);
204 | } else {
205 | res = "00000000" + res;
206 | int index = res.length() - 8;
207 | result.append(res.substring(index, res.length()));
208 | }
209 | return result.toString();
210 | }
211 | }
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/communication/socket/SocketServer.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common.communication.socket;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.DataInputStream;
7 | import java.io.DataOutputStream;
8 | import java.io.IOException;
9 | import java.net.ServerSocket;
10 | import java.net.Socket;
11 | import java.nio.charset.Charset;
12 |
13 | /**
14 | * socket服务器
15 | * @Auther: xcbeyond
16 | * @Date: 2019/4/22 16:29
17 | */
18 | public class SocketServer {
19 | private static Logger log = LoggerFactory.getLogger(SocketServer.class);
20 | private static int port = 9999;
21 |
22 | public SocketServer(int port) {
23 | this.port = port;
24 | }
25 |
26 | public void start() {
27 | log.info("开始启动SocketServer,端口:" + port);
28 | try {
29 | ServerSocket server = new ServerSocket(port);
30 | while (true) {
31 | Socket socket = server.accept();
32 | new Task(socket).start();
33 | }
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | log.error("SocketServer启动失败,异常为:" + e.getMessage());
37 | }
38 | }
39 |
40 | /**
41 | * 用来处理Socket的Task
42 | */
43 | class Task extends Thread {
44 | // 字符集编码
45 | private final Charset UTF8 = Charset.forName("UTF-8");
46 |
47 | private Socket socket;
48 |
49 | public Task(Socket socket) {
50 | this.socket = socket;
51 | }
52 |
53 | @Override
54 | public void run() {
55 | handleSocket();
56 |
57 | }
58 |
59 | // 完成与客户端socket的通信
60 | private void handleSocket() {
61 | DataInputStream dis = null;
62 | DataOutputStream dos = null;
63 | try {
64 |
65 | dis = new DataInputStream(socket.getInputStream());
66 | dos = new DataOutputStream(socket.getOutputStream());
67 |
68 | byte[] contentLengthBy = new byte[8];
69 | dis.read(contentLengthBy);
70 | int contentLength = Integer.parseInt(new String(contentLengthBy, UTF8));
71 | byte[] bytes = new byte[contentLength];
72 | dis.read(bytes); // size是读取到的字节数
73 |
74 | String request = new String(bytes, UTF8);
75 | log.debug("接收到的数据:" + request);
76 |
77 |
78 | //TODO 此处进行服务端的业务逻辑处理
79 | String responseBody = "Request received!";
80 |
81 | //拼装响应数据长度
82 | String response = getWriteHead(responseBody.getBytes("UTF-8").length) + responseBody;
83 |
84 | log.debug("返回的数据:" + response);
85 | dos.write(response.getBytes(UTF8));
86 | dos.flush();
87 | } catch (IOException e) {
88 | e.printStackTrace();
89 | } finally {
90 | try {
91 | dis.close();
92 | dos.close();
93 | socket.close();
94 | } catch (IOException e) {
95 | e.printStackTrace();
96 | }
97 |
98 | }
99 | }
100 | }
101 |
102 | /**
103 | * 拼发送报文长度
104 | * @param length
105 | * @return
106 | */
107 | private String getWriteHead(long length) {
108 | StringBuilder result = new StringBuilder();
109 | String res = String.valueOf(length);
110 | if (res.length() == 8) {
111 | result.append(res);
112 | } else {
113 | res = "00000000" + res;
114 | int index = res.length() - 8;
115 | result.append(res.substring(index, res.length()));
116 | }
117 | return result.toString();
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/com/xcbeyond/common/data/redis/RedisUtils.java:
--------------------------------------------------------------------------------
1 | package com.xcbeyond.common.data.redis;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.data.redis.core.ListOperations;
5 | import org.springframework.data.redis.core.RedisTemplate;
6 | import org.springframework.data.redis.support.atomic.RedisAtomicLong;
7 | import org.springframework.stereotype.Component;
8 |
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.Set;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | /**
15 | * redis操作工具类.
16 | * (基于RedisTemplate)
17 | * @Auther: xcbeyond
18 | * @Date: 2019/1/16 16:13
19 | */
20 | @Component
21 | public class RedisUtils {
22 | @Autowired
23 | private RedisTemplate redisTemplate;
24 |
25 | /**
26 | * 读取缓存
27 | * @param key
28 | * @return
29 | */
30 | public String get(final String key) {
31 | return redisTemplate.opsForValue().get(key);
32 | }
33 |
34 | /**
35 | * 获取所有以prefix开头的key
36 | * @param prefix 前缀key
37 | * @return
38 | */
39 | public Set getKeysByPrefix(String prefix){
40 | return redisTemplate.keys(prefix + "*");
41 | }
42 |
43 | /**
44 | * 写入缓存
45 | * @param key
46 | * @param value
47 | * @return
48 | */
49 | public boolean set(final String key, String value) {
50 | boolean result = false;
51 | try {
52 | redisTemplate.opsForValue().set(key, value);
53 | result = true;
54 | } catch (Exception e) {
55 | e.printStackTrace();
56 | }
57 | return result;
58 | }
59 |
60 | /**
61 | * 写入缓存并设置缓存过期时间
62 | * @param key
63 | * @param value
64 | * @param expiration 过期时间,秒
65 | * @return
66 | */
67 | public boolean set(final String key, String value,long expiration) {
68 | boolean result = false;
69 | try {
70 | redisTemplate.opsForValue().set(key, value, expiration, TimeUnit.SECONDS);
71 | result = true;
72 | } catch (Exception e) {
73 | e.printStackTrace();
74 | }
75 | return result;
76 | }
77 |
78 | /**
79 | * 写入缓存,并带自动序列的key
80 | * @param key
81 | * @param value
82 | * @return
83 | */
84 | public boolean setAutoKey(final String key, String value) {
85 | boolean result = false;
86 | try {
87 | RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
88 | Long increment = entityIdCounter.getAndIncrement();
89 |
90 | redisTemplate.opsForValue().set(key + ":" + increment, value);
91 | result = true;
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | }
95 | return result;
96 | }
97 |
98 | /**
99 | * 是否包含key
100 | * @param key
101 | * @return
102 | */
103 | public boolean hasKey(final String key) {
104 | boolean result = false;
105 | try {
106 | return redisTemplate.hasKey(key);
107 | } catch (Exception e) {
108 | e.printStackTrace();
109 | }
110 | return result;
111 | }
112 |
113 | /**
114 | * 更新缓存
115 | * @param key
116 | * @param value
117 | * @return
118 | */
119 | public boolean getAndSet(final String key, String value) {
120 | boolean result = false;
121 | try {
122 | redisTemplate.opsForValue().getAndSet(key, value);
123 | result = true;
124 | } catch (Exception e) {
125 | e.printStackTrace();
126 | }
127 | return result;
128 | }
129 |
130 | /**
131 | * 删除缓存
132 | * @param key
133 | * @return
134 | */
135 | public boolean delete(final String key) {
136 | boolean result = false;
137 | try {
138 | redisTemplate.delete(key);
139 | result = true;
140 | } catch (Exception e) {
141 | e.printStackTrace();
142 | }
143 | return result;
144 | }
145 |
146 | /**
147 | * 按照key的前缀删除
148 | * @param prefix 前缀key
149 | * @return
150 | */
151 | public void deleteByPrefix(final String prefix) {
152 | Set keys = redisTemplate.keys(prefix + "*");
153 | if (!keys.isEmpty()) {
154 | redisTemplate.delete(keys);
155 | }
156 | }
157 |
158 | /**
159 | * 写入 list 以元素的形式
160 | * @param key
161 | * @param value
162 | * @return
163 | */
164 | public boolean addList(final String key, String value) {
165 | boolean result = false;
166 | try {
167 | ListOperations list = redisTemplate.opsForList();
168 | list.rightPush(key, value);
169 | result = true;
170 | } catch (Exception e) {
171 | e.printStackTrace();
172 | }
173 | return result;
174 | }
175 |
176 | /**
177 | * 直接写入 list
178 | * @param key
179 | * @param list
180 | * @return
181 | */
182 | public boolean addListAll(final String key, List list) {
183 | boolean result = false;
184 | try {
185 | ListOperations list2 = redisTemplate.opsForList();
186 | list2.rightPushAll(key, list);
187 | result = true;
188 | } catch (Exception e) {
189 | e.printStackTrace();
190 | }
191 | return result;
192 | }
193 |
194 | /**
195 | * 删除list中元素
196 | * @param key
197 | * @param value
198 | * @return
199 | */
200 | public boolean deleteListEm(final String key, String value) {
201 | boolean result = false;
202 | try {
203 | ListOperations list2 = redisTemplate.opsForList();
204 | list2.remove(key, 1, value); //将删除list中存储在列表中第一次出现的 value
205 | result = true;
206 | } catch (Exception e) {
207 | e.printStackTrace();
208 | }
209 | return result;
210 | }
211 |
212 | /**
213 | * 判断是否存在key
214 | * @param key
215 | * @return
216 | */
217 | public boolean isExsitKey(final String key){
218 | return redisTemplate.hasKey(key);
219 | }
220 |
221 | /**
222 | * 增加hash结构的数据
223 | * @param key
224 | * @param map
225 | * @return
226 | */
227 | public boolean addHash(final String key, Map map){
228 | boolean result = false;
229 | try {
230 | redisTemplate.opsForHash().putAll(key, map);
231 | result = true;
232 | } catch (Exception e) {
233 | e.printStackTrace();
234 | }
235 | return result;
236 | }
237 |
238 | /**
239 | * 删除Hash结构的数据
240 | * @param key
241 | * @param mapKey
242 | * @return
243 | */
244 | public boolean delHash(final String key, String mapKey){
245 | boolean result = false;
246 | try {
247 | redisTemplate.opsForHash().delete(key, mapKey);
248 | result = true;
249 | } catch (Exception e) {
250 | e.printStackTrace();
251 | }
252 | return result;
253 | }
254 |
255 | /**
256 | * 获取hash中的值
257 | * @param key
258 | */
259 | public Map