标签:扫码 Java String 微信 return 支付 import public
摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路。
一:微信支付接入准备工作:
首先,微信支付,只支持企业用户,个人用户是不能接入微信支付的,所以要想接入微信支付,首先需要有微信公众号,这个的企业才能申请。有了微信公众号,就能申请微信支付的相关内容,所以在准备开始写代码之前需要先把下面的这些参数申请好:公众账号ID、微信支付商户号、API密钥、AppSecret是APPID对应的接口密码、回调地址(回调必须保证外网能访问到此地址)、发起请求的电脑IP
二:微信支付流程说明:
有了上面提到的这些参数,那我们就可以接入微信支付了,下面我来看下微信支付的官方文档(https://pay.weixin.qq.com/wiki/doc/api/index.html)、访问该地址可以看到有多种支付方式可以选择,我们这里选择扫码支付的方式(https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1)
这里我们选择模式二,下面看下模式二的时序图,如下图:
模式二与模式一相比,流程更为简单,不依赖设置的回调支付URL。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。
业务流程说明:
(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。
三:微信支付所需要的maven依赖:
<!--生成二维码jar--> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.2.1</version> </dependency>
四:微信支付调用统一下单接口的核心代码
3.1:微信支付工具类:
HttpUtil.java
package com.micai.springboot.util.pay.wx; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; /** * http工具类,负责发起post请求并获取的返回 */ public class HttpUtil { private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class); private final static int CONNECT_TIMEOUT = 5000; // in milliseconds private final static String DEFAULT_ENCODING = "UTF-8"; public static String postData(String urlStr, String data){ return postData(urlStr, data, null); } public static String postData(String urlStr, String data, String contentType){ BufferedReader reader = null; try { URL url = new URL(urlStr); URLConnection conn = url.openConnection(); conn.setDoOutput(true); conn.setConnectTimeout(CONNECT_TIMEOUT); conn.setReadTimeout(CONNECT_TIMEOUT); if(contentType != null) conn.setRequestProperty("content-type", contentType); OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING); if(data == null) data = ""; writer.write(data); writer.flush(); writer.close(); reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING)); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); sb.append("\r\n"); } return sb.toString(); } catch (IOException e) { logger.error("Error connecting to " + urlStr + ": " + e.getMessage()); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
MD5Util.java
package com.micai.springboot.util.pay.wx; import java.security.MessageDigest; public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; }
PayConfigUtil.java
package com.micai.springboot.util.pay.wx; public class PayConfigUtil { //初始化 // public final static String APP_ID = "11111111111"; //公众账号appid(改为自己实际的) // public final static String APP_SECRET = ""; // public final static String MCH_ID = "111111"; //商户号(改为自己实际的) // public final static String API_KEY = "11111111111"; //(改为自己实际的)key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 //统一下单 public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // public final static String NOTIFY_URL = "http://xxxxxxx"; //微信支付回调接口,就是微信那边收到(改为自己实际的) // //企业向个人账号付款的URL // public final static String SEND_EED_PACK_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // // public final static String CREATE_IP = "113.69.246.11";//发起支付ip(改为自己实际的) }
PayToolUtil.java
package com.micai.springboot.util.pay.wx; import java.text.SimpleDateFormat; import java.util.*; public class PayToolUtil { /** * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 * @return boolean */ public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); String v = (String)entry.getValue(); if(!"sign".equals(k) && null != v && !"".equals(v)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + API_KEY); //算出摘要 String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); String tenpaySign = ((String)packageParams.get("sign")).toLowerCase(); //System.out.println(tenpaySign + " " + mysign); return tenpaySign.equals(mysign); } /** * 创建sign签名 * @param characterEncoding 编码格式 * @param packageParams 请求参数 * @param API_KEY API密钥 * @return */ public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) 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=" + API_KEY); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } /** * 将请求参数转换为xml格式的string * @param parameters 请求参数 * @return 转换后的字符串 */ public static String getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) { sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">"); } else { sb.append("<" + k + ">" + v + "</" + k + ">"); } } sb.append("</xml>"); return sb.toString(); } /** * 取出一个指定长度大小的随机正整数 * @param length int 设定所取出随机数的长度。length小于11 * @return int 返回生成的随机数。 */ public static int buildRandom(int length) { int num = 1; double random = Math.random(); if (random < 0.1) { random = random + 0.1; } for (int i = 0; i < length; i++) { num = num * 10; } return (int) ((random * num)); } /** * 获取当前时间 yyyyMMddHHmmss * @return */ public static String getCurrTime() { Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); return outFormat.format(now); } }
QRUtil.java
package com.micai.springboot.util.pay.wx; import com.google.zxing.common.BitMatrix; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.OutputStream; /** * 二维码生产工具类 */ public class QRUtil { private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; private QRUtil() {} public static BufferedImage toBufferedImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); } } return image; } public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, file)) { throw new IOException("Could not write an image of format " + format + " to " + file); } } public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, stream)) { throw new IOException("Could not write an image of format " + format); } } }
XMLUtil4jdom.java
package com.micai.springboot.util.pay.wx; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class XMLUtil4jdom { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map doXMLParse(String strxml) throws JDOMException, IOException { strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if(null == strxml || "".equals(strxml)) { return null; } Map<String, String> m = new HashMap<String, String>(); 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 = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if(children.isEmpty()) { v = e.getTextNormalize(); } else { v = XMLUtil4jdom.getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; } /** * 获取子结点的xml * @param children * @return String */ public static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if(!children.isEmpty()) { Iterator it = children.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if(!list.isEmpty()) { sb.append(XMLUtil4jdom.getChildrenText(list)); } sb.append(value); sb.append("</" + name + ">"); } } return sb.toString(); } }
3.2:微信支付实体对象:
WxpayVo.java
package com.micai.springboot.vo.pay; import java.io.Serializable; /** * @Auther: zhaoxinguo * @Date: 2018/8/31 11:34 * @Description: */ public class WxpayVo implements Serializable { private String app_id;//公众账号ID private String mch_id;//微信支付商户号 private String key;//API密钥 private String app_secret;//AppSecret是APPID对应的接口密码 private String out_trade_no;// 商户订单号 private String currTime; private String strTime; private String strRandom; private String nonce_str;//随机字符串 private String spbill_create_ip; private String notify_url; private String trade_type; private String total_fee; public String getApp_id() { return app_id; } public void setApp_id(String app_id) { this.app_id = app_id; } public String getMch_id() { return mch_id; } public void setMch_id(String mch_id) { this.mch_id = mch_id; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getApp_secret() { return app_secret; } public void setApp_secret(String app_secret) { this.app_secret = app_secret; } public String getOut_trade_no() { return out_trade_no; } public void setOut_trade_no(String out_trade_no) { this.out_trade_no = out_trade_no; } public String getCurrTime() { return currTime; } public void setCurrTime(String currTime) { this.currTime = currTime; } public String getStrTime() { return strTime; } public void setStrTime(String strTime) { this.strTime = strTime; } public String getStrRandom() { return strRandom; } public void setStrRandom(String strRandom) { this.strRandom = strRandom; } public String getNonce_str() { return nonce_str; } public void setNonce_str(String nonce_str) { this.nonce_str = nonce_str; } public String getSpbill_create_ip() { return spbill_create_ip; } public void setSpbill_create_ip(String spbill_create_ip) { this.spbill_create_ip = spbill_create_ip; } public String getNotify_url() { return notify_url; } public void setNotify_url(String notify_url) { this.notify_url = notify_url; } public String getTrade_type() { return trade_type; } public void setTrade_type(String trade_type) { this.trade_type = trade_type; } public String getTotal_fee() { return total_fee; } public void setTotal_fee(String total_fee) { this.total_fee = total_fee; } }
3.3:微信支付业务对象:
PayBaseController.java
package com.micai.springboot.controller.pay; import com.micai.springboot.base.BaseController; import org.springframework.beans.factory.annotation.Value; /** * @Auther: zhaoxinguo * @Date: 2018/8/31 13:40 * @Description: */ public abstract class PayBaseController extends BaseController { // 支付宝支付参数配置 // @Value("${ALIPAY.APPID}") protected String app_id;//应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号 @Value("${ALIPAY.PRIVATEKEY}") protected String merchant_private_key;//商户私钥,您的PKCS8格式RSA2私钥 @Value("${ALIPAY.PUBLICKEY}") protected String alipay_public_key;//支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。 @Value("${ALIPAY.NOTIFY_URL}") protected String notify_url;//服务器异步通知页面路径 @Value("${ALIPAY.RETURNA_URL}") protected String return_url;//页面跳转同步通知页面路径 @Value("${ALIPAY.SIGN}") protected String sign_type = "RSA2";//签名方式 protected String charset = "utf-8";//字符编码格式 @Value("${ALIPAY.GATEWAY_URL}") protected String gateway_url;//支付宝网关 // 微信支付参数配置 // @Value("${WXPAY.APPID}") protected String APPID;//公众账号ID @Value("${WXPAY.MCHID}") protected String MCHID;//微信支付商户号 @Value("${WXPAY.KEY}") protected String KEY;//API密钥 @Value("${WXPAY.APPSECRET}") protected String APPSECRET;//AppSecret是APPID对应的接口密码 @Value("${WXPAY.NOTIFY_URL}") protected String NOTIFY_URL;//回调地址。测试回调必须保证外网能访问到此地址 @Value("${WXPAY.CREATE_IP}") protected String CREATE_IP;//发起请求的电脑IP }
WxpayController.java
package com.micai.springboot.controller.pay; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.micai.springboot.util.pay.wx.*; import com.micai.springboot.vo.pay.WxpayVo; import org.jdom.JDOMException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.*; /** * @Auther: zhaoxinguo * @Date: 2018/8/31 10:37 * @Description: 微信支付后台接口 */ @RestController @RequestMapping(value = "/wxpay") public class WxpayController extends PayBaseController { /** * 微信支付->扫码支付(模式二)->统一下单->微信二维码 * @return */ @GetMapping("/qrcode") public void wxpayPay(HttpServletResponse response) { String urlCode = null; // 获取订单信息 WxpayVo vo = new WxpayVo(); String out_trade_no = UUID.randomUUID().toString().replace("-", ""); vo.setOut_trade_no(out_trade_no); // 账号信息 vo.setApp_id(APPID); vo.setMch_id(MCHID); vo.setKey(KEY); String currTime = PayToolUtil.getCurrTime(); vo.setCurrTime(currTime); String strTime = currTime.substring(8, currTime.length()); vo.setStrTime(strTime); String strRandom = String.valueOf(PayToolUtil.buildRandom(4)); vo.setStrRandom(strRandom); String nonce_str = strTime + strRandom; vo.setNonce_str(nonce_str); vo.setSpbill_create_ip(CREATE_IP); vo.setNotify_url(NOTIFY_URL); vo.setTrade_type("NATIVE"); String total_fee = "1"; vo.setTotal_fee(total_fee);//价格的单位为分 SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>(); packageParams.put("appid", APPID);//公众账号ID packageParams.put("mch_id", MCHID);//商户号 packageParams.put("nonce_str", nonce_str);//随机字符串 packageParams.put("body", "资源"); //商品描述 packageParams.put("out_trade_no", out_trade_no);//商户订单号 packageParams.put("total_fee", total_fee); //标价金额 订单总金额,单位为分 packageParams.put("spbill_create_ip", CREATE_IP);//终端IP APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP packageParams.put("notify_url", NOTIFY_URL);//通知地址 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数 packageParams.put("trade_type", "NATIVE");//交易类型 NATIVE 扫码支付 // 签名 String sign = PayToolUtil.createSign("UTF-8", packageParams, KEY); packageParams.put("sign", sign); // 将请求参数转换为xml格式的string String requestXML = PayToolUtil.getRequestXml(packageParams); logger.info("requestXML:{}", requestXML); // 调用微信支付统一下单接口 String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML); logger.info("resXml: {}", resXml); // 解析微信支付结果 Map map = null; try { map = XMLUtil4jdom.doXMLParse(resXml); logger.info("map: {}", map); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // 返回微信支付的二维码连接 urlCode = (String) map.get("code_url"); logger.info("urlCode:{}", urlCode); try { int width = 300; int height = 300; //二维码的图片格式 String format = "gif"; Hashtable hints = new Hashtable(); //内容所使用编码 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); BitMatrix bitMatrix; bitMatrix = new MultiFormatWriter().encode(urlCode, BarcodeFormat.QR_CODE, width, height, hints); QRUtil.writeToStream(bitMatrix, format, response.getOutputStream()); } catch (WriterException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 微信支付-回调 * @param request * @param response */ @PostMapping("/notify") public String wxpayNotify(HttpServletRequest request, HttpServletResponse response) { //读取参数 InputStream inputStream ; StringBuffer sb = null; try { sb = new StringBuffer(); inputStream = request.getInputStream(); String s ; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null){ sb.append(s); } in.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } //解析xml成map Map<String, String> map = new HashMap<String, String>(); try { map = XMLUtil4jdom.doXMLParse(sb.toString()); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //过滤空 设置 TreeMap SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>(); Iterator it = map.keySet().iterator(); while (it.hasNext()) { String parameter = (String) it.next(); String parameterValue = map.get(parameter); String v = ""; if(null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } //判断签名是否正确 if(PayToolUtil.isTenpaySign("UTF-8", packageParams, KEY)) { //------------------------------ //处理业务开始 //------------------------------ String resXml = ""; if("SUCCESS".equals((String)packageParams.get("result_code"))){ // 这里是支付成功 //////////执行自己的业务逻辑//////////////// String mch_id = (String)packageParams.get("mch_id"); String openid = (String)packageParams.get("openid"); String is_subscribe = (String)packageParams.get("is_subscribe"); String out_trade_no = (String)packageParams.get("out_trade_no"); String total_fee = (String)packageParams.get("total_fee"); //////////执行自己的业务逻辑//////////////// //暂时使用最简单的业务逻辑来处理:只是将业务处理结果保存到session中 //(根据自己的实际业务逻辑来调整,很多时候,我们会操作业务表,将返回成功的状态保留下来) request.getSession().setAttribute("_PAY_RESULT", "OK"); logger.info("支付成功"); //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; return ("fail"); } //------------------------------ //处理业务完毕 //------------------------------ try { BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } else{ logger.info("通知签名验证失败"); } return ("success"); } }
五:访问支付URL:http://dvnq2b.natappfree.cc/wxpay/qrcode、回返回微信的支付二维码,用户通过微信的扫一扫,就可以扫码支付了、这里注意:由于微信回调需要能外网访问的域名,所以我们这里使用了一个内网穿透工具natapp,具体怎么实现内网穿透,直接官网就可以了很简单,这是附上natapp的官网地址:https://natapp.cn/、配置好内容穿透工具后,修改下微信回调的配置文件,如下:
## 微信支付配置 测试环境(如果需要测试,改成自己的正式环境) ##
WXPAY.APPID=wx82b23234467t34347661
WXPAY.MCHID=1234dsdf5345
WXPAY.KEY=rtert345dfgh345fg34ddfg345fdg
WXPAY.APPSECRET=36546dfghdfgdszdfsdffg45354dfg
WXPAY.NOTIFY_URL= http://dvnq2b.natappfree.cc/wxpay/notify
WXPAY.CREATE_IP=192.168.0.190
访问支付url返回微信二维码,如下图:
使用微信的扫一扫,扫码支付,如下图:
微信支付回调,如下图:
这里对于回调只是简单输出了日志,你可以根据自己的实际情况选择做相应的处理,一般都是对订单的支付状态做更新。
六:总结:
经过上面的所以流程,相信大家都明白了微信支付的流程,这里我们对上面的流程做个总结,要想接入微信支付,必须是企业用户才行,个人用户不支持,所以在开始写代码之前,要和公司的相关负责人申请好微信支付的相关配置参数,有了这些才能进行下面的工作,这里最重要的一点就是微信支付的回调了,回调,在生产环境必须配置可以外网访问的URL,同时域名必须是备案过的,二级域名也可以,这里我们为了方便测试,所以就使用了内网穿透工具natapp,该工具既有免费通道也有收费通道,收费通道也很便宜,如果只是测试,免费通道就够用了,另外还有一点要注意,就是微信支付的回调,默认微信是回调好几次的,所以会有重复回调的问题,这里留给大家一个思考,怎么防止微信的多次回调,以免影响业务,希望有兴趣的小伙伴可以留言交流。以上就是微信支付(扫码支付模式二)的全部内容了,有想要完全源代码的小伙伴,可以加群交流,群号:715224124。
标签:扫码,Java,String,微信,return,支付,import,public 来源: https://www.cnblogs.com/sxdtzhaoxinguo/p/11325197.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。