休息食客

          隨心而動

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            16 隨筆 :: 7 文章 :: 2 評論 :: 0 Trackbacks
          開發之前,最好有一些微信開發的經驗,先看一下文檔,了解一下https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter=13_5
          文檔過了一遍之后,腦海里應該有些印象了,廢話不說,進入開發。
          準備參數,一個一個來。
          參數1:隨機字符串    nonce_str
          //獲取隨機數,這里設定長度20,只要不成長于32位
          String nonce_str = RandomStringGenerator.getRandomStringByLength(20); 

          寫一個RandomStringGenerator類,寫一個getRandomStringByLength靜態方法
          import java.util.Random;
          /**
           * User: rizenguo
           * Date: 2014/10/29
           */
          public class RandomStringGenerator {
              /**
               * 獲取一定長度的隨機字符串
               * @param length 指定字符串長度
               * @return 一定長度的字符串
               */
              public static String getRandomStringByLength(int length) {
                  String base = "abcdefghijklmnopqrstuvwxyz0123456789";
                  Random random = new Random();
                  StringBuffer sb = new StringBuffer();
                  for (int i = 0; i < length; i++) {
                      int number = random.nextInt(base.length());
                      sb.append(base.charAt(number));
                  }
                  return sb.toString();
              }
          }
          參數2 : 商戶號   mch_id
          String mch_id = “xxxxxxxx”;

          參數3 : 商戶訂單號  mch_billno

          String mch_billno = mch_id + GenerateSequenceUtil.generateSequenceNo();

          些一個GenerateSequenceUtil類,寫一個generateSequenceNo方法

          import java.text.DecimalFormat;
          import java.text.FieldPosition;
          import java.text.Format;
          import java.text.NumberFormat;
          import java.text.SimpleDateFormat;
          import java.util.Calendar;
           
          import org.apache.log4j.Logger;
           
          public class GenerateSequenceUtil {
           
           /** .log */
           private static final Logger logger = Logger.getLogger(GenerateSequenceUtil.class);
           
           /** The FieldPosition. */
           private static final FieldPosition HELPER_POSITION = new FieldPosition(0);
           
           /** This Format for format the data to special format. */
           private final static Format dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
           
           /** This Format for format the number to special format. */
           private final static NumberFormat numberFormat = new DecimalFormat("0000");
           
           /** This int is the sequence number ,the default value is 0. */
           private static int seq = 0;
           
           private static final int MAX = 9999;
           
           /**
           * 時間格式生成序列
           * @return String
           */
           public static synchronized String generateSequenceNo() {
           
            Calendar rightNow = Calendar.getInstance();
             
            StringBuffer sb = new StringBuffer();
             
            dateFormat.format(rightNow.getTime(), sb, HELPER_POSITION);
             
            numberFormat.format(seq, sb, HELPER_POSITION);
             
            if (seq == MAX) {
             seq = 0;
            } else {
             seq++;
            }
             
            logger.info("THE SQUENCE IS :" + sb.toString());
             
            return sb.toString();
           }

          參數4: 公眾賬號appid   wxappid

          這個參數可以在微信開發者中心里面看到
          //微信分配的公眾賬號ID
          String wxappid = "wx8888888888888888";
          參數5 : 商戶名稱   send_name
          隨便寫
          String send_name = "測試者";   
          參數6 : 用戶openid   re_openid
          微信號和公眾號對應的唯一的加密過的字符串
          String re_openid = "xxxxxxxxxxxxxxxxxxxxxxx";
          參數7: 付款金額   total_amount
          int total_amount = 100;    單位分
          參數8 : 紅包發放總人數  total_num
          int total_num = 1;
          參數9 : 紅包祝福語   wishing
          隨便寫
          String wishing = "測試";
          參數10 : Ip地址   client_ip
          String client_ip = InetAddress.getLocalHost().getHostAddress().toString();
          這里可能報異常,需要抓取一下
          參數11 : 活動名稱   act_name
          隨便寫
          String act_name = "測試創建20150906";
          參數12 : 備注  remark
          隨便寫
          String remark = "測試";
          最后一個參數sign
          //簽名
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("nonce_str", nonce_str);
            map.put("mch_billno", mch_billno);
            map.put("mch_id", mch_id);
            map.put("wxappid", wxappid);
            map.put("send_name", send_name);
            map.put("re_openid", re_openid);
            map.put("total_amount", total_amount);
            map.put("total_num", total_num);
            map.put("wishing", wishing);
            map.put("client_ip", client_ip);
            map.put("act_name", act_name);
            map.put("remark", remark);
            String sign = Signature.getSign(map);
          寫一個Signature類,代碼如下:
          import org.xml.sax.SAXException;
          import com.yxht.core.common.tools.LoadProperties;
          import javax.xml.parsers.ParserConfigurationException;
          import java.io.IOException;
          import java.lang.reflect.Field;
          import java.util.ArrayList;
          import java.util.Arrays;
          import java.util.Map;
          /**
           * User: rizenguo
           * Date: 2014/10/29
           * Time: 15:23
           */
          public class Signature {
              /**
               * 簽名算法
               * @param o 要參與簽名的數據對象
               * @return 簽名
               * @throws IllegalAccessException
               */
              public static String getSign(Object o) throws IllegalAccessException {
                  ArrayList<String> list = new ArrayList<String>();
                  Class cls = o.getClass();
                  Field[] fields = cls.getDeclaredFields();
                  for (Field f : fields) {
                      f.setAccessible(true);
                      if (f.get(o) != null && f.get(o) != "") {
                          list.add(f.getName() + "=" + f.get(o) + "&");
                      }
                  }
                  int size = list.size();
                  String [] arrayToSort = list.toArray(new String[size]);
                  Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
                  StringBuilder sb = new StringBuilder();
                  for(int i = 0; i < size; i ++) {
                      sb.append(arrayToSort[i]);
                  }
                  String result = sb.toString();
                  result += "key=" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";   //這里是開發者中心里面服務器配置里面的消息加解密密鑰
                  Util.log("Sign Before MD5:" + result);
                  result = MD5.MD5Encode(result).toUpperCase();
                  Util.log("Sign Result:" + result);
                  return result;
              }
              public static String getSign(Map<String,Object> map){
                  ArrayList<String> list = new ArrayList<String>();
                  for(Map.Entry<String,Object> entry:map.entrySet()){
                      if(entry.getValue()!=""){
                          list.add(entry.getKey() + "=" + entry.getValue() + "&");
                      }
                  }
                  int size = list.size();
                  String [] arrayToSort = list.toArray(new String[size]);
                  Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
                  StringBuilder sb = new StringBuilder();
                  for(int i = 0; i < size; i ++) {
                      sb.append(arrayToSort[i]);
                  }
                  String result = sb.toString();
                  result += "key=" + LoadProperties.getSystemdefaultValue("APP_KEY");
                  result = MD5.MD5Encode(result).toUpperCase();
                  return result;
              }
              /**
               * 從API返回的XML數據里面重新計算一次簽名
               * @param responseString API返回的XML數據
               * @return 新鮮出爐的簽名
               * @throws ParserConfigurationException
               * @throws IOException
               * @throws SAXException
               */
              public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {
                  Map<String,Object> map = XMLParser.getMapFromXML(responseString);
                  //清掉返回數據對象里面的Sign數據(不能把這個數據也加進去進行簽名),然后用簽名算法進行簽名
                  map.put("sign","");
                  //將API返回的數據根據用簽名算法進行計算新的簽名,用來跟API返回的簽名進行比較
                  return Signature.getSign(map);
              }
              /**
               * 檢驗API返回的數據里面的簽名是否合法,避免數據在傳輸的過程中被第三方篡改
               * @param responseString API返回的XML數據字符串
               * @return API簽名是否合法
               * @throws ParserConfigurationException
               * @throws IOException
               * @throws SAXException
               */
              public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {
                  Map<String,Object> map = XMLParser.getMapFromXML(responseString);
                  Util.log(map.toString());
                  String signFromAPIResponse = map.get("sign").toString();
                  if(signFromAPIResponse=="" || signFromAPIResponse == null){
                      Util.log("API返回的數據簽名數據不存在,有可能被第三方篡改!!!");
                      return false;
                  }
                  Util.log("服務器回包里面的簽名是:" + signFromAPIResponse);
                  //清掉返回數據對象里面的Sign數據(不能把這個數據也加進去進行簽名),然后用簽名算法進行簽名
                  map.put("sign","");
                  //將API返回的數據根據用簽名算法進行計算新的簽名,用來跟API返回的簽名進行比較
                  String signForAPIResponse = Signature.getSign(map);
                  if(!signForAPIResponse.equals(signFromAPIResponse)){
                      //簽名驗不過,表示這個API返回的數據有可能已經被篡改了
                      Util.log("API返回的數據簽名驗證不通過,有可能被第三方篡改!!!");
                      return false;
                  }
                  Util.log("恭喜,API返回的數據簽名驗證通過!!!");
                  return true;
              }
          }
          先講到這里,所有參數都準備好了,下一步是組成xml
          聲明:工具類代碼參考微信支付開發的demo,有些自己做了小改動。
          posted on 2015-09-10 15:35 休息食客 閱讀(881) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 奉新县| 祁东县| 廊坊市| 临泽县| 梁河县| 长葛市| 多伦县| 衡南县| 浪卡子县| 襄汾县| 玉山县| 鹤壁市| 西乡县| 米脂县| 玉屏| 栾城县| 东乡| 元氏县| 麦盖提县| 秦安县| 株洲县| 东兴市| 珠海市| 鹤壁市| 普兰店市| 宣武区| 保山市| 金乡县| 屏南县| 洛南县| 焦作市| 崇信县| 合肥市| 南华县| 随州市| 堆龙德庆县| 钟祥市| 江达县| 基隆市| 三江| 黑龙江省|