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 = {"&", "<", ">", "'", """}; 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}