001 | packagecom.cucpay.tradeportal.util; |
002 |
003 | importjava.io.UnsupportedEncodingException; |
004 | importjava.lang.reflect.Field; |
005 | importjava.net.URLDecoder; |
006 | importjava.net.URLEncoder; |
007 | importjava.nio.charset.CharacterCodingException; |
008 | importjava.nio.charset.Charset; |
009 | importjava.security.MessageDigest; |
010 | importjava.security.NoSuchAlgorithmException; |
011 | importjava.text.SimpleDateFormat; |
012 | importjava.util.ArrayList; |
013 | importjava.util.Arrays; |
014 | importjava.util.Calendar; |
015 | importjava.util.Collections; |
016 | importjava.util.Date; |
017 | importjava.util.List; |
018 | importjava.util.Map; |
019 | importjava.util.UUID; |
020 |
021 | importorg.apache.commons.lang.StringUtils; |
022 | importorg.apache.mina.core.buffer.IoBuffer; |
023 |
024 | /** |
025 | * 交易前置系统专用工具类 |
026 | * @create Aug 15, 2012 12:16:49 PM |
027 | * @update Sep 27, 2012 3:07:09 PM |
028 | * @author 玄玉<http://blog.csdn/net/jadyer> |
029 | * @version v2.0 |
030 | * @history v1.7.2-->新增<code>getHexSign()</code>经过指定算法签名字符串方法 |
031 | * @history v1.7.2-->新增<code>getString()</code>字节数组转为字符串方法 |
032 | * @history v1.7.3-->修改<code>getSysJournalNo()</code>实现细节为<code>java.util.UUID.randomUUID()</code> |
033 | * @history v1.7.4-->新增<code>getHexSign()</code>根据指定的签名密钥和算法签名Map<String,String> |
034 | * @history v1.7.5-->新增<code>getStringSimple()</code>获取一个字符串的简明效果,返回的字符串格式相似于"abcd***hijk" |
035 | * @history v2.0-->局部的StringBuffer一概StringBuilder之(本思路提示自坦克<captmjc@gmail.com>) |
036 | */ |
037 | publicclassTradePortalUtil { |
038 | privateTradePortalUtil(){} |
039 |
040 | /** |
041 | * 获取系统流水号 |
043 | * @return 长度为20的全数字 |
044 | */ |
045 | publicstaticString getSysJournalNo(){ |
046 | returngetSysJournalNo(20,true); |
047 | } |
048 |
049 |
050 | /** |
051 | * 获取系统流水号 |
052 | * @param length 指定流水号长度 |
053 | * @param toNumber 指定流水号是否全由数字组成 |
054 | */ |
055 | publicstaticString getSysJournalNo(intlength,booleanisNumber){ |
056 | //replaceAll()以后返回的是一个由十六进制形式组成的且长度为32的字符串 |
057 | String uuid = UUID.randomUUID().toString().replaceAll("-",""); |
058 | if(uuid.length() > length){ |
059 | uuid = uuid.substring(0, length); |
060 | }elseif(uuid.length() < length){ |
061 | for(inti=0; i<length-uuid.length(); i++){ |
062 | uuid = uuid + Math.round(Math.random()*9); |
063 | } |
064 | } |
065 | if(isNumber){ |
066 | returnuuid.replaceAll("a","1").replaceAll("b","2").replaceAll("c","3").replaceAll("d","4").replaceAll("e","5").replaceAll("f","6"); |
067 | }else{ |
068 | returnuuid; |
069 | } |
070 | } |
071 |
072 |
073 | /** |
074 | * 判断输入的字符串参数是否为空 |
075 | * @return boolean 空则返回true,非空则flase |
076 | */ |
077 | publicstaticbooleanisEmpty(String input) { |
078 | returnnull==input ||0==input.length() ||0==input.replaceAll("\\s","").length(); |
079 | } |
080 |
081 |
082 | /** |
083 | * 判断输入的字节数组是否为空 |
084 | * @return boolean 空则返回true,非空则flase |
085 | */ |
086 | publicstaticbooleanisEmpty(byte[] bytes){ |
087 | returnnull==bytes ||0==bytes.length; |
088 | } |
089 |
090 |
091 | /** |
092 | * 从org.apache.mina.core.buffer.IoBuffer中读取字符串 |
093 | * @see 该方法默认以GBK解码 |
094 | * @see 若想本身指定字符集,可使用<code>getStringFromIoBuffer(IoBuffer buffer, int size, String charset)</code>方法 |
095 | * @param size 所要读取的字节数 |
096 | */ |
097 | publicstaticString getStringFromIoBuffer(IoBuffer buffer,intsize){ |
098 | returngetStringFromIoBuffer(buffer, size,"GBK"); |
099 | } |
100 |
101 |
102 | /** |
103 | * 从org.apache.mina.core.buffer.IoBuffer中读取字符串 |
104 | * @param size 所要读取的字节数 |
105 | * @param charset 解码的字符集 |
106 | */ |
107 | publicstaticString getStringFromIoBuffer(IoBuffer buffer,intsize, String charset){ |
108 | String result =null; |
109 | try{ |
110 | result = buffer.getString(size, Charset.forName(charset).newDecoder()); |
111 | }catch(CharacterCodingException e) { |
112 | LogUtil.getLogger().error("字符解码异常,自动切换第二种解码方式,本次的堆栈信息以下", e); |
113 | try{ |
114 | result =newString(buffer.array(), charset); |
115 | }catch(UnsupportedEncodingException ee) { |
116 | LogUtil.getLogger().error("字符解码异常,系统不支持该字符集["+ charset +"],本次的堆栈信息以下", ee); |
117 | } |
118 | } |
119 | returnresult; |
120 | } |
121 |
122 |
123 | /** |
124 | * 获取实体类中的属性 |
125 | * @see 本方法用到了反射,其适用于全部的属性类型均为byte[]的JavaBean |
126 | * @return String field11=value11 field22=value22 field33=value33 |
127 | */ |
128 | publicstaticString getStringFromObjectForByte(Object obj){ |
129 | StringBuilder sb =newStringBuilder();//局部的StringBuffer一概StringBuilder之 |
130 | sb.append(obj.getClass().getName()).append("@").append(obj.hashCode()).append("["); |
131 | for(Field field : obj.getClass().getDeclaredFields()){ |
132 | String methodName ="get"+ StringUtils.capitalize(field.getName());//构造getter方法 |
133 | Object fieldValue =null; |
134 | try{ |
135 | fieldValue = obj.getClass().getDeclaredMethod(methodName).invoke(obj);//执行getter方法,获取其返回值 |
136 | }catch(Exception e){ |
137 | //一旦发生异常,便将属性值置为UnKnown,故此处不必一一捕获全部异常 |
138 | sb.append("\n").append(field.getName()).append("=UnKnown"); |
139 | continue; |
140 | } |
141 | if(fieldValue ==null){ |
142 | sb.append("\n").append(field.getName()).append("=null"); |
143 | }else{ |
144 | sb.append("\n").append(field.getName()).append("=").append(newString((byte[])fieldValue)); |
145 | } |
146 | } |
147 | returnsb.append("\n]").toString(); |
148 | } |
149 |
150 |
151 | /** |
152 | * 获取Map中的属性 |
153 | * @see 因为Map.toString()打印出来的参数值对,是横着一排的...参数多的时候,不便于查看各参数值 |
154 | * @see 故此仿照commons-lang.jar中的ReflectionToStringBuilder.toString()编写了本方法 |
155 | * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... |
156 | */ |
157 | publicstaticString getStringFromMap(Map<String, String> map){ |
158 | StringBuilder sb =newStringBuilder(); |
159 | sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("["); |
160 | for(Map.Entry<String,String> entry : map.entrySet()){ |
161 | sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue()); |
162 | } |
163 | returnsb.append("\n]").toString(); |
164 | } |
165 |
166 |
167 | /** |
168 | * 获取Map中的属性 |
169 | * @see 该方法的参数适用于打印Map<String, byte[]>的状况 |
170 | * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... |
171 | */ |
172 | publicstaticString getStringFromMapForByte(Map<String,byte[]> map){ |
173 | StringBuilder sb =newStringBuilder(); |
174 | sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("["); |
175 | for(Map.Entry<String,byte[]> entry : map.entrySet()){ |
176 | sb.append("\n").append(entry.getKey()).append("=").append(newString(entry.getValue())); |
177 | } |
178 | returnsb.append("\n]").toString(); |
179 | } |
180 |
181 |
182 | /** |
183 | * 获取Map中的属性 |
184 | * @see 该方法的参数适用于打印Map<String, Object>的状况 |
185 | * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... |
186 | */ |
187 | publicstaticString getStringFromMapForObject(Map<String, Object> map){ |
188 | StringBuilder sb =newStringBuilder(); |
189 | sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("["); |
190 | for(Map.Entry<String,Object> entry : map.entrySet()){ |
191 | sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue().toString()); |
192 | } |
193 | returnsb.append("\n]").toString(); |
194 | } |
195 |
196 |
197 | /** |
198 | * 金额元转分 |
199 | * @see 注意:该方法可处理贰仟万之内的金额,且如有小数位,则不限小数位的长度 |
200 | * @see 注意:若是你的金额达到了贰仟万以上,则不推荐使用该方法,不然计算出来的结果会使人大吃一惊 |
201 | * @param amount 金额的元进制字符串 |
202 | * @return String 金额的分进制字符串 |
203 | */ |
204 | publicstaticString moneyYuanToFen(String amount){ |
205 | if(isEmpty(amount)){ |
206 | returnamount; |
207 | } |
208 | //传入的金额字符串表明的是一个整数 |
209 | if(-1== amount.indexOf(".")){ |
210 | returnInteger.parseInt(amount) *100+""; |
211 | } |
212 | //传入的金额字符串里面含小数点-->取小数点前面的字符串,并将之转换成单位为分的整数表示 |
213 | intmoney_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) *100; |
214 | //取到小数点后面的字符串 |
215 | String pointBehind = (amount.substring(amount.indexOf(".") +1)); |
216 | //amount=12.3 |
217 | if(pointBehind.length() ==1){ |
218 | returnmoney_fen + Integer.parseInt(pointBehind)*10+""; |
219 | } |
220 | //小数点后面的第一位字符串的整数表示 |
221 | intpointString_1 = Integer.parseInt(pointBehind.substring(0,1)); |
222 | //小数点后面的第二位字符串的整数表示 |
223 | intpointString_2 = Integer.parseInt(pointBehind.substring(1,2)); |
224 | //amount==12.03,amount=12.00,amount=12.30 |
225 | if(pointString_1 ==0){ |
226 | returnmoney_fen + pointString_2 +""; |
227 | }else{ |
228 | returnmoney_fen + pointString_1*10+ pointString_2 +""; |
229 | } |
230 | } |
231 |
232 |
233 | /** |
234 | * 金额元转分 |
235 | * @see 该方法会将金额中小数点后面的数值,四舍五入后只保留两位....如12.345-->12.35 |
236 | * @see 注意:该方法可处理贰仟万之内的金额 |
237 | * @see 注意:若是你的金额达到了贰仟万以上,则很是不建议使用该方法,不然计算出来的结果会使人大吃一惊 |
238 | * @param amount 金额的元进制字符串 |
239 | * @return String 金额的分进制字符串 |
240 | */ |
241 | publicstaticString moneyYuanToFenByRound(String amount){ |
242 | if(isEmpty(amount)){ |
243 | returnamount; |
244 | } |
245 | if(-1== amount.indexOf(".")){ |
246 | returnInteger.parseInt(amount) *100+""; |
247 | } |
248 | intmoney_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) *100; |
249 | String pointBehind = (amount.substring(amount.indexOf(".") +1)); |
250 | if(pointBehind.length() ==1){ |
251 | returnmoney_fen + Integer.parseInt(pointBehind)*10+""; |
252 | } |
253 | intpointString_1 = Integer.parseInt(pointBehind.substring(0,1)); |
254 | intpointString_2 = Integer.parseInt(pointBehind.substring(1,2)); |
255 | //下面这种方式用于处理pointBehind=245,286,295,298,995,998等须要四舍五入的状况 |
256 | if(pointBehind.length() >2){ |
257 | intpointString_3 = Integer.parseInt(pointBehind.substring(2,3)); |
258 | if(pointString_3 >=5){ |
259 | if(pointString_2 ==9){ |
260 | if(pointString_1 ==9){ |
261 | money_fen = money_fen +100; |
262 | pointString_1 =0; |
263 | pointString_2 =0; |
264 | }else{ |
265 | pointString_1 = pointString_1 +1; |
266 | pointString_2 =0; |
267 | } |
268 | }else{ |
269 | pointString_2 = pointString_2 +1; |
270 | } |
271 | } |
272 | } |
273 | if(pointString_1 ==0){ |
274 | returnmoney_fen + pointString_2 +""; |
275 | }else{ |
276 | returnmoney_fen + pointString_1*10+ pointString_2 +""; |
277 | } |
278 | } |
279 |
280 |
281 | /** |
282 | * 金额分转元 |
283 | * @see 注意:若是传入的参数中含小数点,则直接原样返回 |
284 | * @see 该方法返回的金额字符串格式为<code>00.00</code>,其整数位有且至少有一个,小数位有且长度固定为2 |
285 | * @param amount 金额的分进制字符串 |
286 | * @return String 金额的元进制字符串 |
287 | */ |
288 | publicstaticString moneyFenToYuan(String amount){ |
289 | if(isEmpty(amount)){ |
290 | returnamount; |
291 | } |
292 | if(amount.indexOf(".") > -1){ |
293 | returnamount; |
294 | } |
295 | if(amount.length() ==1){ |
296 | return"0.0"+ amount; |
297 | }elseif(amount.length() ==2){ |
298 | return"0."+ amount; |
299 | }else{ |
300 | returnamount.substring(0, amount.length()-2) +"."+ amount.substring(amount.length()-2); |
301 | } |
302 | } |
303 |
304 |
305 | /** |
306 | * 字节数组转为字符串 |
307 | * @see 该方法默认以ISO-8859-1转码 |
308 | * @see 若想本身指定字符集,可使用<code>getString(byte[] data, String charset)</code>方法 |
309 | */ |
310 | publicstaticString getString(byte[] data){ |
311 | returngetString(data,"ISO-8859-1"); |
312 | } |
313 |
314 |
315 | /** |
316 | * 字节数组转为字符串 |
317 | * @see 若是系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 |
318 | */ |
319 | publicstaticString getString(byte[] data, String charset){ |
320 | if(isEmpty(data)){ |
321 | return""; |
322 | } |
323 | if(isEmpty(charset)){ |
324 | returnnewString(data); |
325 | } |
326 | try{ |
327 | returnnewString(data, charset); |
328 | }catch(UnsupportedEncodingException e) { |
329 | LogUtil.getLogger().error("将byte数组["+ data +"]转为String时发生异常:系统不支持该字符集["+ charset +"]"); |
330 | returnnewString(data); |
331 | } |
332 | } |
333 |
334 |
335 | /** |
336 | * 获取一个字符串的简明效果 |
337 | * @return String 返回的字符串格式相似于"abcd***hijk" |
338 | */ |
339 | publicstaticString getStringSimple(String data){ |
340 | returndata.substring(0,4) +"***"+ data.substring(data.length()-4); |
341 | } |
342 |
343 |
344 | /** |
345 | * 字符串转为字节数组 |
346 | * @see 该方法默认以ISO-8859-1转码 |
347 | * @see 若想本身指定字符集,可使用<code>getBytes(String str, String charset)</code>方法 |
348 | */ |
349 | publicstaticbyte[] getBytes(String data){ |
350 | returngetBytes(data,"ISO-8859-1"); |
351 | } |
352 |
353 |
354 | /** |
355 | * 字符串转为字节数组 |
356 | * @see 若是系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 |
357 | */ |
358 | publicstaticbyte[] getBytes(String data, String charset){ |
359 | data = (data==null?"": data); |
360 | if(isEmpty(charset)){ |
361 | returndata.getBytes(); |
362 | } |
363 | try{ |
364 | returndata.getBytes(charset); |
365 | }catch(UnsupportedEncodingException e) { |
366 | LogUtil.getLogger().error("将字符串["+ data +"]转为byte[]时发生异常:系统不支持该字符集["+ charset +"]"); |
367 | returndata.getBytes(); |
368 | } |
369 | } |
370 |
371 |
372 | /** |
373 | * 根据指定的签名密钥和算法签名Map<String,String> |
374 | * @see 方法内部首先会过滤Map<String,String>参数中的部分键值对 |
375 | * @see 过滤规则:移除键名为"cert","hmac","signMsg"或者键值为null或者键值长度为零的键值对 |
376 | * @see 过滤结果:过滤完Map<String,String>后会产生一个字符串,其格式为[key11=value11|key22=value22|key33=value33] |
378 | * @param param 待签名的Map<String,String> |
379 | * @param charset 签名时转码用到的字符集 |
380 | * @param algorithm 签名时所使用的算法,从业务上看,目前其可传入两个值:MD5,SHA-1 |
381 | * @param signKey 签名用到的密钥 |
382 | * @return String algorithm digest as a lowerCase hex string |
383 | */ |
384 | publicstaticString getHexSign(Map<String, String> param, String charset, String algorithm, String signKey){ |
385 | StringBuilder sb =newStringBuilder(); |
386 | List<String> keys =newArrayList<String>(param.keySet()); |
387 | Collections.sort(keys); |
388 | for(inti=0; i<keys.size(); i++){ |
389 | String key = keys.get(i); |
390 | String value = param.get(key); |
391 | if(key.equalsIgnoreCase("cert") || key.equalsIgnoreCase("hmac") || key.equalsIgnoreCase("signMsg") || value==null|| value.length()==0){ |
392 | continue; |
393 | } |
394 | sb.append(key).append("=").append(value).append("|"); |
395 | } |
396 | sb.append("key=").append(signKey); |
397 | returngetHexSign(sb.toString(), charset, algorithm,true); |
398 | } |
399 |
400 |
401 | /** |
402 | * 经过指定算法签名字符串 |
403 | * @see Calculates the algorithm digest and returns the value as a hex string |
404 | * @see If system dosen't support this <code>algorithm</code>, return "" not null |
406 | * @see 若系统不支持<code>charset</code>字符集,则按照系统默认字符集进行转换 |
407 | * @see 若系统不支持<code>algorithm</code>算法,则直接返回""空字符串 |
408 | * @see 另外,commons-codec.jar提供的DigestUtils.md5Hex(String data)与本方法getHexSign(data, "UTF-8", "MD5", false)效果相同 |
409 | * @param data Data to digest |
410 | * @param charset 字符串转码为byte[]时使用的字符集 |
411 | * @param algorithm 目前其有效值为<code>MD5,SHA,SHA1,SHA-1,SHA-256,SHA-384,SHA-512</code> |
412 | * @param toLowerCase 指定是否返回小写形式的十六进制字符串 |
413 | * @return String algorithm digest as a lowerCase hex string |
414 | */ |
415 | publicstaticString getHexSign(String data, String charset, String algorithm,booleantoLowerCase){ |
416 | char[] DIGITS_LOWER = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; |
417 | char[] DIGITS_UPPER = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; |
418 | //Used to build output as Hex |
419 | char[] DIGITS = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER; |
420 | //get byte[] from {@link TradePortalUtil#getBytes(String, String)} |
421 | byte[] dataBytes = getBytes(data, charset); |
422 | byte[] algorithmData =null; |
423 | try{ |
424 | //get an algorithm digest instance |
425 | algorithmData = MessageDigest.getInstance(algorithm).digest(dataBytes); |
426 | }catch(NoSuchAlgorithmException e) { |
427 | LogUtil.getLogger().error("签名字符串["+ data +"]时发生异常:System doesn't support this algorithm["+ algorithm +"]"); |
428 | return""; |
429 | } |
430 | char[] respData =newchar[algorithmData.length <<1]; |
431 | //two characters form the hex value |
432 | for(inti=0,j=0; i<algorithmData.length; i++){ |
433 | respData[j++] = DIGITS[(0xF0& algorithmData[i]) >>>4]; |
434 | respData[j++] = DIGITS[0x0F& algorithmData[i]]; |
435 | } |
436 | returnnewString(respData); |
437 | } |
438 |
439 |
440 | /** |
441 | * 字符编码 |
442 | * @see 该方法默认会以UTF-8编码字符串 |
443 | * @see 若想本身指定字符集,可使用<code>encode(String chinese, String charset)</code>方法 |
444 | */ |
445 | publicstaticString encode(String chinese){ |
446 | returnencode(chinese,"UTF-8"); |
447 | } |
448 |
449 |
450 | /** |
451 | * 字符编码 |
452 | * @see 该方法一般用于对中文进行编码 |
453 | * @see 若系统不支持指定的编码字符集,则直接将<code>chinese</code>原样返回 |
454 | */ |
455 | publicstaticString encode(String chinese, String charset){ |
456 | chinese = (chinese==null?"": chinese); |
457 | try{ |
458 | returnURLEncoder.encode(chinese, charset); |
459 | }catch(UnsupportedEncodingException e) { |
460 | LogUtil.getLogger().error("编码字符串["+ chinese +"]时发生异常:系统不支持该字符集["+ charset +"]"); |
461 | returnchinese; |
462 | } |
463 | } |
464 |
465 |
466 | /** |
467 | * 字符解码 |
468 | * @see 该方法默认会以UTF-8解码字符串 |
469 | * @see 若想本身指定字符集,可使用<code>decode(String chinese, String charset)</code>方法 |
470 | */ |
471 | publicstaticString decode(String chinese){ |
472 | returndecode(chinese,"UTF-8"); |
473 | } |
474 |
475 |
476 | /** |
477 | * 字符解码 |
478 | * @see 该方法一般用于对中文进行解码 |
479 | * @see 若系统不支持指定的解码字符集,则直接将<code>chinese</code>原样返回 |
480 | */ |
481 | publicstaticString decode(String chinese, String charset){ |
482 | chinese = (chinese==null?"": chinese); |
483 | try{ |
484 | returnURLDecoder.decode(chinese, charset); |
485 | }catch(UnsupportedEncodingException e) { |
486 | LogUtil.getLogger().error("解码字符串["+ chinese +"]时发生异常:系统不支持该字符集["+ charset +"]"); |
487 | returnchinese; |
488 | } |
489 | } |
490 |
491 |
492 | /** |
493 | * 字符串右补空格 |
494 | * @see 该方法默认采用空格(其ASCII码为32)来右补字符 |
495 | * @see 若想本身指定所补字符,可使用<code>rightPadForByte(String str, int size, int padStrByASCII)</code>方法 |
496 | */ |
497 | publicstaticString rightPadForByte(String str,intsize){ |
498 | returnrightPadForByte(str, size,32); |
499 | } |
500 |
501 |
502 | /** |
503 | * 字符串右补字符 |
504 | * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str |
505 | * @see 因此size参数很关键..事实上之因此这么处理,是因为支付处理系统接口文档规定了字段的最大长度 |
506 | * @see 若对普通字符串进行右补字符,建议org.apache.commons.lang.StringUtils.rightPad(...) |
507 | * @param size 该参数指的不是字符串长度,而是字符串所对应的byte[]长度 |
508 | * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等 |
509 | */ |
510 | publicstaticString rightPadForByte(String str,intsize,intpadStrByASCII){ |
511 | byte[] srcByte = str.getBytes(); |
512 | byte[] destByte =null; |
513 | if(srcByte.length >= size){ |
514 | //因为size不大于原数组长度,故该方法此时会按照size自动截取,它会在数组右侧填充'(byte)0'以使其具备指定的长度 |
515 | destByte = Arrays.copyOf(srcByte, size); |
516 | }else{ |
517 | destByte = Arrays.copyOf(srcByte, size); |
518 | Arrays.fill(destByte, srcByte.length, size, (byte)padStrByASCII); |
519 | } |
520 | returnnewString(destByte); |
521 | } |
522 |
523 |
524 | /** |
525 | * 字符串左补空格 |
526 | * @see 该方法默认采用空格(其ASCII码为32)来左补字符 |
527 | * @see 若想本身指定所补字符,可使用<code>leftPadForByte(String str, int size, int padStrByASCII)</code>方法 |
528 | */ |
529 | publicstaticString leftPadForByte(String str,intsize){ |
530 | returnleftPadForByte(str, size,32); |
531 | } |
532 |
533 |
534 | /** |
535 | * 字符串左补字符 |
536 | * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str |
537 | * @see 因此size参数很关键..事实上之因此这么处理,是因为支付处理系统接口文档规定了字段的最大长度 |
538 | * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等 |
539 | */ |
540 | publicstaticString leftPadForByte(String str,intsize,intpadStrByASCII){ |
541 | byte[] srcByte = str.getBytes(); |
542 | byte[] destByte =newbyte[size]; |
543 | Arrays.fill(destByte, (byte)padStrByASCII); |
544 | if(srcByte.length >= size){ |
545 | System.arraycopy(srcByte,0, destByte,0, size); |
546 | }else{ |
547 | System.arraycopy(srcByte,0, destByte, size-srcByte.length, srcByte.length); |
548 | } |
549 | returnnewString(destByte); |
550 | } |
551 |
552 |
553 | /** |
554 | * 获取前一天日期yyyyMMdd |
555 | * @see 经测试,针对闰年02月份或跨年等状况,该代码仍有效。测试代码以下 |
556 | * @see calendar.set(Calendar.YEAR, 2013); |
557 | * @see calendar.set(Calendar.MONTH, 0); |
558 | * @see calendar.set(Calendar.DATE, 1); |
559 | * @see 测试时,将其放到<code>calendar.add(Calendar.DATE, -1);</code>前面便可 |
560 | * @return 返回的日期格式为yyyyMMdd |
561 | */ |
562 | publicstaticString getYestoday(){ |
563 | Calendar calendar = Calendar.getInstance(); |
564 | calendar.add(Calendar.DATE, -1); |
565 | returnnewSimpleDateFormat("yyyyMMdd").format(calendar.getTime()); |
566 | } |
567 |
568 |
569 | /** |
570 | * 获取当前的日期yyyyMMdd |
571 | */ |
572 | publicstaticString getCurrentDate(){ |
573 | returnnewSimpleDateFormat("yyyyMMdd").format(newDate()); |
574 | } |
575 |
576 |
577 | /** |
578 | * 获取当前的时间yyyyMMddHHmmss |
579 | */ |
580 | publicstaticString getCurrentTime(){ |
581 | returnnewSimpleDateFormat("yyyyMMddHHmmss").format(newDate()); |
582 | } |
583 |
584 |
585 | /** |
586 | * HTML字符转义 |
587 | * @see 对输入参数中的敏感字符进行过滤替换,防止用户利用JavaScript等方式输入恶意代码 |
588 | * @see String input = <img src='http://t1.baidu.com/it/fm=0&gp=0.jpg'/> |
589 | * @see HtmlUtils.htmlEscape(input); //from spring.jar |
590 | * @see StringEscapeUtils.escapeHtml(input); //from commons-lang.jar |
591 | * @see 尽管Spring和Apache都提供了字符转义的方法,但Apache的StringEscapeUtils功能要更强大一些 |
592 | * @see StringEscapeUtils提供了对HTML,Java,JavaScript,SQL,XML等字符的转义和反转义 |
593 | * @see 但两者在转义HTML字符时,都不会对单引号和空格进行转义,而本方法则提供了对它们的转义 |
594 | * @return String 过滤后的字符串 |
595 | */ |
596 | publicstaticString htmlEscape(String input) { |
597 | if(isEmpty(input)){ |
598 | returninput; |
599 | } |
600 | input = input.replaceAll("&","&"); |
601 | input = input.replaceAll("<","<"); |
602 | input = input.replaceAll(">",">"); |
603 | input = input.replaceAll(" "," "); |
604 | input = input.replaceAll("'","'"); //IE暂不支持单引号的实体名称,而支持单引号的实体编号,故单引号转义成实体编号,其它字符转义成实体名称 |
605 | input = input.replaceAll("\"",""");//双引号也须要转义,因此加一个斜线对其进行转义 |
606 | input = input.replaceAll("\n","<br/>"); //不能把\n的过滤放在前面,由于还要对<和>过滤,这样就会致使<br/>失效了 |
607 | returninput; |
608 | } |
609 | } |