微信:微信扫码支付、调用统一下单接口、网站支付 + springmvc

来源:互联网 发布:广西银河交易软件 编辑:程序博客网 时间:2024/06/05 09:22

微信:微信扫码支付、调用统一下单接口、网站支付 + springmvc

标签: 微信支付微信扫码支付扫码支付 


一、场景:公司需要在网站上进行微信支付。

二、API:使用微信开放平台的接入微信支付

 

-扫码支付。微信支付开发者平台链接

三、分析:

1. 接入扫码支付(包含PC网站支付)包含三个阶段,问这里只讲使用,也就是第2阶段的《启动设计和开发》。

2. 点 击查看开发者文档(扫码支付)后,这里感觉微信的文档没有支付宝好理解(稍微吐槽下~~~),不过我们忽略一切,直接进入模式二:模式二最简单直接,不需 要在商户后台进行配置,推荐大家使用,微信也说流程更为简单,我这里也讲的是模式二,模式一大家有兴趣可以自行研究下。

3. 如上图,总流程有14步,主要流程是生成订单、调统一下单API、将返回的支付交易链接生成二维码展示;我这边主要就是将这三步结合springmvc后,成功生儿二维码之后,用户就可以扫码支付了。后面的回调跟跟我的另一篇博文基本类似,大家借鉴下就行了:支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc

四、实现:

1. 准备:根据统一下单接口API我 先定义了三个对象:UnifiedOrderRequest(统一下单请求参数(必填))、UnifiedOrderRequestExt(统一下单请求 参数(非必填))、UnifiedOrderRespose(统一下单返回参数);具体如下代码,get、set方法可自行生产,太占篇幅。

UnifiedOrderRequest.class

[javascript] view plain copy

1. /** 

2.  * 统一下单请求参数(必填) 

3.  * @author Y 

4.  * 

5.  */  

6. public class UnifiedOrderRequest {  

7.     private String appid;               //公众账号ID  

8.     private String mch_id;              //商户号  

9.     private String nonce_str;           //随机字符串  

10.     private String sign;                //签名  

11.     private String body;                //商品描述  

12.     private String out_trade_no;        <span style="white-space:pre">    </span>//商户订单号  

13.     private String total_fee;           //总金额  

14.     private String spbill_create_ip;    <span style="white-space:pre">    </span>//终端IP  

15.     private String notify_url;          //通知地址  

16.     private String trade_type;          //交易类型  

17. }  

UnifiedOrderRequestExt.class

[javascript] view plain copy

1. /** 

2.  * 统一下单请求参数(非必填) 

3.  * @author Y 

4.  * 

5.  */  

6. public class UnifiedOrderRequestExt extends UnifiedOrderRequest{  

7.       

8.     private String device_info;         //设备号  

9.     private String detail;              //商品详情  

10.     private String attach;              //附加数据  

11.     private String fee_type;            //货币类型  

12.     private String time_start;          //交易起始时间  

13.     private String time_expire;         //交易结束时间  

14.     private String goods_tag;           //商品标记  

15.     private String product_id;          //商品ID  

16.     private String limit_pay;           //指定支付方式  

17.     private String openid;              //用户标识  

18. }  

UnifiedOrderRespose.class

[javascript] view plain copy

1. /** 

2.  * 统一下单返回参数 

3.  * @author Y 

4.  * 

5.  */  

6. public class UnifiedOrderRespose {  

7.     private String return_code;             //返回状态码  

8.     private String return_msg;              //返回信息  

9.     private String appid;                   //公众账号ID  

10.     private String mch_id;                  //商户号  

11.     private String device_info;             //设备号  

12.     private String nonce_str;               //随机字符串  

13.     private String sign;                    //签名  

14.     private String result_code;             //业务结果  

15.     private String err_code;                //错误代码  

16.     private String err_code_des;            <span style="white-space:pre">    </span>//错误代码描述  

17.     private String trade_type;              //交易类型  

18.     private String prepay_id;               //预支付交易会话标识  

19.     private String code_url;                //二维码链接  

20. }  

1. Controller主入口:

[javascript] view plain copy

1. /** 

2.  * 创建二维码 

3.  */  

4. @RequestMapping("createQRCode")  

5. public void createQRCode(String orderId, HttpServletResponse response) {  

6.       

7.     //生成订单  

8.     String orderInfo = createOrderInfo(orderId);  

9.     //调统一下单API  

10.     String code_url = httpOrder(orderInfo);  

11.     //将返回预支付交易链接(code_url)生成二维码图片  

12.     //这里使用的是zxing   <span style="color:#ff0000;"><strong>说明1(见文末)</strong></span>  

13.     try {  

14.         int width = 200;  

15.         int height = 200;  

16.         String format = "png";  

17.         Hashtable hints = new Hashtable();  

18.         hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  

19.         BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);  

20.         OutputStream out = null;  

21.         out = response.getOutputStream();  

22.         MatrixToImageWriter.writeToStream(bitMatrix, format, out);  

23.         out.flush();  

24.         out.close();  

25.     } catch (Exception e) {  

26.     }  

27.   

28. }  

 

1. 生成订单:分两部分:一部分是业务需求的订单信息,就是发起支付前的订单信息,业务系统自行创建存储;另一部分是满足统一下单API要求的订单信息(也是我们这里要讲的)。“xxxxxx”:是你需要自己填写的对应信息:

[javascript] view plain copy

1. /** 

2.  * 生成订单 

3.  * @param orderId 

4.  * @return 

5.  */  

6. private String createOrderInfo(String orderId) {  

7.     //生成订单对象  

8.     UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();  

9.     unifiedOrderRequest.setAppid("xxxxxxxxxxxxx");//公众账号ID  

10.     unifiedOrderRequest.setMch_id("xxxxxxxxx");//商户号  

11.     unifiedOrderRequest.setNonce_str(StringUtil.makeUUID());//随机字符串       <span style="color:#ff0000;"><strong>说明2(见文末)</strong></span>  

12.     unifiedOrderRequest.setBody("xxxxxx");//商品描述  

13.     unifiedOrderRequest.setOut_trade_no(orderId);//商户订单号  

14.     unifiedOrderRequest.setTotal_fee("x");  //金额需要扩大100倍:1代表支付时是0.01  

15.     unifiedOrderRequest.setSpbill_create_ip("xxxxxxxxxxxxx");//终端IP  

16.     unifiedOrderRequest.setNotify_url("xxxxxxxxxxxxxx");//通知地址  

17.     unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付  

18.     unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//签名<span style="color:#ff0000;"><strong>说明5(见文末,签名方法一并给出)</strong></span>  

19.     //将订单对象转为xml格式  

20.     XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); //<span style="color:#ff0000;"><strong>说明3(见文末)</strong></span>  

21.     xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml  

22.     return xStream.toXML(unifiedOrderRequest);  

23. }  

 

1. 调统一下单API:根据要求将生成订单中返回的xml向微信给定的统一下单URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder,发送请求,成功并获得二维码。

[javascript] view plain copy

1. /** 

2.  * 调统一下单API 

3.  * @param orderInfo 

4.  * @return 

5.  */  

6. private String httpOrder(String orderInfo) {  

7.     String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  

8.     try {  

9.         HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();  

10.         //加入数据    

11.            conn.setRequestMethod("POST");    

12.            conn.setDoOutput(true);    

13.                

14.            BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());    

15.            buffOutStr.write(orderInfo.getBytes());  

16.            buffOutStr.flush();    

17.            buffOutStr.close();    

18.                

19.            //获取输入流    

20.            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));    

21.                

22.            String line = null;    

23.            StringBuffer sb = new StringBuffer();    

24.            while((line = reader.readLine())!= null){    

25.                sb.append(line);    

26.            }    

27.              

28.            XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//说明3(见文末)  

29.            //将请求返回的内容通过xStream转换为UnifiedOrderRespose对象  

30.            xStream.alias("xml", UnifiedOrderRespose.class);  

31.            UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());  

32.              

33.            //根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url  

34.            //<span style="color:#ff0000;"><strong>说明4(见文末)</strong></span>  

35.            if(null!=unifiedOrderRespose   

36.                 && "SUCCESS".equals(unifiedOrderRespose.getReturn_code())   

37.                 && "SUCCESS".equals(unifiedOrderRespose.getResult_code())){  

38.             return unifiedOrderRespose.getCode_url();  

39.            }else{  

40.             return null;  

41.            }  

42.     } catch (Exception e) {  

43.         e.printStackTrace();  

44.     }  

45.     return null;  

46. }  

 

1. 将返回的支付交易链接生成二维码展示:没有异常的情况下,在页面中使用<img>标签接收就行。实际使用时,结合前端和业务的需求放置二维码。可以在扫码支付/案例及规范中找到部分素材和界面规范来设计微信风格的支付页面。

[javascript] view plain copy

1. <img src="${ctx}/wxPay/createQRCode?orderId=1111" width="174px">  

 

1. 用户可以通过维系客户端进行扫码支付。支付完成后回调我们notify_url设置的url,通过成功的回调来更改业务系统中的订单状态或者一些业务需求。这里回调没有写出可以参考支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc中的回调。

 

五、说明

1. 二维码可以查看zxing实现二维码生成和解析;微信这边也提供了二维码的学习,大家有兴趣可以看看:http://www.thonky.com/qr-code-tutorial/ 和http://coolshell.cn/articles/10590.html

2. 随机字符串:微信对随机字符串的要求是不超过32位。我这边是这样生成的,用时间戳。

[javascript] view plain copy

1. /** 

2.  * 创建UUID 

3.  * @return 

4.  */  

5. public static synchronized String makeUUID() {  

6.     Date date = new Date();  

7.     StringBuffer s = new StringBuffer(DateUtil.formatYmdhmsm(date));  

8.     return s.append((new Random().nextInt(900) + 100)).toString();  

9. }  


3. 使用Xstream时,由于微信定义的变量名大部分使用了“_”,但是在Xstream中它是关键字,所以会自动变为“__”,引起报错。详情请看:XStream异常:对象转为XML时,会把"_"转成"__";报错:(Lcom/thoughtworks/xstream/io/naming/NameCoder;)V

4. 获取二维码链接时,只有在return_code 和result_code都为SUCCESS的时候有返回;这里我就简单的满足时返回,不满足返回null,您写的时候需要结合业务考虑下,是否需要增加判断,从而满足不同的业务场景。统一下单API

5. 签名在上面一直没有详细说明,首先查看微信的安全规范中签名算法。key值,需要自己填写

[javascript] view plain copy

1. /** 

2.  * 生成签名 

3.  *  

4.  * @param appid_value 

5.  * @param mch_id_value 

6.  * @param productId 

7.  * @param nonce_str_value 

8.  * @param trade_type  

9.  * @param notify_url  

10.  * @param spbill_create_ip  

11.  * @param total_fee  

12.  * @param out_trade_no  

13.  * @return 

14.  */  

15. private String createSign(UnifiedOrderRequest unifiedOrderRequest) {  

16.     //根据规则创建可排序的map集合  

17.     SortedMap<String, String> packageParams = new TreeMap<String, String>();  

18.     packageParams.put("appid", unifiedOrderRequest.getAppid());  

19.     packageParams.put("body", unifiedOrderRequest.getBody());  

20.     packageParams.put("mch_id", unifiedOrderRequest.getMch_id());  

21.     packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());  

22.     packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());  

23.     packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());  

24.     packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());  

25.     packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());  

26.     packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());  

27.   

28.     StringBuffer sb = new StringBuffer();  

29.     Set es = packageParams.entrySet();//字典序  

30.     Iterator it = es.iterator();  

31.     while (it.hasNext()) {  

32.         Map.Entry entry = (Map.Entry) it.next();  

33.         String k = (String) entry.getKey();  

34.         String v = (String) entry.getValue();  

35.         //为空不参与签名、参数名区分大小写  

36.         if (null != v && !"".equals(v) && !"sign".equals(k)  

37.                 && !"key".equals(k)) {  

38.             sb.append(k + "=" + v + "&");  

39.         }  

40.     }  

41.     //第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置  

42.     sb.append("key=" +"xxxxxxxxxxxxxxxxx");  

43.     String sign = MD5Util.MD5Encode(sb.toString(), "utf-8")  

44.             .toUpperCase();//MD5加密  

45.     return sign;  

46. }  

 

 

相关文章:支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc

 

0 0
原创粉丝点击