1. 程式人生 > >微信 統一下單支付 伺服器程式碼和js程式碼

微信 統一下單支付 伺服器程式碼和js程式碼

/**
 *
 * 類名稱:WeixinController.java 類描述: 微信公共平臺開發
 *
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/pay")
public class WeixinPayController extends BaseController
{
 

    // 應用ID
    private static final String APPID = PropertiesFileLoader.getInstance().getProerties("pay.properties", "appid");

    // 應用金鑰
    private static final String APPSECRET = PropertiesFileLoader.getInstance().getProerties("pay.properties", "appsecret");

    // 商戶號
    private static final String PARTNER = PropertiesFileLoader.getInstance().getProerties("pay.properties", "partner");

    // 商戶登陸密碼
    private static final String PARTNERKEY = PropertiesFileLoader.getInstance().getProerties("pay.properties", "partnerkey");

    // 支付驗證祕鑰
    private static final String KEY = PropertiesFileLoader.getInstance().getProerties("pay.properties", "key");

    /**
     * 介面支付總入口
     *
     * @param out
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/toPay")
    @ResponseBody
    public void index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
   
        TbOrderM bOrderM = RequestUtils.getParamBean(request, TbOrderM.class);
   
       
        String backUri = "http://weixin.collegecircle.cn/zsxy/pay/topayServlet.do";
        // 授權後要跳轉的連結所需的引數一般有會員號,金額,訂單號之類,
        // 最好自己帶上一個加密字串將金額加上一個自定義的key用MD5簽名或者自己寫的簽名,
        // 比如 Sign = %3D%2F%CS%
        backUri = backUri + "?userId=" + userId + "&orderNo=" + orderNo + "&describe=" + describe + "&money=" + money;
      System.out.println("backUri:"+backUri);
        // URLEncoder.encode 後可以在backUri 的url裡面獲取傳遞的所有引數
        backUri = URLEncoder.encode(backUri);
        // scope 引數視各自需求而定,這裡用scope=snsapi_base 不彈出授權頁面直接授權目的只獲取統一支付介面的openid
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=" + APPID + "&redirect_uri=" + backUri + "&response_type=code&scope=snsapi_base&  state=123#wechat_redirect";
        System.out.println("去 TopayServlet" + url);
        response.sendRedirect(url);
    }

    @RequestMapping(value = "/topayServlet")
    @ResponseBody
    public ModelAndView topayServlet(HttpServletRequest request, HttpServletResponse response) throws Exception
    {

        System.out.println("TopayServlet進來了-----");
        ModelAndView mv = new ModelAndView("pay/pay");
        // 網頁授權後獲取傳遞的引數
        String userId = request.getParameter("userId");
        String orderNo = request.getParameter("orderNo");
        String money = request.getParameter("money");
        String code = request.getParameter("code");
        // 傳過來的金額為元單位的小數,需轉換為分單位
        String finalmoney = money;

        // 商戶相關資料
        String key = KEY;
        String appid = APPID;
        String appsecret = APPSECRET;
        String partner = PARTNER;
        String partnerkey = PARTNERKEY;

        String openId = "";
        String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=authorization_code";

        HttpResponse temp = HttpConnect.getInstance().doGetStr(URL);
        String tempValue = "";
        if (temp == null)
        {
            mv.setViewName("pay/error");
        }
        else
        {
            try
            {
                tempValue = temp.getStringResult();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            JSONObject jsonObj = JSONObject.fromObject(tempValue);
            if (jsonObj.containsKey("errcode"))
            {
                System.out.println(tempValue);
                mv.setViewName("pay/error");
            }
            openId = jsonObj.getString("openid");
        }

        // 獲取openId後呼叫統一支付介面https://api.mch.weixin.qq.com/pay/unifiedorder
        String currTime = TenpayUtil.getCurrTime();
        // 8位日期
        String strTime = currTime.substring(8, currTime.length());
        // 四位隨機數
        String strRandom = TenpayUtil.buildRandom(4) + "";
        // 10位序列號,可以自行調整。
        String strReq = strTime + strRandom;

        // 商戶號
        String mch_id = partner;
        // 子商戶號 非必輸
        // String sub_mch_id="";
        // 裝置號 非必輸
        String device_info = "";
        // 隨機數
        String nonce_str = strReq;
        // 商品描述
        // String body = describe;

        // 商品描述根據情況修改
        String body = "美食";
        // 附加資料,原樣返回
        String attach = userId;
        // 商戶訂單號
        String out_trade_no = orderNo;
        int intMoney = Integer.parseInt(finalmoney);

        // 總金額以分為單位,不帶小數點
        int total_fee = intMoney;
        // 訂單生成的機器 IP
        String spbill_create_ip = request.getRemoteAddr();
        // 訂 單 生 成 時 間 非必輸
        // String time_start ="";
        // 訂單失效時間 非必輸
        // String time_expire = "";
        // 商品標記 非必輸
        // String goods_tag = "";

        // 這裡notify_url是 支付完成後微信發給該連結資訊,可以判斷會員是否支付成功,改變訂單狀態等。
        String notify_url = "http://weixin.collegecircle.cn/";

        String trade_type = "JSAPI";
        String openid = openId;
        System.out.println("-----------------openid-----------" + openId);
        // 非必輸
        // String product_id = "";
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", body);
        packageParams.put("attach", attach);
        packageParams.put("out_trade_no", out_trade_no);

        // 這裡寫的金額為1 分到時修改
        // packageParams.put("total_fee", "1");
        packageParams.put("total_fee", finalmoney);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);

        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openid);
        packageParams.put("key", key);

        RequestHandler reqHandler = new RequestHandler(request, response);
        reqHandler.init(appid, appsecret, partnerkey);

        String sign = reqHandler.createSign(packageParams);
        String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>" + "<body><![CDATA[" + body + "]]></body>"
                + "<attach><![CDATA[" + attach + "]]></attach>" + "<out_trade_no>" + out_trade_no + "</out_trade_no>"
                +
                // 金額
                "<total_fee>" + finalmoney + "</total_fee>" + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" + "<notify_url>" + notify_url + "</notify_url>" + "<trade_type>"
                + trade_type + "</trade_type>" + "<openid>" + openid + "</openid>" + "<sign><![CDATA[" + sign + "]]></sign>" + "</xml>";
        System.out.println(xml);
        String allParameters = "";
        try
        {
            allParameters = reqHandler.genPackage(packageParams);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String prepay_id = "";
        try
        {
            new GetWxOrderno();
            prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
            System.err.println("prepay_id:" + prepay_id);
            if (prepay_id.equals(""))
            {
                request.setAttribute("ErrorMsg", "統一支付介面獲取預支付訂單出錯");
                mv.setViewName("pay/error");
            }
        }
        catch (Exception e1)
        {
            e1.printStackTrace();
        }
        SortedMap<String, String> finalpackage = new TreeMap<String, String>();
        String appid2 = appid;
        String timestamp = Sha1Util.getTimeStamp();
        String nonceStr2 = nonce_str;
        String prepay_id2 = "prepay_id=" + prepay_id;
        String packages = prepay_id2;
        finalpackage.put("appId", appid2);
        finalpackage.put("timeStamp", timestamp);
        finalpackage.put("nonceStr", nonceStr2);
        finalpackage.put("package", packages);
        finalpackage.put("signType", "MD5");
        finalpackage.put("key", key);

        String finalsign = reqHandler.createSign(finalpackage);

        mv.addObject("appid", appid2);
        mv.addObject("timeStamp", timestamp);
        mv.addObject("nonceStr", nonceStr2);
        mv.addObject("packages", packages);
        mv.addObject("sign", finalsign);
        mv.addObject("appid", appid2);
        System.out.println("完事了" + finalsign);
        return mv;
    }

   

}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

TenpayUtil.java

package com.project.wx.util;





import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TenpayUtil {
    
    private static Object Server;
    private static String QRfromGoogle;

    /**
     * 把物件轉換成字串
     * @param obj
     * @return String 轉換成字串,若物件為null,則返回空字串.
     */
    public static String toString(Object obj) {
        if(obj == null)
            return "";
        
        return obj.toString();
    }
    
    /**
     * 把物件轉換為int數值.
     *
     * @param obj
     *            包含數字的物件.
     * @return int 轉換後的數值,對不能轉換的物件返回0。
     */
    public static int toInt(Object obj) {
        int a = 0;
        try {
            if (obj != null)
                a = Integer.parseInt(obj.toString());
        } catch (Exception e) {

        }
        return a;
    }
    
    /**
     * 獲取當前時間 yyyyMMddHHmmss
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }
    
    /**
     * 獲取當前日期 yyyyMMdd
     * @param date
     * @return String
     */
    public static String formatDate(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String strDate = formatter.format(date);
        return strDate;
    }
    
    /**
     * 取出一個指定長度大小的隨機正整數.
     *
     * @param length
     *            int 設定所取出隨機數的長度。length小於11
     * @return int 返回生成的隨機數。
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }
    
    /**
     * 獲取編碼字符集
     * @param request
     * @param response
     * @return String
     */

    public static String getCharacterEncoding(HttpServletRequest request,
            HttpServletResponse response) {
        
        if(null == request || null == response) {
            return "gbk";
        }
        
        String enc = request.getCharacterEncoding();
        if(null == enc || "".equals(enc)) {
            enc = response.getCharacterEncoding();
        }
        
        if(null == enc || "".equals(enc)) {
            enc = "gbk";
        }
        
        return enc;
    }
    
    public  static String URLencode(String content){
        
        String URLencode;
        
        URLencode= replace(Server.equals(content), "+", "%20");
        
        return URLencode;
    }
    private static String replace(boolean equals, String string, String string2) {
        
        return null;
    }

    /**
     * 獲取unix時間,從1970-01-01 00:00:00開始的秒數
     * @param date
     * @return long
     */
    public static long getUnixTime(Date date) {
        if( null == date ) {
            return 0;
        }
        
        return date.getTime()/1000;
    }
    
     public static String QRfromGoogle(String chl)
        {
            int widhtHeight = 300;
            String EC_level = "L";
            int margin = 0;
            String QRfromGoogle;
            chl = URLencode(chl);
            
            QRfromGoogle = "http://chart.apis.google.com/chart?chs=" + widhtHeight + "x" + widhtHeight + "&cht=qr&chld=" + EC_level + "|" + margin + "&chl=" + chl;
           
            return QRfromGoogle;
        }

    /**
     * 時間轉換成字串
     * @param date 時間
     * @param formatType 格式化型別
     * @return String
     */
    public static String date2String(Date date, String formatType) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatType);
        return sdf.format(date);
    }
    
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GetWxOrderno.java

package com.project.wx.util;


import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;









public class GetWxOrderno
{
  public static DefaultHttpClient httpclient;

  static
  {
    httpclient = new DefaultHttpClient();
    httpclient = (DefaultHttpClient)HttpClientConnectionManager.getSSLInstance(httpclient);
  }


  public static String getPayNo(String url,String xmlParam){
      System.out.println("獲取訂單號"+url);
      System.out.println("獲取訂單號"+xmlParam);
      DefaultHttpClient client = new DefaultHttpClient();
      client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
      HttpPost httpost= HttpClientConnectionManager.getPostMethod(url);
      String prepay_id = "";
     try {
         httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
         HttpResponse response = httpclient.execute(httpost);
         String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
         System.out.println("jsonStr----"+jsonStr);
         
        if(jsonStr.indexOf("FAIL")!=-1){
            return prepay_id;
        }
        Map map = doXMLParse(jsonStr);
        String return_code  = (String) map.get("return_code");
        prepay_id  = (String) map.get("prepay_id");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
     System.out.println("prepay_id-----------------"+prepay_id);
    return prepay_id;
  }
  /**
     * 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml資料。
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map doXMLParse(String strxml) throws Exception {
        if(null == strxml || "".equals(strxml)) {
            return null;
        }
        
        Map m = new HashMap();
        InputStream in = String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            
            m.put(k, v);
        }
        
        //關閉流
        in.close();
        
        return m;
    }
    /**
     * 獲取子結點的xml
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        
        return sb.toString();
    }
  public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }
 
}   
    
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

HttpClientConnectionManager.java

package com.project.wx.util;




import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;


public class HttpClientConnectionManager {
    
    
    
    /**
     * 獲取SSL驗證的HttpClient
     * @param httpClient
     * @return
     */
    public static HttpClient getSSLInstance(HttpClient httpClient){
        ClientConnectionManager ccm = httpClient.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", MySSLSocketFactory.getInstance(), 443));
        httpClient =  new DefaultHttpClient(ccm, httpClient.getParams());
        return httpClient;
    }
    
    /**
     * 模擬瀏覽器post提交
     *
     * @param url
     * @return
     */
    public static HttpPost getPostMethod(String url) {
        HttpPost pmethod = new HttpPost(url); // 設定響應頭資訊
        pmethod.addHeader("Connection", "keep-alive");
        pmethod.addHeader("Accept", "*/*");
        pmethod.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        pmethod.addHeader("Host", "api.mch.weixin.qq.com");
        pmethod.addHeader("X-Requested-With", "XMLHttpRequest");
        pmethod.addHeader("Cache-Control", "max-age=0");
        pmethod.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        return pmethod;
    }

    /**
     * 模擬瀏覽器GET提交
     * @param url
     * @return
     */
    public static HttpGet getGetMethod(String url) {
        HttpGet pmethod = new HttpGet(url);
        // 設定響應頭資訊
        pmethod.addHeader("Connection", "keep-alive");
        pmethod.addHeader("Cache-Control", "max-age=0");
        pmethod.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        pmethod.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/;q=0.8");
        return pmethod;
    }
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


pay.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>微信支付</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
<script language="javascript" src="static/zsxy/script/jquery.js"></script>
</head>

<body>
    <br>
    <br>
    <br>
    <br>
    <br>
    <br>
    <br>
    <div style="text-align:center;size:30px;">
        <input type="button" style="width:200px;height:80px;" value="微信支付"
            onclick="callpay()">
    </div>
</body>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
      function callpay(){
          var appId="${appid}";
          var timeStamp="${timeStamp}";
          var nonceStr="${nonceStr}";
          var sign="${sign}";
          var packageValue="${packages}";
          
         WeixinJSBridge.invoke('getBrandWCPayRequest',{
           "appId" :appId,
           "timeStamp" :timeStamp ,
           "nonceStr" :nonceStr,
           "package" : packageValue,
           "signType" : "MD5",
           "paySign" : sign
        }, function(res) {
            WeixinJSBridge.log(res.err_msg);
            //                 alert(res.err_code + res.err_desc + res.err_msg);
            if (res.err_msg == "get_brand_wcpay_request:ok") {
                alert("微信支付成功!");
            } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
                alert("使用者取消支付!");
            } else {
                alert("支付失敗!");
            }
        })
    }
</script>

</html>