微信支付-公眾號支付
微信支付的步驟集合一樣的
1、統一下單
2、支付結果通知
3、查詢訂單
一、統一下單
統一下單需要的引數 檢視對應網址https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
其中需要用到openid,openid的獲取要先獲取授權code,然後通過code獲取openid
獲取code 我用的是靜默授權
/**微信網頁授權獲取CODE**/
public static String WEB_OAUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
//彈出授權頁面,可通過openid拿到暱稱、性別、所在地。並且,即使在未關注的情況下,只要使用者授權,也能獲取其資訊
public static final String SNSAPI_USERINFO = "snsapi_userinfo";
//不彈出授權頁面,直接跳轉,只能獲取使用者openid 靜默授權
public static final String SNSAPI_BASE = "snsapi_base";
@RequestMapping(params = "getCode",method ={RequestMethod.GET, RequestMethod.POST})
public void getCode(HttpServletRequest request,HttpServletResponse response) throws Exception{
引數根據自己的需求,自己傳的什麼獲取什麼,這些是我要用的。可以不用傳引數
String goodsid = request.getParameter("goodsId");
//String type=request.getParameter("type");
// String priceInterval=request.getParameter("priceInterval");
//獲取商品價格 綠色字的獲取授權code必須填的 1跳轉路徑;2APPID;3使用者授權
String pprice = request.getParameter("pprice");
獲取到一個資源重定向到這個資源路徑中去,只能用微信瀏覽器開啟
String resource=oauthurl( ConfigUtil.getProperty("weChat_redirect_URI")+"&goodsid="+goodsid+"&pprice="+pprice+"&type="+type+"&priceInterval="+priceInterval, ConfigUtil.getProperty("appId")
System.out.println(resource);
response.sendRedirect(resource);
}
//授權路徑做編碼
public static String oauthurl(String targetUrl, String appid,String scope) {
String shareurl = "";
String encodeTargetURL = "";
try {
encodeTargetURL = URLEncoder.encode(targetUrl, "UTF-8");
} catch (UnsupportedEncodingException e) {
//這種一般不做處理
e.printStackTrace();
}
shareurl = WeiXinOpens.WEB_OAUTH_URL.replace("APPID", appid).replace("REDIRECT_URI", encodeTargetURL).replace("SCOPE", scope);
return shareurl;
}
/**
* 通過code獲取openid 統一生成訂單。這個方法就是上面獲取code時填寫的跳轉路徑
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping(params = "buyCourse",method ={RequestMethod.GET, RequestMethod.POST})
public ModelAndView buyCourse(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject object = null;
//獲取openID
String openId = ResourceUtil.getUserOpenId();
String orderid=UUIDGenerator.generate();
String appid = ConfigUtil.getProperty("appId");
String secret = ConfigUtil.getProperty("appSecret");
//獲取code
String code =request.getParameter("code");
String type=request.getParameter("type");
//獲取訂閱週期,每個月按30天算,年按365天。當type=4dates不等於0時儲存到期時間
String priceInterval=request.getParameter("priceInterval");
//判斷openID是否為空,為空根據code獲取token和openID
if(null==openId||"".equals(openId)){
Map<String,Object> maptoken = new RemoteWeixinMethod().getOauth2AccessToken(new Oauth2CodePojo(appid, secret, code));
openId = (String)maptoken.get("openid");
}
request.getSession().setAttribute(WeiXinConstants.USER_OPENID, openId);
//終端IP
String remoteAddr = request.getRemoteAddr();
//獲取商品ID
String goodsid = request.getParameter("goodsid");
//加入訂單詳情
GoodsInfomationEntity goodsInfomation=goodsInfomationDao.getByEbookId(goodsid);
//獲取商品價格
String price = request.getParameter("pprice");
BigDecimal coursePrice =new BigDecimal(price);
String sn = orderid;
OrderEntity orderEntity = orderDao.getorder(openId, goodsid);
// 呼叫pay包中的方法生成微信預支付資訊
//商品描述
String description = "課程購買";
//統一下單生成課程購買訂單,並返回微信需要的預支付資訊 得到prepayid
Map<String,String> map =weixinPrePay.weixinPrePay(sn, coursePrice, description, remoteAddr,openId);
//獲取訂單資訊反給頁面 把通過prepayid進行二次簽名的資訊返給頁面
object = weixinPrePay.getPayParam(map);
String returnCode = map.get("return_code");
if(returnCode.equalsIgnoreCase("FAIL")){
String return_msg=object.getString("return_msg");
request.setAttribute("return_msg", return_msg);
return new ModelAndView("weixin/guanjia/minimail/pay");
}else{
if(null==orderEntity){
OrderEntity newCartOrder = new OrderEntity();
newCartOrder.setOrderid(sn);
newCartOrder.setOpenid(openId);
newCartOrder.setGoodsid(goodsid);
newCartOrder.setPaymode(1l);
newCartOrder.setStatus(0l);
newCartOrder.setPrice(coursePrice);
List<OrderEntity> orderEntityList=orderDao.getByStatus();
if(null!=orderEntityList){
//刪除沒有支付的訂單及詳情
for (OrderEntity orderEntity2 : orderEntityList) {
OrderDetailEntity orderDetailEntity=orderDetailDao.getorderDetail(orderEntity2.getId());
orderService.delete(orderEntity2);
if(null!=orderDetailEntity){
orderdetailService.delete(orderDetailEntity);
}
}
}
orderService.save(newCartOrder);
OrderDetailEntity orderDetail=new OrderDetailEntity();
orderDetail.setAuther(goodsInfomation.getAuther());
orderDetail.setAutherid(goodsInfomation.getAutherid());
orderDetail.setGoodsid(goodsid);
orderDetail.setGoodsname(goodsInfomation.getGoodname());
orderDetail.setPicture(goodsInfomation.getPicture());
orderDetail.setPprice(coursePrice);
orderDetail.setOrderid(newCartOrder.getId());
orderdetailService.save(orderDetail);
}else{
orderEntity.setId(orderEntity.getId());
orderService.saveOrUpdate(orderEntity);
}
//獲取得到的結果傳入前臺頁面 調起支付
String weixinappid=object.getString("appid");
String partnerid=object.getString("partnerid");
String packagewx=object.getString("package");
String noncestr=object.getString("noncestr");
String timestamp=object.getString("timestamp");
String sign=object.getString("sign");
request.setAttribute("appid", weixinappid);
//收款方
request.setAttribute("partnerid", partnerid);
request.setAttribute("package", packagewx);
request.setAttribute("noncestr", noncestr);
request.setAttribute("timestamp", timestamp);
request.setAttribute("sign", sign);
request.setAttribute("pprice", coursePrice);
request.setAttribute("orderid", sn);
request.setAttribute("openId", openId);
request.setAttribute("goodsid", goodsid);
request.setAttribute("type", type);
request.setAttribute("priceInterval", priceInterval);
request.setAttribute("picture", goodsInfomation.getPicture());
request.setAttribute("cxUrl", ConfigUtil.getProperty("weixin_cxUrl"));
request.setAttribute("appPictureUrl",ConfigUtil.getProperty("APP_Picture_url"));
//跳到支付頁面
return new ModelAndView("weixin/guanjia/minimail/pay");
}
}
統一下單,獲取簽名,與調起時的二次生成簽名
public class WinxinAppPrePay {
private PayCommonUtil payCommonUtil;
public String norifyUrl;
public Map<String, String> weixinPrePay(String sn, BigDecimal totalAmount,
String description, String remoteAddr,String openid) {
SortedMap parameterMap = new TreeMap();
//公眾賬號ID
parameterMap.put("appid", this.payCommonUtil.getAppId());
//商戶號
parameterMap.put("mch_id", this.payCommonUtil.getMchId());
//裝置號
parameterMap.put("device_info", this.payCommonUtil.getDeviceInfo());
//隨機字串
parameterMap.put("nonce_str", this.payCommonUtil.getRandomString(32));
//簽名型別
parameterMap.put("sign_type", "MD5");
try {
//如:小張南山店-超市
description = new String(description.getBytes("utf-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
parameterMap.put("body",
StringUtils.abbreviate(description.replaceAll(
"[^0-9a-zA-Z\\u4e00-\\u9fa5 ]", ""), 600));
//商戶訂單號
parameterMap.put("out_trade_no", sn);
//使用者標識
parameterMap.put("openid", openid);
//標價幣種
parameterMap.put("fee_type", "CNY");
BigDecimal total = totalAmount.multiply(new BigDecimal(100));
DecimalFormat df = new DecimalFormat("0");
//標價金額
parameterMap.put("total_fee", df.format(total));
//終端IP
parameterMap.put("spbill_create_ip", remoteAddr);
//非同步接收微信支付結果通知的回撥地址,通知url必須為外網可訪問的url,不能攜帶引數。
parameterMap.put("notify_url", this.norifyUrl);
//交易型別
parameterMap.put("trade_type", "JSAPI");
//通過簽名演算法計算得出的簽名值,詳見簽名生成演算法 第一次簽名
String sign = this.payCommonUtil.createSign("UTF-8", parameterMap);
parameterMap.put("sign", sign);
//請求xml組裝
String requestXML = this.payCommonUtil.getRequestXml(parameterMap);
System.out.println(requestXML);
//統一下單 獲取prepay_id
String result = this.payCommonUtil.httpsRequest(
"https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
requestXML);
System.out.println(result);
Map map = null;
try {
map = this.payCommonUtil.doXMLParse(result);
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
return map;
}
public JSONObject getPayParam(Map<String, String> map) {
JSONObject payPamams = new JSONObject();
if ((map.containsKey("return_code"))
&& (((String) map.get("return_code")).equals("SUCCESS"))) {
String appid = (String) map.get("appid");
String partnerid = (String) map.get("mch_id");
String prepayid = (String) map.get("prepay_id");
String noncestr = this.payCommonUtil.getRandomString(32);
String timestamp = (System.currentTimeMillis() / 1000L) + "";
SortedMap parameterMap = new TreeMap();
parameterMap.put("appId", appid);
parameterMap.put("package", "prepay_id=" + prepayid);
//隨機字串
parameterMap.put("nonceStr", noncestr);
parameterMap.put("signType", "MD5");
parameterMap.put("timeStamp", timestamp);
System.out.println("簽名準備引數"+parameterMap);
//二次簽名 把下面紅色字的資訊返給統一下單那塊,然後傳到頁面上
String sign = this.payCommonUtil.createSign("UTF-8", parameterMap);
payPamams.put("appid", appid);
//商戶號
payPamams.put("partnerid", partnerid);
payPamams.put("package", "prepay_id=" + prepayid);
payPamams.put("noncestr", noncestr);
payPamams.put("timestamp", timestamp);
payPamams.put("signtype", "MD5");
//簽名
payPamams.put("sign", sign);
System.out.println("生成簽名後"+payPamams.getString("sign"));
return payPamams;
}
String return_msg = (String) map.get("return_msg");
payPamams.put("return_msg", return_msg);
return payPamams;
}
public PayCommonUtil getPayCommonUtil() {
return this.payCommonUtil;
}
public void setPayCommonUtil(PayCommonUtil payCommonUtil) {
this.payCommonUtil = payCommonUtil;
}
public String getNorifyUrl() {
return this.norifyUrl;
}
public void setNorifyUrl(String norifyUrl) {
this.norifyUrl = norifyUrl;
}
//支付頁面
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@include file="/context/mytags.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta content="yes" name="apple-mobile-web-app-capable">
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' />
<title>商品支付</title>
<!--2017年6月27日,zq-->
<style type="text/css">
body{ margin:0px auto; padding:0px; background:#EBEBEB; font-family:"微軟雅黑"; font-size:14px;}
.bodydiv{ max-width: 500px; margin: auto;}
.acty2{width:98%; height:auto; background:#FFF; margin:auto; margin-top: 10px ;padding:5px 0px;box-shadow: 0px 0px 5px #000000;}
.acty2 .diva{width:98%; height:auto; margin: auto;}
.acty2 .tup{ width: 100%; background: #FF9900;}
.acty2 .diva .p1{ font-size:14px; line-height:16px;}
.acty2 .diva .p2{ font-size:14px; line-height:14px; padding-left: 10px; color: #FF0000;}
.acty2 .diva .p2 .span1{font-size:12px; text-decoration:line-through; line-height:10px; color:#737373; padding-left: 10px;}
.acty2 .diva .p2 .span2{font-size:13px; float: right;color:#737373;margin-right: 20px;}
a{ text-decoration:none; color: #000000;}
p{font-size:14px;}
span{font-size:14px;}
.clear{ clear:both;}
</style>
</head>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript" src="<%=basePath %>/shop/js/mui.min.js"></script>
<script type="text/javascript">
function onBridgeReady() {
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId" : "${appid}",//"wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
"timeStamp" : "${timestamp}",//"1395712654", //時間戳,自1970年以來的秒數
"nonceStr" : "${noncestr}",//"e61463f8efa94090b1f366cccfbbb444", //隨機串
"package" : "${package}",//"prepay_id=u802345jgfjsdfgsdg888",
"signType" : "MD5",//"MD5", //微信簽名方式:
"paySign" : "${sign}",//"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
}, function(res) { // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回 ok,但並不保證它絕對可靠。
/* alert(res.err_msg); */
if (res.err_msg == "get_brand_wcpay_request:ok") {
//支付成功後跳轉到支付結果查詢修改訂單狀態
window.location.href ="${cxUrl}&orderid=${orderid}&goodsid=${goodsid}&priceInterval=${priceInterval}&type=${type}&price=${pprice}";
/* request.getRequestDispatcher("${cxUrl}&orderid=${orderid}").forward(request,response); */
/* response.sendRedirect("${cxUrl}&orderid=${orderid}"); window.location.href ="${cxUrl}&orderid=${orderid}" */
}
if (res.err_msg == "get_brand_wcpay_request:cancel") {
}
if (res.err_msg == "get_brand_wcpay_request:fail") {
/* alert(JSON.stringify(res)); */
}
});
}
function callpay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady,
false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
}
mui.init();
var oldback = mui.back;
mui.back = function() {
mui.currentWebview.opener().show('none');
alert("要返回上一頁咯");
oldback();
}
</script>
<body>
<div class="bodydiv">
<div class="acty2">
<div class="diva">
<div class="tup">
<img src="${appPictureUrl}${picture}" width="100%" />
</div>
<p class="p2">支付金額:¥${pprice}</p>
</div>
<div class="clear"></div>
</div>
<input style="width:100%; background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" value="立即支付" type="button" onclick="callpay()" >
</div>
</body>
</html>