微信支付分为网页内(JS)支付和原生支付(Native),这里主要说的是JS页面支付
步骤描述如下:
1、组合参数,调用JS微信支付。
2、支付成功后,处理订单(修改订单状态)并给微信平台发送一个success通知。
3、发货处理时,需要给微信后台发送发货提醒。
4、如果到期不发货,则微信会给服务号发送一个警告通知,成功收到告警通知后,还要给微信发送一个success通知。
5、微信用户购买商品后,如果未收到获取或质量有问题等一系列问题,可以在微信端发起维权。
6、微信用户维权之后,后台收到微信发送过来的XML,解析XML转化为Java类保存到数据库。
7、维权结果处理。
8、订单退款处理。
9、对账单下载。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一、参数组装
1、页面涉及到六个参数:appId(公众号 id)、timeStamp(时间戳)、nonceStr(随机字符串)、package(订单详情扩展
字符串)、signType(签名方式)、paySign(签名)。
2、支付后,返回值:err_msg;get_brand_wcpay_request:ok 支付成功
get_brand_wcpay_request:cancel 支付过程中用户取消
get_brand_wcpay_request:fail 支付失败
3、后台生成参数(PayCallbackBean类)---SHA1Util类和RequestHandler类demo例子中有;
(1)获取appId:自己公共号的appId;
(2)获取timeStamp :timestamp = SHA1Util.getTimeStamp();
(3)获取nonceStr:noncestr = SHA1Util.getNonceStr();
(4)获取signType:signType=SHA1;
(5)获取package:
RequestUtil.getClientIP()的方法为:
public static String getClientIP() {
ExternalContext ec = FacesContext.getCurrentInstance()
.getExternalContext();
HttpServletRequest request = (HttpServletRequest) ec.getRequest();
if (request == null)
return "";
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
SortedMap map = new TreeMap();
map.put("bank_type", "WX");
map.put("body", "商品名称");
map.put("partner", "财付通商户身份的标识。前三项审核通过后,在财付通发送的邮件中查看");
map.put("out_trade_no", "订单Id");
map.put("total_fee", "订单总价");
map.put("fee_type", "1");
map.put("notify_url", "公众号申请支付的时候需要填写的一个链接,微信后台通过此链接来通知支付结果的返回");
map.put("spbill_create_ip", RequestUtil.getClientIP());
map.put("input_charset", "UTF-8");
RequestHandler queryReq = new RequestHandler(null, null);
queryReq.init("公众号 id", "自己公众号的appkey", "公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份",
"财付通商户权限密钥 Key");
String packageValue = queryReq.genPackage(map);
(6)获取paySign:
SortedMap map = new TreeMap();
map.put("appid", "appId");
map.put("timestamp", "timeStamp");
map.put("noncestr", "nonceStr");
map.put("package","package");
map.put("appkey", "自己公众号的appkey");
String paySign = SHA1Util.createSHA1Sign(map);
后台组装参数成功之后,返回给页面json格式的信息:appId、timeStamp、nonceStr、packageValue、signType、paySign前文已经获取
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("appId",appId);
jsonObject.accumulate("timeStamp", timeStamp);
jsonObject.accumulate("nonceStr", nonceStr);
jsonObject.accumulate("packageValue", packageValue);
jsonObject.accumulate("signType", signType);
jsonObject.accumulate("paySign", paySign);
jsonObject.accumulate("result", "110000");
System.out.println(jsonObject.toString());
//把json格式发送回页面
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.setResponseContentType("application/json");
externalContext.setResponseCharacterEncoding("UTF-8");
// 写入josn格式数据
try {
externalContext.getResponseOutputWriter().write(jsonObject.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
facesContext.responseComplete();
4、页面js代码:
二、支付后订单处理
微信用户支付成功后,微信后台会通过notify_url返回给商户,商户解析返回来的XML然后做订单处理,并返回给微信后台success通知。
(1)解析微信返回来的XML
解析XML的封装方法为:
public static Map parseXml(HttpServletRequest request) {
// 将解析结果存储在HashMap中
Map map = new HashMap();
// 从request中取得输入流
InputStream inputStream;
try {
inputStream = request.getInputStream();
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (DocumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
inputStream = null;
return map;
}
调用解析方法,把XML解析为Map对象
ExternalContext ec = FacesContext.getCurrentInstance()
.getExternalContext();
HttpServletRequest request = (HttpServletRequest) ec.getRequest();
// 解析微信返回xml文件
Map requestMap = MessageUtil.parseXml(request);
把Map里的值赋给java的一个对象(PayConfiguration类)
PayConfiguration pay= new PayConfiguration();
Set es = requestMap .entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
System.out.println(k + "===" + v);
if (k == "OpenId")
pay.setOpenId(v);
if (k == "AppId")
pay.setAppId(v);
if (k == "IsSubscribe")
pay.setIsSubscribe(v);
if (k == "TimeStamp")
pay.setTimeStamp(v);
if (k == "NonceStr")
pay.setNonceStr(v);
if (k == "AppSignature")
pay.setAppSignature(v);
if (k == "SignMethod")
pay.setSignMethod(v);
String signType = RequestUtil.getRequestParam("sign_type");
pay.setSignType(signType);
String inputCharset = RequestUtil.getRequestParam("input_charset");
pay.setInputCharset(inputCharset);
String sign = RequestUtil.getRequestParam("sign");
pay.setPaySign(sign);
String tradeMode = RequestUtil.getRequestParam("trade_mode");
pay.setTradeMode(tradeMode);
String tradeState = RequestUtil.getRequestParam("trade_state");
pay.setTradeState(tradeState);
String partner = RequestUtil.getRequestParam("partner");
pay.setPartnerId(partner);
String bankType = RequestUtil.getRequestParam("bank_type");
pay.setBankType(bankType);
String bankBillno = RequestUtil.getRequestParam("bank_billno");
pay.setBankBillno(bankBillno);
String totalFee = RequestUtil.getRequestParam("total_fee");
pay.setTotalFee(totalFee);
String feeType = RequestUtil.getRequestParam("fee_type");
pay.setFeeType(feeType);
String notifyId = RequestUtil.getRequestParam("notify_id");
pay.setNotifyId(notifyId);
String transactionId = RequestUtil.getRequestParam("transaction_id");
pay.setTransactionId(transactionId);
String outTradeNo = RequestUtil.getRequestParam("out_trade_no");
pay.setProductId(outTradeNo);
String attach = RequestUtil.getRequestParam("attach");
pay.setAttach(attach);
String timeEnd = RequestUtil.getRequestParam("time_end");
pay.setTimeEnd(timeEnd);
String transportFee = RequestUtil.getRequestParam("transport_fee");
pay.setTransportFee(transportFee);
String productFee = RequestUtil.getRequestParam("product_fee");
pay.setProductFee(productFee);
String discount = RequestUtil.getRequestParam("discount");
pay.setDiscount(discount);
String content = "signType=" + signType + ",inputCharset="
+ inputCharset + ",sign=" + sign + ",tradeMode=" + tradeMode
+ ",tradeState=" + tradeState + ",partner=" + partner
+ ",bankType=" + bankType + ",bankBillno=" + bankBillno
+ ",totalFee=" + totalFee + ",feeType=" + feeType
+ ",notifyId=" + notifyId + ",transactionId=" + transactionId
+ ",outTradeNo=" + outTradeNo + ",attach=" + attach
+ ",timeEnd=" + timeEnd + ",transportFee=" + transportFee
+ ",productFee=" + productFee + ",discount=" + discount;
//验证微信回调支付成功的签名
SortedMap map = new TreeMap();
map.put("appid", pay.getAppId());
map.put("appkey", pay.getPaySignKey());
map.put("timestamp", pay.getTimeStamp());
map.put("noncestr", pay.getNonceStr());
map.put("openid", pay.getOpenId());
map.put("issubscribe", pay.getIsSubscribe());
String paySign = SHA1Util.createSHA1Sign(map);
boolean falt=false;
if (paySign == pay.getAppSignature() || paySign.equals(pay.getAppSignature())) {
falt=true;
} else {
falt=true;
}
//如果签名正确(即falt=true)
则进一步处理自己的业务逻辑,保存该此支付信息。
.........
//如果如果签名正确(即falt=true),并且从微信获取的字段tradeState==0或者tradeState.equals("0"),
//则修改数据库订单状态、支付时间等,并且返回给微信一个success通知。
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.setResponseCharacterEncoding("UTF-8");
// 写入xml格式数据
try {
externalContext.getResponseOutputWriter().write();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
facesContext.responseComplete();
三、发货处理
。。。。。。待更新