一、获取微信支付四大参数

首先获取两个账号:

1、微信公众号已认证的服务号,并且需要开通微信支付功能;

微信公众平台:1)账户、密码 ;  2)公众APPID ; 3)APPSECEPT

2、微信商户平台账号

微信商户平台:1)账号、密码 ;2)商户ID  ;3)API密钥(在商户平台的账户中心下,需要用户自行下载证书及安装)

注意:获取API密钥

二、平台配置

1、配置微信公众平台授权域名

支付过程需要获取用户openId,必须经过网页授权配置才可以,要不然获取不到openId。公众号设置——功能设置——网页授权域名设置,  点击设置,有操作说明。

2、配置商户平台支付目录

三、开发流程

微信支付原理调用官方文档的统一下单接口,将微信服务器返回的参数根据微信的需求加工,返回到前台。

官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

其中必填参数:

1、appid(公众账号ID)

2、mch_id(商户号)

3、nonce_str(随机字符串)

4、sign(签名)

5、body(商品描述)

6、out_trade_no (商品订单号)

7、total_fee(标价金额)

8、spbill_create_ip(终端IP)

9、notify_url(通知地址)

10、trade_type(交易类型)

11、openid 支付人的微信公众号对应的唯一标识

1> 首先从官网把公众号支付的SDK与DEMO下载下来,可以使用里面的WXPayUtil工具类

2>获取必填项的值

1、appid       在刚开始获取微信支付四大参数中获的

2、mch_id     在刚开始获取微信支付四大参数中获的,商户号ID

3、nonce_str    随机字符串用WXPayUtil中的generateNonceStr()获取,生成UUID的方法

4、body      所支付的名称  (注意:一定要转换成UTF-8形式,不然后续获取prepay_id将获取不到)

5、out_trade_no       订单号,一定要保证唯一

6、total_fee   支付金额 ,单位是分(一定要换算成分进行操作)

7、spbill_create_ip  IP地址

8、notify_url  回调地址

9、trade_type  支付类型  此支付类型为 "JSAPI"

10、openid    支付人的微信公众号对应的唯一标识,每个人的openid在不同的公众号不一样。(获取openid属于微信公众号网页授权的,参考微信网页授权:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842)

11、sign  签名:用WXPayUtil中的generateSignature(finalMap<String,String> data,String key)方法,data是将除了sign外其他10个参数放到map中,key是四大配置参数中的API密钥(paternerKey)

3>获取openid

1、用户同意授权,获取code

参考访问地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
                   注意事项:1、redirect_uri参数:授权后重定向的回调链接地址,请使用urlEncode对链接进行处理

2、scope:用snsapi_base

通过此链接可以获取code,可以写到前台页面a标签中或者在后台访问,redirect_uri可以链接到本项目的方法并可获取code。

<a href="https://open.weixin.qq.com/connect/oauth2/authorize?
appid=wx15c*********&redirect_uri=http%3a%2f%2fwww.ourpay.com%2fpay.jsp&response_type=code&
scope=snsapi_base#wechat_redirect">获取code</a>

2、通过code获取网页授权access_token(access_token中含有openid)

参考访问地址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

注意事项:1、CODE需要换成第一步获取的code

通过参考地址,在后台中用http相关类发送get请求,返回的json结果为:

{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",//就是它,只要这个值
"scope":"SCOPE" }

4>获取十一个必填项之后,使用WXPayUtil工具类中的public static String   mapToXml(Map<String,String> data)方法将有11个参数的map转成XML格式,用post请求的方法,请求微信统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder,发送后会返回String类型的返回值,会得到XML的字符串:

<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wx2421b1c4370ec43b]]></appid><mch_id><![CDATA[10000100]]></mch_id><nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str><openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid><sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id><trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

到此时后台获取的数据已经全部完成,最后就是获取prepay_id。使用WXPayUtil类中的public static Map<String,String>  xmlToMap(String strXML)方法,将刚才返回的XML格式的字符串转成map,map中获取prepay_id。

5>前台

1、appId : 四大参数之一的APPID

2、timestamp:时间戳

3、nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr()获取

4、package:使用的就是后台最后获取的prepay_id,但是还不是直接取值,还非要固定格式的,值的格式:“prepay_id=wx35465465....5656”

5、signType:MD5

6、paySign:还是签名算法,按照上面的方法,用WXPayUtil中的public static String generateSignature(final Map<String,String> data,String key)方法,data是将除了paySign外,其他5个参数放到map中,key是四大配置参数中的API密钥(paternerKey)

function onBridgeReady(){WeixinJSBridge.invoke( 'getBrandWCPayRequest', {"appId":appId,     //公众号名称,由商户传入     "timeStamp":timeStamp,         //时间戳,自1970年以来的秒数     "nonceStr":nonceStr, //随机串     "package":package,     "signType":signType,         //微信签名方式:     "paySign":paySign //微信签名 }, function(res){      if(res.err_msg == "get_brand_wcpay_request:ok" ) {console.log('支付成功');//支付成功后跳转的页面}else if(res.err_msg == "get_brand_wcpay_request:cancel"){console.log('支付取消');}else if(res.err_msg == "get_brand_wcpay_request:fail"){console.log('支付失败');WeixinJSBridge.call('closeWindow');} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。});
}

6>以下是参考代码

1》把四大参数和所需要的访问地址放到wechatPay.properties中

######微信支付配置文件######
######应用id
wechat.appid=wxdb384*********7
######商户ID
wechat.mch_id=154*******1
######appSecret密钥
wechat.appSecret=1636e***********a57222
######支付类型
wechat.trade_type=JSAPI
######API密钥
wechat.paternerKey=wxdb384e**********4eb0e4de
######域名
wechat.ym=www.ourpay.com
######返回结果回调函数
wechat.afterUrl=phone/wxpay/afterUrl
######获取code的url
wechat.code=https://open.weixin.qq.com/connect/oauth2/authorize
######获取Access_token的url
wechat.access_token=https://api.weixin.qq.com/sns/oauth2/access_token
######获取统一下单url
wechat.unifiedorder_url=https://api.mch.weixin.qq.com/pay/unifiedorder

/**
*
*在类中获取值
*
**/
public void loadData() {rb = ResourceBundle.getBundle("wechatPay");wxAppid = rb.getString("wechat.appid");// 微信APPidwxAppSecret = rb.getString("wechat.appSecret");// 微信APPSECEPTwxMchId = rb.getString("wechat.mch_id");// 微信商户IDwxTradeType = rb.getString("wechat.trade_type");// 支付的方式wxAfterUrl = rb.getString("wechat.afterUrl");// 成功之后回调函数wxPaternerKey = rb.getString("wechat.paternerKey");// 微信api密钥wxUnifiedorderUrl = rb.getString("wechat.unifiedorder_url");// 统一下单地址
}

2》后台发送get(post)请求的方法

package com.jeeplus.common.pay;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;public class HttpRequest {/*** 向指定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());// 获取URLConnection对象对应的输出流(进行编码)out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"UTF-8"));// 发送请求参数out.print(param);// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));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;}}

3》从微信官网下载的SDK和DEMO中使用微信中的WXPayUtil类

package com.jeeplus.common.pay.wechat;import com.jeeplus.common.pay.wechat.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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;public class WXPayUtil {private static final String SYMBOLS = "0123456789abcd**************LMNOPQRSTUVWXYZ";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 {java.security.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();}/*** 流转换xml字符串* * @param in* @param charset* @return*/public static String inputStream2String(InputStream in, String charset) {if (charset == null) {charset = "UTF-8";}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();String result = null;int bufferSize = 2048;byte[] data = new byte[bufferSize];int count = -1;try {while ((count = in.read(data, 0, bufferSize)) != -1) {outputStream.write(data, 0, count);}result = new String(outputStream.toByteArray(), charset);} catch (Exception e) {e.printStackTrace();} finally {try {if (outputStream != null) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}}return result;}}

4》首先获取code,我是后台重定向获取的

/*** 支付* * @return*/@RequestMapping("/pay")public String pay( HttpServletRequest request) {ResourceBundle rb = ResourceBundle.getBundle("wechatPay");String url = rb.getString("wechat.code");// 获取code的urlString appid = rb.getString("wechat.appid");// 获取appidString ym = rb.getString("wechat.ym");// 获取域名url = url+ "?appid="+ appid+ "&redirect_uri=http%3a%2f%2f"+ ym+ "%2fphone%2fwxpay%2fgetCode%3fmeetingId%3d"+ id+ "%26orderId%3d"+ orderId+ "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";return "redirect:" + url;}

后台中redirect_uri中指定的方法将会获得code(request.getParameter("code")),发送到前台。

5》获取openid

/*** 获取access_token* * @param code* @return*/public String getOpenId(String code) {loadData();String accessTokenUrl = rb.getString("wechat.access_token");String param = "appid=" + wxAppid + "&secret=" + wxAppSecret + "&code="+ code + "&grant_type=authorization_code";String result = HttpRequest.sendGet(accessTokenUrl, param);JSONObject jo = new JSONObject(result);String openid = jo.get("openid") + "";return openid;}

6》获取prepay_id

/*** 获取getPrepay_id* * @param openId*            获取openId* @param orderId*            订单号* @param orderName*            所支付的名称* @param money*            支付费用单位分* @param request* @return*/public String getPrepay_id(String openId, String orderId, String orderName,String money, HttpServletRequest request) {loadData();// 拼接统一下单地址参数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();}paraMap.put("appid", wxAppid);orderName = orderName.replace(" ", "");try {paraMap.put("body", new String(orderName.getBytes("ISO8859-1"),"utf-8"));} catch (UnsupportedEncodingException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}paraMap.put("mch_id", wxMchId);paraMap.put("nonce_str", WXPayUtil.generateNonceStr());paraMap.put("openid", openId);paraMap.put("out_trade_no", orderId);// 订单号paraMap.put("spbill_create_ip", ip);paraMap.put("total_fee", money);paraMap.put("trade_type", wxTradeType);paraMap.put("notify_url", request.getServerName() + "/" + wxAfterUrl);// 此路径是微信服务器调用支付结果通知路径随意写String prepay_id = "";// 预支付idtry {String sign = WXPayUtil.generateSignature(paraMap, wxPaternerKey);paraMap.put("sign", sign);String xml = WXPayUtil.mapToXml(paraMap);// 将所有参数(map)转xml格式String xmlStr = HttpRequest.sendPost(wxUnifiedorderUrl, xml);// 发送post请求"统一下单接口"返回预支付id:prepay_id// 以下内容是返回前端页面的json数据Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);if (xmlStr.indexOf("SUCCESS") != -1) {prepay_id = (String) map.get("prepay_id");}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return prepay_id;}

7》往前台发送数据

/*** 往前台发送数据* * @param prepay_id* @return*/public Map<String, String> sendMap(String prepay_id) {loadData();Map<String, String> payMap = new HashMap<String, String>();payMap.put("appId", wxAppid);payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");payMap.put("nonceStr", WXPayUtil.generateNonceStr());payMap.put("signType", "MD5");payMap.put("package", "prepay_id=" + prepay_id);String paySign;try {paySign = WXPayUtil.generateSignature(payMap, wxPaternerKey);payMap.put("paySign", paySign);payMap.put("packageMsg", "prepay_id=" + prepay_id);System.out.println(payMap);return payMap;} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();return null;}}

8》前台js

<script type="text/javascript">
var appId,timeStamp,nonceStr,packageMsg,signType,paySign;
//微信支付
function wxpay(){var code ="${wxcode}";if(code){var url ="${prefix}/phone/wxpay/getMessage?code="+code+"&meetingId=${meeting.id}&orderId=${orderId}";$.get(url,function(data) {var result = data.body.msg;appId = result.appId;timeStamp = result.timeStamp;nonceStr = result.nonceStr;packageMsg = result.packageMsg;signType = result.signType;paySign = result.paySign;if (typeof WeixinJSBridge == "undefined") {if (document.addEventListener) {document.addEventListener('WeixinJSBridgeReady',onBridgeReady, false);} else if (document.attachEvent) {document.attachEvent('WeixinJSBridgeReady',onBridgeReady);document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);}} else {onBridgeReady();}});} else {alert("服务器错误")}}function onBridgeReady(){WeixinJSBridge.invoke( 'getBrandWCPayRequest', {"appId":appId,     //公众号名称,由商户传入     "timeStamp":timeStamp,         //时间戳,自1970年以来的秒数     "nonceStr":nonceStr, //随机串     "package":packageMsg,     "signType":signType,         //微信签名方式:     "paySign":paySign //微信签名 }, function(res){      if(res.err_msg == "get_brand_wcpay_request:ok" ) {console.log('支付成功');//支付成功后跳转的页面}else if(res.err_msg == "get_brand_wcpay_request:cancel"){console.log('支付取消');layer.msg('支付取消', {icon: 1,time:1000});}else if(res.err_msg == "get_brand_wcpay_request:fail"){console.log('支付失败');layer.msg('支付失败', {icon: 1,time:1000});/*  WeixinJSBridge.call('closeWindow'); */} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。window.location.href="${prefix}/phone/meeting/meetingDetail?id=${meeting.id}";});
}</script>

9》支付成功后回调

/*** 返回结果* * @return*/@RequestMapping("/afterUrl")public String afterUrl(HttpServletRequest request,HttpServletResponse response) {InputStream is = null;try {is = request.getInputStream();// 获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)String xml = WXPayUtil.inputStream2String(is, "UTF-8");Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);// 将微信发的xml转mapif (notifyMap.get("return_code").equals("SUCCESS")) {if (notifyMap.get("result_code").equals("SUCCESS")) {String orderId = notifyMap.get("out_trade_no");// 商户订单号String meetingId = orderPayService.saveOrderPay(orderId);return "redirect:/phone/meeting/meetingDetail?id="+meetingId;}}// 告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");is.close();} catch (Exception e) {e.printStackTrace();}return "redirect:/phone/meeting/meetinglist";}

7>参考文献

https://blog.csdn.net/javaYouCome/article/details/79473743

Java微信支付——公众号支付JSAPI相关推荐

  1. 微信jsapi支付获取code_JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

    写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了.本以为网上的微信开发教程 ...

  2. 企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET

    企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET 原文:企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET 先看效果 1.本文演示的是 ...

  3. 微信jsapi支付获取code_微信支付(公众号支付JSAPI)

    微信公众号支付/微信浏览器支付(JSAPI) 一:获取微信支付四大参数 步骤二:平台配置 配置支付目录:商户平台. 配置此目录是代码中"微信支付"所在页面的地址,一级域名需ICP备 ...

  4. php微信统一公众号支付接口,微信公众号支付怎么实现统一下单接口

    微信公众号支付怎么实现统一下单接口 发布时间:2021-03-12 09:44:45 来源:亿速云 阅读:89 作者:小新 这篇文章将为大家详细讲解有关微信公众号支付怎么实现统一下单接口,小编觉得挺实 ...

  5. 微信公众号支付php demo,200行代码实现微信支付-公众号支付,不再踩坑,附:demo...

    开发微信支付需要认证服务号并且已经开通微信支付,获得微信支付商ID,设置apikey了的. 官方给了公众号支付的php源码SDK 但是这个SDK文件非常多,源码乱七八糟的,真的一开始接触的人拿着官方的 ...

  6. 微信跨公众号支付(appid 与 openid 不匹配)-koa

    实现不同主体公众号的跨公众号支付其实原理很简单,就下面几点: 1.用一个公众号的appid来进行收款 2.这个公众号的appid需要和商户号绑定 3.用这个appid来获取用户的openid 进过上面 ...

  7. 微信跨公众号支付(appid 与 openid 不匹配)

    实现不同主体公众号的跨公众号支付其实原理很简单,就下面几点: 1.用一个公众号的appid来进行收款 2.这个公众号的appid需要和商户号绑定 3.用这个appid来获取用户的openid 进过上面 ...

  8. java微信测试公众号实现文本、图片消息回复

    微信测试公众号实现文本.图片消息回复 学习记录: 源码地址:https://gitee.com/jack_liujilong/WeiXin.git 1.申请微信测试公众号https://mp.weix ...

  9. java微信公共帐号支付(JS支付)

    最近公司需要开发微信商城,然后各种作微信的东西啊,各种看API,头大,这里先记录下来以免后面忘记了~ 首先是微信提供的api地址:https://pay.weixin.qq.com/wiki/doc/ ...

最新文章

  1. 多校1010 Taotao Picks Apples
  2. c# bitmap 去除噪点_黑头怎么去除最有效用盐处理的方法推荐
  3. mysql 商业版备份_MySQL企业版备份工具MEB
  4. Python学习系列day5-python基础
  5. php websocket 实战,一次WebSocket项目实战后总结的经验
  6. java学习(138):异常处理
  7. grunt 前端开发环境搭建
  8. 转: 自适应css布局—-流动布局新时代(译文)
  9. Git笔记(7) 撤消操作
  10. daily scrum 11.9
  11. springMVC集成缓存框架Ehcache
  12. 【开源工程】视频主观质量评测工具 video quality compare tool
  13. 不狂热不忧虑:观看波士顿动力机器人视频的正确姿势
  14. tarjan用法——割点
  15. spotlight on mysql--安装以及简介
  16. 【转】Linux删除文件未释放空间问题处理
  17. Android基于腾讯X5内核的WebView(超级浏览器)
  18. UI设计中的原型图用什么工具?怎么做?给谁看?
  19. 商业虚拟专用网络技术五IPSec
  20. 【LeetCode - Java】14. 最长公共前缀 (简单)

热门文章

  1. 操作系统原理学习笔记(文件与I/O)
  2. linux平台xpt2046驱动,XPT2046触摸屏实验过程详解与STM32代码解析
  3. 可能真正解决Windows睡眠耗电
  4. We're sorry but *** doesn't work properly without JavaScript enabled. Please enable it
  5. HJ40 统计字符 【python3】
  6. Redis常见命令操作
  7. html盒子边框内部线条,详解CSS从条纹边框的实现盒子模型的方法
  8. 开源的python有限元软件_Python与有限元--基于Python编程的有限元分析及应用扩展...
  9. 通过百度API检测人脸特征,获取颜值、年龄、性别--C语言实现
  10. 简单的特效--css画圆圈