目前支付寶支付和微信支付是算是目前app的標(biāo)配了
支付寶支付在更新過后有了官方專門的sdk和demo,所以相對而言比較簡單,而微信支付稍微復(fù)雜一點(diǎn),下面的文章會附實(shí)例代碼,微信支付也是參考的github上的某位大神級人物的代碼。
首先是微信支付
先準(zhǔn)備各種數(shù)據(jù),我一般都是放到配置類中,當(dāng)然也可以放到數(shù)據(jù)庫或者配置文件中
`public final class WxpayConfig? {
?????? /**
?????? ?*商家可以考慮讀取配置文件
?????? ?*/
?????? //微信開發(fā)平臺應(yīng)用id
?????? public static final String APP_ID = "wx8888888888888888";
?????? //財(cái)付通商戶號
?????? public static final String PARTNER = "1900000109";//app請求的商戶號
?????? public static final String MCHID = "1900000109";//預(yù)支付請求的商戶號????????????????
?????? //商戶號對應(yīng)的密鑰
?????? public static final String PARTNER_KEY = "";
?????? //預(yù)支付接口
?????? public static final String PREPAY_URL =? "https://api.mch.weixin.qq.com/pay/unifiedorder";?
?????? //查詢訂單接口
?????? public static final String QUERY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
?????? //簽名算法常量值
?????? public static final String SIGN_METHOD = "sha1";
?????? //異步通知地址
?????? public static final String NOTIFY_URL = “”;
?????? //交易類型
?????? public static final String TRADE_TYPE = "APP";
?????? //暫定包值
?????? public static final String PACKAGE = "Sign=WXPay";
?????? //返回狀態(tài)成功
?????? public static final String SUCCESS = "SUCCESS";
?????? //返回狀態(tài)失敗
?????? public static final String FAIL = "FAIL";
}`
這是關(guān)于微信支付的封裝的工具類,其中httpclient和md5加密的需要自己去封裝工具類
`public class? WxpayUtil {
?????? /**
?????? ?*隨機(jī)串
?????? ?* @return
?????? ?*/
?????? public static String getNonceStr() {
????????????? Random random = new Random();
????????????? return? MD5Util.getMD5String(String.valueOf(random.nextInt(10000)));
?????? }
?????? /**
?????? ?*時(shí)間戳
?????? ?* @return
?????? ?*/
?????? public static String getTimeStamp() {
????????????? return? String.valueOf(System.currentTimeMillis() / 1000);
?????? }
?????? /**
?????? ?*解析xml,返回第一級元素鍵值對。如果第一級元素有子節(jié)點(diǎn),則此節(jié)點(diǎn)的值是子節(jié)點(diǎn)的xml數(shù)據(jù)。
?????? ?* @param strxml
?????? ?* @return
?????? ?* @throws JDOMException
?????? ?* @throws IOException
?????? ?*/
?????? @SuppressWarnings("unchecked")
?????? public static Map? parseToMap(String strXml) throws JDOMException, IOException {
????????????? 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 = 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);
????????????? }
????????????? //關(guān)閉流
????????????? in.close();
????????????? return m;
?????? }
?????? /**
?????? ?*獲取子結(jié)點(diǎn)的xml
?????? ?* @param children
?????? ?* @return String
?????? ?*/
?????? @SuppressWarnings("unchecked")
?????? private static String? getChildrenText(List children) {
????????????? StringBuffer sb = new? StringBuffer();
????????????? if(!children.isEmpty()) {
???????????????????? Iterator? it = children.iterator();
???????????????????? while(it.hasNext()) {
??????????????????????????? Element e =? 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("");
???????????????????? }
????????????? }
????????????? return sb.toString();
?????? }
?????? /**
?????? ?*只支持String,并且value非空
?????? ?* @param map
?????? ?* @return
?????? ?*/
?????? public static String? parseToXml(Map map){
????????????? StringBuffer sb = new? StringBuffer("");
????????????? for(Map.Entry entry : map.entrySet()){
???????????????????? sb.append("<"+entry.getKey()+">");
???????????????????? sb.append("");
???????????????????? sb.append("");
????????????? }
????????????? sb.append("");
????????????? return sb.toString();
?????? }
?????? /**
???? * POST提交XML對象
???? * @param document
???? */?
??? public static String postXmlClient(String? url,String xmlParams) throws Exception {?
//??? ???? return? HttpUtils.postXmlEntity(url, xmlParams).getContent();
???? return? HttpClient.postRequest(url, xmlParams);
??? }?
}
這是關(guān)于微信支付一些參數(shù)處理的方法
public class? WxpayHelper {
?????? ?/**
???? *除去數(shù)組中的空值和簽名參數(shù)
???? * @param sArray簽名參數(shù)組
???? * @return去掉空值與簽名參數(shù)后的新簽名參數(shù)組
???? */
??? public static Map? paraFilter(Map sArray) {
??????? Map result =? new HashMap();
??????? if (sArray == null || sArray.size()? <= 0) {
??????????? return result;
??????? }
??????? for (String key : sArray.keySet()) {
??????????? String value = sArray.get(key);
??????????? if (value == null ||? value.equals("") || key.equalsIgnoreCase("sign") ||? key.equalsIgnoreCase("key")) {
??????????????? continue;
??????????? }
??????????? result.put(key, value);
??????? }
??????? return result;
??? }
??? /**
???? *把數(shù)組所有元素,并按照“參數(shù)=參數(shù)值”的模式用“&”字符拼接成字符串
???? * @param params需要參與字符拼接的參數(shù)組
???? * @param sorts?? 是否需要排序 true 或者false
???? * @return拼接后字符串
???? */
??? public static String? createLinkString(Map params) {
??????? List keys = new? ArrayList(params.keySet());
??????? Collections.sort(keys);
??????? String prestr = "";
??????? for (int i = 0; i < keys.size();? i++) {
??????????? String key = keys.get(i);
??????????? String value = params.get(key);
??????????? if (i == keys.size() - 1) {//拼接時(shí),不包括最后一個(gè)&字符
??????????????? prestr = prestr + key +? "=" + value;
??????????? } else {
??????????????? prestr = prestr + key +? "=" + value + "&";
??????????? }
??????? }
??????? return prestr;
??? }
??? /**
???? *驗(yàn)簽響應(yīng)簽名
???? * @param paras
???? * @return
???? */
??? public static boolean? verify(Map paras){
???? String? sign = paras.get("sign");
???? if(StringUtils.isBlank(sign))? return false;
???? return? sign.equals(WxpayBuilder.buildRequestMysign(paraFilter(paras)));
??? }
??? /**
???? *響應(yīng)成功
???? * @param loggerAgent -日志代理
???? * @return String
???? */
??? /*public static String yes(ILoggerAgent? loggerAgent){
???? Map? return_wx = new HashMap<>();
???? return_wx.put("return_code",? WxpayConfig.SUCCESS);
???? loggerAgent.payParamsLogger(null? , "WX-NOTIFY", false, return_wx);
???? return? WxpayUtil.parseToXml(return_wx);
??? }*/
?? }
public class? WxpayBuilder {
?????? ?/**
???? *生成簽名結(jié)果
???? * @param sPara要簽名的數(shù)組
???? * @return簽名結(jié)果字符串
???? */
?????? public static String? buildRequestMysign(Map sPara) {
???? String? prestr =? WxpayHelper.createLinkString(sPara)+"&key="+WxpayConfig.PARTNER_KEY;
???? LogFactory.getInstance().getLogger().debug("微信支付簽名的字符串:"+prestr);
??????? return? MD5Util.getMD5String(prestr).toUpperCase();
??? }
??? public static Map? buildRequestPara(Map sParaTemp) {
??????? //除去數(shù)組中的空值和簽名參數(shù)
??????? Map sPara =? WxpayHelper.paraFilter(sParaTemp);
??????? //生成簽名結(jié)果
??????? String mysign =? buildRequestMysign(sPara);
? LogFactory.getInstance().getLogger().debug("微信支付簽名數(shù)據(jù):"+mysign);
??????? //簽名結(jié)果與簽名方式加入請求提交參數(shù)組中
??????? sPara.put("sign", mysign);
?????? ?return sPara;
??? }
}`
使用例程
其中業(yè)務(wù)接口信息,參考https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3
? `? ? ?/**
?????? ?*微信訂單邏輯
?????? ?*
?????? ?* @throws Exception
?????? ?*/
?????? public?
? Map wxPayLogic() throws Exception {
????????????? //微信業(yè)務(wù)代碼
????????????? Map xmlData? = new HashMap();
????????????? xmlData.put("appid",? WxpayConfig.APP_ID);
????????????? xmlData.put("mch_id",? WxpayConfig.MCHID);
????????????? xmlData.put("nonce_str",? WxpayUtil.getNonceStr());
????????????? xmlData.put("out_trade_no",);
????????????? xmlData.put("total_fee",);
????????????? xmlData.put("spbill_create_ip",“”);
????????????? //從數(shù)據(jù)字典里面去主機(jī)地址
????????????? DataDictionary dataDictionary =? dataDictionaryService.getDicByKey("PAY_CALLBACK");
????????????? xmlData.put("notify_url",? dataDictionary.getValue() + WxpayConfig.NOTIFY_URL);
????????????? xmlData.put("trade_type",? WxpayConfig.TRADE_TYPE);
????????????? xmlData.put("body",? "");
????????????? //少寫簽名
????????????? Map result? = WxpayBuilder.buildRequestPara(xmlData);
????????????? // Map? result = WxpayHelper.paraFilter(xmlData);
????????????? String xmlParams =? WxpayUtil.parseToXml(result);
????????????? LogFactory.getInstance().getLogger().debug("微信支付請求報(bào)文:" + xmlParams);
????????????? String xmlResult =? WxpayUtil.postXmlClient(WxpayConfig.PREPAY_URL, xmlParams);
????????????? Map map =? WxpayUtil.parseToMap(xmlResult);
????????????? LogFactory.getInstance().getLogger().debug("微信支付返回報(bào)文:" + JsonHelper.toJson(map));
????????????? //返回時(shí)SUCCESS
????????????? if? (WxpayConfig.SUCCESS.equals(map.get("return_code"))) {
???????????????????? //驗(yàn)證返回是否成功
???????????????????? if? (WxpayConfig.SUCCESS.equals(map.get("result_code"))) {
??????????????????????????? //除去簽名和空值
??????????????????????????? Map paraFilter = WxpayHelper.paraFilter(map);
??????????????????????????? //獲得簽名
??????????????????????????? String mysign =? WxpayBuilder.buildRequestMysign(paraFilter);
??????????????????????????? //驗(yàn)證簽名
??????????????????????????? if? (mysign.equals(map.get("sign"))) {
?????????????????????????????????? String? prepay_id = map.get("prepay_id");
?????????????????????????????????? //驗(yàn)證簽名成功
??????????????????? //進(jìn)行操作
??????????????????????????? } else {
?????????????????????????????????? //簽名驗(yàn)證失敗
?????????????????????????????????? LogFactory.getInstance().getLogger().debug("微信支付驗(yàn)證簽名失敗");
??????????????????????????? }
???????????????????? } else {
??????????????????????????? // result_code返回失敗
??????????????????????????? String err_code =? map.get("err_code");
??????????????????????????? String? err_code_des = map.get("err_code_des");
??????????????????????????? chargeRecord.setCauses(err_code+err_code_des);
??????????????????????????? LogFactory.getInstance().getLogger().debug("微信支付結(jié)果失敗:失敗碼為"+err_code+",失敗原因是"+err_code_des);
??????????????????????????? chargeRecord.setState(2);
???????????????????? }
????????????? } else {
???????????????????? // return_code返回失敗
???????????????????? String return_msg =? map.get("return_msg");
???????????????????? LogFactory.getInstance().getLogger().debug("微信支付返回失?。悍祷叵椋? + return_msg);
???????????????????? return null;
????????????? }
????????????? //微信支付
????????????? Map? mapBack = new HashMap<>();
????????????? mapBack.put("appid",? WxpayConfig.APP_ID);
????????????? mapBack.put("partnerid",? WxpayConfig.PARTNER);
????????????? mapBack.put("prepayid",? chargeRecord.getOpenId());
????????????? mapBack.put("package",? WxpayConfig.PACKAGE);
????????????? mapBack.put("noncestr",? WxpayUtil.getNonceStr());
????????????? mapBack.put("timestamp",? WxpayUtil.getTimeStamp());
????????????? return? WxpayBuilder.buildRequestPara(mapBack);
?????? }`
支付異步回傳
接收到異步通知之后,才算是付款成功
`@Controller
@RequestMapping(value? = "/api")
public class? WxPayCallbackController extends BaseController {
?????? @Autowired
?????? OrderLogic orderLogic;
?????? @Autowired
?????? RedisFactory redisFactory;
?????? @Autowired
?????? ApplicationContext applicationContext;
?????? @RequestMapping(value =? "/wxPayCallback", method = RequestMethod.POST)
?????? @ResponseBody
?????? public String? wxPayCallback(@RequestBody String body) {
????????????? MDC.put("seqID",? SeqIdGenerator.generate());//日志序列
????????????? LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的異步支付結(jié)果通知信息data=" + body);
????????????? Map? resultMap = new HashMap<>();
????????????? if? (StringUtils.isNotBlank(body)) {
???????????????????? try {
??????????????????????????? Map map = WxpayUtil.parseToMap(body);
??????????????????????????? //返回代碼
??????????????????????????? if? (WxpayConfig.SUCCESS.equals(map.get("return_code"))) {
?????????????????????????????????? //驗(yàn)證簽名
?????????????????????????????????? if? (WxpayHelper.verify(map)) {
????????????????????????????????????????? //驗(yàn)證業(yè)務(wù)結(jié)果是否成功
????????????????????????????????????????? String? outTradeNo = map.get("out_trade_no");
????????????????????????????????????????? if? (WxpayConfig.SUCCESS.equals(map.get("result_code"))) {
???????????????????????????????????????????????? //設(shè)置支付類型,1為支付寶,2為微信
???????????????????????????????????????????????? map.put("payType","2");
?????????????????????????? //通過所有驗(yàn)證,啟動事件,通過spring的監(jiān)聽器進(jìn)行監(jiān)聽,并執(zhí)行付款成功后的業(yè)務(wù)
???????????????????????????????????????????????? applicationContext.publishEvent(new? OrderFinishEvent(map));
????????????????????????????????????????? }? else {
???????????????????????????????????????????????? //業(yè)務(wù)結(jié)果失敗
???????????????????????????????????????????????? LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的異步支付業(yè)務(wù)結(jié)果失敗");
???????????????????????????????????????????????? orderLogic.updateState(outTradeNo,2);
???????????????????????????????????????????????? resultMap.put("return_code",? WxpayConfig.SUCCESS);
????????????????????????????????????????? }
?????????????????????????????????? } else {
????????????????????????????????????????? //簽名失敗
????????????????????????????????????????? LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的異步支付簽名失敗");
????????????????????????????????????????? resultMap.put("return_code",? WxpayConfig.FAIL);
????????????????????????????????????????? resultMap.put("return_msg",? "簽名失敗");
?????????????????????????????????? }
??????????????????????????? } else {
?????????????????????????????????? //返回結(jié)果失敗
?????????????????????????????????? LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的異步支付返回結(jié)果失敗");
?????????????????????????????????? resultMap.put("return_code",? WxpayConfig.FAIL);
?????????????????????????????????? resultMap.put("return_msg",? "參數(shù)格式校驗(yàn)錯(cuò)誤");
??????????????????????????? }
???????????????????? } catch (Exception e) {
??????????????????????????? e.printStackTrace();
???????????????????? }
????????????? } else {
???????????????????? //返回結(jié)果為空
???????????????????? LogFactory.getInstance().getPayCallbackLogger().info("參數(shù)格式校驗(yàn)錯(cuò)誤");
???????????????????? resultMap.put("return_code",? WxpayConfig.FAIL);
???????????????????? resultMap.put("return_msg",? "參數(shù)格式校驗(yàn)錯(cuò)誤");
????????????? }
????????????? return? WxpayUtil.parseToXml(resultMap);
?????? }
}`
付款成功統(tǒng)一處理事件監(jiān)聽
`@Component
public class OrderFinishLister {
? @EventListener
? public void onApplicationEvent(OrderFinishEvent event){//這里不能拋出異常,外層無法處理,會造成中斷
? try {
??????????? Map params =? (HashMap) event.getSource();
??????????? String payType =? params.get("payType");
??????????? String outTradeNo =? params.get("out_trade_no");
??????????? String trade_no = null;
??????????? String buyerLogonId = null;
??????????? String buyerId = null;
??????????? String transactionId = null;
??????????? UserOrder order = null;
? if("1".equals(payType)){
??????????????? //支付寶
???????????????? trade_no =? params.get("trade_no");
???????????????? buyerLogonId =? params.get("buyer_logon_id");
???????????????? buyerId =? params.get("buyer_id");
?????????????? ??//執(zhí)行付款成功后的業(yè)務(wù)邏輯
? LogFactory.getInstance().getLogger().debug("支付寶獲取支付更新狀態(tài):" + outTradeNo);
??????????? }else? if("2".equals(payType)){
??????????????? //微信
???????????????? transactionId =? params.get("transaction_id");
??????????????? //執(zhí)行微信付款成功后的業(yè)務(wù)邏輯
? LogFactory.getInstance().getLogger().debug("微信獲取支付更新狀態(tài):" + outTradeNo);
??????????? }
? }catch (Exception e){
??????????? e.printStackTrace();
? }
? }
}`
這就是單獨(dú)的微信支付業(yè)務(wù)流程