【微信支付】(亲测可用)对接app微信支付V2版本 后端代码示例
生活随笔
收集整理的這篇文章主要介紹了
【微信支付】(亲测可用)对接app微信支付V2版本 后端代码示例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
業務場景:基本上做業務的話,也是逃不開對接各種支付接口的,比如數字人民幣支付、農行免密支付、支付寶支付、微信支付等等。在著手開發時候,也是遇到不少阻力,微信官方提供的接口文檔很散亂,如果之前沒接觸過,一上來就來搞微信支付,即使參考很多文檔、材料,也是很令人抓狂的。在這篇文章中,主要記錄的就是對接微信支付的流程,以及開發中遇到的問題。
一、了解支付流程
即使這樣,還是推薦去閱覽 微信app支付開發文檔
商戶自行申請入駐微信支付,無服務商協助。(商戶平臺申請)成為直連商戶
申請APPID
申請mchid
綁定APPID及mchid
配置API key
(這些是需要準備的參數)
…
二、開發流程
2.1 添加依賴
<dependency><groupId>com.github.liyiorg</groupId><artifactId>weixin-popular</artifactId><version>2.8.5</version></dependency>2.2 建配置類:WxPayConfig
public class WxPayConfig {/** APPID */public static final String APPID = "";/** 商戶號 */public static final String MCH_ID = "";/** 密鑰 */public static final String PRIVATE_KEY = "";/**AppSecret 微信開放平臺 對應app的開發密碼,app支付不需要 */public static final String APPSECRET = "";/** 用戶訂單支付結果異步通知url */public static final String NOTIFY_URL = "";}2.3 建工具類:WxPayConfig
import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.w3c.dom.Node; import org.w3c.dom.NodeList;import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.StringWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.util.*;public class WXPayUtil {/*** 生成微信支付sign* @return*/public static String createSign(SortedMap<String, String> params, String key){StringBuilder sb = new StringBuilder();Set<Map.Entry<String, String>> es = params.entrySet();Iterator<Map.Entry<String, String>> it = es.iterator();//生成 stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";while (it.hasNext()){Map.Entry<String, String> entry = (Map.Entry<String, String>)it.next();String k = (String)entry.getKey();String v = (String)entry.getValue();if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)){sb.append(k+"="+v+"&");}}sb.append("key=").append(key);String sign = MD5(sb.toString()).toUpperCase();return sign;}/*** XML格式字符串轉換為Map* @param strXML XML字符串* @return XML數據轉換后的Map* @throws Exception*/public static Map<String, String> xmlToMap(String strXML) throws Exception {try {Map<String, String> data = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));org.w3c.dom.Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}try {stream.close();} catch (Exception ex) {}return data;} catch (Exception ex) {throw ex;}}/*** 將Map轉換為XML格式的字符串* @param data Map類型數據* @return XML格式的字符串* @throws Exception*/public static String mapToXml(Map<String, String> data) throws Exception {DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();org.w3c.dom.Document document = documentBuilder.newDocument();org.w3c.dom.Element root = document.createElement("xml");document.appendChild(root);for (String key: data.keySet()) {String value = data.get(key);if (value == null) {value = "";}value = value.trim();org.w3c.dom.Element filed = document.createElement(key);filed.appendChild(document.createTextNode(value));root.appendChild(filed);}TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer = tf.newTransformer();DOMSource source = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");StringWriter writer = new StringWriter();StreamResult result = new StreamResult(writer);transformer.transform(source, result);String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");try {writer.close();}catch (Exception ex) {}return output;}/*** 生成uuid,即用來標識一筆單,也用做 微信支付的nonce_str* @return*/public static String generateUUID(){String uuid = UUID.randomUUID().toString().replaceAll("-","").substring(0,32);return uuid;}/*** MD* @param data* @return*/public static String MD5(String data){try {MessageDigest md5 = MessageDigest.getInstance("MD5");byte [] array = md5.digest(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();}catch (Exception e){e.printStackTrace();}return null;}/*** 獲取用戶請求ip* @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {//根據網卡取本機配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}//對于通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}return ipAddress;}/*** 封裝post,返回請求的結果* @return*/public static String doPost(String url, String data, int timeout){CloseableHttpClient httpClient = HttpClients.createDefault();//超時設置RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout) //連接超時.setConnectionRequestTimeout(timeout)//請求超時.setSocketTimeout(timeout).setRedirectsEnabled(true) //允許自動重定向.build();HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);httpPost.addHeader("Content-Type","application/json;charset=utf-8");if(data != null && data instanceof String){ //使用字符串傳參StringEntity stringEntity = new StringEntity(data,"UTF-8");httpPost.setEntity(stringEntity);}try{CloseableHttpResponse httpResponse = httpClient.execute(httpPost);HttpEntity httpEntity = httpResponse.getEntity();if(httpResponse.getStatusLine().getStatusCode() == 200){String result = EntityUtils.toString(httpEntity, "UTF-8");return result;}}catch (Exception e){e.printStackTrace();}finally {try{httpClient.close();}catch (Exception e){e.printStackTrace();}}return null;}}2.4 建控制層:WxController
/*** 微信app支付* @param* @return* @throws Exception*/@PostMapping("/WXPayment")ResultMsg<Object> WXPayment(@RequestBody OrderVO orderVO) throws Exception {ResultMsg<Object> resultMsg = new ResultMsg<>();try {resultMsg = wxService.WXPayment(orderVO);} catch (Exception e) {e.printStackTrace();resultMsg.setSuccess(false);resultMsg.setResultMsg("系統異常,支付失敗!");return resultMsg;}return resultMsg;}/*** 微信支付回調* @param request* @param response* @return* @throws Exception*/@PostMapping(value = "/wechatPay/callback")public String wechatPayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {return wxService.wechatPayCallback(request, response);}2.4 service實現類:WxServiceImpl
/**** 微信預支付接口* @param orderVO* @return*/@Overridepublic ResultMsg<Object> WXPayment(OrderVO orderVO) {ResultMsg<Object> resultMsg = new ResultMsg<Object>();if (StringUtils.isBlank(orderVO.getUserId()) ||StringUtils.isBlank(orderVO.getOrderId())||StringUtils.isBlank(orderVO.getType())||StringUtils.isBlank(orderVO.getTotalPrice())) {resultMsg.setSuccess(false);resultMsg.setResultMsg("信息不完整!");return resultMsg;}Unifiedorder unifiedorder = new Unifiedorder();unifiedorder.setAppid(WxPayConfig.APPID);unifiedorder.setMch_id(WxPayConfig.MCH_ID);unifiedorder.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));unifiedorder.setBody(orderVO.getOrderId());//訂單id 拉起后,在微信頁面上方顯示的數據unifiedorder.setOut_trade_no(orderVO.getOrderId());//訂單idString receivableAmount = orderVO.getTotalPrice();//自己業務的支付總價,但是微信支付接口以分為單位String money = new BigDecimal(receivableAmount).multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();String fee = money;unifiedorder.setTotal_fee(fee); // 訂單總金額,單位為分;unifiedorder.setSpbill_create_ip("127.0.0.1");unifiedorder.setNotify_url(WxPayConfig.NOTIFY_URL);//回調接口地址,用來接收微信通知,以及處理我們自己的業務邏輯unifiedorder.setTrade_type("APP");unifiedorder.setAttach(orderVO.getType());//附加數據,在查詢API和支付通知中原樣返回,可作為自定義參數使用,實際情況下只有支付完成狀態才會返回該字段。示例值:自定義數據 說白了就是前端調微信拉起預支付接口的某些參數,需要我們在回調接口處理業務邏輯使用log.info("微信APP支付--(簽名前):" + XMLConverUtil.convertToXML(unifiedorder));/** 獲取簽名 */UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, WxPayConfig.PRIVATE_KEY);log.info("微信APP支付--支付統一下單接口請求狀態(return_code):" + unifiedorderResult.getReturn_code());log.info("微信APP支付--支付統一下單接口請求狀態(return_msg):" + unifiedorderResult.getReturn_msg());log.info("微信APP支付--支付統一下單接口請求狀態(result_code):" + unifiedorderResult.getResult_code());log.info("微信APP支付--支付請求參數封裝(簽名后):" + XMLConverUtil.convertToXML(unifiedorder));log.info("微信APP支付--支付統一下單接口返回數據:" + JsonUtil.toJson(unifiedorderResult));// 下單結果驗簽;if (unifiedorderResult.getSign_status() != null && unifiedorderResult.getSign_status()) {log.info("微信APP支付驗簽成功");MchPayApp generateMchAppData = PayUtil.generateMchAppData(unifiedorderResult.getPrepay_id(), WxPayConfig.APPID, WxPayConfig.MCH_ID,WxPayConfig.PRIVATE_KEY);Map<String, Object> map = new HashMap<>();map.put("payOrderId", orderVO.getOrderId());//訂單idmap.put("mchPayApp", generateMchAppData);log.info(" WXPayment return map" + map);resultMsg.setData(map);resultMsg.setSuccess(true);return resultMsg;}return resultMsg;}/**** 微信回調接口* @return*/@Overridepublic String wechatPayCallback(HttpServletRequest request, HttpServletResponse response) {ResultMsg<Object> resultMsg = new ResultMsg<>();// 解析微信支付異步通知請求參數;String xml = null;try {xml = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf-8"));} catch (IOException e) {e.printStackTrace();}Map<String, String> params = XMLConverUtil.convertToMap(xml);MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class, xml);/** 打印日志信息 */log.info("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$---進入微信支付異步通知請求接口---$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");log.info("微信支付用戶訂單支付結果異步通知請求參數(xml):" + params);log.info("微信支付用戶訂單支付結果異步通知請求參數(map):" + params);log.info("return_code:" + payNotify.getReturn_code());log.info("return_msg:" + params.get("return_msg"));String out_trade_no = payNotify.getOut_trade_no(); // 用戶訂單號;String money = String.valueOf(payNotify.getTotal_fee());//支付金額String total_amount = new BigDecimal(money).multiply(new BigDecimal("0.01")).stripTrailingZeros().toPlainString();//單位換算成元String trade_no = payNotify.getTransaction_id();//微信交易號//CampOrder campOrder = campDao.selectOrderDetail(orderId);/** 校驗支付成功還是失敗 */if ("SUCCESS".equals(payNotify.getReturn_code())) {/** 獲取微信后臺返回來的異步通知參數 */String tradeNo = payNotify.getTransaction_id(); // 微信交易號;String tradeStatus = payNotify.getResult_code(); // 微信支付狀態;Integer totalFee = payNotify.getTotal_fee(); // 支付金額 (單位:分)String subject = payNotify.getAttach(); // 附加數據,在查詢API和支付通知中原樣返回,可作為自定義參數使用,實際情況下只有支付完成狀態才會返回該字段。示例值:自定義數據boolean flag = SignatureUtil.validateSign(params, WxPayConfig.PRIVATE_KEY);//返回結果return_code 和result_code都為SUCCESS的時候才算成功if (flag && "SUCCESS".equals(tradeStatus)) {/** 更新訂單支付信息: */log.info("********************** 支付成功(微信異步通知) **********************");log.info("* 訂單號: " + out_trade_no);log.info("* 微信交易號: " + trade_no);log.info("* 實付金額: " + total_amount);log.info("***************************************************************");/************ 愣著干嘛,處理業務啊 ************/log.info("微信支付成功...");/** 封裝通知信息 */MchBaseResult baseResult = new MchBaseResult();baseResult.setReturn_code("SUCCESS");baseResult.setReturn_msg("OK");xml = XMLConverUtil.convertToXML(baseResult);} else {MchBaseResult baseResult = new MchBaseResult();baseResult.setReturn_code("FAIL");baseResult.setReturn_msg("FAIL");xml = XMLConverUtil.convertToXML(baseResult);//TODO 支付失敗;邏輯}} else {MchBaseResult baseResult = new MchBaseResult();baseResult.setReturn_code("FAIL");baseResult.setReturn_msg("FAIL");xml = XMLConverUtil.convertToXML(baseResult);}log.info("微信支付--APP支付方式支付用戶訂單異步通知返回數據:" + xml);return xml;}總結
以上是生活随笔為你收集整理的【微信支付】(亲测可用)对接app微信支付V2版本 后端代码示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GAMS介绍
- 下一篇: C语言MIPS指令翻译成机器码,计算机指