一、首先申请公众号,认证,开通支付功能(具体配置参照API)

二、登录商户平台进行开发设置(具体配置参照API)

三、具体开发流程

首先,官方给出的SDK和demo和一些具体的API文档看起来比较麻烦,这里我做了简要的步骤介绍,这里我采用的是微信的JSAPI支付方式来做介绍的。

3.1 导入maven依赖

<!--  JSONOBJECT-->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.28</version>
</dependency><!-- httpclient-->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.3</version>
</dependency><!-- wx  -->
<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>

3.2 前台首先要 用户同意授权,获取code,方法如下:

调用:https://open.weixin.qq.com/connect/oauth2/authorize?=XXXXXXX&redirect_uri=www.baidu.com/callback&response_type=code&scope=snsapi_base&state=1#wechat_redirect

appid:公众号的APPID、redirect_uri:授权后重定向的地址(此处域名用NGINX映射到了网站的首页)、response_type:固定值code、scope:应用授权作用域,snsapi_base (未关注,不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )、state:重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节

在回调方法中可以获取到code值;在页面的地址栏中也可以获取到;

3.3通过code换取网页授权的access_token(这里只需要其中的openId),获取方法如下:

调用:https://api.weixin.qq.com/sns/oauth2/access_token?appid=XXXXXXXXXXXX&secret=XXXXXXXXXc&code=XXXXXXXX&grant_type=authorization_code

参数介绍:appid:同上、secret:微信公众号里的开发者密码(APPSecret)、code:3.2获取的code、grant_type:固定值authorization_code(返回参数中会有我们需要的openId)

3.4就是调用微信统一下单的接口了

3.5把统一下单的返回数据返回给前台,前台在携带参数跳转到微信的支付页面(后续的工作就是微信那边处理的了,不需要我们考虑)

3.6统一下单传入的参数有一个回调地址,微信支付完后会根据你传的回调地址进行异步通知你,我们只需要接受消息处理我们支付成功后的逻辑,并返回给微信已收到通知。

四、直接上代码(简单易懂)

4.1 官网demo中的常量

/*** 常量*/
public class WXPayConstants {public enum SignType {MD5, HMACSHA256}public static final String APP_ID = "";//appidpublic static final String MCH_ID = "";//商家IDpublic static final String SECRET = "";//APP KEYpublic static final String OPENID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";public static final String NOTIFY_URL = "";//回调ippublic static final String UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单接口public static final String RESOUT_CALLBACK_URL = "xxxxxxx/resout/callback";//统一下单接口public static final String PATERNER_KEY = "";//商户keypublic static final String DOMAIN_API = "api.mch.weixin.qq.com";public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com";public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com";public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com";public static final String FAIL     = "FAIL";public static final String SUCCESS  = "SUCCESS";public static final String HMACSHA256 = "HMAC-SHA256";public static final String MD5 = "MD5";public static final String FIELD_SIGN = "sign";public static final String FIELD_SIGN_TYPE = "sign_type";public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9";public static final String USER_AGENT = WXPAYSDK_VERSION +" (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();public static final String MICROPAY_URL_SUFFIX     = "/pay/micropay";public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";public static final String ORDERQUERY_URL_SUFFIX   = "/pay/orderquery";public static final String REVERSE_URL_SUFFIX      = "/secapi/pay/reverse";public static final String CLOSEORDER_URL_SUFFIX   = "/pay/closeorder";public static final String REFUND_URL_SUFFIX       = "/secapi/pay/refund";public static final String REFUNDQUERY_URL_SUFFIX  = "/pay/refundquery";public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";public static final String REPORT_URL_SUFFIX       = "/payitil/report";public static final String SHORTURL_URL_SUFFIX     = "/tools/shorturl";public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid";// sandboxpublic static final String SANDBOX_MICROPAY_URL_SUFFIX     = "/sandboxnew/pay/micropay";public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";public static final String SANDBOX_ORDERQUERY_URL_SUFFIX   = "/sandboxnew/pay/orderquery";public static final String SANDBOX_REVERSE_URL_SUFFIX      = "/sandboxnew/secapi/pay/reverse";public static final String SANDBOX_CLOSEORDER_URL_SUFFIX   = "/sandboxnew/pay/closeorder";public static final String SANDBOX_REFUND_URL_SUFFIX       = "/sandboxnew/secapi/pay/refund";public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX  = "/sandboxnew/pay/refundquery";public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";public static final String SANDBOX_REPORT_URL_SUFFIX       = "/sandboxnew/payitil/report";public static final String SANDBOX_SHORTURL_URL_SUFFIX     = "/sandboxnew/tools/shorturl";public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";}

4.2  官网demo中的WXPayUtil

package com.wanrongwang.zulin.wanmobile.wechat;
import com.github.wxpay.sdk.WXPayConstants.SignType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
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.*;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;public class WXPayUtil {private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private static final Random RANDOM = new SecureRandom();/*** 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>();DocumentBuilder documentBuilder = WXPayXmlUtil.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) {// do nothing}return data;} catch (Exception ex) {WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);throw ex;}}/*** 将Map转换为XML格式的字符串** @param data Map类型数据* @return XML格式的字符串* @throws Exception*/public static String mapToXml(Map<String, String> data) throws Exception {org.w3c.dom.Document document = WXPayXmlUtil.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;}/*** 生成带有 sign 的 XML 格式字符串** @param data Map类型数据* @param key API密钥* @return 含有sign字段的XML*/public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {return generateSignedXml(data, key, SignType.MD5);}/*** 生成带有 sign 的 XML 格式字符串** @param data Map类型数据* @param key API密钥* @param signType 签名类型* @return 含有sign字段的XML*/public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {String sign = generateSignature(data, key, signType);data.put(WXPayConstants.FIELD_SIGN, sign);return mapToXml(data);}/*** 判断签名是否正确** @param xmlStr XML格式数据* @param key API密钥* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(String xmlStr, String key) throws Exception {Map<String, String> data = xmlToMap(xmlStr);if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {return false;}String sign = data.get(WXPayConstants.FIELD_SIGN);return generateSignature(data, key).equals(sign);}/*** 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。** @param data Map类型数据* @param key API密钥* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {return isSignatureValid(data, key, SignType.MD5);}/*** 判断签名是否正确,必须包含sign字段,否则返回false。** @param data Map类型数据* @param key API密钥* @param signType 签名方式* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {return false;}String sign = data.get(WXPayConstants.FIELD_SIGN);return generateSignature(data, key, signType).equals(sign);}/*** 生成签名** @param data 待签名数据* @param key API密钥* @return 签名*/public static String generateSignature(final Map<String, String> data, String key) throws Exception {return generateSignature(data, key, SignType.MD5);}/*** 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。** @param data 待签名数据* @param key API密钥* @param signType 签名方式* @return 签名*/public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {Set<String> keySet = data.keySet();String[] keyArray = keySet.toArray(new String[keySet.size()]);Arrays.sort(keyArray);StringBuilder sb = new StringBuilder();for (String k : keyArray) {if (k.equals(WXPayConstants.FIELD_SIGN)) {continue;}if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名sb.append(k).append("=").append(data.get(k).trim()).append("&");}sb.append("key=").append(key);if (SignType.MD5.equals(signType)) {return MD5(sb.toString()).toUpperCase();}else if (SignType.HMACSHA256.equals(signType)) {return HMACSHA256(sb.toString(), key);}else {throw new Exception(String.format("Invalid sign_type: %s", signType));}}/*** 获取随机字符串 Nonce Str** @return String 随机字符串*/public static String generateNonceStr() {char[] nonceChars = new char[32];for (int index = 0; index < nonceChars.length; ++index) {nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));}return new String(nonceChars);}/*** 生成 MD5** @param data 待处理数据* @return MD5结果*/public static String MD5(String data) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");byte[] array = md.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();}/*** 生成 HMACSHA256* @param data 待处理数据* @param key 密钥* @return 加密结果* @throws Exception*/public static String HMACSHA256(String data, String key) throws Exception {Mac sha256_HMAC = Mac.getInstance("HmacSHA256");SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");sha256_HMAC.init(secret_key);byte[] array = sha256_HMAC.doFinal(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();}/*** 日志* @return*/public static Logger getLogger() {Logger logger = LoggerFactory.getLogger("wxpay java sdk");return logger;}/*** 获取当前时间戳,单位秒* @return*/public static long getCurrentTimestamp() {return System.currentTimeMillis()/1000;}/*** 获取当前时间戳,单位毫秒* @return*/public static long getCurrentTimestampMs() {return System.currentTimeMillis();}public static String inputStream2String(InputStream in) {InputStreamReader reader = null;try {reader = new InputStreamReader(in, "UTF-8");} catch (UnsupportedEncodingException e1) {e1.printStackTrace();}BufferedReader br = new BufferedReader(reader);StringBuilder sb = new StringBuilder();String line = "";try {while ((line = br.readLine()) != null) {sb.append(line);}} catch (IOException e) {e.printStackTrace();}return sb.toString();}
}

4.3 官网demo中WXPayXmlUtil

package com.wanrongwang.zulin.wanmobile.wechat;import org.w3c.dom.Document;import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;/*** 2018/7/3*/
public final class WXPayXmlUtil {public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);documentBuilderFactory.setXIncludeAware(false);documentBuilderFactory.setExpandEntityReferences(false);return documentBuilderFactory.newDocumentBuilder();}public static Document newDocument() throws ParserConfigurationException {return newDocumentBuilder().newDocument();}
}

4.4 后台发送http请求的工具

package com.wanrongwang.zulin.wanmobile.utils;import org.apache.http.client.HttpClient;
import org.hibernate.validator.internal.util.privilegedactions.GetMethod;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;/** Http请求工具类* @author Administrator* @date crete by on 2019/3/8 18:08* @description*/
public class HttpClientUtil {/*** 向指定URL发送GET方法的请求** @param url* 发送请求的URL* @param param* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return URL 所代表远程资源的响应结果*/public static String sendGet(String url, String param) {String result = "";BufferedReader in = null;try {String urlNameString = url + "?" + param;System.out.println(urlNameString);URL realUrl = new URL(urlNameString);// 打开和URL之间的连接URLConnection connection = realUrl.openConnection();// 设置通用的请求属性connection.setRequestProperty("accept", "*/*");connection.setRequestProperty("connection", "Keep-Alive");connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 建立实际的连接connection.connect();// 获取所有响应头字段Map<String, List<String>> map = connection.getHeaderFields();// 遍历所有的响应头字段for (String key : map.keySet()) {System.out.println(key + "--->" + map.get(key));}// 定义 BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e);e.printStackTrace();}// 使用finally块来关闭输入流finally {try {if (in != null) {in.close();}} catch (Exception e2) {e2.printStackTrace();}}return result;}/*** 向指定 URL 发送POST方法的请求** @param url* 发送请求的 URL* @param param* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return 所代表远程资源的响应结果*/public static String sendPost(String url, String param) {PrintWriter out = null;BufferedReader in = null;String result = "";try {URL realUrl = new URL(url);// 打开和URL之间的连接URLConnection conn = realUrl.openConnection();// 设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("user-agent",  "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);// 获取URLConnection对象对应的输出流out = new PrintWriter(conn.getOutputStream());// 发送请求参数out.print(param);// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送 POST 请求出现异常!"+e);e.printStackTrace();}//使用finally块来关闭输出流、输入流finally{try{if(out!=null){out.close();}if(in!=null){in.close();}}catch(IOException ex){ex.printStackTrace();}}return result;}}

4.5 自己定义的控制层(这里的code采用前台获取,直接传到后台)

/***  获取openid* @param code* @return*/@GetMapping("/wechat/getOpenId")@CrossOriginpublic  Map<String , Object> getOpenId(@RequestParam("code") String code){Map<String , Object> resMap = new HashMap<String,Object>();//页面获取openId接口String getopenid_url = WXPayConstants.OPENID_URL;String param="appid="+WXPayConstants.APP_ID+"&secret="+WXPayConstants.SECRET+"&code="+code+"&grant_type=authorization_code";//向微信服务器发送get请求获取openIdStrString openIdStr = HttpClientUtil.sendGet(getopenid_url, param);JSONObject json = JSONObject.parseObject(openIdStr);//转成Json格式String openId = json.getString("openid");//获取openIdif (openId != null){resMap.put("openid",openId);resMap.put("code",1);resMap.put("msg","success");}else {resMap.put("code",0);resMap.put("msg","请求失败");}return resMap;}/***  支付* @param orderId* @param request* @return*/@GetMapping("/wechat/payfor")@CrossOriginpublic  Map<String , Object> wxpay(@RequestParam("openid") String openid,@RequestParam("orderId") String orderId,HttpServletRequest request){Map<String , Object> resMap = new HashMap<String,Object>();logger.info("=============code:{}");try {//根据orderId查询 订单MprOrder order = orderService.queryById(Long.parseLong(orderId));if (order == null){resMap.put("code",0);resMap.put("msg","订单不存在");return resMap;}String orderNum = order.getOrderNumber();BigDecimal amount = order.getPrice();//拼接统一下单地址参数Map<String, String> paraMap = new HashMap<String, String>();//获取请求ip地址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.getRemoteAddr();}if(ip.indexOf(",")!=-1){String[] ips = ip.split(",");ip = ips[0].trim();}String money =  amount.multiply(new BigDecimal(100)).toString();paraMap.put("appid", WXPayConstants.APP_ID);paraMap.put("mch_id", WXPayConstants.MCH_ID);paraMap.put("nonce_str", WXPayUtil.generateNonceStr());paraMap.put("body", "happy rent - order");   //开心易租-订单结算paraMap.put("out_trade_no", orderNum);//订单号paraMap.put("total_fee","1");    //测试改为固定金额paraMap.put("spbill_create_ip", ip);paraMap.put("notify_url",WXPayConstants.RESOUT_CALLBACK_URL);// 此路径是微信服务器调用支付结果通知路径随意写paraMap.put("trade_type", "JSAPI");paraMap.put("openid", openid);//用公众号key  失败  ----改为商户key  19-3-12//String sign = WXPayUtil.generateSignature(paraMap, WXPayConstants.PATERNER_KEY);//微信公众号开发者密码String sign = WXPayUtil.generateSignature(paraMap, WXPayConstants.MCH_SECRET);//商户密码paraMap.put("sign", sign);String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorderString unifiedorder_url = WXPayConstants.UNIFIEDORDER_URL;String xmlStr = HttpClientUtil.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id//以下内容是返回前端页面的json数据String prepay_id = "";//预支付idif (xmlStr.indexOf("SUCCESS") != -1) {Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);prepay_id = (String) map.get("prepay_id");}Map<String, String> payMap = new HashMap<String, String>();payMap.put("appId", WXPayConstants.APP_ID);payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");payMap.put("nonceStr", WXPayUtil.generateNonceStr());payMap.put("signType", "MD5");payMap.put("package", "prepay_id=" + prepay_id);logger.info("=======prepay_id:"+prepay_id);//String paySign = WXPayUtil.generateSignature(payMap, WXPayConstants.PATERNER_KEY);  //公众号key  失败 改为下面  19-3-12String paySign = WXPayUtil.generateSignature(payMap, WXPayConstants.MCH_SECRET);payMap.put("paySign", paySign);resMap.put("code",1);resMap.put("payMap",payMap);} catch (Exception e) {e.printStackTrace();resMap.put("code",0);resMap.put("msg","调用统一订单接口错误");}return resMap;}/*** 获取code微信回调---callback* @param request* @param response*/@GetMapping("/callback")@CrossOriginpublic void callback(HttpServletRequest request, HttpServletResponse response){logger.info("-------------callback ---------------");String code = request.getParameter("code");String state = request.getParameter("state");//把code放到redis里redisTemplate.opsForValue().set(state,code);redisTemplate.expire(state,60*5, TimeUnit.SECONDS);logger.info("--------code:{},state:{}",code,state);}@RequestMapping("/resout/callback")@CrossOriginpublic String callBack(HttpServletRequest request,HttpServletResponse response){//System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");InputStream is = null;try {is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)String xml = WXPayUtil.inputStream2String(is);Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转mapif(notifyMap.get("return_code").equals("SUCCESS")){if(notifyMap.get("result_code").equals("SUCCESS")){String ordersSn = notifyMap.get("out_trade_no");//商户订单号//处理订单状态orderService.updateByOrderNum(ordersSn);}}//告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");is.close();} catch (Exception e) {e.printStackTrace();}return null;}

相关前台JS或有疑虑的地方请参考:https://www.cnblogs.com/gopark/p/9394951.html;

微信公众号支付对接流程相关推荐

  1. php 公众号微信支付流程,微信公众号支付完整流程案例

    简介 微信公众号支付,顾名思义就是必须在微信中实现支付,并且需要公众号配合. 教程 由于我们使用的是第三方封装好的接口,这里省去了我们自己配置公众号.为什么用第三方?因为个人没有申请权限. 交互细节: ...

  2. 微信公众号支付完整流程

    一.微信支付相关文档 jsapi支付下单:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml jsapi支付场景:http ...

  3. 公众号支付成功后执行ajax,真香,微信公众号支付完整流程案例

    /** * 获取授权链接,首先调用此方法 * @return */ @GetMapping(value= "getOauthUrl") public void getOauthUr ...

  4. 微信公众号支付(JSAPI)对接备忘

    0 说明 本文里说的微信公众号支付对接指的是对接第三方支付平台的微信公众号支付接口. 非微信支付官方文档里的公众号支付开发者文档那样的对接.不过,毕竟腾讯会把一部分渠道放给银行或有支付牌照的支付机构, ...

  5. 微信公众号支付申请配置流程

    微信公众号支付申请配置流程 公众号支付申请步骤 微信公众号支付配置 公众号支付:用户在微信内进入商家H5页面,在页面内完成支付. 公众号支付申请步骤 注册公众账号(政府或媒体订阅号.服务号才能接入支付 ...

  6. 前端对接微信公众号网页开发流程,前期配置

    微信公众号网页开发,其实就是我们开发的h5网页需要放到微信浏览器环境中使用,但是需要对接公众号授权,授权之后可以获取到用户的个人信息,以及可以使用公众号提供的一些API,如:图片上传.图片预览.获取位 ...

  7. 前端对接微信公众号网页开发流程,授权对接

    前面讲到 前端对接微信公众号网页开发流程,前期配置,本篇文章主要详细介绍关于公众号的授权对接. 一.引入微信js-sdk 在需要调用 JS 接口的页面引入如下 JS 文件 http://res.wx. ...

  8. 对接银联商务微信公众号支付遇到的坑

    微信公众号支付和微信扫码支付在 支付结果通知上有很大的区别,公众号支付主要是以异步通知去确定支付结果,也可以通过查询接口,而扫码支付通常调用查询接口去查询支付状态.因而,公众号支付的异步通知是一个需要 ...

  9. 前端对接微信公众号网页开发流程,JSSDK使用

    前面两篇文章讲解了前端对接微信公众号网页开发流程,前期配置 和 前端对接微信公众号网页开发流程,授权对接,本篇文章讲解关于微信JSSDK的使用,官方文档地址 一.通过 config 接口注入权限验证配 ...

最新文章

  1. pybind传输list
  2. 神经网络为什么要归一化
  3. gin将请求体绑定到不同的结构体中
  4. # Consumed parameters
  5. flutter和webapp_Flutter Web Beta版本终于发布了
  6. 风险评估资产重要性识别_如何有效的进行风险评估?
  7. 阿里云推出CloudDBA,解决数据库性能优化和问题诊断难题
  8. Android之支付宝设计与开发
  9. Vue 框架-05-动态绑定 css 样式
  10. ES6 里面的 class
  11. 计算机桌面设置定时,如何设置可以每月自动变化的日历桌面?
  12. php和数据库的接口,php数据库接口
  13. JAVA求数组的平均数,众数,中位数
  14. 【IOS】ios8推送消息注册
  15. VMware终端用户计算的战略和愿景
  16. 【python实战】爬取起点中文网自制小说阅读器
  17. Linux切换jdk版本
  18. phpMyAdmin 登陆超时(1440秒未活动),请重新登录问题
  19. Css+Jquery实现点击图片放大缩小预览 图片预览 查看大图
  20. 为什么我玩游戏那么卡?

热门文章

  1. 卫健委最新报告对医疗设备售后服务产生了什么影响
  2. 智能回收机、垃圾分拣机器人 垃圾回收这是技术活儿
  3. 谷粒商城2-环境安装
  4. crtsiii型无砟轨道板_北京雄安城际全线轨道贯通:全程设5座车站,1小时通勤,“刷脸”进站...
  5. 出现BOOTMGR is missing 最简单实用的解决方案
  6. 实践干货!猿题库 iOS 客户端架构设计
  7. 零和博弈-极大极小搜索Alpha-Beta剪枝(井字游戏)
  8. 杭电 HDU 1234 开门人和关门人
  9. Java零基础学习全套视频笔记
  10. 寒假集训三(暴力枚举)2020.01.02(11题)