首先是H5的支付,先看控制层的代码
@Autowired AliPayH5Bean aliPayH5Bean; @Autowired WxPayH5MWEB wxPayH5MWEB; @Autowired WxPayH5JSAPI wxPayH5JSAPI; @LoginRequired(isNeedLogin = true) @ApiOperation("H5去支付,支付主接口,用于控制支付流程") @GetMapping(value = "/h5/pay" ,produces = { "application/json;charset=UTF-8" }) @ResponseBody public Object wxPrepay(String orderSn,BigDecimal totalAmount,String code,String channelId){ //正常开发情况下是根据用户登录的id和订单编号查询该订单是否为登录用户的订单并获取订单信息,订单价格是不会作为参数传入的,这里只是演示支付不做那么麻烦 String result = ""; if(PayConstant.CHANNELALIH5.equals(channelId)){ Map<String, Object> wxMap = aliPayH5Bean.getPayMap(); wxMap.put("out_trade_no", orderSn); wxMap.put("total_fee", "1".equals(aliPayH5Bean.getPayMap().get("is_real_pay")) ? totalAmount : 0.01); //手机网站支付,调用支付宝(网页类支付接口),这里没有写(系统调用类支付接口) result = PayUtils.alipayh5(wxMap); if (StringUtils.isEmpty(result)) { throw new AppException("凭证生成失败!"); } return result; }else if(PayConstant.CHANNELWXMWEB.equals(channelId)){ Map<String, Object> wxMap = wxPayH5MWEB.getPayMap(); wxMap.put("out_trade_no", orderSn); wxMap.put("total_fee", "1".equals(wxPayH5MWEB.getPayMap().get("is_real_pay")) ? MoneyUtil.convertYuanToFen(String.valueOf(totalAmount)): 1); //MWEB支付是微信之外的浏览器,访问手机网站时使用的支付手段 Map<String, String> map = PayUtils.wxh5MWEBPay(wxMap); if (map == null) { throw new AppException("支付凭证生成失败!"); } return map; }else if(PayConstant.CHANNELWXJSAPI.equals(channelId)){ Map<String, Object> wxMap = wxPayH5JSAPI.getPayMap(); wxMap.put("out_trade_no", orderSn); wxMap.put("total_fee", "1".equals(wxPayH5MWEB.getPayMap().get("is_real_pay")) ? MoneyUtil.convertYuanToFen(String.valueOf(totalAmount)): 1); //JSAPI支付需要微信授权,前端引导用户到指定页面获取到微信给code,code五分钟内只能用一次, // 后端根据code获取openid,微信公众平台配置时需要配置支付目录与授权目录要注意域名是否与后台配置一致 String openId = PayUtils.getOpenId(code, wxMap); wxMap.put("openId",openId); Map<String, String> map = PayUtils.wxJSAPIPay(wxMap); if (map == null) { throw new AppException("支付凭证生成失败!"); } return map; } return null; }
以上三种支付方式都是需要和前端交互的网页类支付接口
然后看看H5的配置类:
@Configuration @PropertySource("classpath:H5Pay.properties") public class H5PayConfig { //是否真实支付 @Value("${is_real_pay}") private String is_real_pay; //支付宝H5 @Value("${alipay_h5_app_id}") private String alipay_h5_app_id; @Value("${alipay_h5_private_key}") private String alipay_h5_private_key; @Value("${alipay_h5_public_key}") private String alipay_h5_public_key; @Value("${alipay_h5_notify_url}") private String alipay_h5_notify_url; @Value("${aplipay_h5_return_url}") private String aplipay_h5_return_url; //微信H5 @Value("${wx_h5_appid}") private String wx_h5_appid; @Value("${wx_h5_appsecret}") private String wx_h5_appsecret; @Value("${wx_h5_partnerkey}") private String wx_h5_partnerkey; @Value("${wx_h5_mch_id}") private String wx_h5_mch_id; //微信H5交易类型是trade_type=MWEB @Value("${wx_mweb_notify_url}") private String wx_mweb_notify_url; @Value("${wx_mweb_return_url_h5}") private String wx_mweb_return_url_h5; //微信H5交易类型是trade_type=JSAPI @Value("${wx_jsapi_notify_url}") private String wx_jsapi_notify_url; @Value("${wx_jsapi_return_url_h5}") private String wx_jsapi_return_url_h5; /** * 微信H5支付,微信浏览器 * @return */ @Bean public WxPayH5JSAPI getWxPayH5JSAPI(){ WxPayH5JSAPI wxPayH5JSAPI = new WxPayH5JSAPI(); Map<String, String> map = new HashMap<>(); map.put("wx_h5_appid", wx_h5_appid); map.put("wx_h5_appsecret", wx_h5_appsecret); map.put("wx_h5_partnerkey", wx_h5_partnerkey); map.put("wx_h5_mch_id", wx_h5_mch_id); map.put("wx_jsapi_notify_url", wx_jsapi_notify_url); map.put("wx_jsapi_return_url_h5",wx_jsapi_return_url_h5); wxPayH5JSAPI.setPayMap(map); return wxPayH5JSAPI; } /** * 微信H5支付,非微信浏览器 * @return */ @Bean public WxPayH5MWEB getWxPayH5MWEB(){ WxPayH5MWEB wxPayH5Bean = new WxPayH5MWEB(); Map<String, String> map = new HashMap<>(); map.put("wx_h5_appid", wx_h5_appid); map.put("wx_h5_appsecret", wx_h5_appsecret); map.put("wx_h5_partnerkey", wx_h5_partnerkey); map.put("wx_h5_mch_id", wx_h5_mch_id); map.put("wx_mweb_notify_url", wx_mweb_notify_url); map.put("wx_mweb_return_url_h5",wx_mweb_return_url_h5); wxPayH5Bean.setPayMap(map); return wxPayH5Bean; } /** * 支付宝H5支付,非微信浏览器,微信不允许调用支付宝的支付接口 * @return */ @Bean public AliPayH5Bean getAlipayH5Info(){ AliPayH5Bean payBean = new AliPayH5Bean(); Map<String, String> map = new HashMap<>(); map.put("alipay_app_id", alipay_h5_app_id); map.put("alipay_private_key", alipay_h5_private_key); map.put("alipay_public_key", alipay_h5_public_key); map.put("notify_url", alipay_h5_notify_url); map.put("return_url", aplipay_h5_return_url); map.put("is_real_pay", is_real_pay); payBean.setPayMap(map); return payBean; } }
然后看看自定义实体类:
public class AliPayH5Bean { private Map payMap; public Map getPayMap() { return payMap; } public void setPayMap(Map payMap) { this.payMap = payMap; } } public class WxPayH5MWEB { private Map payMap; public Map getPayMap() { return payMap; } public void setPayMap(Map payMap) { this.payMap = payMap; } } public class WxPayH5JSAPI { private Map payMap; public Map getPayMap() { return payMap; } public void setPayMap(Map payMap) { this.payMap = payMap; } }
然后是pc扫码的支付:
@Autowired WxClient wxClient; @LoginRequired(isNeedLogin = true) @ApiOperation("pc端去支付,支付主接口,用于控制整体支付流程") @RequestMapping(value = "/alipay/submit", method = RequestMethod.GET) @ResponseBody public String goToPay(String orderSn, BigDecimal totalAmount, Integer channelId) { //根据订单创建支付信息并保存,这里真实开发不会使用金额传参,容易被篡改价格,但是为了方便暂时先这样写 Map<String, String> requestMap = savePayInfo(orderSn, totalAmount); String form=""; if(PayConstant.CHANNELALINATIVE.equals(channelId)){ //阿里支付 form = generateForm(requestMap, form); }else if (PayConstant.CHANNELWXNATIVE.equals(channelId)){ //微信支付 Map map = wxClient.getMap(); map.put("out_trade_no",orderSn); map.put("total_fee",totalAmount); String code_url = PayUtils.wxPcPay(map); String fileName = TimeUtils.getCurrentTime("yyyyMMddHHmmss") + ".png"; String img_path = String.valueOf(map.get("img_path")); //说明:商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url, // 商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。 // 注意:code_url有效期为2小时,过期后扫码不能再发起支付。 //将code_url的值生成二维码图片上传到七牛云,这里就不写上传七牛云的代码了, // img_path:保存二维码的基础全路径+"/qrcode/"+fileName:保存二维码的图片名称+code_url:保存到二维码里的内容 form = img_path + "/qrcode/" + fileName; }else{ //其他第三方支付(未接入) } //发送检查支付结果的消息队列(这里只检查了阿里的支付) payService.sendingPayMQ(orderSn,6,channelId); return form; } /** * 支付宝pc端扫码支付没有写到工具类里面了,支付宝生成表单 * @param requestMap * @param form * @return */ private String generateForm(Map<String, String> requestMap, String form) { //创建PC场景下单并支付请求对象 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request //设置同步返回地址,HTTP/HTTPS开头字符串 alipayRequest.setReturnUrl(PCPayConfig.alipay_pc_return_url); //支付宝服务器主动通知商户服务器里指定的页面http/https路径。 alipayRequest.setNotifyUrl(PCPayConfig.alipay_pc_notify_url);//在公共参数中设置回跳和通知地址 //填充业务参数 alipayRequest.setBizContent(JSON.toJSONString(requestMap)); try { //调用SDK生成表单 form = alipayClient.pageExecute(alipayRequest).getBody(); } catch (AlipayApiException e) { e.printStackTrace(); } return form; }
看看自定义的实体类:
public class WxClient { private Map map; public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } }
然后看看pc的配置类:
import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.javaliao.portal.bean.WxClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import java.util.HashMap; import java.util.Map; @Configuration @PropertySource("classpath:PCPay.properties") public class PCPayConfig { //阿里pc端 @Value("${alipay_pc_url}") private String alipay_pc_url; @Value("${alipay_pc_public_key}") public static String alipay_pc_public_key; @Value("${alipay_pc_private_key}") private String alipay_pc_private_key; @Value("${alipay_pc_app_id}") private String alipay_pc_app_id; @Value("${alipay_pc_notify_url}") public static String alipay_pc_notify_url; @Value("${alipay_pc_return_url}") public static String alipay_pc_return_url; //微信pc端 @Value("${wx_pc_appid}") public static String wx_pc_appid; @Value("${wx_pc_url}") public static String wx_pc_url; @Value("${wx_pc_appsecret}") public static String wx_pc_appsecret; @Value("${wx_pc_partnerkey}") public static String wx_pc_partnerkey; @Value("${wx_pc_mch_id}") public static String wx_pc_mch_id; @Value("${wx_pc_notify_url}") public static String wx_pc_notify_url; @Value("${img_path}") public static String img_path; public final static String format="json"; public final static String charset="utf-8"; public final static String sign_type="RSA2"; @Bean public WxClient wxClient(){ WxClient wxClient = new WxClient(); Map<String , Object> map = new HashMap<>(); map.put("wx_pc_appid",wx_pc_appid); map.put("wx_pc_appsecret",wx_pc_appsecret); map.put("wx_pc_partnerkey",wx_pc_partnerkey); map.put("wx_pc_mch_id",wx_pc_mch_id); map.put("wx_pc_notify_url",wx_pc_notify_url); map.put("wx_pc_url",wx_pc_url); map.put("img_path",img_path); wxClient.setMap(map); return wxClient; } /** * pc端支付宝支付Native * @return */ @Bean public AlipayClient alipayClient(){ return new DefaultAlipayClient(alipay_pc_url,alipay_pc_app_id,alipay_pc_private_key,format,charset,alipay_pc_public_key,sign_type); } }
支付的工具类:
package com.javaliao.portal.util; import com.alibaba.fastjson.JSON; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.domain.AlipayTradeAppPayModel; import com.alipay.api.domain.AlipayTradeWapPayModel; import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.request.*; import com.alipay.api.response.AlipayTradeAppPayResponse; import com.alipay.api.response.AlipayTradeRefundResponse; import com.javaliao.portal.bean.WXPubBean; import com.javaliao.portal.log4j.BaseLogger; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContexts; 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.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.net.ssl.SSLContext; import javax.xml.parsers.DocumentBuilder; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URLEncoder; import java.security.KeyStore; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; public class PayUtils { /** * 支付宝H5支付 * @param map * @return */ public static String alipayh5(Map<String, Object> map) { AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",map.get("alipay_app_id").toString(), map.get("alipay_private_key").toString(), "json", "utf-8", map.get("alipay_public_key").toString(),"RSA2"); AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); model.setOutTradeNo(map.get("out_trade_no").toString()); model.setSubject("委托检测服务"); model.setTotalAmount(map.get("total_fee").toString()); model.setBody("委托检测服务"); model.setTimeoutExpress("2m"); model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 创建手机网站API对应的request:AlipayTradeWapPayRequest;pc端的是AlipayTradePagePayRequest AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest(); alipayRequest.setReturnUrl(map.get("return_url").toString()); alipayRequest.setNotifyUrl(map.get("notify_url").toString()); alipayRequest.setBizModel(model); // 调用SDK生成表单 String form = null; try { form = alipayClient.pageExecute(alipayRequest).getBody(); BaseLogger.info("支付宝支付生成同步响应报文: " + form); /*直接将完整的表单html输出到页面。说明:手机网站支付alipay.trade.wap.pay: 对于页面跳转类API,SDK不会也无法像系统调用类API一样自动请求支付宝并获得结果, 而是在接受request请求对象后,为开发者生成前台页面请求需要的完整form表单的html(包含自动提交脚本), 商户直接将这个表单的String输出到http response中即可。*/ return form; } catch (AlipayApiException e) { e.printStackTrace(); } return null; } /** * 微信JSAPI支付 * @param map * @return */ public static Map<String, String> wxJSAPIPay(Map<String, Object> map) { SortedMap<String, String> paraMap = new TreeMap<String, String>(); String random = NumberUtils.createRandom(false, 32); paraMap.put("appid", String.valueOf(map.get("wx_h5_appid")));// "wxe5703c4e06a09cc8"; paraMap.put("attach", StringUtils.isNull(String.valueOf(map.get("attach"))) ? "商品购买" : map.get("attach") + ""); paraMap.put("body", StringUtils.isNull(String.valueOf(map.get("body"))) ? "商品购买" : map.get("body") + ""); paraMap.put("mch_id", String.valueOf(map.get("wx_h5_mch_id"))); paraMap.put("nonce_str", random); paraMap.put("openid", String.valueOf(map.get("openId"))); paraMap.put("out_trade_no", String.valueOf(map.get("out_trade_no"))); paraMap.put("spbill_create_ip", "172.168.0.1");//终端ip,在APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 paraMap.put("total_fee", String.valueOf(map.get("total_fee"))); paraMap.put("trade_type", "JSAPI"); paraMap.put("notify_url", map.get("wx_jsapi_notify_url") + ""); paraMap.put("sign_type", "MD5"); // 签名 RequestHandler reqHandler = new RequestHandler(null, null); reqHandler.init(String.valueOf(map.get("wx_h5_appid")), String.valueOf(map.get("wx_h5_appsecret")), String.valueOf(map.get("wx_h5_partnerkey"))); paraMap.put("sign", reqHandler.createSign(paraMap)); // 统一下单 String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; String xml = WXUtils.ArrayToXml(paraMap); String prepay_id = ""; try { // 提交 prepay_id = getPayPubNo(url, xml); if (prepay_id.equals("")) { return null; } } catch (Exception e) { e.printStackTrace(); System.out.println(e.getMessage()); return null; } SortedMap<String, String> packageParams = new TreeMap<String, String>(); // 需要再次签名,这里要加上时间戳 String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String prepay_id2 = "prepay_id=" + prepay_id; String packages = prepay_id2; packageParams.put("appId", String.valueOf(map.get("wx_h5_appid"))); packageParams.put("timeStamp", timestamp); packageParams.put("nonceStr", random); packageParams.put("package", packages); packageParams.put("signType", "MD5"); String finalsign = reqHandler.createSign(packageParams); packageParams.put("paySign", finalsign); return packageParams; } /** * 根据code获取微信openid * @param code * @param map * @return */ public static String getOpenId(String code,Map<String, Object> map) { WXPubBean wxUserInfo = WXUtils.getWXUserInfo((String) map.get("wx_pub_appid"), (String) map.get("wx_pub_appsecret"), code); BaseLogger.info("获取微信用户授权信息:"+wxUserInfo.toString()); if(wxUserInfo != null){ return wxUserInfo.getOpenid(); } return null; } /** * 提交url给微信获取响应信息 * @param url * @param xml * @return */ private static String getPayPubNo(String url, String xml) { String prepay_id = ""; try { String result = HttpUtils.getDataByJson(url, xml); if (result.indexOf("FAIL") != -1) { return prepay_id; } Document document = XmlUtils.getDocumentByXml(result); prepay_id = XmlUtils.getValueByTagName(document, "prepay_id"); } catch (Exception e) { e.printStackTrace(); System.out.println("------------------------------" + e.getMessage()); } return prepay_id; } /** * 微信h5mweb支付 * @param map * @return */ public static Map<String, String> wxh5MWEBPay(Map<String, Object> map) { // 设置微信原生支付所需参数 // 封装 SortedMap<String, String> paraMap = new TreeMap<String, String>(); paraMap.put("appid", String.valueOf(map.get("wx_h5_appid"))); paraMap.put("attach", StringUtils.isNull(map.get("attach") + "") ? "商品购买" : map.get("attach") + ""); paraMap.put("body", StringUtils.isNull(map.get("body") + "") ? "商品购买" : map.get("body") + ""); paraMap.put("mch_id", String.valueOf(map.get("wx_h5_mch_id"))); paraMap.put("nonce_str", NumberUtils.createRandom(false, 32)); paraMap.put("out_trade_no", String.valueOf(map.get("out_trade_no"))); paraMap.put("spbill_create_ip", "172.168.0.1"); paraMap.put("total_fee", String.valueOf(map.get("total_fee"))); paraMap.put("trade_type", "MWEB"); paraMap.put("notify_url", String.valueOf(map.get("wx_mweb_notify_url"))); paraMap.put("sign_type", "MD5"); // 签名 RequestHandler reqHandler = new RequestHandler(null, null); reqHandler.init(String.valueOf(map.get("wx_h5_appid")), String.valueOf(map.get("wx_h5_appsecret")), String.valueOf(map.get("wx_h5_partnerkey"))); String sign = reqHandler.createSign(paraMap); paraMap.put("sign", sign); // 统一下单 String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; String xml = WXUtils.ArrayToXml(paraMap); String mweb_url = ""; try { // 提交 mweb_url = getPayNo(url, xml,map); if (mweb_url.equals("")) { return null; } } catch (Exception e1) { e1.printStackTrace(); return null; } SortedMap<String, String> packageParams = new TreeMap<String, String>(); //直接将拼接好的url发给前端即可,后端的支付代码就没啥事了 packageParams.put("mweb_url", mweb_url); return packageParams; } /** * 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")); 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; } } /** * 微信Native支付 * @param map * @return */ public static String wxPcPay(Map<String, Object> map) { // 设置微信原生支付所需参数 String nonce_str = NumberUtils.createRandom(false, 32); // 封装 SortedMap<String, String> paraMap = new TreeMap<String, String>(); paraMap.put("appid",String.valueOf(map.get("wx_pc_appid"))); paraMap.put("attach",StringUtils.isNull(map.get("attach") + "") ? "商品购买" : map.get("attach") + ""); paraMap.put("body",StringUtils.isNull(map.get("body") + "") ? "商品购买" : map.get("body") + ""); paraMap.put("mch_id",String.valueOf(map.get("wx_pc_mch_id"))); paraMap.put("nonce_str",nonce_str); paraMap.put("out_trade_no",String.valueOf(map.get("out_trade_no"))); paraMap.put("spbill_create_ip","172.168.0.1");//用户点击微信支付的浏览器的IP paraMap.put("total_fee",String.valueOf(map.get("total_fee"))); paraMap.put("trade_type","NATIVE");//扫码支付类型 paraMap.put("notify_url",String.valueOf(map.get("wx_pc_notify_url"))); paraMap.put("sign_type", "MD5"); // 签名 RequestHandler reqHandler = new RequestHandler(null, null); reqHandler.init(String.valueOf(map.get("wx_pc_appid")), String.valueOf(map.get("wx_pc_appsecret")), String.valueOf(map.get("wx_pc_partnerkey"))); String sign = reqHandler.createSign(paraMap); paraMap.put("sign", sign); // 统一下单 String xml = WXUtils.ArrayToXml(paraMap); System.out.println(xml); String code_url = ""; try { String result = HttpUtils.getDataByJson(String.valueOf(map.get("wx_pc_url")), xml); BaseLogger.info("微信支付生成同步响应报文:" + result); if (result.indexOf("FAIL") != -1) { return null; } Document document = XmlUtils.getDocumentByXml(result); code_url = XmlUtils.getValueByTagName(document, "code_url"); return code_url; } catch (Exception e) { e.printStackTrace(); System.out.println("------------------------------" + e.getMessage()); } return null; } public static String getPayNo(String url, String xmlParam,Map<String, Object> maps) { String prepay_id = ""; try { String result = HttpUtils.getDataByJson(url, xmlParam); if (result.indexOf("FAIL") != -1) { return prepay_id; }else if(result.indexOf("SUCCESS") != -1){ //以下内容是返回前端页面的json数据 String mweb_url = "";//跳转链接 Map<String, String> map = WXPayUtil.xmlToMap(result); mweb_url = map.get("mweb_url"); //支付完返回浏览器跳转的地址,如跳到查看订单页面 String redirect_url = maps.get("wx_mweb_return_url_h5") + "?payWay=1&orderId=" + maps.get("out_trade_no") + ""; String redirect_urlEncode = URLEncoder.encode(redirect_url,"utf-8");//对上面地址urlencode mweb_url = mweb_url + "&redirect_url=" + redirect_urlEncode;//拼接返回地址 return mweb_url; } } catch (Exception e) { e.printStackTrace(); System.out.println("------------------------------" + e.getMessage()); } return prepay_id; } }
其他工具类:微信的一些工具类可以去微信官方的demo里面找都是现成的,阿里的也一样。
这里给上一个链接:https://www.cnblogs.com/javawxid/p/11852918.html
里面是我做支付时踩到的一些坑以及解决方案
说实话代码没多少,坑特别多,难度也不是很高,但是需要细心看官方文档。
如果还有什么问题,可以关注我,或者私聊我