SpringBoot整合Vue實(shí)現(xiàn)微信掃碼支付以及微信退款功能詳解
直接上代碼,在order模塊添加依賴
<dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency>
在配置類添加申請(qǐng)的商家號(hào)信息
#關(guān)聯(lián)的公眾號(hào)appid weixin.pay.appid=wxXXXXXXX #商戶號(hào) weixin.pay.partner=XXXXXXXXX #商戶key weixin.pay.partnerkey=XXXXXXXXXX
添加微信生成二維碼service
@Service public class WeiXinServiceImpl implements WeiXinService { @Autowired private PaymentInfoService paymentInfoService; @Autowired private OrderInfoService orderInfoService; @Autowired private WeiXinService weiXinService; //生成支付的二維碼 @Override public Map createNative(Long orderId) { //支付記錄表添加數(shù)據(jù) //根據(jù)單號(hào)查詢訂單相關(guān)信息 OrderInfo orderInfo = orderInfoService.getById(orderId); if (orderInfo == null){ throw new OrderException(20001,"訂單不存在"); } //添加訂單狀態(tài) paymentInfoService.savePaymentInfo(orderInfo,PaymentTypeEnum.WEIXIN.getStatus()); //調(diào)用微信接口返回二維碼 try { //2 調(diào)用微信接口,得到二維碼地址等信息 //封裝傳遞微信地址參數(shù) Map paramMap = new HashMap(); paramMap.put("appid", ConstantPropertiesUtils.APPID); //公眾號(hào)id paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER); //商戶號(hào) paramMap.put("nonce_str", WXPayUtil.generateNonceStr()); //隨機(jī)字符串,調(diào)用工具類 Date reserveDate = orderInfo.getReserveDate(); String reserveDateString = new DateTime(reserveDate).toString("yyyy/MM/dd"); String body = reserveDateString + "就診"+ orderInfo.getDepname(); paramMap.put("body", body);//掃碼后手機(jī)顯示內(nèi)容 paramMap.put("out_trade_no", orderInfo.getOutTradeNo()); //訂單流水號(hào) //paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+""); paramMap.put("total_fee", "1");//TODO 為了測(cè)試 支付金額 paramMap.put("spbill_create_ip", "127.0.0.1"); //終端ip paramMap.put("notify_url", "http://xxxxxxxxx");//回調(diào)地址 paramMap.put("trade_type", "NATIVE"); //二維碼類型 //請(qǐng)求微信生成二維碼接口 HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //設(shè)置post請(qǐng)求相關(guān)參數(shù) //微信支付要求傳遞參數(shù)xml格式 //把封裝map集合變成xml,加密處理,傳輸 String xml = WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY); client.setXmlParam(xml); //支持https協(xié)議 client.setHttps(true); //發(fā)送 client.post(); //調(diào)用微信接口,返回?cái)?shù)據(jù),xml格式的數(shù)據(jù) String resultXml = client.getContent(); System.out.println("微信二維碼:"+resultXml); //把xml格式數(shù)據(jù)轉(zhuǎn)換map Map<String, String> resultMap = WXPayUtil.xmlToMap(resultXml); Map map = new HashMap<>(); map.put("orderId", orderId); map.put("totalFee", orderInfo.getAmount()); map.put("resultCode", resultMap.get("result_code")); map.put("codeUrl", resultMap.get("code_url")); //微信二維碼地址 return map; } catch (Exception e) { e.printStackTrace(); throw new orderException(20001,"生成二維碼失敗"); } } }
控制層
@RestController @RequestMapping("/api/order/weixin") public class WeixinController { @Autowired private WeiXinService weixinPayService; /** * 下單 生成二維碼 */ @GetMapping("/createNative/{orderId}") public R createNative( @ApiParam(name = "orderId", value = "訂單id", required = true) @PathVariable("orderId") Long orderId) { Map map = weixinPayService.createNative(orderId); return R.ok().data(map); } }
前端微信支付二維碼,wx.js定義方法
createNative(orderId) { return request({ url: `/api/order/weixin/createNative/${orderId}`, method: 'get' }) }
顯示二維碼需要前端安裝插件 安裝npm install vue-qriously
訂單詳情頁(yè),修改order/show.vue組件
import weixinApi from '@/api/yygh/wx' <!-- 微信支付彈出框 --> <el-dialog :visible.sync="dialogPayVisible" style="text-align: left" :append-to-body="true" width="500px" @close="closeDialog"> <div class="container"> <div class="operate-view" style="height: 350px;"> <div class="wrapper wechat"> <div> <qriously :value="payObj.codeUrl" :size="220"/> <div style="text-align: center;line-height: 25px;margin-bottom: 40px;"> 請(qǐng)使用微信掃一掃<br/> 掃描二維碼支付 </div> </div> </div> </div> </div> </el-dialog> //生成二維碼 pay() { //彈框 this.dialogPayVisible = true //調(diào)用接口 weixinApi.createNative(this.orderId).then(response => { this.payObj = response.data if(this.payObj.codeUrl == '') { this.dialogPayVisible = false this.$message.error("支付錯(cuò)誤") } else { //每隔3秒查詢一次支付狀態(tài) this.timer = setInterval(()=>{ this.queryPayStatus(this.orderId) },3000) } }) },
查詢訂單支付狀態(tài),添加定時(shí)器方法,每隔3秒去查詢一次支付狀態(tài),api
queryPayStatus(orderId) { return request({ url: `/api/order/weixin/queryPayStatus/${orderId}`, method: 'get' }) },
后端,weixinservice封裝信息請(qǐng)求微信提供的接口,判斷是否支付成功,因?yàn)槲⑿欧祷氐氖莤ml文件,所以需要轉(zhuǎn)換
//調(diào)用微信接口查詢支付狀態(tài) @Override public Map queryPayStatus(Long orderId, String paymentType) { //1 根據(jù)orderId查詢訂單信息 OrderInfo orderInfo = orderInfoService.getById(orderId); if(orderInfo == null) { throw new orderException(20001,"訂單不存在"); } try { //2 封裝微信接口需要數(shù)據(jù) Map paramMap = new HashMap<>(); paramMap.put("appid", ConstantPropertiesUtils.APPID); paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER); paramMap.put("out_trade_no", orderInfo.getOutTradeNo()); paramMap.put("nonce_str", WXPayUtil.generateNonceStr()); //3 調(diào)用微信接口,傳遞數(shù)據(jù),設(shè)置參數(shù) HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery"); client.setXmlParam(WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY)); client.setHttps(true); client.post(); //4 獲取微信接口返回?cái)?shù)據(jù) String xml = client.getContent(); System.out.println("支付狀態(tài)返回xml: "+xml); Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); return resultMap; } catch (Exception e) { e.printStackTrace(); throw new orderException(20001,"查詢失敗"); } }
支付成功后,更新狀態(tài)
控制層,查詢狀態(tài)
@ApiOperation(value = "查詢支付狀態(tài)") @GetMapping("/queryPayStatus/{orderId}") public Result queryPayStatus( @ApiParam(name = "orderId", value = "訂單id", required = true) @PathVariable("orderId") Long orderId) { //調(diào)用查詢接口 Map<String, String> resultMap = weixinPayService.queryPayStatus(orderId, PaymentTypeEnum.WEIXIN.name()); if (resultMap == null) {//出錯(cuò) return Result.fail().message("支付出錯(cuò)"); } if ("SUCCESS".equals(resultMap.get("trade_state"))) {//如果成功 //更改訂單狀態(tài),處理支付結(jié)果 String out_trade_no = resultMap.get("out_trade_no"); paymentInfoService.paySuccess(out_trade_no, PaymentTypeEnum.WEIXIN.getStatus(), resultMap); return Result.ok().message("支付成功"); } return Result.ok().message("支付中"); }
退款
退款與支付唯一不同的是需要在下載微信提供的退款證書,下載好后通過配置文件加載退款證書路徑
weixin.cert=C:\\apiclient_cert.p12
weixinservice中
//退款 @Override public Boolean refund(Long orderId) { //1 根據(jù)訂單號(hào)查詢訂單支付記錄信息 QueryWrapper<PaymentInfo> wrapper = new QueryWrapper<>(); wrapper.eq("order_id",orderId); PaymentInfo paymentInfo = paymentInfoService.getOne(wrapper); //2 TODO 添加退款信息到退款表 try { //3 調(diào)用微信退款接口 //封裝微信接口需要數(shù)據(jù) Map<String,String> paramMap = new HashMap<>(8); paramMap.put("appid",ConstantPropertiesUtils.APPID); //公眾賬號(hào)ID paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER); //商戶編號(hào) paramMap.put("nonce_str",WXPayUtil.generateNonceStr()); paramMap.put("transaction_id",paymentInfo.getTradeNo()); //微信訂單號(hào) paramMap.put("out_trade_no",paymentInfo.getOutTradeNo()); //商戶訂單編號(hào) paramMap.put("out_refund_no","tk"+paymentInfo.getOutTradeNo()); //商戶退款單號(hào) // paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+""); // paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+""); paramMap.put("total_fee","1"); paramMap.put("refund_fee","1"); //設(shè)置接口和參數(shù) HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund"); client.setXmlParam(WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY)); client.setHttps(true); client.setCert(true);//退款證書 client.setCertPassword(ConstantPropertiesUtils.PARTNER);//證書密碼 商戶key //發(fā)送post請(qǐng)求 client.post(); //4、返回退款數(shù)據(jù) String xml = client.getContent(); Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); } catch (Exception e) { e.printStackTrace(); } return null; }
總結(jié)
到此這篇關(guān)于SpringBoot整合Vue實(shí)現(xiàn)微信掃碼支付以及微信退款功能的文章就介紹到這了,更多相關(guān)SpringBoot整合Vue微信掃碼支付退款內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決JAVA非對(duì)稱加密不同系統(tǒng)加密結(jié)果不一致的問題
這篇文章主要介紹了解決JAVA非對(duì)稱加密不同系統(tǒng)加密結(jié)果不一致的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-10-10圖書管理系統(tǒng)java代碼實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了java代碼實(shí)現(xiàn)的圖書管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Spring MVC過濾器-登錄過濾的代碼實(shí)現(xiàn)
本篇文章主要介紹了Spring MVC過濾器-登錄過濾,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧。2017-01-01SpringBoot+Spring Security無(wú)法實(shí)現(xiàn)跨域的解決方案
這篇文章主要介紹了SpringBoot+Spring Security無(wú)法實(shí)現(xiàn)跨域的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java反射機(jī)制詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Java 反射機(jī)制。通俗來(lái)講呢,就是在運(yùn)行狀態(tài)中,我們可以根據(jù)“類的部分已經(jīng)的信息”來(lái)還原“類的全部的信息”。這篇文章給大家詳細(xì)介紹了java反射機(jī)制的知識(shí),感興趣的朋友一起看看吧2017-06-06Java通過URL獲取公眾號(hào)文章生成HTML的方法
這篇文章主要介紹了Java通過URL獲取公眾號(hào)文章生成HTML的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12