概要

主要记录自己的开发流程,使用的springMVC

支付流程

引入相关依赖

<!-- 微信支付 -->
<dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-io</artifactId><version>1.3.2</version>
</dependency>

编码

1. 配置

package com.hejx.pay.wxpay;import com.github.wxpay.sdk.WXPayConfig;
import com.xiaoyaoke.util.PropertyUtil;import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;/*** Created by 追风少年* https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3* 微信支付配置参数为Map<String, String>对象,返回类型也是Map<String, String>。方法内部会将参数会转换成含有appid、mch_id、nonce_str、sign\_type和sign的XML;默认使用MD5进行签名;通过HTTPS请求得到返回数据后会对其做必要的处理(例如验证签名,签名错误则抛出异常)。对于downloadBill,无论是否成功都返回Map,且都含有return_code和return_msg。若成功,其中return_code为SUCCESS,另外data对应对账单数据。本系统使用的微信扫码支付模式为模式二:模式二与模式一相比,流程更为简单,不依赖设置的回调支付URL。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。*@email doubihah@foxmail.com*@create 2017-06-21 14:49**/
public class MyWxPayConfig implements WXPayConfig {//商户号就是mchIDprivate final String mch_id = PropertyUtil.getProperty("wxpay.mchId");private final String app_id = PropertyUtil.getProperty("wxpay.appId");//商户秘钥keyprivate final String key = PropertyUtil.getProperty("wxpay.key");private final String certPath = PropertyUtil.getProperty("wxpay.certPath");public final static String notify_url = PropertyUtil.getProperty("wxpay.notify_url");private byte[] certData;public MyWxPayConfig() throws Exception {File file = new File(certPath);InputStream certStream = new FileInputStream(file);this.certData = new byte[(int) file.length()];certStream.read(this.certData);certStream.close();}public String getAppID() {return app_id;}public String getMchID() {return mch_id;}public String getKey() {return key;}public InputStream getCertStream() {ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);return certBis;}public int getHttpConnectTimeoutMs() {return 8000;}public int getHttpReadTimeoutMs() {return 10000;}}

2. 封装支付请求

package com.hejx.pay;import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.github.wxpay.sdk.WXPay;
import com.xiaoyaoke.pay.alipay.AlipayConfig;
import com.xiaoyaoke.pay.wxpay.WxPayConfig;
import org.apache.log4j.Logger;import java.util.HashMap;
import java.util.Map;/*** Created by 追风少年* 封装支付请求*@email doubihah@foxmail.com*@create 2017-06-22 10:13**/
public class PayRequest {private Logger logger = Logger.getLogger(PayRequest.class);/*** 支付宝* PC端支付请求*@param out_trade_no*@param bizContent*@return*@throws AlipayApiException*/public String alipayByPc(String out_trade_no,String bizContent) throws AlipayApiException {//获得初始化的AlipayClientAlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);//设置请求参数AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(AlipayConfig.return_url);    //同步的回调地址 不做任何处理alipayRequest.setNotifyUrl(AlipayConfig.notify_url);    //异步回调地址 用于判断支付的情况alipayRequest.setBizContent(bizContent);String result = alipayClient.pageExecute(alipayRequest).getBody();return result;}/*** 微信PC支付*@param orderId*@param body*@param fen*@return*@throws Exception*/public Map<String, String> wxpayByPc(String orderId,String body,Long fen) throws Exception{WxPayConfig config = new WxPayConfig();WXPay wxpay = new WXPay(config);Map<String, String> data = new HashMap<String, String>();data.put("body", body);//商品简单描述 String(128)data.put("out_trade_no", orderId);//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一data.put("device_info", "WEB");    //可以不填 自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"data.put("fee_type", "CNY");    //符合ISO 4217标准的三位字母代码,默认人民币:CNYdata.put("total_fee", String.valueOf(fen)); //订单总金额,单位为分 int(88)data.put("spbill_create_ip", "123.12.12.123");  //APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。data.put("notify_url", WxPayConfig.notify_url); //异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。data.put("trade_type", "NATIVE");  // 此处指定为扫码支付data.put("product_id", "1");   //trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品IDMap<String, String> resp = wxpay.unifiedOrder(data);return resp;}}

3. 生成订单,调用微信统一下单API

/**
* 微信支付
*@return
*/
@RequestMapping(value = "/wxpay",method = RequestMethod.POST)
@ResponseBody
public Result wxpay(@RequestParam("money") Double money){//todo 参数验证//生成唯一的订单号:time + useridString orderId = String.valueOf(System.currentTimeMillis()) + userid;   String orderName = "订单名称";//参数传的为元,需要转化为分Long fen = AmountUtils.yuanToFen(money);//充值的所使用的人民币单位 分//todo 储存订单信息try {Map<String, String> map = payRequest.wxpayByPc(orderId, orderName, fen);if("SUCCESS".equals(map.get("result_code"))){//接口返回成功Map<String, String> resultMap = new HashMap<>();resultMap.put("code_url",map.get("code_url"));//传回前端 前端根据code_url生成二维码resultMap.put("orderId",orderId);return ResultUtil.success(resultMap);}else{logger.error("微信下单失败:" + map.toString());throw new Exception("微信下单失败!");}}catch (Exception e){logger.error("微信下单异常:" + e);logger.error("当前登录的用户手机号:" + nowUser.getPhone());return ResultUtil.error(ResultEnum.WXPAY_ERROR);}}

4. 微信异步通知支付信息

private Logger logger = Logger.getLogger(WxPayController.class);
private final String SUCCESS = "SUCCESS";//微信回调
@RequestMapping(value = "/notify",method = RequestMethod.POST)
@ResponseBody
public String notify(HttpServletRequest request){logger.info("扫码成功,微信服务器回调>>>>>>>>");try {Map<String, String> map = WXPayUtil.xmlToMap(IOUtils.toString(request.getInputStream(), "UTF-8"));logger.info("通知参数:" + map);WxPayConfig config = new WxPayConfig();WXPay wxpay = new WXPay(config);if (wxpay.isPayResultNotifySignatureValid(map)) {// 签名正确 进行处理。// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功String return_code = map.get("return_code");if(this.SUCCESS.equals(return_code)){//交易成功String transaction_id = map.get("transaction_id");//交易编号 微信的String out_trade_no = map.get("out_trade_no");//订单IDString total_fee = map.get("total_fee");//订单总金额,单位为分//验证该通知数据中的out_trade_no是否为商户系统中创建的订单号Recharge recharge = rechargeDao.findOne(out_trade_no);  //根据订单ID 查询订单信息if(recharge == null){String errLog = String.format("没有查询到对应的订单信息 【out_trade_no:%s】",out_trade_no);logger.error(errLog);return ResultEnum.ORDER_NOT_FOUND_ERROR.getMsg();}//判断total_fee是否确实为该订单的实际金额(即商户订单创建时的金额)Long fen = Long.valueOf(total_fee);if(!fen.equals(recharge.getRechargeMoney())){String errLog = String.format("订单信息被篡改 【total_amount:%s,传入的 total_amount:%s】",recharge.getRechargeMoney(),fen);logger.error(errLog);return ResultEnum.ORDER_TAMPER_ERROR.getMsg();}if(recharge.getRechargeStatus() == 0){//没有做过处理recharge.setTradeNo(transaction_id);try{//service 里执行发货操作 + 更新订单信息rechargeService.rechargeToPlayer(recharge,"wxpay");logger.info("订单处理完成:" + recharge.getOrderId());}catch (Exception e){logger.error(e);logger.error("参数转换失败:" + e.getMessage());return "请检查游戏充值服务器是否正常";}}}else{String return_msg = map.get("return_msg");logger.error("交易失败,错误原因:" + return_msg);return return_msg;}} else {// 签名错误,如果数据里没有sign字段,也认为是签名错误String return_msg = map.get("return_msg");logger.error("签名错误,如果数据里没有sign字段,也认为是签名错误:" + return_msg);return return_msg;}return success();   //返回成功}catch (Exception e){return "内部错误";}
}

5.查询订单状态

//查询订单状态
@RequestMapping(value = "/queryOrder",method = RequestMethod.POST)
@ResponseBody
/*** SUCCESS—支付成功REFUND—转入退款NOTPAY—未支付CLOSED—已关闭REVOKED—已撤销(刷卡支付)USERPAYING--用户支付中PAYERROR--支付失败(其他原因,如银行返回失败)*/
public Result queryOrder(@RequestParam("orderId") String orderId) throws Exception{WxPayConfig config = new WxPayConfig();WXPay wxpay = new WXPay(config);Map<String, String> data = new HashMap<String, String>();data.put("out_trade_no", orderId);try {Map<String, String> resp = wxpay.orderQuery(data);//检查订单支付状态 根据订单支付状态传给前端做处理if(SUCCESS.equals(resp.get("return_code"))){ //通讯成功String trade_state = resp.get("trade_state"); //交易状态if(TradeState.SUCCESS.name().equals(trade_state)){    //支付成功return ResultUtil.success(trade_state);}else if(TradeState.CLOSED.name().equals(trade_state)){ //已关闭logger.info("交易已被关闭,orderId:" + orderId);return ResultUtil.success(trade_state);}}else{logger.error("查询订单状态失败:"+resp.get("return_msg")+",orderId:"+orderId);}} catch (Exception e) {e.printStackTrace();}return ResultUtil.success();
}

充值页面代码

html:

<input type="number" class="form-control" name="money" ng-model="data.money" maxlength="11" id="phone" placeholder="充值的钻石数量" required>

js:

//封装充值的URL
$scope.URL = {WXPAY_URL:"/wxpay" //充值URL
};$scope.data = {money:0   //付款金额,必填
};$scope.wxpay = function(){//加载层var index = layer.load(0, {shade: false}); //0代表加载的风格,支持0-2//提交数据$http({method : 'POST', data:$scope.data, url : $scope.URL.WXPAY_URL}).success(function(data,status,headers,config){layer.close(index);if(data.code==0){if(pt == 0){//支付宝$('#returnAli').html(data.data);}else{//微信弹出扫描窗口var url = "/wxpay/pay?url=" + data.data.code_url+ "&money=" + $scope.data.money + "&orderId=" + data.data.orderId;openInputWin(url,'微信支付');}}else{layer.alert(data.msg, {skin: 'layui-layer-molv' //样式类名,closeBtn: 0});}}).error(function(data,status,headers,config){layer.close(index);console.log('error..........');console.log(data);});
}/*** 根据浏览器的长宽打开input窗口*@param url*@param title*/
function openInputWin(url,title){//获取当前网页可见区域宽var offsetWidth = document.body.offsetWidth;  // pc:1694 ipad:798(比较大的ipad,不是最大的那种)if(offsetWidth<860){//则为移动端登录layer.open({type: 2,title: title,area: ['90%', '80%'],    //宽和高 原来为:90% 80%anim:1,//出场动画全部采用CSS3。这意味着除了ie6-9,其它所有浏览器都是支持的。目前anim可支持的动画类型有0-6 如果不想显示动画,设置 anim: -1 即可content: url, //这里content是一个URL,如果你不想让iframe出现滚动条,你还可以content: ['http://sentsin.com', 'no']success: function(layero) {$(layero).addClass("scroll-wrapper"); //苹果 iframe 滚动条失效解决方式 经测试 无效}});}else{//PC网页端layer.open({type: 2,title: title,// area: ['800px', '500px'],    //宽和高area: ['1000px', '700px'],    //宽和高anim:1,//出场动画全部采用CSS3。这意味着除了ie6-9,其它所有浏览器都是支持的。目前anim可支持的动画类型有0-6 如果不想显示动画,设置 anim: -1 即可content: url, //这里content是一个URL,如果你不想让iframe出现滚动条,你还可以content: ['http://sentsin.com', 'no']success: function(layero) {$(layero).addClass("scroll-wrapper"); //苹果 iframe 滚动条失效解决方式 经测试 无效}});}
}

窗口页面代码

wxpay.js

/*** Created by hejx on 2017/6/22.*/var timer;//微信支付模块
var wxpay = {URL:{CHECK_ORDER_STATE:"/queryOrder"},load:function(){//初始化页面wxpay.create2WM(url);//因为微信支付完成后页面并没有响应,所以在这里轮询订单状态进行相应的响应timer = setInterval("wxpay.checkState()", 3000);},create2WM:function(text){//生成二维码jQuery('#paycode').qrcode({text     : text,  //设置二维码内容render   : "canvas",//设置渲染方式width       : 200,     //设置宽度height      : 200,     //设置高度typeNumber  : -1,      //计算模式correctLevel    : 0,    //纠错等级background      : "#ffffff",//背景颜色foreground      : "#000000" //前景颜色});},checkState:function(){ //查看订单支付状态$.ajax({url:wxpay.URL.CHECK_ORDER_STATE,type:'POST', //GETasync:false,    //或false,是否异步data:{orderId:orderId},timeout:5000,    //超时时间dataType:'json',    //返回的数据格式:json/xml/html/script/jsonp/textsuccess:function(data,textStatus,jqXHR){if(data.code==0){//成功if(data.data == "SUCCESS"){ //支付成功clearInterval(timer);layer.alert('充值成功', {icon: 1,skin: 'layer-ext-moon',end:function(){//支付完成 跳转页面parent.wxpay_success();}})}else if(data.data == "CLOSED"){ //交易已关闭clearInterval(timer);layer.alert('交易已关闭', {icon: 2,skin: 'layer-ext-moon',end:function(){//支付完成 跳转页面parent.closeWin();}})}}else{layer.alert(data.msg, {skin: 'layui-layer-molv' //样式类名,closeBtn: 0});}},error:function(xhr,textStatus){console.log('错误')console.log(xhr)console.log(textStatus)}})}
};

html

<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><!--头部--><link href="<%=basePath%>static/css/bootstrap.min14ed.css?v=3.3.6" rel="stylesheet"><link href="<%=basePath%>static/css/font-awesome.min93e3.css?v=4.4.0" rel="stylesheet"><link href="<%=basePath%>static/css/animate.min.css" rel="stylesheet"><link href="<%=basePath%>static/css/style.min862f.css?v=4.1.0" rel="stylesheet"><!--头部结束--><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><title>微信扫码支付</title><style>body {background:#eee;font-size:14px;font-family:"微软雅黑", Helvetica, serif;color:#666;}a img {border:0;}input {border:1px solid #CCC;height:25px;line-height:25px;text-indent:5px;}#header {padding:10px 0;}.mass {max-width:920px;min-height:600px;margin:0 auto;background:#fcfcfc;border:1px solid #CCC;padding:10px 50px 50px 50px;}.sub-logo {display:inline-block;vertical-align:bottom;padding:0 0 5px 0;}.sub-logo span {font-size:18px;color:#49afcd;font-weight:bold;}.taglineWrap {margin-top:10px;padding:10px 30px 8px 18px;min-height:20px;min-width:300px;border:2px solid #ddd;}#payinfo {line-height:32px;font-size:16px;float:right;}.price {color:#F60;font-size:20px;margin:0 2px 0 5px;}#title {text-align:center;margin:30px 0 20px 0;}#title span {font-size:21px;}#paycode {text-align:center;margin-top:20px;}#paymsg {text-align:center;margin-top:10px;}.msg_default_box i {margin-left:-16px}.msg_default_box p {display:inline-block;*display:inline;*zoom:1;vertical-align:middle;letter-spacing:normal;text-align:left;font-size:16px;line-height:150%;}</style>
</head>
<body><div class="mass"><div id="header"><div class="sub-logo"><span style="margin-left:-3px;">收银台</span></div></div><div id="content"><p></p><div class="taglineWrap"><img id="wxpay" title="微信支付" src="/static/img/pay/wxpay.png" height="66"><span id="payinfo">支付<b class="price">${money}</b></span></div><div id="title"><span>交易名称</span></div><div id="paycode"></div><div id="paymsg"><img src="/static/img/pay/pay-desc.png"></div></div></div></body>
<script src="<%=basePath%>static/js/jquery.min.js?v=2.1.4"></script>
<!-- 二维码生成插件 用于微信支付 -->
<script src="https://cdn.bootcss.com/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
<script src="<%=basePath%>static/plugins/layer/layer.js"></script>
<script src="<%=basePath%>static/js/pay/wxpay.js"></script>
<script>var url = '${url}';var orderId = '${orderId}';$(function(){wxpay.load();});</script>
</html>

微信 扫码支付模式二 开发相关推荐

  1. JAVA微信扫码支付模式二功能实现完整例子

    概述 本例子实现微信扫码支付模式二的支付功能,应用场景是,web网站微信扫码支付.实现从点击付费按钮.到弹出二维码.到用户用手机微信扫码支付.到手机上用户付费成功.web网页再自动调整到支付成功后的页 ...

  2. 随手记录JAVA微信扫码支付模式二功能

    概述 本例子实现微信扫码支付模式二的支付功能,应用场景是,web网站微信扫码支付.实现从点击付费按钮.到弹出二维码.到用户用手机微信扫码支付.到手机上用户付费成功.web网页再自动调整到支付成功后的页 ...

  3. 微信扫码支付模式二【无法回调】解决方案

    微信扫码支付模式二[无法回调]解决方案 参考文章: (1)微信扫码支付模式二[无法回调]解决方案 (2)https://www.cnblogs.com/lhat/p/5611242.html 备忘一下 ...

  4. 微信扫码支付模式二【无法回调】解决方案(转)

    微信扫码支付模式二[无法回调]解决方案(转) 参考文章: (1)微信扫码支付模式二[无法回调]解决方案(转) (2)https://www.cnblogs.com/kenshinobiy/p/8724 ...

  5. 微信扫码支付dome php,帝国cms 微信扫码支付 模式二 扫码付款demo

    [实例简介] 到处没找到帝国扫码支付的插件,找到的都是收费的.所以自己随便改了个扫码支付,官方DEMO改的.功能都已实现.支付测试扫码的都没问题.后台支付记录也能正常添加 [实例截图] [核心代码] ...

  6. php微信支付使用ajax,微信扫码支付模式二支付状态Ajax轮询实例

    Ajax 轮训支付状态代码: //设置每隔1000毫秒执行一次load() 方法 setInterval(function(){load()},1000); function load(){ var ...

  7. 微信支付ajax实现支付,微信扫码支付模式二支付状态Ajax轮询实例

    Ajax 轮训支付状态代码: //设置每隔1000毫秒执行一次load() 方法 setInterval(function(){load()},1000); function load(){ var ...

  8. Java微信扫码支付(模式二)

    更多最新文章欢迎大家访问我的个人博客

  9. Java之微信支付(扫码支付模式二)案例实战

    摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...

最新文章

  1. 线性代数:03 向量空间 -- 基本概念
  2. 关于webcontrols的TreeView中转义符的处理问题
  3. PHP进行图片下载的时候,出现图片损坏,无法打开(实质原因,多输出了一个空白字符ZWNBSP )
  4. for(;;)是什么,for(;;)的作用
  5. 如果再不要求进步,那么你就是下一个陨落的巨头
  6. Mysql带返回值与不带返回值的2种存储过程
  7. c iostream.源码_通达信《K线上画趋势线预警》精选指标(附源码)
  8. 重读经典:《An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale》
  9. 钉钉怎么设置考勤打卡规则
  10. win下anaconda装python2.7和3.5以及jupyter共存 (本篇实践通过)
  11. Spring的@bean注解
  12. LeetCode 51. N-Queens
  13. 安装Oracle11gR2先决条件检查失败的详细解决处理过程
  14. 山东联通中兴B860 AV1.1机顶盒 刷机问题解决
  15. php关闭notice_屏蔽PHP默认设置中的Notice警告的方法
  16. HDU - 6287 口算训练
  17. getmonth_日期getMonth()方法以及JavaScript中的示例
  18. “蔚来杯“2022牛客暑期多校训练营1 J Serval and Essay(图的启发式合并)
  19. 【JavaScript】事件绑定、事件解绑、常见事件类型、事件对象
  20. JAVA学习心得--自勉(转)

热门文章

  1. java比较两个list是否相同_Java判断两个List是否相同
  2. java 方法名相同_我们可以在Java中定义与类名称相同的方法名称吗?
  3. 武林传刀剑江湖录(下)攻略
  4. -1073740791 (0xC0000409)”错误解决的一种可能性
  5. 计算机一级考试Office2007,计算机一级辅导:Office2007的两个技巧
  6. 解决ff浏览器下载文件中文乱码问题
  7. 音质好的电脑录音软件是哪个
  8. 全球及中国家用除湿机行业“十四五”规划与投资规模分析报告2022-2027年版
  9. C++中typename关键字的使用方法和注意事项
  10. Windows10 软件推荐