001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.utils;
017
018import com.jfinal.core.JFinal;
019import com.jfinal.kit.StrKit;
020import com.jfinal.log.Log;
021import com.jfinal.plugin.activerecord.Model;
022import io.jboot.web.validate.Regex;
023import org.apache.commons.lang3.ArrayUtils;
024import org.apache.commons.lang3.StringUtils;
025
026import java.io.UnsupportedEncodingException;
027import java.net.URLDecoder;
028import java.net.URLEncoder;
029import java.util.*;
030import java.util.regex.Matcher;
031import java.util.regex.Pattern;
032
033public class StrUtil extends StrKit {
034
035    private static final Log log = Log.getLog(StrUtil.class);
036
037    public static final String EMPTY = "";
038    public static final String SPACE = " ";
039
040    public static String urlDecode(String string) {
041        try {
042            return URLDecoder.decode(string, JFinal.me().getConstants().getEncoding());
043        } catch (UnsupportedEncodingException e) {
044            log.error("urlDecode is error", e);
045        }
046        return string;
047    }
048
049    public static String urlEncode(String string) {
050        try {
051            return URLEncoder.encode(string, JFinal.me().getConstants().getEncoding());
052        } catch (UnsupportedEncodingException e) {
053            log.error("urlEncode is error", e);
054        }
055        return string;
056    }
057
058    public static String urlRedirect(String redirect) {
059        try {
060            redirect = new String(redirect.getBytes(JFinal.me().getConstants().getEncoding()), "ISO8859_1");
061        } catch (UnsupportedEncodingException e) {
062            log.error("urlRedirect is error", e);
063        }
064        return redirect;
065    }
066
067    private static final Map<String, String> EMPTY_MAP = new HashMap<>();
068
069    public static Map<String, String> queryStringToMap(String queryString) {
070        if (StrUtil.isBlank(queryString)) {
071            return EMPTY_MAP;
072        }
073
074        Map<String, String> map = new HashMap<>();
075        String[] params = queryString.split("&");
076        for (String paramPair : params) {
077            String[] keyAndValue = paramPair.split("=");
078            if (keyAndValue.length == 2) {
079                map.put(keyAndValue[0], keyAndValue[1]);
080            } else if (keyAndValue.length == 1) {
081                map.put(keyAndValue[0], "");
082            }
083        }
084        return map;
085    }
086
087
088    public static String mapToQueryString(Map map) {
089        if (map == null || map.isEmpty()) {
090            return EMPTY;
091        }
092
093        StringBuilder sb = new StringBuilder();
094
095        for (Object key : map.keySet()) {
096            if (key == null || key.equals(StrUtil.EMPTY)) {
097                continue;
098            }
099            if (sb.length() > 0) {
100                sb.append("&");
101            }
102
103            sb.append(key.toString().trim());
104            sb.append("=");
105            Object value = map.get(key);
106            sb.append(value == null ? EMPTY : StrUtil.urlEncode(value.toString().trim()));
107        }
108
109
110        return sb.toString();
111    }
112
113    public static boolean areNotEmpty(String... strs) {
114        if (strs == null || strs.length == 0) {
115            return false;
116        }
117
118        for (String string : strs) {
119            if (string == null || EMPTY.equals(string)) {
120                return false;
121            }
122        }
123        return true;
124    }
125
126    public static boolean isAnyBlank(String... strs) {
127        if (strs == null || strs.length == 0) {
128            return false;
129        }
130
131        for (String str : strs) {
132            if (isBlank(str)) {
133                return true;
134            }
135        }
136        return false;
137    }
138
139    public static boolean isStartsWithAny(String str, String... prefixes) {
140        if (isBlank(str) || prefixes == null || prefixes.length == 0) {
141            return false;
142        }
143
144        for (String prefix : prefixes) {
145            if (str.startsWith(prefix)) {
146                return true;
147            }
148        }
149        return false;
150    }
151
152
153    public static String requireNonBlank(String str) {
154        if (isBlank(str)) {
155            throw new NullPointerException();
156        }
157        return str;
158    }
159
160    public static String requireNonBlank(String str, String message) {
161        if (isBlank(str)) {
162            throw new NullPointerException(message);
163        }
164        return str;
165    }
166
167    @Deprecated
168    public static String obtainDefaultIfBlank(String value, String defaultValue) {
169        return obtainDefault(value, defaultValue);
170    }
171
172
173    public static String obtainDefault(String value, String defaultValue) {
174        return isBlank(value) ? defaultValue : value;
175    }
176
177
178    public static String obtainNotBlank(String... values) {
179        if (values == null || values.length == 0) {
180            throw new IllegalArgumentException("Arguments is null or empty.");
181        }
182
183        for (String value : values) {
184            if (isNotBlank(value)) {
185                return value;
186            }
187        }
188
189        return null;
190    }
191
192    /**
193     * 不是空数据,注意:空格不是空数据
194     *
195     * @param str
196     * @return
197     */
198    public static boolean isNotEmpty(String str) {
199        return str != null && !str.equals(EMPTY);
200    }
201
202
203    /**
204     * 确保不是空白字符串
205     *
206     * @param str
207     * @return
208     */
209    public static boolean isNotBlank(Object str) {
210        return str != null && notBlank(str.toString());
211    }
212
213
214    /**
215     * null 或者 空内容字符串
216     * 使用 isBlank 代替
217     *
218     * @param str
219     * @return
220     */
221    @Deprecated
222    public static boolean isNullOrBlank(String str) {
223        return isBlank(str);
224    }
225
226
227    /**
228     * 字符串是否匹配某个正则
229     *
230     * @param string
231     * @param regex
232     * @return
233     */
234    public static boolean match(String string, String regex) {
235        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
236        Matcher matcher = pattern.matcher(string);
237        return matcher.matches();
238    }
239
240
241    /**
242     * 这个字符串是否是全是数字
243     *
244     * @param str
245     * @return
246     */
247    public static boolean isNumeric(String str) {
248        if (isBlank(str)) {
249            return false;
250        }
251        for (int i = str.length(); --i >= 0; ) {
252            int chr = str.charAt(i);
253            if (chr < 48 || chr > 57) {
254                return false;
255            }
256        }
257        return true;
258    }
259
260    /**
261     * 这个字符串是否是可能包含小数点的数字
262     *
263     * @param str
264     * @return
265     */
266    public static boolean isDecimal(String str) {
267        if (isBlank(str)) {
268            return false;
269        }
270        boolean hasDot = false;
271        for (int i = str.length(); --i >= 0; ) {
272            int chr = str.charAt(i);
273            if ((chr < 48 || chr > 57) && chr != '.') {
274                return false;
275            }
276            if (chr == '.') {
277                if (hasDot) {
278                    return false;
279                } else {
280                    hasDot = true;
281                }
282            }
283        }
284        return true;
285    }
286
287    /**
288     * 是否是邮件的字符串
289     *
290     * @param email
291     * @return
292     */
293    public static boolean isEmail(String email) {
294        return isNotBlank(email) && email.matches(Regex.EMAIL);
295    }
296
297
298    /**
299     * 是否是中国地区手机号码
300     *
301     * @param mobileNumber
302     * @return
303     */
304    public static boolean isMobileNumber(String mobileNumber) {
305        return isNotBlank(mobileNumber) && mobileNumber.matches(Regex.MOBILE);
306    }
307
308
309    /**
310     * 生成一个新的UUID
311     *
312     * @return
313     */
314    public static String uuid() {
315        return UUID.randomUUID().toString().replace("-", "");
316    }
317
318
319    /**
320     * 根据逗号分隔为set
321     *
322     * @param src
323     * @return
324     */
325    public static Set<String> splitToSetByComma(String src) {
326        return splitToSet(src, ",");
327    }
328
329    /**
330     * 把字符串拆分成一个set
331     *
332     * @param src
333     * @param regex
334     * @return
335     */
336    public static Set<String> splitToSet(String src, String regex) {
337        if (src == null) {
338            return null;
339        }
340
341        String[] strings = src.split(regex);
342        Set<String> set = new LinkedHashSet<>();
343        for (String s : strings) {
344            if (StrUtil.isBlank(s)) {
345                continue;
346            }
347            set.add(s.trim());
348        }
349        return set;
350    }
351
352
353    private static final String[] htmlChars = {"&", "<", ">", "'", "\""};
354    private static final String[] escapeChars = {"&amp;", "&lt;", "&gt;", "&#39;", "&quot;"};
355
356    public static String escapeHtml(String content) {
357        return isBlank(content) ? content : StringUtils.replaceEach(content, htmlChars, escapeChars);
358    }
359
360    public static String unEscapeHtml(String content) {
361        return isBlank(content) ? content : StringUtils.replaceEach(content, escapeChars, htmlChars);
362    }
363
364    public static Model escapeModel(Model model, String... ignoreAttrs) {
365        String[] attrNames = model._getAttrNames();
366        for (String attr : attrNames) {
367
368            if (ArrayUtils.contains(ignoreAttrs, attr)) {
369                continue;
370            }
371
372            Object value = model.get(attr);
373
374            if (value instanceof String) {
375                model.set(attr, escapeHtml(value.toString()));
376            }
377        }
378
379        return model;
380    }
381
382    public static Map escapeMap(Map map, Object... ignoreKeys) {
383        if (map == null || map.isEmpty()) {
384            return map;
385        }
386
387        Set<?> keys = map.keySet();
388        for (Object key : keys) {
389            if (ArrayUtils.contains(ignoreKeys, key)) {
390                continue;
391            }
392
393            Object value = map.get(key);
394
395            if (value instanceof String) {
396                map.put(key, escapeHtml(value.toString()));
397            }
398        }
399
400        return map;
401    }
402
403
404    public static String join(String[] array, String split) {
405        if (array == null || array.length == 0) {
406            return EMPTY;
407        }
408        StringBuilder sb = new StringBuilder();
409        for (int i = 0; i < array.length; i++) {
410            if (i > 0) {
411                sb.append(split);
412            }
413            sb.append(array[i]);
414        }
415        return sb.toString();
416    }
417
418
419    public static String join(Collection<String> coll, String split) {
420        if (coll == null || coll.isEmpty()) {
421            return EMPTY;
422        }
423
424        StringBuilder sb = new StringBuilder();
425        boolean isFirst = true;
426        for (String s : coll) {
427            if (isFirst) {
428                isFirst = false;
429            } else {
430                sb.append(split);
431            }
432            sb.append(s);
433        }
434        return sb.toString();
435    }
436
437}