微信支付之掃碼支付(java版 native原生支付)本文直接從代碼調(diào)用微信掃碼支付講起。賬號(hào)配置,參數(shù)生成等請(qǐng)參考官方文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 微信掃碼支付。簡(jiǎn)單來(lái)說(shuō),就是你把微信支付需要的信息,生成到二維碼圖片中。通過(guò)微信掃一掃,發(fā)起支付。我們需要做的就是二件事: 一是:按照微信掃碼支付規(guī)則生成二維碼信息. 二是:微信沒(méi)有提供生成二維碼圖片的接口。需要我們自己把二維碼信息生成到二維碼圖片中。 1.模式選擇: 微信掃碼支付,有兩種模式,文檔中有介紹。第二種模式,微信接口會(huì)返回二維碼信息給我們。而第一種模式則需要我們自己去生成二維碼信息。會(huì)有些麻煩。尤其是參數(shù)大小寫(xiě),還有簽名的問(wèn)題,容易出錯(cuò)??偟膩?lái)說(shuō)第二種模式比第一種模式簡(jiǎn)單。所有我采用的是第二種模式,比較通用。京東與攜程亦用的是第二種模式。 2.調(diào)用統(tǒng)一下單接口獲取帶有二維碼信息的url:(模式二) 模式二的微信掃碼支付,需要先調(diào)用微信的統(tǒng)一下單接口,生成預(yù)交易單。(參數(shù)傳遞與接收都是XML 數(shù)據(jù)格式。) 正確調(diào)用后,會(huì)返回含有交易標(biāo)示ID,和二維碼鏈接的URL。 HashMap<String, String> paramMap = Maps.newHashMap(); paramMap.put("trade_type", "NATIVE"); //交易類(lèi)型 paramMap.put("spbill_create_ip",localIp()); //本機(jī)的Ip paramMap.put("product_id", payOrderIdsStr); // 商戶根據(jù)自己業(yè)務(wù)傳遞的參數(shù) 必填 paramMap.put("body", orderSubject); //描述 paramMap.put("out_trade_no", payOrderIdsStr); //商戶 后臺(tái)的貿(mào)易單號(hào) paramMap.put("total_fee", "" + totalCount); //金額必須為整數(shù) 單位為分 paramMap.put("notify_url", "http://" + getAccessDomain() + "/wx_pay_notify"); //支付成功后,回調(diào)地址 paramMap.put("appid", siteConfig.getWxPayAppId()); //appid paramMap.put("mch_id", siteConfig.getWxPayMchId()); //商戶號(hào) paramMap.put("nonce_str", CommonUtilPub.createNoncestr(32)); //隨機(jī)數(shù) paramMap.put("sign",CommonUtilPub.getSign(paramMap,siteConfig.getWxPayPartnerKey()));//根據(jù)微信簽名規(guī)則,生成簽名 String xmlData = CommonUtilPub.mapToXml(paramMap);//把參數(shù)轉(zhuǎn)換成XML數(shù)據(jù)格式
1 /** 2 * 獲取本機(jī)Ip 3 * 4 * 通過(guò) 獲取系統(tǒng)所有的networkInterface網(wǎng)絡(luò)接口 然后遍歷 每個(gè)網(wǎng)絡(luò)下的InterfaceAddress組。 5 * 獲得符合 <code>InetAddress instanceof Inet4Address</code> 條件的一個(gè)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("獲取本機(jī)Ip失敗:異常信息:"+e.getMessage()); 27 } 28 return ip; 29 }
成功時(shí)返回的XML數(shù)據(jù)為: 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.動(dòng)態(tài)生成二維碼圖片 使用的是google ZXing庫(kù)。 提供一個(gè) jar 地址 直接引入到自己項(xiàng)目即可。http://download.csdn.net/detail/gonwy/7658135 頁(yè)面代碼: <img src="qr_code.img?code_url= <#if code_url??>${code_url}</#if>" style="width:300px;height:300px;"/> java 代碼:
1 /** 2 * 生成二維碼圖片 不存儲(chǔ) 直接以流的形式輸出到頁(yè)面 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"); //設(shè)置字符集編碼類(lèi)型 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 } 生成二維碼圖片完整代碼:(這里生成的是黑白相間的二維碼,沒(méi)有插入圖片。有興趣的,可以去研究一下) 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 * 靜態(tài)生成二維碼 存儲(chǔ)在磁盤(pán)上 29 * @param content //二維碼信息 30 * @param contextPath //上下文相對(duì)路徑 31 * @param realPath //磁盤(pán)真實(shí)路徑 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;//圖片在項(xiàng)目中存儲(chǔ)的相對(duì)路徑 41 String filePath = url; 42 //如果是部署在服務(wù)器上的情況,則需要到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"); //設(shè)置字符集編碼類(lèi)型 49 BitMatrix bitMatrix = null; 50 try { 51 bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300,hints); 52 File file1 = new File(realPath,filePath); //創(chuàng)建存儲(chǔ)圖片的文件 53 try { 54 GenerateQrCodeUtil.writeToFile(bitMatrix, "png", file1); //存儲(chǔ)二維碼圖片 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 < width; x++) { 77 for (int y = 0; y < height; 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 * 生成二維碼圖片 不存儲(chǔ) 直接以流的形式輸出到頁(yè)面 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"); //設(shè)置字符集編碼類(lèi)型 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 }
然后生成的圖片,通過(guò)微信掃碼就可以發(fā)起支付了。 支付成功后,微信會(huì)調(diào)用,你之前設(shè)置的回調(diào)函數(shù)地址。并且會(huì)把你之前傳給微信的商戶自定義參數(shù)帶給你,以幫助商戶完成余下業(yè)務(wù)流程。
分類(lèi): java
3
0
(請(qǐng)您對(duì)文章做出評(píng)價(jià))
|
|
|
來(lái)自: quasiceo > 《待分類(lèi)1》