微信 統一下單支付 伺服器程式碼和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>