勤奋鸟旗下 软件定制开发 安全交付平台!一次合作,终身售后!全程项目经理一对一跟进测试!公司以自研团队结合搭档圈,为用户提供安全快速稳定的软件源码开发服务!

Java微信扫码支付流程重要点

2024-09-04 17:20:52
复制链接

1844

微信扫码支付。简单来说,就是你把微信支付需要的信息,生成到二维码图片中。通过微信扫一扫,发起支付。我们需要做的就是二件事:

  一是:按照微信扫码支付规则生成二维码信息.

  二是:微信没有提供生成二维码图片的接口。需要我们自己把二维码信息生成到二维码图片中。

1.模式选择:

微信扫码支付,有两种模式,文档中有介绍。第二种模式,微信接口会返回二维码信息给我们。而第一种模式则需要我们自己去生成二维码信息。会有些麻烦。尤其是参数大小写,还有签名的问题,容易出错。总的来说第二种模式比第一种模式简单。因此我采用的是第二种模式,比较通用。京东与携程亦用的是第二种模式。

2.调用统一下单接口获取带有二维码信息的url:(模式二)

模式二的微信扫码支付,需要先调用微信的统一下单接口,生成预交易单。(参数传递与接收都是XML 数据格式。)

正确调用后,会返回含有交易标示ID,和二维码链接的URL。

复制代码
HashMap paramMap = Maps.newHashMap(); 
paramMap.put("trade_type", "NATIVE"); //交易类型
paramMap.put("spbill_create_ip",localIp()); //本机的Ip
paramMap.put("product_id", payOrderIdsStr); // 商户根据自己业务传递的参数 必填
paramMap.put("body", orderSubject);         //描述
paramMap.put("out_trade_no", payOrderIdsStr); //商户 后台的贸易单号
paramMap.put("total_fee", "" + totalCount); //金额必须为整数  单位为分
paramMap.put("notify_url", "http://" + getAccessDomain() + "/wx_pay_notify"); //支付成功后,回调地址     
paramMap.put("appid", siteConfig.getWxPayAppId()); //appid
paramMap.put("mch_id", siteConfig.getWxPayMchId()); //商户号      
paramMap.put("nonce_str", CommonUtilPub.createNoncestr(32));  //随机数  
paramMap.put("sign",CommonUtilPub.getSign(paramMap,siteConfig.getWxPayPartnerKey()));//根据微信签名规则,生成签名 
String xmlData = CommonUtilPub.mapToXml(paramMap);//把参数转换成XML数据格式
复制代码
复制代码
 1 /**
 2      * 获取本机Ip 
 3      *  
 4      *  通过 获取系统所有的networkInterface网络接口 然后遍历 每个网络下的InterfaceAddress组。
 5      *  获得符合 InetAddress instanceof Inet4Address 条件的一个IpV4地址
 6      * @return
 7      */
 8     @SuppressWarnings("rawtypes")
 9     private String localIp(){
10         String ip = null;
11         Enumeration allNetInterfaces;
12         try {
13             allNetInterfaces = NetworkInterface.getNetworkInterfaces();            
14             while (allNetInterfaces.hasMoreElements()) {
15                 NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
16                 List InterfaceAddress = netInterface.getInterfaceAddresses();
17                 for (InterfaceAddress add : InterfaceAddress) {
18                     InetAddress Ip = add.getAddress();
19                     if (Ip != null && Ip instanceof Inet4Address) {
20                         ip = Ip.getHostAddress();
21                     }
22                 }
23             }
24         } catch (SocketException e) {
25             // TODO Auto-generated catch block        
26             logger.warn("获取本机Ip失败:异常信息:"+e.getMessage());
27         }
28         return ip;
29     }
复制代码

 

 成功时返回的XML数据为:

复制代码
 1 xml>return_code>SUCCESS]]>return_code>
 2 return_msg>OK]]>return_msg>
 3 appid>wx49342bda0ef105dd]]>appid>
 4 mch_id>10019460]]>mch_id>
 5 nonce_str>UneMQd4qWQd0hJ4L]]>nonce_str>
 6 sign>C621A9C586C1F0397D4C6B8003E0CBCE]]>sign>
 7 result_code>SUCCESS]]>result_code>
 8 prepay_id>wx2015070818251790742fea5e0865034508]]>prepay_id>
 9 trade_type>NATIVE]]>trade_type>
10 code_url>weixin://wxpay/bizpayurl?pr=AOFEsxf]]>code_url>
11 xml>
复制代码

解析XML 获取 code_url:

复制代码
 1 String resXml = HtmlUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlData);
 2 Document dd = null;
 3 String code_url=null;
 4 try {
 5     dd = DocumentHelper.parseText(resXml);
 6   } catch (DocumentException e) {
 7        return ""; 
 8 }
 9 if (dd != null) {
10     Element root = dd.getRootElement();
11     if (root == null) {
12     return "";
13     }
14     Element codeUrl = root.element("code_url");
15     if (codeUrl == null) {
16     return "";
17     }  
18     code_url = codeUrl.getText();  //解析 xml 获得 code_url
19 }
复制代码

 postData方法:

复制代码
 1     private static Logger logger_ = LoggerFactory.getLogger(HtmlUtil.class);
 2 
 3     private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
 4     private final static String DEFAULT_ENCODING = "UTF-8";
 5     
 6     public static String postData(String urlStr, String data){
 7         return postData(urlStr, data, null);
 8     }
 9     
10     public static String postData(String urlStr, String data, String contentType) {
11         BufferedReader reader = null;
12         try {
13             URL url = new URL(urlStr);
14             URLConnection conn = url.openConnection();
15             conn.setDoOutput(true);
16             conn.setConnectTimeout(CONNECT_TIMEOUT);
17             conn.setReadTimeout(CONNECT_TIMEOUT);
18             if(StringUtils.isNotBlank(contentType))
19                 conn.setRequestProperty("content-type", contentType);
20             OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
21             if(data == null)
22                 data = "";
23             writer.write(data); 
24             writer.flush();
25             writer.close();  
26 
27             reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
28             StringBuilder sb = new StringBuilder();
29             String line = null;
30             while ((line = reader.readLine()) != null) {
31                 sb.append(line);
32                 sb.append("\r\n");
33             }
34             return sb.toString();
35         } catch (IOException e) {
36             logger_.error("Error connecting to " + urlStr + ": " + e.getMessage());
37         } finally {
38             try {
39                 if (reader != null)
40                     reader.close();
41             } catch (IOException e) {
42             }
43         }
44         return null;
45     }
复制代码

 

3.动态生成二维码图片

使用的是google ZXing库。 提供一个 jar 地址 直接引入到自己项目即可。http://download.csdn.net/detail/gonwy/7658135  

 页面代码:

img src="qr_code.img?code_url= ${code_url}#if>" style="width:300px;height:300px;"/>

java 代码:

1
2
3
4
5
6
7
8
9
10
/**
   * 生成二维码图片并直接以流的形式输出到页面
   * @param code_url
   * @param response
   */
  @RequestMapping("qr_code.img")
  @ResponseBody
  public void getQRCode(String code_url,HttpServletResponse response){
    GenerateQrCodeUtil.encodeQrcode(code_url, response);
  }
复制代码
 1 /**
 2      * 生成二维码图片 不存储 直接以流的形式输出到页面
 3      * @param content
 4      * @param response
 5      */
 6     @SuppressWarnings({ "unchecked", "rawtypes" })
 7     public static void encodeQrcode(String content,HttpServletResponse response){
 8         if(StringUtils.isBlank(content))
 9             return;
10         MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
11         Map hints = new HashMap();
12         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
13         BitMatrix bitMatrix = null;
14         try {
15             bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300,hints);
16             BufferedImage image = toBufferedImage(bitMatrix);
17             //输出二维码图片流
18             try {
19                 ImageIO.write(image, "png", response.getOutputStream());
20             } catch (IOException e) {
21                 // TODO Auto-generated catch block
22                 e.printStackTrace();
23             }
24         } catch (WriterException e1) {
25             // TODO Auto-generated catch block
26             e1.printStackTrace();
27         }         
28     }
复制代码

生成二维码图片完整代码:(这里生成的是黑白相间的二维码,没有插入图片。有兴趣的,可以去研究一下)

复制代码
  1 import java.awt.image.BufferedImage;   
  2 import java.io.File;
  3 import java.io.IOException;
  4 import java.util.HashMap;
  5 import java.util.Map;
  6 
  7 import javax.imageio.ImageIO;
  8 import javax.servlet.http.HttpServletResponse;
  9 
 10 import org.apache.commons.lang3.StringUtils;
 11 
 12 import com.google.zxing.BarcodeFormat;
 13 import com.google.zxing.EncodeHintType;
 14 import com.google.zxing.MultiFormatWriter;
 15 import com.google.zxing.WriterException;
 16 import com.google.zxing.common.BitMatrix;
 17 /**
 18  * 生成二维码
 19  *2015年7月7日
 20  * @author clc
 21  *
 22  */
 23 public class GenerateQrCodeUtil {
 24     private static final int WHITE = 0xFFFFFFFF;
 25     private static final int BLACK = 0xFF000000;
 26     private static final String UPLOAD ="upload";
 27     /**
 28      * 静态生成二维码 存储在磁盘上
 29      * @param content  //二维码信息
 30      * @param contextPath //上下文相对路径
 31      * @param realPath    //磁盘真实路径
 32      * @param subPath     //子路径
 33      * @return
 34      */
 35     @SuppressWarnings({ "rawtypes", "unchecked" })
 36     public static String generateQrcode(String content,String contextPath,String realPath,String subPath){
 37         if(content==null || realPath==null)
 38             return null;
 39         String fileName = generateFileName(content.getBytes())+".png";
 40         String url = "/" + UPLOAD + contextPath + "/" + subPath + "/" + fileName;//图片在项目中存储的相对路径
 41         String filePath = url;
 42         //如果是部署在服务器上的情况,则需要到webapps/下面的upload目录
 43         if (StringUtils.isNotBlank(contextPath) || realPath.endsWith("root")) {    
 44             filePath = ".." + url;
 45         }
 46         MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
 47         Map hints = new HashMap();
 48         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
 49         BitMatrix bitMatrix = null;
 50         try {
 51             bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300,hints);
 52             File file1 = new File(realPath,filePath); //创建存储图片的文件
 53             try {
 54                 GenerateQrCodeUtil.writeToFile(bitMatrix, "png", file1); //存储二维码图片
 55                 return filePath;
 56             } catch (IOException e) {
 57                 // TODO Auto-generated catch block
 58                 e.printStackTrace();
 59             }
 60         } catch (WriterException e1) {
 61             // TODO Auto-generated catch block
 62             e1.printStackTrace();
 63         }         
 64         return null;
 65     }
 66     private static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
 67         BufferedImage image = toBufferedImage(matrix);
 68         if (!ImageIO.write(image, format, file)) {
 69             throw new IOException("Could not write an image of format " + format + " to " + file);
 70         }
 71     }
 72     private static BufferedImage toBufferedImage(BitMatrix matrix) {
 73          int width = matrix.getWidth();
 74          int height = matrix.getHeight();
 75          BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 76          for (int x = 0; x ) {
 77            for (int y = 0; y ) {
 78              image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
 79            }
 80          }
 81          return image;
 82     }    
 83     private static String generateFileName(byte[] content) {
 84         return CryptUtil.md5(content);  //md5加密
 85     }
 86     
 87     /**
 88      * 生成二维码图片 不存储 直接以流的形式输出到页面
 89      * @param content
 90      * @param response
 91      */
 92     @SuppressWarnings({ "unchecked", "rawtypes" })
 93     public static void encodeQrcode(String content,HttpServletResponse response){
 94         if(StringUtils.isBlank(content))
 95             return;
 96         MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
 97         Map hints = new HashMap();
 98         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
 99         BitMatrix bitMatrix = null;
100         try {
101             bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300,hints);
102             BufferedImage image = toBufferedImage(bitMatrix);
103             //输出二维码图片流
104             try {
105                 ImageIO.write(image, "png", response.getOutputStream());
106             } catch (IOException e) {
107                 // TODO Auto-generated catch block
108                 e.printStackTrace();
109             }
110         } catch (WriterException e1) {
111             // TODO Auto-generated catch block
112             e1.printStackTrace();
113         }         
114     }
115 }
复制代码

 

然后生成的图片,通过微信扫码就可以发起支付了。

支付成功后,微信会调用,你之前设置的回调函数地址。并且会把你之前传给微信的商户自定义参数带给你,以帮助商户完成余下业务流程。

17330196230 13230981129

多线程同步开发
项目经理1v1跟进
源码定制交付
一次合作/终身售后

微信扫码登录/注册

提示

您的诉求已经提交请等待工作人员联系,快速通过请联系管理员

微信扫一扫快速联系

用户协议

欢迎访问我们的网站!我们非常重视用户的隐私权和信息安全,因此制定了以下用户协议,以明确我们与您之间的关系以及您在使用本网站时应遵守的条款。请您仔细阅读并同意本协议的所有条款,以便您能够合法、安全地使用本网站。如果您不同意本协议的任何内容,请立即停止使用本网站。

  1. 服务说明:本网站是一个提供定制软件开发服务和在线找技术搭档的互联网平台。我们保留随时更改、更新或暂停本网站的权利。我们会尽力确保网站的正常运行,但对于因技术问题、系统维护或其他原因导致的网站暂时不可用,我们不承担任何责任。

  2. 用户注册:用户需要通过提供手机号、微信扫码和其他必要信息来注册一个账户。您有责任保护您的用户名和密码,不得将其透露给任何第三方。对于因您的用户名和密码被泄露而导致的任何损失或损害,我们将不承担责任。

  3. 用户行为规范:用户应遵守中华人民共和国相关法律法规,不得发布或传播违法信息、侵犯他人权益的内容。用户应对其发布的内容负责,并承担因发布不当内容而引起的任何法律责任。

  4. 版权声明:本网站所包含的所有文字、图片、音频、视频等素材的著作权均归本网站所有(会员用户上传的默认承诺为不侵权的合法自有技术成果,本网站审核信息后可展示,所有权不归本网站)。未经本网站书面许可,任何单位或个人不得以任何形式复制、转载、修改或传播本网站的任何内容。对于侵犯本网站知识产权的行为,将依法追究其法律责任。

  5. 免责声明:本网站不对因使用本网站而引起的任何直接、间接、偶然、特殊或后果性的损害承担责任。包括但不限于利润损失、数据丢失、业务中断等。

  6. 适用法律和争议解决:本协议的签订、履行、解释及争议解决均适用中华人民共和国法律。如发生争议,双方应首先协商解决;协商不成的,任何一方均有权向有管辖权的人民法院提起诉讼。

  7. 本协议的解释权归本网站所有。如有未尽事宜,本网站保留最终解释权。

  8. 本协议自用户点击“同意”或“接受”按钮时生效。

同意

隐私政策

欢迎访问我们的网站!我们致力于为您提供一个安全、可靠的在线环境。本隐私政策旨在说明我们在您使用我们的网站时如何收集、使用和保护您的个人信息。请仔细阅读以下内容,以了解我们的隐私政策。

  1. 信息收集

在使用我们的网站时,我们可能会收集以下类型的信息:

a) 个人识别信息:如姓名、电子邮件地址、电话号码等。 b) 非个人识别信息:如浏览器类型、操作系统、设备类型、IP地址等。 c) 用户行为信息:如访问页面、点击链接、搜索查询等。

  1. 信息使用

我们收集的信息将用于以下目的:

a) 提供、改进和个性化我们的服务。 b) 与您联系,回应您的询问和请求。 c) 发送您请求的或我们认为对您有帮助的信息。 d) 进行市场调研和分析,以改进我们的产品和服务。 e) 防止欺诈和其他非法活动。

  1. 信息共享

我们不会出售、出租或以其他方式与第三方共享您的个人信息,除非:

a) 获得您的明确同意。 b) 与可信赖的合作伙伴共享,以提供您请求的服务。 c) 根据法律要求或政府机关的要求。 d) 为保护我们的权利、财产或安全。

  1. 信息安全

我们采取合理的安全措施,以保护您的个人信息不受未经授权的访问、披露、更改或破坏。然而,请注意,没有任何一种电子存储方法是100%安全的。

  1. Cookie和跟踪技术

我们的网站使用Cookie和类似的跟踪技术来收集有关您使用我们网站的信息。这些信息有助于我们分析和改进我们的网站,以及提供个性化的内容和广告。您可以通过浏览器设置拒绝接受Cookie,但这可能会影响您使用我们网站的能力。

  1. 第三方链接

我们的网站可能包含指向其他网站的链接。请注意,我们对其他网站的隐私政策和实践不承担任何责任。我们建议您在访问这些网站时查看其隐私政策。

  1. 隐私政策的变更

我们可能会不时更新本隐私政策。请定期查看此页面,以确保您了解我们对个人信息的最新政策。

  1. 联系我们

如果您对我们的隐私政策有任何疑问或建议,请通过以下联系方式与我们联系:

电子邮件:[wangye-101@163.com]

电话:+86-173-3019-6230

地址:中国石家庄市长安区吾悦广场2010室

感谢您的信任和支持!我们将竭诚为您提供更优质的服务。

同意