一、支付流程

PS:做这个之前  ,先去下载官方的SDK吧  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

1.首先要拿到appid,key,AppSecret, mch_id (商户号) 。  这几个参数由你或者是你公司去申请

2.前端需要给后端的(统一下单接口)传递code(登录凭证),标题body(自定义,比如游戏充值)和支付金额 。

3.后端需要有统一下单的接口和一个支付成功后的回调接口

4.统一下单接口在收到这三个参数后,先根据code去获取openid(JSAPI必传openid),

官网放出的获取openid的请求地址  需要appid ,secret,  code,   grant_type的值写成固定的->authorization_code

GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

5.然后把各种参数封装为一个map 再根据secret和map进行MD5加密返回一个签名 ,再把这个签名封装到map中

最后 发送请求并返回结果

6.获取到第一次签名请求的结果后,再对返回的数据进行第二次签名,最后返回给前端一系列的参数

7.前端在收到返回的参数后,如果为success ,就调起微信支付页面,付款成功后微信会自动调用我们定义的回调函数,在回调函数中需要响应结果给微信系统,表示我们已经支付完成 ,不然微信会调用我们的回调函数8次。

8.回调函数会返回结果,如果为success就表示此次支付成功完成

官网放出的获取openid的请求地址  需要appid , secret,code,grant_type写成固定的->authorization_code

具体代码:

统一下单,回调函数,查询订单--具体代码:

注意: 这里面的地址我都不是用的localhost  ,需要弄成外网的样子  所以这里我做了一个内网穿透  不然回调函数无法执行

内网穿透我用的是ngrok,官网下载后启动执行ngrok http 端口号 。然后就会生成一行地址,你把你接口的地址加在生成的地址后面就可以访问了

1.

package com.github.wxpay.sdk.wxpaydemo.controller;import com.github.wxpay.sdk.wxpaydemo.config.WXPay;
import com.github.wxpay.sdk.wxpaydemo.config.WXPayConstants;
import com.github.wxpay.sdk.wxpaydemo.config.WXPayUtil;
import com.github.wxpay.sdk.wxpaydemo.domain.OrderQueryReturnDomain;
import com.github.wxpay.sdk.wxpaydemo.domain.OrderReturnDomain;
import com.github.wxpay.sdk.wxpaydemo.domain.PayDomain;
import com.github.wxpay.sdk.wxpaydemo.util.PayUtil;
import com.github.wxpay.sdk.wxpaydemo.util.RandomStringGenerator;
import com.github.wxpay.sdk.wxpaydemo.util.WxPayGobal;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.XStream;
import org.springframework.web.bind.annotation.*;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;/*** 微信小程序支付接口*/@RestController
@RequestMapping("/pay")
public class wxpay {//JSAPI和APP 统一下单请求地址 (固定的)private static  final String JSAPI_URL="https://api.mch.weixin.qq.com/pay/unifiedorder";//支付回调地址(你自己的请求地址,可以自己随意配置啦,写在这方便你理解)private static final String  NOTIFY_URL = "http://04a3af668030.ngrok.io/pay/back/wxNotify";//支付订单查询地址 (固定的)private static  final String ORDER_URL="https://api.mch.weixin.qq.com/pay/orderquery";//交易类型(这里是公众号支付)private static final String TRADE_TYPE = "JSAPI";/*** JSAPI 统一下单接口** @param code  登录凭证* @param body  标题* @param money 支付金额* @return 返回交易类型和预支付会话标识* @throws Exception*/@PostMapping("/wxJSApiPay")public Map<String, Object> wxJSApiPay(String code, String body, String money) throws Exception {String orderNumber = WxPayGobal.orderNumber();Map<String, String> data = new HashMap<String, String>();Map<String, Object> map = new HashMap<String, Object>();data.put("appid", PayDomain.getAppid());   //appiddata.put("mch_id", PayDomain.getMch_id()); //商户iddata.put("body", body);                            //标题data.put("out_trade_no", orderNumber);//订单号data.put("total_fee", money);                      //金额  单位为分data.put("spbill_create_ip", InetAddress.getLocalHost().getHostAddress());//终端IPdata.put("notify_url", NOTIFY_URL);                                       //回调地址data.put("trade_type", TRADE_TYPE);                                       // 交易类型data.put("openid", WxPayGobal.getOpenId(code));                           //用户标识data.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32)); //随机字符串System.out.println(data);String result = WxPayGobal.wxPay(data,JSAPI_URL);                                   //传递参数发送请求并返回结果XStream xStream = new XStream();//出于安全考虑,这里必须限制类型,不然会报错xStream.allowTypes(new Class[]{OrderReturnDomain.class});xStream.alias("xml", OrderReturnDomain.class);OrderReturnDomain s = (OrderReturnDomain) xStream.fromXML(result);        //返回结果转换为实体//当请求返回结果为success时  进行二次签名if ("SUCCESS".equals(s.getReturn_code()) && s.getReturn_code().equals(s.getResult_code())) {//生成签名(官方给出来的签名方法)Map<String, String> map2 = new HashMap<String, String>();long time = System.currentTimeMillis() / 1000;map2.put("appId", PayDomain.getAppid());map2.put("timeStamp", String.valueOf(time));//这边的随机字符串必须是第一次生成sign时,微信返回的随机字符串,不然小程序支付时会报签名错误map2.put("nonceStr", s.getNonce_str());map2.put("package", "prepay_id=" + s.getPrepay_id());map2.put("signType", "MD5");String sign2 = WXPayUtil.generateSignature(map2, PayDomain.getKey(), WXPayConstants.SignType.MD5);System.out.println("二次签名的sign2----->" + sign2);Map<String, Object> payInfo = new HashMap<String, Object>();payInfo.put("timeStamp", String.valueOf(time));payInfo.put("nonceStr", s.getNonce_str());payInfo.put("package", "prepay_id="+s.getPrepay_id());payInfo.put("signType", "MD5");payInfo.put("paySign", sign2);payInfo.put("orderNumber",orderNumber);map.put("status", 200);map.put("msg", "success");map.put("data", payInfo);//此处写逻辑代码实现/*** --* --*/} else {return null;}return map;}/**** @param request* @param response* @param orderNumber  下单成功后的订单号* @param sign  下单成功后的签名* @return* @throws Exception*/@PostMapping(value = "/orderQuery")public static OrderQueryReturnDomain orderQuery(HttpServletRequest request, HttpServletResponse response,String orderNumber,String sign) throws Exception {Map<String, String> data = new HashMap<String, String>();data.put("appid", PayDomain.getAppid());data.put("mch_id", PayDomain.getMch_id());data.put("out_trade_no", orderNumber);//订单号data.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32)); //随机字符串data.put("sign",sign);                                                    //签名System.out.println(data);String s = WxPayGobal.wxPay(data,ORDER_URL);                                   //传递参数发送请求并返回结果XStream xStream = new XStream();OrderQueryReturnDomain result = (OrderQueryReturnDomain) xStream.fromXML(s);return result;}/*** 微信小程序支付成功回调函数** @param request* @param response* @throws Exception*/@RequestMapping(value = "/callback/wxNotify")public static void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));String line = null;StringBuilder sb = new StringBuilder();while ((line = br.readLine()) != null) {sb.append(line);}br.close();//sb为微信返回的xmlString notityXml = sb.toString();String resXml = "";System.out.println("接收到的报文:" + notityXml);@SuppressWarnings("unchecked")Map<String, String> map = PayUtil.doXMLParse(notityXml);String returnCode = (String) map.get("return_code");if ("SUCCESS".equals(returnCode)) {//验证签名是否正确Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数String validStr = PayUtil.createLinkString(validParams);//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串String sign = PayUtil.sign(validStr, PayDomain.getKey(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名// 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了//根据微信官网的介绍,此处不仅对回调的参数进行验签,还需要对返回的金额与系统订单的金额进行比对等if (sign.equals(map.get("sign"))) {/**此处添加自己的业务逻辑代码start**/// bla bla bla..../**此处添加自己的业务逻辑代码end**///通知微信服务器已经支付成功resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";} else {System.out.println("微信支付回调失败!签名不一致");}} else {resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";}System.out.println(resXml);System.out.println("微信支付回调数据结束");BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());out.write(resXml.getBytes());out.flush();out.close();}}

2.工具类   用于发送请求  获取openid  生成订单号(具体的订单号生成规则需要修改,我这里只是演示,不能用于上线)

package com.github.wxpay.sdk.wxpaydemo.util;import com.github.wxpay.sdk.wxpaydemo.config.WXPayUtil;
import com.github.wxpay.sdk.wxpaydemo.domain.PayDomain;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import java.io.IOException;import java.time.LocalDateTime;
import java.util.Map;import com.alibaba.fastjson.JSONObject;/*** 小程序支付工具类*/@Component
public class WxPayGobal {/*** 请求地址  (用于获取openid)*/private final static String url = "https://api.weixin.qq.com/sns/jscode2session";private static Logger logger = LoggerFactory.getLogger(WxPayGobal.class);public static String wxPay(Map<String, String> data,String url) {//生成签名String sign = null;try {sign = WXPayUtil.generateSignature(data, PayDomain.getKey());} catch (Exception e) {e.printStackTrace();}data.put("sign", sign);String s = null;try {s = WXPayUtil.mapToXml(data);} catch (Exception e) {e.printStackTrace();}//发生请求并返回请求结果String s1 = doPostXml(url, s);System.out.println(s1);return s1;}/*** 发送请求** @param url            请求地址* @param requestDataXml 请求的xml类型的字符串* @return*/public static String doPostXml(String url, String requestDataXml) {CloseableHttpClient httpClient = null;CloseableHttpResponse httpResponse = null;httpClient = HttpClients.createDefault();HttpPost httpPost = new HttpPost(url);RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(15000).setConnectionRequestTimeout(60000).setSocketTimeout(60000).build();httpPost.setConfig(requestConfig);httpPost.setEntity(new StringEntity(requestDataXml, "UTF-8"));httpPost.addHeader("Content-Type", "text/xml");String result = "";try {httpResponse = httpClient.execute(httpPost);HttpEntity entity = httpResponse.getEntity();result = EntityUtils.toString(entity, "UTF-8");} catch (Exception e) {e.printStackTrace();}return result;}/*** 获取openId* @param code 登录凭证* @return*/public static String getOpenId(String code) {//请求参数String params = url + "?appid=" + PayDomain.getAppid() + "&secret=" + PayDomain.getSecret() + "&js_code=" + code + "&grant_type=" + "authorization_code";logger.info("请求地址:"+params);//发送请求HttpGet httpGet = new HttpGet(params);CloseableHttpClient httpClients = HttpClients.createDefault();String result = null;try {CloseableHttpResponse execute = httpClients.execute(httpGet);HttpEntity entity = execute.getEntity();result = EntityUtils.toString(entity);System.out.println(result+"...");} catch (IOException e) {e.printStackTrace();}JSONObject jsonObject = JSONObject.parseObject(result);logger.info("获取openid" + jsonObject.getString("openid"));if (null!=jsonObject.getString("openid")) {String openid = jsonObject.getString("openid");return openid;}return null;}/*** 订单号生成    当前日期+随机数字+商户ID*/public static String orderNumber(){LocalDateTime now = LocalDateTime.now();String str=now.getYear()+""+now.getMonthValue()+now.getDayOfMonth()+"";//当前年月日String randomNumber=""; //随机数字for (int i = 0; i < 6; i++) {int max=9,min=0;int ran2 = (int) (Math.random()*(max-min)+min);randomNumber=ran2+randomNumber;}System.out.println(str+randomNumber);return str+randomNumber;}}

实体类:

package com.github.wxpay.sdk.wxpaydemo.domain;import lombok.Data;/*** 接收统一下单调用微信接口返回的参数* @author Administrator*   */
@Data
public class OrderReturnDomain {/*** 返回状态码 (SUCCESS或 fail)*/private String return_code;/*** 返回信息*/private String return_msg;/*** 返回的结果状态码*/private String result_code;/*** 返回的appid*/private String appid;/*** 返回的商户号*/private String mch_id;/*** 返回的随机字符串*/private String nonce_str;/*** 返回的签名*/private String sign;/***微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时*/private String prepay_id;/*** 返回的交易类型 (JSAPI,APP,NATIVE)*/private String trade_type;/*** 返回的错误码*/private String err_code;/*** 返回的错误信息描述*/private String err_code_des;
}
package com.github.wxpay.sdk.wxpaydemo.domain;import lombok.Data;/*** 封装订单支付成功后的返回结果*/@Data
public class OrderQueryReturnDomain {private String return_code;     //返回返回状态码private String return_msg;      //返回信息private String appid;           //公众账号IDprivate String mch_id;          //商户号private String nonce_str;       //随机字符串private String sign;            //签名private String result_code;     //业务结果private String openid;          //用户标识private String is_subscribe;    //是否关注公众账号private String trade_type;      //交易类型private String bank_type;       //付款银行private String total_fee;       //标价金额private String fee_type;        //标价币种private String transaction_id;  //微信支付订单号private String out_trade_no;    //商户订单号private String time_end;        //支付完成时间private String trade_state;     //交易状态private String cash_fee;        //现金支付金额private String trade_state_desc;//交易状态描述private String cash_fee_type;   //现金支付币种}
package com.github.wxpay.sdk.wxpaydemo.domain;import com.github.wxpay.sdk.wxpaydemo.config.WXPayConfig;
import lombok.Data;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
public class PayDomain  {/*** 密钥key*/private static  String key;/*** 应用ID*/private static  String appid;/*** 商户号*/private static  String mch_id;/*** 密钥* @param key*/private static  String secret;@Value("${com.wx.wxpay.key}")public void setKey(String key) {this.key = key;}@Value("${com.wx.wxpay.appid}")public void setAppid(String appid) {this.appid = appid;}@Value("${com.wx.wxpay.mch_id}")public void setMch_id(String mch_id) {this.mch_id = mch_id;}@Value("${com.wx.wxpay.secret}")public  void setSecret(String secret) {PayDomain.secret = secret;}public static String getSecret() {return secret;}public static  String getKey() {return key;}public static  String getAppid() {return appid;}public static  String getMch_id() {return mch_id;}}

pom:

<dependencies>
<!--        map和xml之间的转换器--><dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.9</version></dependency>
<!--        操作xml标签--><dependency><groupId>org.jdom</groupId><artifactId>jdom</artifactId><version>2.0.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.4</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.3</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.18</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies>

记得一定要下载官方SDK !!! 然后把我这些代码加上去就OK   。

由于需要得朋友太多了,我就直接上传文件吧。

完整demo文件下载地址:不需要积分

https://download.csdn.net/download/aSmart_Q/36142998

觉得好用,给我点个赞吧!!感谢

SpringBoot 搭建微信小程序支付(JSAPI) 纯后端相关推荐

  1. SpringBoot对接微信小程序支付功能开发(一,下单功能)

    1,接入前准备: 接入模式选择直连模式: 申请小程序,得到APPID,并开通微信支付: 申请微信商户号,得到mchid,并绑定APPID: 配置商户API key,下载并配置商户证书,根据微信官方文档 ...

  2. SpringBoot对接微信小程序支付功能开发(二,支付回调功能)

    接着上一篇: SpringBoot对接微信小程序支付功能开发(一,下单功能) 在上一篇下单功能中我们有传支付结果回调地址. 下面是回调接口实现 package com.office.miniapp.c ...

  3. 关于使用nodejs搭建微信小程序支付接口

    前言 前段时间在开发一个微信小程序的时候需要用到支付功能,我就去看了下微信支付的官方文档,好家伙,微信官方只提供了java.php还有Go语言的sdk.PHP我会点吧,但又不是很会,做为一个菜鸡前端, ...

  4. SpringBoot实现微信小程序支付

    本文给大家讲解微信小程序支付全流程,以及相关功能源代码,项目不开放,带来不便尽请谅解.小程序支付主要 包含如下几步骤,1.预下单-调用微信统一下单接口进行预下单.2.小程序拿到支付参数唤醒支付.3.支 ...

  5. 微信小程序支付(java后端)

    微信支付文档传送门:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3 1.开发工具: idea+springclou ...

  6. 微信小程序支付以及退款功能(超详细)

    Springboot整合微信小程序支付 第一步: 第二步:导入微信支付的依赖 第三步:在springboot核心配置文件中配置参数 第四步:创建配置类WxPayAppConfig 第五步:支付方法 s ...

  7. 微信小程序支付流程(Java后端)

    微信小程序支付(Java后端) 一.小程序支付的交互图如下 按住ctrl点击 微信支付平台开发文档 二.准备工作 第一步:在pom文件中导入微信支付SDK 有可能自动下载不了,可以到微信支付平台下载手 ...

  8. 基于springboot微信小程序支付功能实现

    基于springboot微信小程序支付功能实现 简单的封装微信小程序支付功能,支付工具类所依赖的fastjson.lombok.wagegger, 1.添加maven依赖: 版本号可根据自己项目的实际 ...

  9. 微信小程序调用JSAPI进行微信支付

    微信小程序调用JSAPI进行微信支付 1.小程序中先调用接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付: 2.商户server调用再次签名: 3.唤起微信支付页面,进行支付: ...

最新文章

  1. 如何看待亚马逊 AI 李沐团队大批人员离职?
  2. 2019年25大人工智能趋势!一文看到未来
  3. 解决 'config.h' file not found。升级xcode 新版本导致旧的RN项目打开报错 解决方法。...
  4. 前端开发面试题总结之——CSS3
  5. 博为峰Java技术文章 ——JavaSE Swing JPanel III
  6. 详解RPC远程调用和消息队列MQ的区别
  7. 本地上传文件到Linux云服务器
  8. android使用greedao踩坑日记
  9. Ubuntu使用谷歌浏览器登录账号时崩溃
  10. 黑马程序员全套Java教程_Java基础入门视频教程零基础自学Java必备教程视频讲义(3)
  11. Java网络编程-简易聊天室源码分享
  12. CRCNN PCNN
  13. 汽车制造商代码表_汽车制造商合作打造未来汽车
  14. 中国菜刀使用与原理分析
  15. 大型网站图片服务器架构的演进!
  16. Flask入门flask-script 蓝本 钩子函数(3)
  17. 5g cpe参数及功能介绍
  18. TIA博途中使用T-CONFIG指令修改S7-1200 PLC的IP地址和设备名称
  19. php 变量 问号,php – Laravel查询返回问号而不是变量值
  20. php开发商城系统怎么样?有哪些PHP开源商城系统推荐?

热门文章

  1. 微软魔镜——从“解语花”到“读心树”的神奇魔法
  2. 在金融行业中,直播获客应该怎么做呢?
  3. SUSE Linux Enterprise助力企业数字化转型
  4. 在键盘上同时按3个键有时会有一个键不起作用是什么原因?
  5. 《数字图像处理》题库5:计算题 ②
  6. matlab与abaqus结构优化,基于MATLAB和ABAQUS的螺旋钻杆参数优化与数值模拟
  7. 标题Macvim连接Mac终端前期终端配置
  8. 未来的计算机科技画,未来科技生活绘画作品有哪些
  9. Unity_Skybox自定义插件可实现日夜更替Polyverse Skies | Low Poly
  10. CTFshow sql注入 上篇(web221-253)