請求過程: 小程式端,先送出微信支付請求,服務端擷取請求。然後再向微信發生支付請求,微信擷取服務端送出的支付請求。根據api文檔裡的notify_url(設定接收回報結果的路徑)傳回給服務端。伺服器接收到微信端的結果之後,再把相應參數傳回給小程式,小程式端再請調取微信支付接口,生成訂單,最後客戶完成支付。然後通知微信支付成功,整個過程就是這樣,下面貼出詳細的代碼;
小程式微信支付api文檔 :https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
//首先服務端得有個接口,來接收 小程式端來 送出支付請求
@RequestMapping(value = "addWaybillTest", produces ="application/json;charset=UTF-8")
@ResponseBod
public Map addWaybillTest(HttpServletRequest request,HttpServletResponse response,@RequestBody MlApiEntity mlApiEntity) {
Map<String, Object> resultMap=new HashMap();
try { //得到一個時間戳
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String str = sdf.format(new Date());
String body="MLSystem"+"礦泉水2瓶測試";
String total_fee="1";
String notify_url="擷取微信支付通知接口URL,自定義" ;
String openId=WxCommon.getOpenId(mlApiEntity.getCode());
//先微信支付
resultMap =WxCommon.wexinPlace( body, "220", total_fee, request, notify_url, openId);
} catch (Exception e) {
e.printStackTrace();
loger.info("checkLogin=============error====" + e);
resultMap.put("result", "系統伺服器繁忙,請稍候!");
e.printStackTrace();
}
return resultMap;
}
//微信支付工具類
public class WxCommon {
private static String appid="";
private static String secret="";
private static String mch_id="";
private static String key="";
//擷取oppenid
public static String getOpenId(String code){
Map<String, String>params=new HashMap();
params.put("appid", appid);
params.put("secret",secret );
params.put("js_code", code);
params.put("grant_type", "authorization_code");
String result=HttpXmlClient.post("https://api.weixin.qq.com/sns/jscode2session", params);
JSONObject jsonObj = JSONObject.fromObject(result);
if(jsonObj.has("openid")){
String openid=jsonObj.getString("openid");
if("".equals(openid)){
return "invalidCode";
}else{
return openid;
}
}else{
return "invalidCode";
}
}
//統一下單
public static Map wexinPlace( String body,String waybillNo,String total_fee,HttpServletRequest request,String notify_url,String account){
Map<String, String> paramMap=new HashMap();
paramMap.put("appid", appid);
paramMap.put("mch_id", mch_id);
paramMap.put("device_info", "WEB");
paramMap.put("nonce_str", GeneratePwd.genRandomNum(32));
paramMap.put("sign_type","MD5");
paramMap.put("body",body);
paramMap.put("out_trade_no",waybillNo);
paramMap.put("total_fee",total_fee);
paramMap.put("spbill_create_ip",getIpAddr(request));
paramMap.put("notify_url",notify_url);
paramMap.put("trade_type","JSAPI");
paramMap.put("openid",account);
paramMap.put("sign", createSign(paramMap));
// 把參數轉換成XML資料格式
String xmlWeChat = assembParamToXml(paramMap);
String resXml = HttpUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlWeChat);
Map<String, String> resMap = null;
if (!StrUtil.isBlank(resXml)) {
try {
resMap = parseXMLToMap(resXml);
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
Map<String, String> map = new HashMap();
if (resMap == null) {
map.put("status", "false");
return map;
}
String return_code = resMap.get("return_code");
if (return_code.equalsIgnoreCase("FAIL")) {
map.put("message", resMap.get("return_msg"));
map.put("status", "false");
return map;
} else if (return_code.equalsIgnoreCase("SUCCESS")) {
String err_code = resMap.get("err_code");
if (!StrUtil.isBlank(err_code)) {
map.put("status", "false");
map.put("message", resMap.get("err_code_des"));
} else if (resMap.get("result_code").equalsIgnoreCase("SUCCESS")) {
map.put("appId",appid);
// 時間戳 目前的時間 需要轉換成秒
map.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
// 随機字元串 不長于32位
map.put("nonceStr", GeneratePwd.genRandomNum(32));
// 訂單詳情擴充字元串 統一下單接口傳回的prepay_id參數值,送出格式如:prepay_id=***
map.put("package", "prepay_id=" + resMap.get("prepay_id"));
// 簽名方式 簽名算法,暫支援MD5
map.put("signType", "MD5");
// 簽名
map.put("paySign", createSign(map));
map.remove("appId");
map.put("status", "true");
}else {
map.put("status", "false");
}
}
return map;
}
public static String createSign(Map<String, String> param) {
//簽名步驟一:按字典排序參數
List list = new ArrayList(param.keySet());
Object[] ary = list.toArray();
Arrays.sort(ary);
list = Arrays.asList(ary);
String str = "";
for (int i = 0; i < list.size(); i++) {
str += list.get(i) + "=" + param.get(list.get(i) + "") + "&";
}
//簽名步驟二:加上key
str += "key=" + key;
System.err.println(str);
//步驟三:加密并大寫
str = MD5Util.md5(str).toUpperCase();
return str;
}
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (!StrUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
if (ip.contains("../") || ip.contains("..\\")) {
return "";
}
return ip;
}
ip = request.getHeader("X-Forwarded-For");
if (!StrUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理後會有多個IP值,第一個為真實IP。
int index = ip.indexOf(',');
if (index != -1) {
ip = ip.substring(0, index);
}
if (ip.contains("../") || ip.contains("..\\")) {
return "";
}
return ip;
} else {
ip = request.getRemoteAddr();
if (ip.contains("../") || ip.contains("..\\")) {
return "";
}
if (ip.equals("0:0:0:0:0:0:0:1")) {
ip = "127.0.0.1";
}
return ip;
}
}
// 通知微信正确接收
public static void noticeWeChatSuccess(String weiXinPayUrl) {
Map<String, String> parames = new HashMap<String, String>();
parames.put("return_code", "SUCCESS");
parames.put("return_msg", "OK");
// 将參數轉成xml格式
String xmlWeChat = assembParamToXml(parames);
try {
if (!StrUtil.isBlank(weiXinPayUrl)) {
String s = HttpUtil.post(weiXinPayUrl, xmlWeChat);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 通知微信錯誤
public static void noticeWeChatFAIL(String weiXinPayUrl) {
Map<String, String> parames = new HashMap<String, String>();
parames.put("return_code", "FAIL");
parames.put("return_msg", "校驗錯誤");
// 将參數轉成xml格式
String xmlWeChat = assembParamToXml(parames);
try {
if (!StrUtil.isBlank(weiXinPayUrl)) {
String s = HttpUtil.post(weiXinPayUrl, xmlWeChat);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Map parseXMLToMap(String strxml) throws IOException, JDOMException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if (null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
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;
}
private 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();
}
private static String assembParamToXml(Map<String, String> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set<String> es = parameters.keySet();
List<Object> list = new ArrayList<Object>(es);
Object[] ary = list.toArray();
Arrays.sort(ary);
list = Arrays.asList(ary);
Iterator<Object> it = list.iterator();
while (it.hasNext()) {
String key = (String) it.next();
String val = (String) parameters.get(key);
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<" + key + ">" + "<![CDATA[" + val + "]]></" + key + ">");
} else {
sb.append("<" + key + ">" + val + "</" + key + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
public static String getWeiXinResponse(HttpServletRequest request) {
BufferedReader bis = null;
String result = "";
try {
bis = new BufferedReader(new InputStreamReader(request.getInputStream()));
String line = null;
while ((line = bis.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
@RequestMapping(value = "wxPayResult", produces ="application/json;charset=UTF-8")
@ResponseBody
public void wxPayResult(HttpServletRequest request,HttpServletResponse response)throws Exception {
String resXml=WxCommon.getWeiXinResponse(request);//位元組流 轉換成 字元流
Map<String, String> resMap = null;
if (!StrUtil.isBlank(resXml)) {
try {
resMap = WxCommon.parseXMLToMap(resXml);
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
Map<String, String> map = new HashMap();
if (resMap != null) {
String return_code = resMap.get("return_code");
if(return_code.equals("FAIL")){
String return_msg="";
return_msg=resMap.get("return_msg");
loger.info("===========================微信支付接口調用失敗,傳回結果=====================" +return_msg);
}else if(return_code.equals("SUCCESS")){
String result_code=resMap.get("result_code");
if(result_code.equals("SUCCESS")){
String sign=resMap.get("sign");
resMap.remove("sign");
String result=WxCommon.createSign(resMap);
if(sign.equals(result)){
String out_trade_no=resMap.get("out_trade_no");
WxCommon.noticeWeChatSuccess("https://api.mch.weixin.qq.com/pay/unifiedorder");//支付成功後我們要通知微信
loger.info("===========================微信支付成=====================");
}
}else{
loger.info("===========================微信支付失=====================" );
}
}else if(result_code.equals("FAIL")){
String err_code=resMap.get("err_code");
if(!StrUtil.isBlank(err_code)){
loger.info("===========================微信支付失敗:錯誤傳回的資訊描述:====================="+err_code );
String err_code_des=resMap.get("err_code_des");
if(!StrUtil.isBlank(err_code_des)){
loger.info("===========================微信支付失敗:錯誤傳回的資訊描述:====================="+err_code_des );
}
}else{
}
}
}
}
}