Java开发常用工具类

6 篇文章 1 订阅
  1. package com.cucpay.tradeportal.util;    
  2.     
  3. import java.io.UnsupportedEncodingException;    
  4. import java.lang.reflect.Field;    
  5. import java.net.URLDecoder;    
  6. import java.net.URLEncoder;    
  7. import java.nio.charset.CharacterCodingException;    
  8. import java.nio.charset.Charset;    
  9. import java.security.MessageDigest;    
  10. import java.security.NoSuchAlgorithmException;    
  11. import java.text.SimpleDateFormat;    
  12. import java.util.ArrayList;    
  13. import java.util.Arrays;    
  14. import java.util.Calendar;    
  15. import java.util.Collections;    
  16. import java.util.Date;    
  17. import java.util.List;    
  18. import java.util.Map;    
  19. import java.util.UUID;    
  20.     
  21. import javax.crypto.Cipher;    
  22. import javax.crypto.spec.SecretKeySpec;    
  23.     
  24. import org.apache.commons.codec.binary.Base64;    
  25. import org.apache.commons.lang.StringUtils;    
  26. import org.apache.mina.core.buffer.IoBuffer;    
  27.     
  28. /**  
  29.  * 交易前置系统专用工具类  
  30.  * @create Aug 15, 2012 12:16:49 PM  
  31.  * @update Sep 27, 2012 3:07:09 PM  
  32.  * @author 玄玉<http://blog.csdn/net/jadyer>  
  33.  * @version v2.4  
  34.  * @history v1.1-->新增<code>getHexSign()</code>通过指定算法签名字符串方法  
  35.  * @history v1.2-->新增<code>getString()</code>字节数组转为字符串方法  
  36.  * @history v1.3-->修改<code>getSysJournalNo()</code>实现细节为<code>java.util.UUID.randomUUID()</code>  
  37.  * @history v1.4-->新增<code>getHexSign()</code>根据指定的签名密钥和算法签名Map<String,String>  
  38.  * @history v1.5-->新增<code>getStringSimple()</code>获取一个字符串的简明效果,返回的字符串格式类似于"abcd***hijk"  
  39.  * @history v2.0-->局部的StringBuffer一律StringBuilder之(本思路提示自坦克<captmjc@gmail.com>)  
  40.  * @history v2.1-->新增<code>formatToHexStringWithASCII()</code>用于格式化字节数组为十六进制字符串的方法  
  41.  * @history v2.2-->新增<code>isNotEmpty()</code>用于判断输入的字符串或字节数组是否为非空的方法  
  42.  * @history v2.3-->修改<code>rightPadForByte(),leftPadForByte()</code>方法左右填充的字符为0x00  
  43.  * @history v2.4-->新增<code>genAESEncrypt()和genAESDecrypt()</code>用于AES加解密的方法  
  44.  */    
  45. public class TradePortalUtil {    
  46.     private TradePortalUtil(){}    
  47.         
  48.     /**  
  49.      * 获取系统流水号  
  50.      * @see 若欲指定返回值的长度or是否全由数字组成等,you can call {@link TradePortalUtil#getSysJournalNo(int, boolean)}  
  51.      * @return 长度为20的全数字  
  52.      */    
  53.     public static String getSysJournalNo(){    
  54.         return getSysJournalNo(20true);    
  55.     }    
  56.         
  57.         
  58.     /**  
  59.      * 获取系统流水号  
  60.      * @param length   指定流水号长度  
  61.      * @param toNumber 指定流水号是否全由数字组成  
  62.      */    
  63.     public static String getSysJournalNo(int length, boolean isNumber){    
  64.         //replaceAll()之后返回的是一个由十六进制形式组成的且长度为32的字符串    
  65.         String uuid = UUID.randomUUID().toString().replaceAll("-""");    
  66.         if(uuid.length() > length){    
  67.             uuid = uuid.substring(0, length);    
  68.         }else if(uuid.length() < length){    
  69.             for(int i=0; i<length-uuid.length(); i++){    
  70.                 uuid = uuid + Math.round(Math.random()*9);    
  71.             }    
  72.         }    
  73.         if(isNumber){    
  74.             return uuid.replaceAll("a""1").replaceAll("b""2").replaceAll("c""3").replaceAll("d""4").replaceAll("e""5").replaceAll("f""6");    
  75.         }else{    
  76.             return uuid;    
  77.         }    
  78.     }    
  79.         
  80.         
  81.     /**  
  82.      * 判断输入的字符串参数是否为空  
  83.      * @return boolean 空则返回true,非空则flase  
  84.      */    
  85.     public static boolean isEmpty(String input) {    
  86.         return null==input || 0==input.length() || 0==input.replaceAll("\\s""").length();    
  87.     }    
  88.         
  89.         
  90.     /**  
  91.      * 判断输入的字符串参数是否为非空  
  92.      * @return boolean 非空则返回true,空则flase  
  93.      */    
  94.     public static boolean isNotEmpty(String input){    
  95.         return !isEmpty(input);    
  96.     }    
  97.         
  98.         
  99.     /**  
  100.      * 判断输入的字节数组是否为空  
  101.      * @return boolean 空则返回true,非空则flase  
  102.      */    
  103.     public static boolean isEmpty(byte[] bytes){    
  104.         return null==bytes || 0==bytes.length;    
  105.     }    
  106.         
  107.         
  108.     /**  
  109.      * 判断输入的字节数组是否为非空  
  110.      * @return boolean 非空则返回true,空则flase  
  111.      */    
  112.     public static boolean isNotEmpty(byte[] bytes){    
  113.         return !isEmpty(bytes);    
  114.     }    
  115.         
  116.         
  117.     /**  
  118.      * 从org.apache.mina.core.buffer.IoBuffer中读取字符串  
  119.      * @see 该方法默认以GBK解码  
  120.      * @see 若想自己指定字符集,可以使用<code>getStringFromIoBuffer(IoBuffer buffer, int size, String charset)</code>方法  
  121.      * @param size 所要读取的字节数  
  122.      */    
  123.     public static String getStringFromIoBuffer(IoBuffer buffer, int size){    
  124.         return getStringFromIoBuffer(buffer, size, "GBK");    
  125.     }    
  126.         
  127.         
  128.     /**  
  129.      * 从org.apache.mina.core.buffer.IoBuffer中读取字符串  
  130.      * @param size    所要读取的字节数  
  131.      * @param charset 解码的字符集  
  132.      */    
  133.     public static String getStringFromIoBuffer(IoBuffer buffer, int size, String charset){    
  134.         String result = null;    
  135.         try {    
  136.             result = buffer.getString(size, Charset.forName(charset).newDecoder());    
  137.         } catch (CharacterCodingException e) {    
  138.             LogUtil.getLogger().error("字符解码异常,自动切换第二种解码方式,本次的堆栈信息如下", e);    
  139.             try {    
  140.                 result = new String(buffer.array(), charset);    
  141.             } catch (UnsupportedEncodingException ee) {    
  142.                 LogUtil.getLogger().error("字符解码异常,系统不支持该字符集[" + charset + "],本次的堆栈信息如下", ee);    
  143.             }    
  144.         }    
  145.         return result;    
  146.     }    
  147.         
  148.         
  149.     /**  
  150.      * 获取实体类中的属性  
  151.      * @see 本方法用到了反射,其适用于所有的属性类型均为byte[]的JavaBean  
  152.      * @return String field11=value11 field22=value22 field33=value33  
  153.      */    
  154.     public static String getStringFromObjectForByte(Object obj){    
  155.         StringBuilder sb = new StringBuilder(); //局部的StringBuffer一律StringBuilder之    
  156.         sb.append(obj.getClass().getName()).append("@").append(obj.hashCode()).append("[");    
  157.         for(Field field : obj.getClass().getDeclaredFields()){    
  158.             String methodName = "get" + StringUtils.capitalize(field.getName()); //构造getter方法    
  159.             Object fieldValue = null;    
  160.             try{    
  161.                 fieldValue = obj.getClass().getDeclaredMethod(methodName).invoke(obj); //执行getter方法,获取其返回值    
  162.             }catch(Exception e){    
  163.                 //一旦发生异常,便将属性值置为UnKnown,故此处没必要一一捕获所有异常    
  164.                 sb.append("\n").append(field.getName()).append("=UnKnown");    
  165.                 continue;    
  166.             }    
  167.             if(fieldValue == null){    
  168.                 sb.append("\n").append(field.getName()).append("=null");    
  169.             }else{    
  170.                 sb.append("\n").append(field.getName()).append("=").append(new String((byte[])fieldValue));    
  171.             }    
  172.         }    
  173.         return sb.append("\n]").toString();    
  174.     }    
  175.         
  176.         
  177.     /**  
  178.      * 获取Map中的属性  
  179.      * @see 由于Map.toString()打印出来的参数值对,是横着一排的...参数多的时候,不便于查看各参数值  
  180.      * @see 故此仿照commons-lang.jar中的ReflectionToStringBuilder.toString()编写了本方法  
  181.      * @return String key11=value11 \n key22=value22 \n key33=value33 \n......  
  182.      */    
  183.     public static String getStringFromMap(Map<String, String> map){    
  184.         StringBuilder sb = new StringBuilder();    
  185.         sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");    
  186.         for(Map.Entry<String,String> entry : map.entrySet()){    
  187.             sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue());    
  188.         }    
  189.         return sb.append("\n]").toString();    
  190.     }    
  191.     
  192.         
  193.     /**  
  194.      * 获取Map中的属性  
  195.      * @see 该方法的参数适用于打印Map<String, byte[]>的情况  
  196.      * @return String key11=value11 \n key22=value22 \n key33=value33 \n......  
  197.      */    
  198.     public static String getStringFromMapForByte(Map<String, byte[]> map){    
  199.         StringBuilder sb = new StringBuilder();    
  200.         sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");    
  201.         for(Map.Entry<String,byte[]> entry : map.entrySet()){    
  202.             sb.append("\n").append(entry.getKey()).append("=").append(new String(entry.getValue()));    
  203.         }    
  204.         return sb.append("\n]").toString();    
  205.     }    
  206.         
  207.         
  208.     /**  
  209.      * 获取Map中的属性  
  210.      * @see 该方法的参数适用于打印Map<String, Object>的情况  
  211.      * @return String key11=value11 \n key22=value22 \n key33=value33 \n......  
  212.      */    
  213.     public static String getStringFromMapForObject(Map<String, Object> map){    
  214.         StringBuilder sb = new StringBuilder();    
  215.         sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");    
  216.         for(Map.Entry<String,Object> entry : map.entrySet()){    
  217.             sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue().toString());    
  218.         }    
  219.         return sb.append("\n]").toString();    
  220.     }    
  221.     
  222.         
  223.     /**  
  224.      * 通过ASCII码将十六进制的字节数组格式化为十六进制字符串  
  225.      * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法  
  226.      */    
  227.     public static String formatHexToHexStringWithASCII(byte[] hexData, int offset, int length){    
  228.         byte[] data = new byte[hexData.length];    
  229.         for (int i = 0; i < data.length; i++) {    
  230.             data[i] = Integer.valueOf(""+hexData[i], 16).byteValue(); //获取16进制数的ASCII值,比如16进制的41对应ASCII的65    
  231.         }    
  232.         return formatToHexStringWithASCII(data, offset, length);    
  233.     }    
  234.         
  235.         
  236.     /**  
  237.      * 通过ASCII码将十进制的字节数组格式化为十六进制字符串  
  238.      * @see 该方法会将字节数组中的所有字节均格式化为字符串  
  239.      * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法  
  240.      */    
  241.     public static String formatToHexStringWithASCII(byte[] data){    
  242.         return formatToHexStringWithASCII(data, 0, data.length);    
  243.     }    
  244.         
  245.         
  246.     /**  
  247.      * 通过ASCII码将十进制的字节数组格式化为十六进制字符串  
  248.      * @see 该方法常用于字符串的十六进制打印,打印时左侧为十六进制数值,右侧为对应的字符串原文  
  249.      * @see 在构造右侧的字符串原文时,该方法内部使用的是平台的默认字符集,来解码byte[]数组  
  250.      * @see 该方法在将字节转为十六进制时,默认使用的是<code>java.util.Locale.getDefault()</code>  
  251.      * @see 详见String.format(String, Object...)方法和new String(byte[], int, int)构造方法  
  252.      * @param data   十进制的字节数组  
  253.      * @param offset 数组下标,标记从数组的第几个字节开始格式化输出  
  254.      * @param length 格式长度,其不得大于数组长度,否则抛出java.lang.ArrayIndexOutOfBoundsException  
  255.      * @return 格式化后的十六进制字符串  
  256.      */    
  257.     public static String formatToHexStringWithASCII(byte[] data, int offset, int length){    
  258.         int end = offset + length;    
  259.         StringBuilder sb = new StringBuilder();    
  260.         StringBuilder sb2 = new StringBuilder();    
  261.         sb.append("\r\n------------------------------------------------------------------------");    
  262.         boolean chineseCutFlag = false;    
  263.         for(int i=offset; i<end; i+=16){    
  264.             sb.append(String.format("\r\n%04X: ", i-offset)); //X或x表示将结果格式化为十六进制整数    
  265.             sb2.setLength(0);    
  266.             for(int j=i; j<i+16; j++){    
  267.                 if(j < end){    
  268.                     byte b = data[j];    
  269.                     if(b >= 0){ //ENG ASCII    
  270.                         sb.append(String.format("%02X ", b));    
  271.                         if(b<32 || b>126){ //不可见字符    
  272.                             sb2.append(" ");    
  273.                         }else{    
  274.                             sb2.append((char)b);    
  275.                         }    
  276.                     }else//CHA ASCII    
  277.                         if(j == i+15){ //汉字前半个字节    
  278.                             sb.append(String.format("%02X ", data[j]));    
  279.                             chineseCutFlag = true;    
  280.                             String s = new String(data, j, 2);    
  281.                             sb2.append(s);    
  282.                         }else if(j == i&&chineseCutFlag){ //后半个字节    
  283.                             sb.append(String.format("%02X ", data[j]));    
  284.                             chineseCutFlag = false;    
  285.                             String s = new String(data, j, 1);    
  286.                             sb2.append(s);    
  287.                         }else{    
  288.                             sb.append(String.format("%02X %02X ", data[j], data[j + 1]));    
  289.                             String s = new String(data, j, 2);    
  290.                             sb2.append(s);    
  291.                             j++;    
  292.                         }    
  293.                     }    
  294.                 }else{    
  295.                     sb.append("   ");    
  296.                 }    
  297.             }    
  298.             sb.append("| ");    
  299.             sb.append(sb2.toString());    
  300.         }    
  301.         sb.append("\r\n------------------------------------------------------------------------");    
  302.         return sb.toString();    
  303.     }    
  304.         
  305.         
  306.     /**  
  307.      * 金额元转分  
  308.      * @see 注意:该方法可处理贰仟万以内的金额,且若有小数位,则不限小数位的长度  
  309.      * @see 注意:如果你的金额达到了贰仟万以上,则不推荐使用该方法,否则计算出来的结果会令人大吃一惊  
  310.      * @param amount  金额的元进制字符串  
  311.      * @return String 金额的分进制字符串  
  312.      */    
  313.     public static String moneyYuanToFen(String amount){    
  314.         if(isEmpty(amount)){    
  315.             return amount;    
  316.         }    
  317.         //传入的金额字符串代表的是一个整数    
  318.         if(-1 == amount.indexOf(".")){    
  319.             return Integer.parseInt(amount) * 100 + "";    
  320.         }    
  321.         //传入的金额字符串里面含小数点-->取小数点前面的字符串,并将之转换成单位为分的整数表示    
  322.         int money_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) * 100;    
  323.         //取到小数点后面的字符串    
  324.         String pointBehind = (amount.substring(amount.indexOf(".") + 1));    
  325.         //amount=12.3    
  326.         if(pointBehind.length() == 1){    
  327.             return money_fen + Integer.parseInt(pointBehind)*10 + "";    
  328.         }    
  329.         //小数点后面的第一位字符串的整数表示    
  330.         int pointString_1 = Integer.parseInt(pointBehind.substring(01));    
  331.         //小数点后面的第二位字符串的整数表示    
  332.         int pointString_2 = Integer.parseInt(pointBehind.substring(12));    
  333.         //amount==12.03,amount=12.00,amount=12.30    
  334.         if(pointString_1 == 0){    
  335.             return money_fen + pointString_2 + "";    
  336.         }else{    
  337.             return money_fen + pointString_1*10 + pointString_2 + "";    
  338.         }    
  339.     }    
  340.         
  341.         
  342.     /**  
  343.      * 金额元转分  
  344.      * @see 该方法会将金额中小数点后面的数值,四舍五入后只保留两位....如12.345-->12.35  
  345.      * @see 注意:该方法可处理贰仟万以内的金额  
  346.      * @see 注意:如果你的金额达到了贰仟万以上,则非常不建议使用该方法,否则计算出来的结果会令人大吃一惊  
  347.      * @param amount  金额的元进制字符串  
  348.      * @return String 金额的分进制字符串  
  349.      */    
  350.     public static String moneyYuanToFenByRound(String amount){    
  351.         if(isEmpty(amount)){    
  352.             return amount;    
  353.         }    
  354.         if(-1 == amount.indexOf(".")){    
  355.             return Integer.parseInt(amount) * 100 + "";    
  356.         }    
  357.         int money_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) * 100;    
  358.         String pointBehind = (amount.substring(amount.indexOf(".") + 1));    
  359.         if(pointBehind.length() == 1){    
  360.             return money_fen + Integer.parseInt(pointBehind)*10 + "";    
  361.         }    
  362.         int pointString_1 = Integer.parseInt(pointBehind.substring(01));    
  363.         int pointString_2 = Integer.parseInt(pointBehind.substring(12));    
  364.         //下面这种方式用于处理pointBehind=245,286,295,298,995,998等需要四舍五入的情况    
  365.         if(pointBehind.length() > 2){    
  366.             int pointString_3 = Integer.parseInt(pointBehind.substring(23));    
  367.             if(pointString_3 >= 5){    
  368.                 if(pointString_2 == 9){    
  369.                     if(pointString_1 == 9){    
  370.                         money_fen = money_fen + 100;    
  371.                         pointString_1 = 0;    
  372.                         pointString_2 = 0;    
  373.                     }else{    
  374.                         pointString_1 = pointString_1 + 1;    
  375.                         pointString_2 = 0;    
  376.                     }    
  377.                 }else{    
  378.                     pointString_2 = pointString_2 + 1;    
  379.                 }    
  380.             }    
  381.         }    
  382.         if(pointString_1 == 0){    
  383.             return money_fen + pointString_2 + "";    
  384.         }else{    
  385.             return money_fen + pointString_1*10 + pointString_2 + "";    
  386.         }    
  387.     }    
  388.         
  389.         
  390.     /**  
  391.      * 金额分转元  
  392.      * @see 注意:如果传入的参数中含小数点,则直接原样返回  
  393.      * @see 该方法返回的金额字符串格式为<code>00.00</code>,其整数位有且至少有一个,小数位有且长度固定为2  
  394.      * @param amount  金额的分进制字符串  
  395.      * @return String 金额的元进制字符串  
  396.      */    
  397.     public static String moneyFenToYuan(String amount){    
  398.         if(isEmpty(amount)){    
  399.             return amount;    
  400.         }    
  401.         if(amount.indexOf(".") > -1){    
  402.             return amount;    
  403.         }    
  404.         if(amount.length() == 1){    
  405.             return "0.0" + amount;    
  406.         }else if(amount.length() == 2){    
  407.             return "0." + amount;    
  408.         }else{    
  409.             return amount.substring(0, amount.length()-2) + "." + amount.substring(amount.length()-2);    
  410.         }    
  411.     }    
  412.         
  413.     
  414.     /**  
  415.      * 字节数组转为字符串  
  416.      * @see 该方法默认以ISO-8859-1转码  
  417.      * @see 若想自己指定字符集,可以使用<code>getString(byte[] data, String charset)</code>方法  
  418.      */    
  419.     public static String getString(byte[] data){    
  420.         return getString(data, "ISO-8859-1");    
  421.     }    
  422.         
  423.         
  424.     /**  
  425.      * 字节数组转为字符串  
  426.      * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换  
  427.      */    
  428.     public static String getString(byte[] data, String charset){    
  429.         if(isEmpty(data)){    
  430.             return "";    
  431.         }    
  432.         if(isEmpty(charset)){    
  433.             return new String(data);    
  434.         }    
  435.         try {    
  436.             return new String(data, charset);    
  437.         } catch (UnsupportedEncodingException e) {    
  438.             LogUtil.getLogger().error("将byte数组[" + data + "]转为String时发生异常:系统不支持该字符集[" + charset + "]");    
  439.             return new String(data);    
  440.         }    
  441.     }    
  442.         
  443.         
  444.     /**  
  445.      * 获取一个字符串的简明效果  
  446.      * @return String 返回的字符串格式类似于"abcd***hijk"  
  447.      */    
  448.     public static String getStringSimple(String data){    
  449.         return data.substring(0,4) + "***" + data.substring(data.length()-4);    
  450.     }    
  451.         
  452.         
  453.     /**  
  454.      * 字符串转为字节数组  
  455.      * @see 该方法默认以ISO-8859-1转码  
  456.      * @see 若想自己指定字符集,可以使用<code>getBytes(String str, String charset)</code>方法  
  457.      */    
  458.     public static byte[] getBytes(String data){    
  459.         return getBytes(data, "ISO-8859-1");    
  460.     }    
  461.         
  462.         
  463.     /**  
  464.      * 字符串转为字节数组  
  465.      * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换  
  466.      */    
  467.     public static byte[] getBytes(String data, String charset){    
  468.         data = (data==null ? "" : data);    
  469.         if(isEmpty(charset)){    
  470.             return data.getBytes();    
  471.         }    
  472.         try {    
  473.             return data.getBytes(charset);    
  474.         } catch (UnsupportedEncodingException e) {    
  475.             LogUtil.getLogger().error("将字符串[" + data + "]转为byte[]时发生异常:系统不支持该字符集[" + charset + "]");    
  476.             return data.getBytes();    
  477.         }    
  478.     }    
  479.         
  480.         
  481.     /**  
  482.      * 根据指定的签名密钥和算法签名Map<String,String>  
  483.      * @see 方法内部首先会过滤Map<String,String>参数中的部分键值对  
  484.      * @see 过滤规则:移除键名为"cert","hmac","signMsg"或者键值为null或者键值长度为零的键值对  
  485.      * @see 过滤结果:过滤完Map<String,String>后会产生一个字符串,其格式为[key11=value11|key22=value22|key33=value33]  
  486.      * @see And the calls {@link TradePortalUtil#getHexSign(String,String,String,boolean)}进行签名  
  487.      * @param param     待签名的Map<String,String>  
  488.      * @param charset   签名时转码用到的字符集  
  489.      * @param algorithm 签名时所使用的算法,从业务上看,目前其可传入两个值:MD5,SHA-1  
  490.      * @param signKey   签名用到的密钥  
  491.      * @return String algorithm digest as a lowerCase hex string  
  492.      */    
  493.     public static String getHexSign(Map<String, String> param, String charset, String algorithm, String signKey){    
  494.         StringBuilder sb = new StringBuilder();    
  495.         List<String> keys = new ArrayList<String>(param.keySet());    
  496.         Collections.sort(keys);    
  497.         for(int i=0; i<keys.size(); i++){    
  498.             String key = keys.get(i);    
  499.             String value = param.get(key);    
  500.             if(key.equalsIgnoreCase("cert") || key.equalsIgnoreCase("hmac") || key.equalsIgnoreCase("signMsg") || value==null || value.length()==0){    
  501.                 continue;    
  502.             }    
  503.             sb.append(key).append("=").append(value).append("|");    
  504.         }    
  505.         sb.append("key=").append(signKey);    
  506.         return getHexSign(sb.toString(), charset, algorithm, true);    
  507.     }    
  508.         
  509.         
  510.     /**  
  511.      * 通过指定算法签名字符串  
  512.      * @see Calculates the algorithm digest and returns the value as a hex string  
  513.      * @see If system dosen't support this <code>algorithm</code>, return "" not null  
  514.      * @see It will Calls {@link TradePortalUtil#getBytes(String str, String charset)}  
  515.      * @see 若系统不支持<code>charset</code>字符集,则按照系统默认字符集进行转换  
  516.      * @see 若系统不支持<code>algorithm</code>算法,则直接返回""空字符串  
  517.      * @see 另外,commons-codec.jar提供的DigestUtils.md5Hex(String data)与本方法getHexSign(data, "UTF-8", "MD5", false)效果相同  
  518.      * @param data        Data to digest  
  519.      * @param charset     字符串转码为byte[]时使用的字符集  
  520.      * @param algorithm   目前其有效值为<code>MD5,SHA,SHA1,SHA-1,SHA-256,SHA-384,SHA-512</code>  
  521.      * @param toLowerCase 指定是否返回小写形式的十六进制字符串  
  522.      * @return String algorithm digest as a lowerCase hex string  
  523.      */    
  524.     public static String getHexSign(String data, String charset, String algorithm, boolean toLowerCase){    
  525.         char[] DIGITS_LOWER = {'0''1''2''3''4''5''6''7''8''9''a''b''c''d''e''f'};    
  526.         char[] DIGITS_UPPER = {'0''1''2''3''4''5''6''7''8''9''A''B''C''D''E''F'};    
  527.         //Used to build output as Hex    
  528.         char[] DIGITS = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER;    
  529.         //get byte[] from {@link TradePortalUtil#getBytes(String, String)}    
  530.         byte[] dataBytes = getBytes(data, charset);    
  531.         byte[] algorithmData = null;    
  532.         try {    
  533.             //get an algorithm digest instance    
  534.             algorithmData = MessageDigest.getInstance(algorithm).digest(dataBytes);    
  535.         } catch (NoSuchAlgorithmException e) {    
  536.             LogUtil.getLogger().error("签名字符串[" + data + "]时发生异常:System doesn't support this algorithm[" + algorithm + "]");    
  537.             return "";    
  538.         }    
  539.         char[] respData = new char[algorithmData.length << 1];    
  540.         //two characters form the hex value    
  541.         for(int i=0,j=0; i<algorithmData.length; i++){    
  542.             respData[j++] = DIGITS[(0xF0 & algorithmData[i]) >>> 4];    
  543.             respData[j++] = DIGITS[0x0F & algorithmData[i]];    
  544.         }    
  545.         return new String(respData);    
  546.     }    
  547.         
  548.         
  549.     /**  
  550.      * 字符编码  
  551.      * @see 该方法默认会以UTF-8编码字符串  
  552.      * @see 若想自己指定字符集,可以使用<code>encode(String chinese, String charset)</code>方法  
  553.      */    
  554.     public static String encode(String chinese){    
  555.         return encode(chinese, "UTF-8");    
  556.     }    
  557.         
  558.         
  559.     /**  
  560.      * 字符编码  
  561.      * @see 该方法通常用于对中文进行编码  
  562.      * @see 若系统不支持指定的编码字符集,则直接将<code>chinese</code>原样返回  
  563.      */    
  564.     public static String encode(String chinese, String charset){    
  565.         chinese = (chinese==null ? "" : chinese);    
  566.         try {    
  567.             return URLEncoder.encode(chinese, charset);    
  568.         } catch (UnsupportedEncodingException e) {    
  569.             LogUtil.getLogger().error("编码字符串[" + chinese + "]时发生异常:系统不支持该字符集[" + charset + "]");    
  570.             return chinese;    
  571.         }    
  572.     }    
  573.         
  574.         
  575.     /**  
  576.      * 字符解码  
  577.      * @see 该方法默认会以UTF-8解码字符串  
  578.      * @see 若想自己指定字符集,可以使用<code>decode(String chinese, String charset)</code>方法  
  579.      */    
  580.     public static String decode(String chinese){    
  581.         return decode(chinese, "UTF-8");    
  582.     }    
  583.         
  584.         
  585.     /**  
  586.      * 字符解码  
  587.      * @see 该方法通常用于对中文进行解码  
  588.      * @see 若系统不支持指定的解码字符集,则直接将<code>chinese</code>原样返回  
  589.      */    
  590.     public static String decode(String chinese, String charset){    
  591.         chinese = (chinese==null ? "" : chinese);    
  592.         try {    
  593.             return URLDecoder.decode(chinese, charset);    
  594.         } catch (UnsupportedEncodingException e) {    
  595.             LogUtil.getLogger().error("解码字符串[" + chinese + "]时发生异常:系统不支持该字符集[" + charset + "]");    
  596.             return chinese;    
  597.         }    
  598.     }    
  599.         
  600.         
  601.     /**  
  602.      * 字符串右补字符  
  603.      * @see 该方法默认采用0x00右补字符  
  604.      * @see 若想自己指定所补字符,可以使用<code>rightPadForByte(String str, int size, int padStrByASCII)</code>方法  
  605.      */    
  606.     public static String rightPadForByte(String str, int size){    
  607.         return rightPadForByte(str, size, 0);    
  608.     }    
  609.         
  610.         
  611.     /**  
  612.      * 字符串右补字符  
  613.      * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str  
  614.      * @see 所以size参数很关键..事实上之所以这么处理,是由于支付处理系统接口文档规定了字段的最大长度  
  615.      * @see 若对普通字符串进行右补字符,建议org.apache.commons.lang.StringUtils.rightPad(...)  
  616.      * @param size          该参数指的不是字符串长度,而是字符串所对应的byte[]长度  
  617.      * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等  
  618.      */    
  619.     public static String rightPadForByte(String str, int size, int padStrByASCII){    
  620.         byte[] srcByte = str.getBytes();    
  621.         byte[] destByte = null;    
  622.         if(srcByte.length >= size){    
  623.             //由于size不大于原数组长度,故该方法此时会按照size自动截取,它会在数组右侧填充'(byte)padStrByASCII'以使其具有指定的长度    
  624.             destByte = Arrays.copyOf(srcByte, size);    
  625.         }else{    
  626.             destByte = Arrays.copyOf(srcByte, size);    
  627.             Arrays.fill(destByte, srcByte.length, size, (byte)padStrByASCII);    
  628.         }    
  629.         return new String(destByte);    
  630.     }    
  631.         
  632.         
  633.     /**  
  634.      * 字符串左补字符  
  635.      * @see 该方法默认采用0x00左补字符  
  636.      * @see 若想自己指定所补字符,可以使用<code>leftPadForByte(String str, int size, int padStrByASCII)</code>方法  
  637.      */    
  638.     public static String leftPadForByte(String str, int size){    
  639.         return leftPadForByte(str, size, 0);    
  640.     }    
  641.         
  642.         
  643.     /**  
  644.      * 字符串左补字符  
  645.      * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str  
  646.      * @see 所以size参数很关键..事实上之所以这么处理,是由于支付处理系统接口文档规定了字段的最大长度  
  647.      * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等  
  648.      */    
  649.     public static String leftPadForByte(String str, int size, int padStrByASCII){    
  650.         byte[] srcByte = str.getBytes();    
  651.         byte[] destByte = new byte[size];    
  652.         Arrays.fill(destByte, (byte)padStrByASCII);    
  653.         if(srcByte.length >= size){    
  654.             System.arraycopy(srcByte, 0, destByte, 0, size);    
  655.         }else{    
  656.             System.arraycopy(srcByte, 0, destByte, size-srcByte.length, srcByte.length);    
  657.         }    
  658.         return new String(destByte);    
  659.     }    
  660.         
  661.         
  662.     /**  
  663.      * 获取前一天日期yyyyMMdd  
  664.      * @see 经测试,针对闰年02月份或跨年等情况,该代码仍有效。测试代码如下  
  665.      * @see calendar.set(Calendar.YEAR, 2013);  
  666.      * @see calendar.set(Calendar.MONTH, 0);  
  667.      * @see calendar.set(Calendar.DATE, 1);  
  668.      * @see 测试时,将其放到<code>calendar.add(Calendar.DATE, -1);</code>前面即可  
  669.      * @return 返回的日期格式为yyyyMMdd  
  670.      */    
  671.     public static String getYestoday(){    
  672.         Calendar calendar = Calendar.getInstance();    
  673.         calendar.add(Calendar.DATE, -1);    
  674.         return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());    
  675.     }    
  676.         
  677.         
  678.     /**  
  679.      * 获取当前的日期yyyyMMdd  
  680.      */    
  681.     public static String getCurrentDate(){    
  682.         return new SimpleDateFormat("yyyyMMdd").format(new Date());    
  683.     }    
  684.         
  685.         
  686.     /**  
  687.      * 获取当前的时间yyyyMMddHHmmss  
  688.      */    
  689.     public static String getCurrentTime(){    
  690.         return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());    
  691.     }    
  692.         
  693.         
  694.     /**  
  695.      * HTML字符转义  
  696.      * @see 对输入参数中的敏感字符进行过滤替换,防止用户利用JavaScript等方式输入恶意代码  
  697.      * @see String input = <img src='http://t1.baidu.com/it/fm=0&gp=0.jpg'/>  
  698.      * @see HtmlUtils.htmlEscape(input);         //from spring.jar  
  699.      * @see StringEscapeUtils.escapeHtml(input); //from commons-lang.jar  
  700.      * @see 尽管Spring和Apache都提供了字符转义的方法,但Apache的StringEscapeUtils功能要更强大一些  
  701.      * @see StringEscapeUtils提供了对HTML,Java,JavaScript,SQL,XML等字符的转义和反转义  
  702.      * @see 但二者在转义HTML字符时,都不会对单引号和空格进行转义,而本方法则提供了对它们的转义  
  703.      * @return String 过滤后的字符串  
  704.      */    
  705.     public static String htmlEscape(String input) {    
  706.         if(isEmpty(input)){    
  707.             return input;    
  708.         }    
  709.         input = input.replaceAll("&""&");    
  710.         input = input.replaceAll("<""<");    
  711.         input = input.replaceAll(">"">");    
  712.         input = input.replaceAll(" "" ");    
  713.         input = input.replaceAll("'""'");   //IE暂不支持单引号的实体名称,而支持单引号的实体编号,故单引号转义成实体编号,其它字符转义成实体名称    
  714.         input = input.replaceAll("\"""""); //双引号也需要转义,所以加一个斜线对其进行转义    
  715.         input = input.replaceAll("\n""<br/>");  //不能把\n的过滤放在前面,因为还要对<和>过滤,这样就会导致<br/>失效了    
  716.         return input;    
  717.     }    
  718.         
  719.         
  720.     /**  
  721.      * AES算法加密数据  
  722.      * @param data 待加密数据  
  723.      * @param key  密钥  
  724.      * @return 加密后的数据,若加密遇到异常时则返回<code>Encrypt Terminated</code>字符串  
  725.      * */    
  726.     public static String genAESEncrypt(String data, String key){    
  727.         try{    
  728.             //实例化Cipher对象,它用于完成实际的加密操作    
  729.             Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");    
  730.             //还原密钥,并初始化Cipher对象,设置为加密模式    
  731.             cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key), "AES"));    
  732.             //执行加密操作,加密后的结果通常都会用Base64编码进行传输    
  733.             //将Base64中的URL非法字符如'+','/','='转为其他字符,详见RFC3548    
  734.             return Base64.encodeBase64URLSafeString(cipher.doFinal(data.getBytes()));    
  735.         }catch(Exception e){    
  736.             LogUtil.getLogger().error("加密字符串[" + data + "]时遇到异常,堆栈信息如下", e);    
  737.             return "Encrypt Terminated";    
  738.         }    
  739.     }    
  740.         
  741.         
  742.     /**  
  743.      * AES算法解密数据  
  744.      * @param data 待解密数据  
  745.      * @param key  密钥  
  746.      * @return 解密后的数据,若加密遇到异常时则返回<code>Decrypt Terminated</code>字符串  
  747.      * */    
  748.     public static String genAESDecrypt(String data, String key){    
  749.         try {    
  750.             Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");    
  751.             cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key), "AES"));    
  752.             return new String(cipher.doFinal(Base64.decodeBase64(data)));    
  753.         }catch(Exception e){    
  754.             LogUtil.getLogger().error("解密字符串[" + data + "]时遇到异常,堆栈信息如下", e);    
  755.             return "Decrypt Terminated";    
  756.         }    
  757.     }    
  758. }    
package com.cucpay.tradeportal.util;  
  
import java.io.UnsupportedEncodingException;  
import java.lang.reflect.Field;  
import java.net.URLDecoder;  
import java.net.URLEncoder;  
import java.nio.charset.CharacterCodingException;  
import java.nio.charset.Charset;  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
import java.text.SimpleDateFormat;  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.Calendar;  
import java.util.Collections;  
import java.util.Date;  
import java.util.List;  
import java.util.Map;  
import java.util.UUID;  
  
import javax.crypto.Cipher;  
import javax.crypto.spec.SecretKeySpec;  
  
import org.apache.commons.codec.binary.Base64;  
import org.apache.commons.lang.StringUtils;  
import org.apache.mina.core.buffer.IoBuffer;  
  
/** 
 * 交易前置系统专用工具类 
 * @create Aug 15, 2012 12:16:49 PM 
 * @update Sep 27, 2012 3:07:09 PM 
 * @author 玄玉<http://blog.csdn/net/jadyer> 
 * @version v2.4 
 * @history v1.1-->新增<code>getHexSign()</code>通过指定算法签名字符串方法 
 * @history v1.2-->新增<code>getString()</code>字节数组转为字符串方法 
 * @history v1.3-->修改<code>getSysJournalNo()</code>实现细节为<code>java.util.UUID.randomUUID()</code> 
 * @history v1.4-->新增<code>getHexSign()</code>根据指定的签名密钥和算法签名Map<String,String> 
 * @history v1.5-->新增<code>getStringSimple()</code>获取一个字符串的简明效果,返回的字符串格式类似于"abcd***hijk" 
 * @history v2.0-->局部的StringBuffer一律StringBuilder之(本思路提示自坦克<captmjc@gmail.com>) 
 * @history v2.1-->新增<code>formatToHexStringWithASCII()</code>用于格式化字节数组为十六进制字符串的方法 
 * @history v2.2-->新增<code>isNotEmpty()</code>用于判断输入的字符串或字节数组是否为非空的方法 
 * @history v2.3-->修改<code>rightPadForByte(),leftPadForByte()</code>方法左右填充的字符为0x00 
 * @history v2.4-->新增<code>genAESEncrypt()和genAESDecrypt()</code>用于AES加解密的方法 
 */  
public class TradePortalUtil {  
    private TradePortalUtil(){}  
      
    /** 
     * 获取系统流水号 
     * @see 若欲指定返回值的长度or是否全由数字组成等,you can call {@link TradePortalUtil#getSysJournalNo(int, boolean)} 
     * @return 长度为20的全数字 
     */  
    public static String getSysJournalNo(){  
        return getSysJournalNo(20, true);  
    }  
      
      
    /** 
     * 获取系统流水号 
     * @param length   指定流水号长度 
     * @param toNumber 指定流水号是否全由数字组成 
     */  
    public static String getSysJournalNo(int length, boolean isNumber){  
        //replaceAll()之后返回的是一个由十六进制形式组成的且长度为32的字符串  
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");  
        if(uuid.length() > length){  
            uuid = uuid.substring(0, length);  
        }else if(uuid.length() < length){  
            for(int i=0; i<length-uuid.length(); i++){  
                uuid = uuid + Math.round(Math.random()*9);  
            }  
        }  
        if(isNumber){  
            return uuid.replaceAll("a", "1").replaceAll("b", "2").replaceAll("c", "3").replaceAll("d", "4").replaceAll("e", "5").replaceAll("f", "6");  
        }else{  
            return uuid;  
        }  
    }  
      
      
    /** 
     * 判断输入的字符串参数是否为空 
     * @return boolean 空则返回true,非空则flase 
     */  
    public static boolean isEmpty(String input) {  
        return null==input || 0==input.length() || 0==input.replaceAll("\\s", "").length();  
    }  
      
      
    /** 
     * 判断输入的字符串参数是否为非空 
     * @return boolean 非空则返回true,空则flase 
     */  
    public static boolean isNotEmpty(String input){  
        return !isEmpty(input);  
    }  
      
      
    /** 
     * 判断输入的字节数组是否为空 
     * @return boolean 空则返回true,非空则flase 
     */  
    public static boolean isEmpty(byte[] bytes){  
        return null==bytes || 0==bytes.length;  
    }  
      
      
    /** 
     * 判断输入的字节数组是否为非空 
     * @return boolean 非空则返回true,空则flase 
     */  
    public static boolean isNotEmpty(byte[] bytes){  
        return !isEmpty(bytes);  
    }  
      
      
    /** 
     * 从org.apache.mina.core.buffer.IoBuffer中读取字符串 
     * @see 该方法默认以GBK解码 
     * @see 若想自己指定字符集,可以使用<code>getStringFromIoBuffer(IoBuffer buffer, int size, String charset)</code>方法 
     * @param size 所要读取的字节数 
     */  
    public static String getStringFromIoBuffer(IoBuffer buffer, int size){  
        return getStringFromIoBuffer(buffer, size, "GBK");  
    }  
      
      
    /** 
     * 从org.apache.mina.core.buffer.IoBuffer中读取字符串 
     * @param size    所要读取的字节数 
     * @param charset 解码的字符集 
     */  
    public static String getStringFromIoBuffer(IoBuffer buffer, int size, String charset){  
        String result = null;  
        try {  
            result = buffer.getString(size, Charset.forName(charset).newDecoder());  
        } catch (CharacterCodingException e) {  
            LogUtil.getLogger().error("字符解码异常,自动切换第二种解码方式,本次的堆栈信息如下", e);  
            try {  
                result = new String(buffer.array(), charset);  
            } catch (UnsupportedEncodingException ee) {  
                LogUtil.getLogger().error("字符解码异常,系统不支持该字符集[" + charset + "],本次的堆栈信息如下", ee);  
            }  
        }  
        return result;  
    }  
      
      
    /** 
     * 获取实体类中的属性 
     * @see 本方法用到了反射,其适用于所有的属性类型均为byte[]的JavaBean 
     * @return String field11=value11 field22=value22 field33=value33 
     */  
    public static String getStringFromObjectForByte(Object obj){  
        StringBuilder sb = new StringBuilder(); //局部的StringBuffer一律StringBuilder之  
        sb.append(obj.getClass().getName()).append("@").append(obj.hashCode()).append("[");  
        for(Field field : obj.getClass().getDeclaredFields()){  
            String methodName = "get" + StringUtils.capitalize(field.getName()); //构造getter方法  
            Object fieldValue = null;  
            try{  
                fieldValue = obj.getClass().getDeclaredMethod(methodName).invoke(obj); //执行getter方法,获取其返回值  
            }catch(Exception e){  
                //一旦发生异常,便将属性值置为UnKnown,故此处没必要一一捕获所有异常  
                sb.append("\n").append(field.getName()).append("=UnKnown");  
                continue;  
            }  
            if(fieldValue == null){  
                sb.append("\n").append(field.getName()).append("=null");  
            }else{  
                sb.append("\n").append(field.getName()).append("=").append(new String((byte[])fieldValue));  
            }  
        }  
        return sb.append("\n]").toString();  
    }  
      
      
    /** 
     * 获取Map中的属性 
     * @see 由于Map.toString()打印出来的参数值对,是横着一排的...参数多的时候,不便于查看各参数值 
     * @see 故此仿照commons-lang.jar中的ReflectionToStringBuilder.toString()编写了本方法 
     * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... 
     */  
    public static String getStringFromMap(Map<String, String> map){  
        StringBuilder sb = new StringBuilder();  
        sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");  
        for(Map.Entry<String,String> entry : map.entrySet()){  
            sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue());  
        }  
        return sb.append("\n]").toString();  
    }  
  
      
    /** 
     * 获取Map中的属性 
     * @see 该方法的参数适用于打印Map<String, byte[]>的情况 
     * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... 
     */  
    public static String getStringFromMapForByte(Map<String, byte[]> map){  
        StringBuilder sb = new StringBuilder();  
        sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");  
        for(Map.Entry<String,byte[]> entry : map.entrySet()){  
            sb.append("\n").append(entry.getKey()).append("=").append(new String(entry.getValue()));  
        }  
        return sb.append("\n]").toString();  
    }  
      
      
    /** 
     * 获取Map中的属性 
     * @see 该方法的参数适用于打印Map<String, Object>的情况 
     * @return String key11=value11 \n key22=value22 \n key33=value33 \n...... 
     */  
    public static String getStringFromMapForObject(Map<String, Object> map){  
        StringBuilder sb = new StringBuilder();  
        sb.append(map.getClass().getName()).append("@").append(map.hashCode()).append("[");  
        for(Map.Entry<String,Object> entry : map.entrySet()){  
            sb.append("\n").append(entry.getKey()).append("=").append(entry.getValue().toString());  
        }  
        return sb.append("\n]").toString();  
    }  
  
      
    /** 
     * 通过ASCII码将十六进制的字节数组格式化为十六进制字符串 
     * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法 
     */  
    public static String formatHexToHexStringWithASCII(byte[] hexData, int offset, int length){  
        byte[] data = new byte[hexData.length];  
        for (int i = 0; i < data.length; i++) {  
            data[i] = Integer.valueOf(""+hexData[i], 16).byteValue(); //获取16进制数的ASCII值,比如16进制的41对应ASCII的65  
        }  
        return formatToHexStringWithASCII(data, offset, length);  
    }  
      
      
    /** 
     * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 
     * @see 该方法会将字节数组中的所有字节均格式化为字符串 
     * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法 
     */  
    public static String formatToHexStringWithASCII(byte[] data){  
        return formatToHexStringWithASCII(data, 0, data.length);  
    }  
      
      
    /** 
     * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 
     * @see 该方法常用于字符串的十六进制打印,打印时左侧为十六进制数值,右侧为对应的字符串原文 
     * @see 在构造右侧的字符串原文时,该方法内部使用的是平台的默认字符集,来解码byte[]数组 
     * @see 该方法在将字节转为十六进制时,默认使用的是<code>java.util.Locale.getDefault()</code> 
     * @see 详见String.format(String, Object...)方法和new String(byte[], int, int)构造方法 
     * @param data   十进制的字节数组 
     * @param offset 数组下标,标记从数组的第几个字节开始格式化输出 
     * @param length 格式长度,其不得大于数组长度,否则抛出java.lang.ArrayIndexOutOfBoundsException 
     * @return 格式化后的十六进制字符串 
     */  
    public static String formatToHexStringWithASCII(byte[] data, int offset, int length){  
        int end = offset + length;  
        StringBuilder sb = new StringBuilder();  
        StringBuilder sb2 = new StringBuilder();  
        sb.append("\r\n------------------------------------------------------------------------");  
        boolean chineseCutFlag = false;  
        for(int i=offset; i<end; i+=16){  
            sb.append(String.format("\r\n%04X: ", i-offset)); //X或x表示将结果格式化为十六进制整数  
            sb2.setLength(0);  
            for(int j=i; j<i+16; j++){  
                if(j < end){  
                    byte b = data[j];  
                    if(b >= 0){ //ENG ASCII  
                        sb.append(String.format("%02X ", b));  
                        if(b<32 || b>126){ //不可见字符  
                            sb2.append(" ");  
                        }else{  
                            sb2.append((char)b);  
                        }  
                    }else{ //CHA ASCII  
                        if(j == i+15){ //汉字前半个字节  
                            sb.append(String.format("%02X ", data[j]));  
                            chineseCutFlag = true;  
                            String s = new String(data, j, 2);  
                            sb2.append(s);  
                        }else if(j == i&&chineseCutFlag){ //后半个字节  
                            sb.append(String.format("%02X ", data[j]));  
                            chineseCutFlag = false;  
                            String s = new String(data, j, 1);  
                            sb2.append(s);  
                        }else{  
                            sb.append(String.format("%02X %02X ", data[j], data[j + 1]));  
                            String s = new String(data, j, 2);  
                            sb2.append(s);  
                            j++;  
                        }  
                    }  
                }else{  
                    sb.append("   ");  
                }  
            }  
            sb.append("| ");  
            sb.append(sb2.toString());  
        }  
        sb.append("\r\n------------------------------------------------------------------------");  
        return sb.toString();  
    }  
      
      
    /** 
     * 金额元转分 
     * @see 注意:该方法可处理贰仟万以内的金额,且若有小数位,则不限小数位的长度 
     * @see 注意:如果你的金额达到了贰仟万以上,则不推荐使用该方法,否则计算出来的结果会令人大吃一惊 
     * @param amount  金额的元进制字符串 
     * @return String 金额的分进制字符串 
     */  
    public static String moneyYuanToFen(String amount){  
        if(isEmpty(amount)){  
            return amount;  
        }  
        //传入的金额字符串代表的是一个整数  
        if(-1 == amount.indexOf(".")){  
            return Integer.parseInt(amount) * 100 + "";  
        }  
        //传入的金额字符串里面含小数点-->取小数点前面的字符串,并将之转换成单位为分的整数表示  
        int money_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) * 100;  
        //取到小数点后面的字符串  
        String pointBehind = (amount.substring(amount.indexOf(".") + 1));  
        //amount=12.3  
        if(pointBehind.length() == 1){  
            return money_fen + Integer.parseInt(pointBehind)*10 + "";  
        }  
        //小数点后面的第一位字符串的整数表示  
        int pointString_1 = Integer.parseInt(pointBehind.substring(0, 1));  
        //小数点后面的第二位字符串的整数表示  
        int pointString_2 = Integer.parseInt(pointBehind.substring(1, 2));  
        //amount==12.03,amount=12.00,amount=12.30  
        if(pointString_1 == 0){  
            return money_fen + pointString_2 + "";  
        }else{  
            return money_fen + pointString_1*10 + pointString_2 + "";  
        }  
    }  
      
      
    /** 
     * 金额元转分 
     * @see 该方法会将金额中小数点后面的数值,四舍五入后只保留两位....如12.345-->12.35 
     * @see 注意:该方法可处理贰仟万以内的金额 
     * @see 注意:如果你的金额达到了贰仟万以上,则非常不建议使用该方法,否则计算出来的结果会令人大吃一惊 
     * @param amount  金额的元进制字符串 
     * @return String 金额的分进制字符串 
     */  
    public static String moneyYuanToFenByRound(String amount){  
        if(isEmpty(amount)){  
            return amount;  
        }  
        if(-1 == amount.indexOf(".")){  
            return Integer.parseInt(amount) * 100 + "";  
        }  
        int money_fen = Integer.parseInt(amount.substring(0, amount.indexOf("."))) * 100;  
        String pointBehind = (amount.substring(amount.indexOf(".") + 1));  
        if(pointBehind.length() == 1){  
            return money_fen + Integer.parseInt(pointBehind)*10 + "";  
        }  
        int pointString_1 = Integer.parseInt(pointBehind.substring(0, 1));  
        int pointString_2 = Integer.parseInt(pointBehind.substring(1, 2));  
        //下面这种方式用于处理pointBehind=245,286,295,298,995,998等需要四舍五入的情况  
        if(pointBehind.length() > 2){  
            int pointString_3 = Integer.parseInt(pointBehind.substring(2, 3));  
            if(pointString_3 >= 5){  
                if(pointString_2 == 9){  
                    if(pointString_1 == 9){  
                        money_fen = money_fen + 100;  
                        pointString_1 = 0;  
                        pointString_2 = 0;  
                    }else{  
                        pointString_1 = pointString_1 + 1;  
                        pointString_2 = 0;  
                    }  
                }else{  
                    pointString_2 = pointString_2 + 1;  
                }  
            }  
        }  
        if(pointString_1 == 0){  
            return money_fen + pointString_2 + "";  
        }else{  
            return money_fen + pointString_1*10 + pointString_2 + "";  
        }  
    }  
      
      
    /** 
     * 金额分转元 
     * @see 注意:如果传入的参数中含小数点,则直接原样返回 
     * @see 该方法返回的金额字符串格式为<code>00.00</code>,其整数位有且至少有一个,小数位有且长度固定为2 
     * @param amount  金额的分进制字符串 
     * @return String 金额的元进制字符串 
     */  
    public static String moneyFenToYuan(String amount){  
        if(isEmpty(amount)){  
            return amount;  
        }  
        if(amount.indexOf(".") > -1){  
            return amount;  
        }  
        if(amount.length() == 1){  
            return "0.0" + amount;  
        }else if(amount.length() == 2){  
            return "0." + amount;  
        }else{  
            return amount.substring(0, amount.length()-2) + "." + amount.substring(amount.length()-2);  
        }  
    }  
      
  
    /** 
     * 字节数组转为字符串 
     * @see 该方法默认以ISO-8859-1转码 
     * @see 若想自己指定字符集,可以使用<code>getString(byte[] data, String charset)</code>方法 
     */  
    public static String getString(byte[] data){  
        return getString(data, "ISO-8859-1");  
    }  
      
      
    /** 
     * 字节数组转为字符串 
     * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 
     */  
    public static String getString(byte[] data, String charset){  
        if(isEmpty(data)){  
            return "";  
        }  
        if(isEmpty(charset)){  
            return new String(data);  
        }  
        try {  
            return new String(data, charset);  
        } catch (UnsupportedEncodingException e) {  
            LogUtil.getLogger().error("将byte数组[" + data + "]转为String时发生异常:系统不支持该字符集[" + charset + "]");  
            return new String(data);  
        }  
    }  
      
      
    /** 
     * 获取一个字符串的简明效果 
     * @return String 返回的字符串格式类似于"abcd***hijk" 
     */  
    public static String getStringSimple(String data){  
        return data.substring(0,4) + "***" + data.substring(data.length()-4);  
    }  
      
      
    /** 
     * 字符串转为字节数组 
     * @see 该方法默认以ISO-8859-1转码 
     * @see 若想自己指定字符集,可以使用<code>getBytes(String str, String charset)</code>方法 
     */  
    public static byte[] getBytes(String data){  
        return getBytes(data, "ISO-8859-1");  
    }  
      
      
    /** 
     * 字符串转为字节数组 
     * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 
     */  
    public static byte[] getBytes(String data, String charset){  
        data = (data==null ? "" : data);  
        if(isEmpty(charset)){  
            return data.getBytes();  
        }  
        try {  
            return data.getBytes(charset);  
        } catch (UnsupportedEncodingException e) {  
            LogUtil.getLogger().error("将字符串[" + data + "]转为byte[]时发生异常:系统不支持该字符集[" + charset + "]");  
            return data.getBytes();  
        }  
    }  
      
      
    /** 
     * 根据指定的签名密钥和算法签名Map<String,String> 
     * @see 方法内部首先会过滤Map<String,String>参数中的部分键值对 
     * @see 过滤规则:移除键名为"cert","hmac","signMsg"或者键值为null或者键值长度为零的键值对 
     * @see 过滤结果:过滤完Map<String,String>后会产生一个字符串,其格式为[key11=value11|key22=value22|key33=value33] 
     * @see And the calls {@link TradePortalUtil#getHexSign(String,String,String,boolean)}进行签名 
     * @param param     待签名的Map<String,String> 
     * @param charset   签名时转码用到的字符集 
     * @param algorithm 签名时所使用的算法,从业务上看,目前其可传入两个值:MD5,SHA-1 
     * @param signKey   签名用到的密钥 
     * @return String algorithm digest as a lowerCase hex string 
     */  
    public static String getHexSign(Map<String, String> param, String charset, String algorithm, String signKey){  
        StringBuilder sb = new StringBuilder();  
        List<String> keys = new ArrayList<String>(param.keySet());  
        Collections.sort(keys);  
        for(int i=0; i<keys.size(); i++){  
            String key = keys.get(i);  
            String value = param.get(key);  
            if(key.equalsIgnoreCase("cert") || key.equalsIgnoreCase("hmac") || key.equalsIgnoreCase("signMsg") || value==null || value.length()==0){  
                continue;  
            }  
            sb.append(key).append("=").append(value).append("|");  
        }  
        sb.append("key=").append(signKey);  
        return getHexSign(sb.toString(), charset, algorithm, true);  
    }  
      
      
    /** 
     * 通过指定算法签名字符串 
     * @see Calculates the algorithm digest and returns the value as a hex string 
     * @see If system dosen't support this <code>algorithm</code>, return "" not null 
     * @see It will Calls {@link TradePortalUtil#getBytes(String str, String charset)} 
     * @see 若系统不支持<code>charset</code>字符集,则按照系统默认字符集进行转换 
     * @see 若系统不支持<code>algorithm</code>算法,则直接返回""空字符串 
     * @see 另外,commons-codec.jar提供的DigestUtils.md5Hex(String data)与本方法getHexSign(data, "UTF-8", "MD5", false)效果相同 
     * @param data        Data to digest 
     * @param charset     字符串转码为byte[]时使用的字符集 
     * @param algorithm   目前其有效值为<code>MD5,SHA,SHA1,SHA-1,SHA-256,SHA-384,SHA-512</code> 
     * @param toLowerCase 指定是否返回小写形式的十六进制字符串 
     * @return String algorithm digest as a lowerCase hex string 
     */  
    public static String getHexSign(String data, String charset, String algorithm, boolean toLowerCase){  
        char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};  
        char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};  
        //Used to build output as Hex  
        char[] DIGITS = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER;  
        //get byte[] from {@link TradePortalUtil#getBytes(String, String)}  
        byte[] dataBytes = getBytes(data, charset);  
        byte[] algorithmData = null;  
        try {  
            //get an algorithm digest instance  
            algorithmData = MessageDigest.getInstance(algorithm).digest(dataBytes);  
        } catch (NoSuchAlgorithmException e) {  
            LogUtil.getLogger().error("签名字符串[" + data + "]时发生异常:System doesn't support this algorithm[" + algorithm + "]");  
            return "";  
        }  
        char[] respData = new char[algorithmData.length << 1];  
        //two characters form the hex value  
        for(int i=0,j=0; i<algorithmData.length; i++){  
            respData[j++] = DIGITS[(0xF0 & algorithmData[i]) >>> 4];  
            respData[j++] = DIGITS[0x0F & algorithmData[i]];  
        }  
        return new String(respData);  
    }  
      
      
    /** 
     * 字符编码 
     * @see 该方法默认会以UTF-8编码字符串 
     * @see 若想自己指定字符集,可以使用<code>encode(String chinese, String charset)</code>方法 
     */  
    public static String encode(String chinese){  
        return encode(chinese, "UTF-8");  
    }  
      
      
    /** 
     * 字符编码 
     * @see 该方法通常用于对中文进行编码 
     * @see 若系统不支持指定的编码字符集,则直接将<code>chinese</code>原样返回 
     */  
    public static String encode(String chinese, String charset){  
        chinese = (chinese==null ? "" : chinese);  
        try {  
            return URLEncoder.encode(chinese, charset);  
        } catch (UnsupportedEncodingException e) {  
            LogUtil.getLogger().error("编码字符串[" + chinese + "]时发生异常:系统不支持该字符集[" + charset + "]");  
            return chinese;  
        }  
    }  
      
      
    /** 
     * 字符解码 
     * @see 该方法默认会以UTF-8解码字符串 
     * @see 若想自己指定字符集,可以使用<code>decode(String chinese, String charset)</code>方法 
     */  
    public static String decode(String chinese){  
        return decode(chinese, "UTF-8");  
    }  
      
      
    /** 
     * 字符解码 
     * @see 该方法通常用于对中文进行解码 
     * @see 若系统不支持指定的解码字符集,则直接将<code>chinese</code>原样返回 
     */  
    public static String decode(String chinese, String charset){  
        chinese = (chinese==null ? "" : chinese);  
        try {  
            return URLDecoder.decode(chinese, charset);  
        } catch (UnsupportedEncodingException e) {  
            LogUtil.getLogger().error("解码字符串[" + chinese + "]时发生异常:系统不支持该字符集[" + charset + "]");  
            return chinese;  
        }  
    }  
      
      
    /** 
     * 字符串右补字符 
     * @see 该方法默认采用0x00右补字符 
     * @see 若想自己指定所补字符,可以使用<code>rightPadForByte(String str, int size, int padStrByASCII)</code>方法 
     */  
    public static String rightPadForByte(String str, int size){  
        return rightPadForByte(str, size, 0);  
    }  
      
      
    /** 
     * 字符串右补字符 
     * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str 
     * @see 所以size参数很关键..事实上之所以这么处理,是由于支付处理系统接口文档规定了字段的最大长度 
     * @see 若对普通字符串进行右补字符,建议org.apache.commons.lang.StringUtils.rightPad(...) 
     * @param size          该参数指的不是字符串长度,而是字符串所对应的byte[]长度 
     * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等 
     */  
    public static String rightPadForByte(String str, int size, int padStrByASCII){  
        byte[] srcByte = str.getBytes();  
        byte[] destByte = null;  
        if(srcByte.length >= size){  
            //由于size不大于原数组长度,故该方法此时会按照size自动截取,它会在数组右侧填充'(byte)padStrByASCII'以使其具有指定的长度  
            destByte = Arrays.copyOf(srcByte, size);  
        }else{  
            destByte = Arrays.copyOf(srcByte, size);  
            Arrays.fill(destByte, srcByte.length, size, (byte)padStrByASCII);  
        }  
        return new String(destByte);  
    }  
      
      
    /** 
     * 字符串左补字符 
     * @see 该方法默认采用0x00左补字符 
     * @see 若想自己指定所补字符,可以使用<code>leftPadForByte(String str, int size, int padStrByASCII)</code>方法 
     */  
    public static String leftPadForByte(String str, int size){  
        return leftPadForByte(str, size, 0);  
    }  
      
      
    /** 
     * 字符串左补字符 
     * @see 若str对应的byte[]长度不小于size,则按照size截取str对应的byte[],而非原样返回str 
     * @see 所以size参数很关键..事实上之所以这么处理,是由于支付处理系统接口文档规定了字段的最大长度 
     * @param padStrByASCII 该值为所补字符的ASCII码,如32表示空格,48表示0,64表示@等 
     */  
    public static String leftPadForByte(String str, int size, int padStrByASCII){  
        byte[] srcByte = str.getBytes();  
        byte[] destByte = new byte[size];  
        Arrays.fill(destByte, (byte)padStrByASCII);  
        if(srcByte.length >= size){  
            System.arraycopy(srcByte, 0, destByte, 0, size);  
        }else{  
            System.arraycopy(srcByte, 0, destByte, size-srcByte.length, srcByte.length);  
        }  
        return new String(destByte);  
    }  
      
      
    /** 
     * 获取前一天日期yyyyMMdd 
     * @see 经测试,针对闰年02月份或跨年等情况,该代码仍有效。测试代码如下 
     * @see calendar.set(Calendar.YEAR, 2013); 
     * @see calendar.set(Calendar.MONTH, 0); 
     * @see calendar.set(Calendar.DATE, 1); 
     * @see 测试时,将其放到<code>calendar.add(Calendar.DATE, -1);</code>前面即可 
     * @return 返回的日期格式为yyyyMMdd 
     */  
    public static String getYestoday(){  
        Calendar calendar = Calendar.getInstance();  
        calendar.add(Calendar.DATE, -1);  
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());  
    }  
      
      
    /** 
     * 获取当前的日期yyyyMMdd 
     */  
    public static String getCurrentDate(){  
        return new SimpleDateFormat("yyyyMMdd").format(new Date());  
    }  
      
      
    /** 
     * 获取当前的时间yyyyMMddHHmmss 
     */  
    public static String getCurrentTime(){  
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());  
    }  
      
      
    /** 
     * HTML字符转义 
     * @see 对输入参数中的敏感字符进行过滤替换,防止用户利用JavaScript等方式输入恶意代码 
     * @see String input = <img src='http://t1.baidu.com/it/fm=0&gp=0.jpg'/> 
     * @see HtmlUtils.htmlEscape(input);         //from spring.jar 
     * @see StringEscapeUtils.escapeHtml(input); //from commons-lang.jar 
     * @see 尽管Spring和Apache都提供了字符转义的方法,但Apache的StringEscapeUtils功能要更强大一些 
     * @see StringEscapeUtils提供了对HTML,Java,JavaScript,SQL,XML等字符的转义和反转义 
     * @see 但二者在转义HTML字符时,都不会对单引号和空格进行转义,而本方法则提供了对它们的转义 
     * @return String 过滤后的字符串 
     */  
    public static String htmlEscape(String input) {  
        if(isEmpty(input)){  
            return input;  
        }  
        input = input.replaceAll("&", "&");  
        input = input.replaceAll("<", "<");  
        input = input.replaceAll(">", ">");  
        input = input.replaceAll(" ", " ");  
        input = input.replaceAll("'", "'");   //IE暂不支持单引号的实体名称,而支持单引号的实体编号,故单引号转义成实体编号,其它字符转义成实体名称  
        input = input.replaceAll("\"", """); //双引号也需要转义,所以加一个斜线对其进行转义  
        input = input.replaceAll("\n", "<br/>");  //不能把\n的过滤放在前面,因为还要对<和>过滤,这样就会导致<br/>失效了  
        return input;  
    }  
      
      
    /** 
     * AES算法加密数据 
     * @param data 待加密数据 
     * @param key  密钥 
     * @return 加密后的数据,若加密遇到异常时则返回<code>Encrypt Terminated</code>字符串 
     * */  
    public static String genAESEncrypt(String data, String key){  
        try{  
            //实例化Cipher对象,它用于完成实际的加密操作  
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");  
            //还原密钥,并初始化Cipher对象,设置为加密模式  
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key), "AES"));  
            //执行加密操作,加密后的结果通常都会用Base64编码进行传输  
            //将Base64中的URL非法字符如'+','/','='转为其他字符,详见RFC3548  
            return Base64.encodeBase64URLSafeString(cipher.doFinal(data.getBytes()));  
        }catch(Exception e){  
            LogUtil.getLogger().error("加密字符串[" + data + "]时遇到异常,堆栈信息如下", e);  
            return "Encrypt Terminated";  
        }  
    }  
      
      
    /** 
     * AES算法解密数据 
     * @param data 待解密数据 
     * @param key  密钥 
     * @return 解密后的数据,若加密遇到异常时则返回<code>Decrypt Terminated</code>字符串 
     * */  
    public static String genAESDecrypt(String data, String key){  
        try {  
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");  
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key), "AES"));  
            return new String(cipher.doFinal(Base64.decodeBase64(data)));  
        }catch(Exception e){  
            LogUtil.getLogger().error("解密字符串[" + data + "]时遇到异常,堆栈信息如下", e);  
            return "Decrypt Terminated";  
        }  
    }  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值