微信掃碼支付springboot版本


發布時間:2018-11-06
 
技術:springboot+freemarker
 

概述

該項目是一個采用springboot構建的web項目,主要實現了微信掃碼支付功能。包含最基本的創建訂單,生成二維碼,接收微信回調功能。實測可行,可在其基本上根據需要自行添加業務邏輯。

詳細

一、環境搭建

首先要想支持微信支付,必須擁有兩個賬號:①微信公眾已認證的服務號,並且需要開通微信支付該能(必須是企業才有資格申請,請你找你家產品去申請吧),②微信商戶平台賬號;這兩個賬號一個不能少。此處已默認你已有上兩個賬號。

a 搭建springboot項目,可以自己在eclipse中新建maven項目導入springboot依賴,也可以直接從springboot官網中下載項目模板。如下圖

QQ截圖20181106141435.png

在依賴框中填寫需要引入的模塊,我這里因為需要頁面展示,所以選擇了freemarker,填入首字母自然就有提示,然后點擊下方的GenerateProject按鈕即可,eclips導入該maven項目。把各種包和文件先建起來。如下圖

QQ截圖20181106141107.png

二、程序實現

payconfig.properties文件是自己新建的,里面填寫如下信息:

#公眾號appleId
APPID=
#商戶號
MCH_ID=
#商戶密鑰
KEY=
#APP和網頁支付提交用戶端ip, Native支付填調用微信支付API的機器IP, 即:服務器ip地址
SPBILL_CREATE_IP=127.0.0.1
#接收微信支付異步通知回調地址,通知url必須為直接可訪問的url,不能攜帶參數。(需要配置)
NOTIFY_URL=http://225m5x.natappfree.cc/page/notify
#支付方式,取值如下:JSAPI,NATIVE,APP
TRADE_TYPE=NATIVE
# 微信支付 - 統一下單地址
PLACEANORDER_URL=https://api.mch.weixin.qq.com/pay/unifiedorder

 

最上面三個參數改成自己的。NOTIFY_URL 填寫自己的接口地址,需要能外網訪問的(自己測試可用內網穿透工具,這里一起上傳了),這是別人支付成功后,微信服務端會回調這個接口,這樣我們才能知道支付成功與否。對於自定義的配置文件,我們需要自己去配置,讓springboot加載進來。這里添加相應注解即可。

@Component
@ConfigurationProperties
@PropertySource("classpath:/payconfig.properties")
public class WxPayConfig {
	
	@Value("${APPID}")
	private String APPID;
	
	@Value("${MCH_ID}")
	private String MCH_ID;
	
	@Value("${KEY}")
	private String KEY;
	
	@Value("${SPBILL_CREATE_IP}")
	private String SPBILL_CREATE_IP;
	
	@Value("${NOTIFY_URL}")
	private String NOTIFY_URL;
	
	@Value("${TRADE_TYPE}")
	private String TRADE_TYPE;
	
	@Value("${PLACEANORDER_URL}")
	private String PLACEANORDER_URL;

 

freemarker配置,新建頁面,freemarker配置比較固定,具體可自行百度這里不是重點,頁面也就三個基本頁面,分別是index.ftl 用於提交訂單信息,payQrCode.ftl 用於展示支付二維碼信息,paySuccess.ftl 支付成功后的通知頁面,頁面很簡單,主要是完成功能。

生成訂單信息並向前端返回支付二維碼

@RequestMapping(value = "/createPreOrder")
	public String createPreOrder(String amount, String title,
			HttpServletRequest request,
			HttpServletResponse response,
			Map<String, Object> model
			) throws Exception {
		System.out.println(config.getAPPID());
		// 商品描述
		String body = title;
		// 商戶訂單號
		String out_trade_no =String.valueOf(System.currentTimeMillis());
		// 訂單總金額,單位為分 
		String total_fee = amount;
		// 統一下單
		PreOrderResult preOrderResult = wxOrderService.placeOrder(body, out_trade_no, total_fee);
		model.put("qrCodeUrl", preOrderResult.getCode_url());
		return "payQrCode";
	}

 

這是控制層方法,邏輯在placeOrder方法中。

		// 生成預付單對象
		PreOrder o = new PreOrder();
		// 生成隨機字符串
		String nonce_str = UUID.randomUUID().toString().trim().replaceAll("-", "");
		o.setAppid(config.getAPPID());
		o.setBody(body);
		o.setMch_id(config.getMCH_ID());
		o.setNotify_url(config.getNOTIFY_URL());
		o.setOut_trade_no(out_trade_no);
		// 判斷有沒有輸入訂單總金額,沒有輸入默認1分錢
		if (total_fee != null && !total_fee.equals("")) {
			o.setTotal_fee(Integer.parseInt(total_fee));
		} else {
			o.setTotal_fee(1);
		}
		o.setNonce_str(nonce_str);
		o.setTrade_type(config.getTRADE_TYPE());
		o.setSpbill_create_ip(config.getSPBILL_CREATE_IP());
		SortedMap<Object, Object> p = new TreeMap<Object, Object>();
		p.put("appid", config.getAPPID());
		p.put("mch_id", config.getMCH_ID());
		p.put("body", body);
		p.put("nonce_str", nonce_str);
		p.put("out_trade_no", out_trade_no);
		p.put("total_fee", total_fee);
		p.put("spbill_create_ip", config.getSPBILL_CREATE_IP());
		p.put("notify_url", config.getNOTIFY_URL());
		p.put("trade_type", config.getTRADE_TYPE());
		// 獲得簽名
		String sign = Sign.createSign("utf-8", p, config.getKEY());
		o.setSign(sign);
		// Object轉換為XML
		String xml = XmlUtil.object2Xml(o, PreOrder.class);
		// 統一下單地址
		String url = config.getPLACEANORDER_URL();
		// 調用微信統一下單地址
		String returnXml = HttpUtil.sendPost(url, xml);
		// XML轉換為Object
		PreOrderResult preOrderResult = (PreOrderResult) XmlUtil.xml2Object(returnXml, PreOrderResult.class);
		return preOrderResult;	

這里的功能就是,將數據封裝成對象,進行簽名,由於微信采用的是xml的交換格式,所以需要將對象轉為xml,通過統一下單地址進行提交,然后根據微信服務端的返回值將xml組裝成對象。

前端接收二維碼信息,利用juery的二維碼插件生成支付二維碼,然后每隔3秒輪詢后台,看用戶是否已完成支付。

		// 查詢是否支付成功 
		function checkPayResult() {
			$.get("/page/wxPayIsSuccess", function(data) {
// 				debugger;
				console.log(data);
				if (data) {
					window.location.href = "/page/paySuccess";
				}
			});
		}
		
		$(function() {
			// 每個3秒調用后台方法,查看訂單是否已經支付成功
			window.setInterval("checkPayResult()", 3000);
		});

接收微信回調通知

@RequestMapping(value = "/notify",method = RequestMethod.POST)
	public void Mynotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
		if (request==null||response==null) {
			System.out.println("請求出錯");
		}
		PayResult payResult = wxOrderService.getWxPayResult(request);
		boolean isPaid = payResult.getReturn_code().equals("SUCCESS") ? true : false;
		// 查詢該筆訂單在微信那邊是否成功支付
		// 支付成功,商戶處理后同步返回給微信參數
		PrintWriter writer = response.getWriter();
		if (isPaid) {
			System.out.println("================================= 支付成功 =================================");
			
			// ====================== 操作商戶自己的業務,比如修改訂單狀態,生成支付流水等 start ==========================
			// TODO
			this.isOrderPaid = true;
			// ============================================ 業務結束, end ==================================
			// 通知微信已經收到消息,不要再給我發消息了,否則微信會8連擊調用本接口
			String noticeStr = setXML("SUCCESS", "");
			writer.write(noticeStr);
			writer.flush();
						
		} else {
			System.out.println("================================= 支付失敗 =================================");
			
			// 支付失敗
			String noticeStr = setXML("FAIL", "");
			writer.write(noticeStr);
			writer.flush();
		}
		
	}

由於是post方式提交,數據在request的body中,所以可以通過request.getInputStream()來獲取。最后通過xml字符串轉為java對象

	@Override
	public PayResult getWxPayResult(HttpServletRequest request) throws Exception {
		InputStream inStream = request.getInputStream();
		BufferedReader in = null;
		String result = "";
		in = new BufferedReader(
				new InputStreamReader(inStream));
		String line;
		while ((line = in.readLine()) != null) {
			result += line;
		}
		PayResult pr = (PayResult)XmlUtil.xml2Object(result, PayResult.class);
		System.out.println(pr.toString());
		return pr;
	}

 

微信對調請求方式是post,數據放在body里面,所以可以通過request.getInputStream()的方法獲取回調信息,回調信息是xml格式的,也需要將其轉為我們需要的對象方便后續處理。

三、運行效果

QQ截圖20181106122549.png

QQ截圖20181106122542.png

QQ截圖20181106122536.png

四、其他補充

建議結合官方文檔一起看,這樣更能了解整個過程。

 

關於回調下面文字摘自微信支付文檔:

支付完成后,微信會把相關支付結果和用戶信息發送給商戶,商戶需要接收處理,並返回應答。

對后台通知交互時,如果微信收到商戶的應答不是成功或超時,微信認為通知失敗,微信會通過一定的策略定期重新發起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)

注意:同樣的通知可能會多次發送給商戶系統。商戶系統必須能夠正確處理重復的通知。

推薦的做法是,當收到通知進行處理時,首先檢查對應業務數據的狀態,判斷該通知是否已經處理過,如果沒有處理過再進行處理,如果處理過直接返回結果成功。在對業務數據進行狀態檢查和處理之前,要采用數據鎖進行並發控制,以避免函數重入造成的數據混亂。

有疑問請QQ聯系:740393778

注:本文著作權歸作者,由demo大師發表,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM