免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6701 | 回复: 0
打印 上一主题 下一主题

微信支付之扫码支付(java版 native原生支付) [复制链接]

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-07-10 22:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-07-09 10:37 |只看该作者 |倒序浏览
本文直接从代码调用微信扫码支付讲起。账号配置,参数生成等请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

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

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

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

1.模式选择:

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

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

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

正确调用后,会返回含有交易标示ID,和二维码链接的URL。
  1. HashMap<String, String> paramMap = Maps.newHashMap();
  2. paramMap.put("trade_type", "NATIVE"); //交易类型
  3. paramMap.put("spbill_create_ip",localIp()); //本机的Ip
  4. paramMap.put("product_id", payOrderIdsStr); // 商户根据自己业务传递的参数 必填
  5. paramMap.put("body", orderSubject);         //描述
  6. paramMap.put("out_trade_no", payOrderIdsStr); //商户 后台的贸易单号
  7. paramMap.put("total_fee", "" + totalCount); //金额必须为整数  单位为分
  8. paramMap.put("notify_url", "http://" + getAccessDomain() + "/wx_pay_notify"); //支付成功后,回调地址     
  9. paramMap.put("appid", siteConfig.getWxPayAppId()); //appid
  10. paramMap.put("mch_id", siteConfig.getWxPayMchId()); //商户号      
  11. paramMap.put("nonce_str", CommonUtilPub.createNoncestr(32));  //随机数  
  12. paramMap.put("sign",CommonUtilPub.getSign(paramMap,siteConfig.getWxPayPartnerKey()));//根据微信签名规则,生成签名
  13. String xmlData = CommonUtilPub.mapToXml(paramMap);//把参数转换成XML数据格式
复制代码
  1. /**
  2.      * 获取本机Ip
  3.      *  
  4.      *  通过 获取系统所有的networkInterface网络接口 然后遍历 每个网络下的InterfaceAddress组。
  5.      *  获得符合 <code>InetAddress instanceof Inet4Address</code> 条件的一个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> 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><![CDATA[SUCCESS]]></return_code>
  2. <return_msg><![CDATA[OK]]></return_msg>
  3. <appid><![CDATA[wx49342bda0ef105dd]]></appid>
  4. <mch_id><![CDATA[10019460]]></mch_id>
  5. <nonce_str><![CDATA[UneMQd4qWQd0hJ4L]]></nonce_str>
  6. <sign><![CDATA[C621A9C586C1F0397D4C6B8003E0CBCE]]></sign>
  7. <result_code><![CDATA[SUCCESS]]></result_code>
  8. <prepay_id><![CDATA[wx2015070818251790742fea5e0865034508]]></prepay_id>
  9. <trade_type><![CDATA[NATIVE]]></trade_type>
  10. <code_url><![CDATA[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 (piEle == null) {
  16.     return "";
  17.     }  
  18.     code_url = codeUrl.getText();  //解析 xml 获得 code_url
复制代码
3.动态生成二维码图片

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

页面代码:
  1. <img src="qr_code.img?code_url= <#if code_url??>${code_url}</#if>" style="width:300px;height:300px;"/>
复制代码
java 代码:
  1. /**
  2.    * 生成二维码图片并直接以流的形式输出到页面
  3.    * @param code_url
  4.    * @param response
  5.    */
  6.   @RequestMapping("qr_code.img")
  7.   @ResponseBody
  8.   public void getQRCode(String code_url,HttpServletResponse response){
  9.     GenerateQrCodeUtil.encodeQrcode(code_url, response);
  10.   }
复制代码
  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. import javax.imageio.ImageIO;
  7. import javax.servlet.http.HttpServletResponse;

  8. import org.apache.commons.lang3.StringUtils;

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

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

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP