微信小程序> 微信小程序调用微信支付(java后台)

微信小程序调用微信支付(java后台)

浏览量:1156 时间: 来源:我是死宅萝莉控

目录标题

      • 参考链接
      • 准备事项
      • 开发工具
      • 使用框架
      • 小程序代码
      • pom.xml
      • 后台java代码
    • 用到的外部jar包和工具类
    • 补充说明

参考链接

  • 微信官方支付文档
  • csdn博客

准备事项

  1. 小程序appid
    进入
    小程序
    小程序

  2. 小程序AppSecret

  3. 商户id

  4. 商户平台api密钥

  5. 后台服务器(听说可以使用云开发就不用准备服务器,但是我这边使用的不是云开发)

开发工具

eclipse+tomcat+微信开发者工具

使用框架

spring,spring-mvc

小程序代码

  //获取用户openid  getWXOpenId: function () {    var that = this;    wx.login({      //获取code      success: function (res) {        var code = res.code; //返回code        var appId = '填入appid';        var secret = '填入sercret';        wx.request({          url: 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appId + '&secret=' + secret + '&js_code=' + code + '&grant_type=authorization_code',          data: {},          header: {            'content-type': 'json'          },          success: function (res) {            var openid = res.data.openid //返回openid            that.setData({              openId: openid            });            that.buyGoods(openid);          }        })      }    });  },  //发送信息到后台  buyGoods: function (openId) {    var that = this;    var courseName = 0;    //后台服务地址    var address = "后台接口路径";    wx.request({      url: address,      data: {        openId: openId,        courseName: courseName      },      header: {        'content-type': 'application/x-www-form-urlencoded' // 默认值      },      method: "POST",      success: function (res) {        console.log(res);        that.doWxPay(res.data);      },      fail: function (err) {        wx.showToast({          icon: "none",          title: '服务器异常,清稍候再试'        })      },    });  },  doWxPay(param) {    console.log(param);    //小程序发起微信支付    wx.requestPayment({      timeStamp: param.data.timeStamp,//记住,这边的timeStamp一定要是字符串类型的,不然会报错      nonceStr: param.data.nonceStr,      package: param.data.package,      signType: 'MD5',      paySign: param.data.paySign,      success: function (event) {        // success        console.log(event);        wx.showToast({          title: '支付成功',          icon: 'success',          duration: 2000        });      },      fail: function (error) {        // fail        console.log("支付失败")        console.log(error)      },      complete: function () {        // complete        console.log("pay complete")      }    });  },

pom.xml

有很多是用不到的,可以自己去掉

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.jt</groupId>  <artifactId>pay</artifactId>  <version>0.0.1-SNAPSHOT</version>  <packaging>war</packaging>  <dependencies>  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-webmvc</artifactId>  <version>4.3.9.RELEASE</version>  </dependency>  <dependency>  <groupId>mysql</groupId>  <artifactId>mysql-connector-java</artifactId>  <version>5.1.40</version>  </dependency>  <dependency>  <groupId>com.alibaba</groupId>  <artifactId>druid</artifactId>  <version>1.0.29</version>  </dependency>  <dependency>  <groupId>org.mybatis</groupId>  <artifactId>mybatis</artifactId>  <version>3.2.8</version>  </dependency>  <dependency>  <groupId>org.mybatis</groupId>  <artifactId>mybatis-spring</artifactId>  <version>1.3.1</version>  </dependency>  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-jdbc</artifactId>  <version>4.3.9.RELEASE</version>  </dependency>  <dependency>  <groupId>com.fasterxml.jackson.core</groupId>  <artifactId>jackson-databind</artifactId>  <version>2.8.5</version>  </dependency>  <dependency>  <groupId>junit</groupId>  <artifactId>junit</artifactId>  <version>4.12</version>  </dependency>  <dependency>  <groupId>jstl</groupId>  <artifactId>jstl</artifactId>  <version>1.2</version>  </dependency>    <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.3.2</version></dependency><!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient --><dependency>    <groupId>commons-httpclient</groupId>    <artifactId>commons-httpclient</artifactId>    <version>3.1</version></dependency><dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId>    <version>4.5.2</version></dependency>  </dependencies></project>

后台java代码

package com.jt.sys.controller;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Random;import org.apache.commons.httpclient.HttpException;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpClient;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.DefaultHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.protocol.HTTP;import org.apache.http.util.EntityUtils;import org.springframework.http.HttpMethod;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.util.DigestUtils;import org.springframework.util.LinkedMultiValueMap;import org.springframework.util.MultiValueMap;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.client.RestTemplate;import com.jt.common.vo.HttpRequest;import com.jt.common.vo.HttpUtil;import com.jt.common.vo.JsonResult;@RequestMapping("/")@Controllerpublic class PageController {@RequestMapping("test")public String test(){return "test";}@RequestMapping("buyStepOne")@ResponseBodypublic JsonResult buyStepOne(String openId,String courseName) throws UnsupportedEncodingException {String appId = "appid";String mch_id = "商户id";String notify_url = "支付成功后台回调地址";String trade_type = "JSAPI";//签名类型String SIGNTYPE = "MD5";//第一次发起支付请求的接口地址String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//key为商户平台设置的密钥keyString WXKeHukey = "商户平台密钥";//生成的随机字符串String nonce_str = getRandomString(32);//商品名称String body = new String(courseName.getBytes("ISO-8859-1"),"UTF-8");//本机的ip地址String spbill_create_ip = "ip地址";//商户订单号(先用时间代替)Date date = new Date();String orderNo = date.getTime()+"";String money = "1";//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败Map<String, String> packageParams = new HashMap<String, String>();//小程序ID,微信分配的小程序IDpackageParams.put("appid", appId);//商户号,微信支付分配的商户号packageParams.put("mch_id", mch_id);//随机字符串,长度要求在32位以内。packageParams.put("nonce_str", nonce_str);//商品简单描述packageParams.put("body", body);//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一packageParams.put("out_trade_no", orderNo);//商户订单号//订单总金额,单位为分packageParams.put("total_fee", money);//终端IP,支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IPpackageParams.put("spbill_create_ip", spbill_create_ip);//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。packageParams.put("notify_url", notify_url);//交易类型(JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付,不同trade_type决定了调起支付的方式,请根据支付产品正确上传)packageParams.put("trade_type", trade_type);//用户标识,trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。packageParams.put("openid", openId);  // 除去数组中的空值和签名参数packageParams = paraFilter(packageParams);String prestr = createLinkString(packageParams); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口,key为商户平台设置的密钥keyString mysign = sign(prestr, WXKeHukey, "utf-8").toUpperCase();System.out.println("=======================第一次签名:" + mysign + "=====================");//拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去String xml = "<xml version='1.0' encoding='gbk'>" + "<appid>" + appId + "</appid>" + "<body><![CDATA[" + body + "]]></body>" + "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>" + "<notify_url>" + notify_url + "</notify_url>" + "<openid>" + openId + "</openid>" + "<out_trade_no>" + orderNo + "</out_trade_no>" + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" + "<total_fee>" + money + "</total_fee>" + "<trade_type>" + trade_type + "</trade_type>" + "<sign>" + mysign + "</sign>" + "</xml>"; System.out.println("调试模式_统一下单接口 请求XML数据:" + xml);//调用统一下单接口,并接受返回的结果String result = httpRequest(pay_url, "POST", xml); System.out.println("调试模式_统一下单接口 返回XML数据:" + result); // 将解析结果存储在HashMap中//Map map = doXMLParse(result); //String return_code = (String) map.get("return_code");//返回状态码//解析结果,将结果存在map中Map map = doXMLToMap(result);String return_code = (String) map.get("return_code");        //返回给移动端需要的参数        Map<String, Object> response = new HashMap<String, Object>();        if(return_code == "SUCCESS" || return_code.equals(return_code)){            // 业务结果            String prepay_id = (String) map.get("prepay_id");//返回的预付单信息            response.put("nonceStr", nonce_str);            response.put("package", "prepay_id=" + prepay_id);            Long timeStamp = System.currentTimeMillis() / 1000;            response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误            String stringSignTemp = "appId=" + appId + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + SIGNTYPE + "&timeStamp=" + timeStamp;            //再次签名,这个签名用于小程序端调用wx.requesetPayment方法            String paySign = sign(stringSignTemp, WXKeHukey, "utf-8").toUpperCase();            System.out.println("=======================第二次签名:" + paySign + "=====================");                        response.put("paySign", paySign);            response.put("appid", appId);        }        return new JsonResult(response);        }/** * 解析xml,取出其中的result_code,和prepay_id */public HashMap<String ,String> doXMLToMap(String results) {HashMap<String ,String> result = new HashMap<String ,String>();String return_code = results.substring(results.indexOf("<return_code><![CDATA[")+22, results.indexOf("]]></return_code>"));result.put("return_code", return_code);if(return_code.equals("SUCCESS")) {String prepay_id = results.substring(results.indexOf("<prepay_id><![CDATA[")+20, results.indexOf("]]></prepay_id>"));result.put("prepay_id", prepay_id);}return result;}/** * * @param requestUrl请求地址 * @param requestMethod请求方法 * @param outputStr参数 */public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {// 创建SSLContextStringBuffer buffer = null;try {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod(requestMethod);conn.setDoOutput(true);conn.setDoInput(true);conn.connect();// 往服务器端写内容if (null != outputStr) {OutputStream os = conn.getOutputStream();os.write(outputStr.getBytes("utf-8"));os.close();}// 读取服务器端返回的内容InputStream is = conn.getInputStream();InputStreamReader isr = new InputStreamReader(is, "utf-8");BufferedReader br = new BufferedReader(isr);buffer = new StringBuffer();String line = null;while ((line = br.readLine()) != null) {buffer.append(line);}br.close();} catch (Exception e) {e.printStackTrace();}return buffer.toString();}/** * 除去数组中的空值和签名参数 *  * @param sArray 签名参数组 * @return 去掉空值与签名参数后的新签名参数组 */public static Map<String, String> paraFilter(Map<String, String> sArray) {Map<String, String> result = new HashMap<String, String>();if (sArray == null || sArray.size() <= 0) {return result;}for (String key : sArray.keySet()) {String value = sArray.get(key);if (value == null || value.equals("") || key.equalsIgnoreCase("sign")|| key.equalsIgnoreCase("sign_type")) {continue;}result.put(key, value);}return result;}/** * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 *  * @param params 需要排序并参与字符拼接的参数组 * @return 拼接后字符串 */public static String createLinkString(Map<String, String> params) {List<String> keys = new ArrayList<String>(params.keySet());Collections.sort(keys);String prestr = "";for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);String value = params.get(key);if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符prestr = prestr + key + "=" + value;} else {prestr = prestr + key + "=" + value + "&";}}return prestr;}/**  * 签名字符串  * @param text需要签名的字符串  * @param key 密钥  * @param input_charset编码格式  * @return 签名结果  */public static String sign(String text, String key, String input_charset) {text = text + "&key=" + key;return DigestUtils.md5DigestAsHex(getContentBytes(text, input_charset));   }/** * @param content * @param charset * @return * @throws SignatureException * @throws UnsupportedEncodingException */public static byte[] getContentBytes(String content, String charset) {if (charset == null || "".equals(charset)) {return content.getBytes();}try {return content.getBytes(charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);}} /** * 支付成功后回调方法 * @return */@RequestMapping("buySteptwo")@ResponseBodypublic JsonResult buySteptwo() {  Map<String, Object> params = getParamsMap();        try {        //读取参数          InputStream inputStream ;          StringBuffer sb = new StringBuffer();          inputStream = getRequest().getInputStream();          String s ;          BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));          while ((s = in.readLine()) != null){              sb.append(s);          }          in.close();          inputStream.close();          //解析xml成map          Map<String, String> m = new HashMap<String, String>();          m = XMLUtil.doXMLParse(sb.toString());          //过滤空 设置 TreeMap          SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();                Iterator<String> it = m.keySet().iterator();          while (it.hasNext()) {              String parameter = it.next();              String parameterValue = m.get(parameter);              String v = "";              if(null != parameterValue) {                  v = parameterValue.trim();              }              packageParams.put(parameter, v);          }          // 微信支付的API密钥          String key = WXKeHukey; // key          //判断签名是否正确          if(PayForUtil.isTenpaySign("UTF-8", packageParams,key)) {              //------------------------------              //处理业务开始              //------------------------------              String resXml = "";              if("SUCCESS".equals((String)packageParams.get("result_code"))){             System.out.println("+++++++++++++++++++回调参数+++++++++++++++++++");            System.out.println(packageParams);                // 这里是支付成功              //执行自己的业务逻辑开始            String app_id = (String)packageParams.get("appid");                String mch_id = (String)packageParams.get("mch_id");                  String openid = (String)packageParams.get("openid");                 String is_subscribe = (String)packageParams.get("is_subscribe");//是否关注公众号                //公用回传参数                 String attach = (String)packageParams.get("attach");                //商户订单号                String out_trade_no = ((String)packageParams.get("out_trade_no"));                  out_trade_no = out_trade_no.replace(" ", "");                //付款金额【以分为单位】                String total_fee = (String)packageParams.get("total_fee");                 //微信生成的交易订单号                String transaction_id = (String)packageParams.get("transaction_id");//微信支付订单号                //支付完成时间                String time_end=(String)packageParams.get("time_end");//                //回调一次后进行判断,查询是否以及添加记录到数据库//                Record huidiao = Db.findById("c_order" , "order_number", transaction_id);//                if(huidiao != null) {//                redirect("/");//                return;//                }                //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.                  resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"                          + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";                  /**                 * 支付成功后的处理                 */                Record order =              Db.findFirst("select * from c_order where order_number = '"+out_trade_no+"'");                System.out.println("+++++++++++++++++++++++++sql+++++++++++++++++++++++++");                System.out.println("select * from c_order where order_number = '"+out_trade_no+"'");                System.out.println(order);                //Record order = Db.findById("c_order" , "order_number", out_trade_no);                //付款金额                order.set("order_money" ,total_fee);                order.set("order_flag", 1 );                order.set("order_time",  new Date());                Db.update("c_order", "order_id",order);                //TODO 支付成功后去哪个页面 我这里先写首页                rendSuccessJson();                return;            } else {                  lg.info("支付失败,错误信息:" + packageParams.get("err_code"));                  resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"                          + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";                 //TODO 支付失败要做什么 我这里先不写            //------------------------------              //处理业务完毕              //------------------------------              BufferedOutputStream out = new BufferedOutputStream(                      getResponse().getOutputStream());              out.write(resXml.getBytes());              out.flush();              out.close();            }          } else{              lg.info("通知签名验证失败");          }          }catch(IOException e) {        e.printStackTrace();        rendFailedJson("IO处理失败,请联系管理员!");        } catch (JDOMException e) {e.printStackTrace();        rendFailedJson("JDOM处理失败,请联系管理员!");}   }//length用户要求产生字符串的长度 public static String getRandomString(int length){     String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";     Random random=new Random();     StringBuffer sb=new StringBuffer();     for(int i=0;i<length;i++){       int number=random.nextInt(62);       sb.append(str.charAt(number));     }     return sb.toString(); }}

用到的外部jar包和工具类

https://download.csdn.net/download/qq_40488121/11704169

补充说明

上线阶段出现了问题,因为微信不希望开发者将appid和密钥存储在前台,所以直接调用微信的接口获取appid是不行的,只能通过后台来获取,这样的话应该是前台一步到位发一次请求就好了,但是我比较懒,就直接把请求微信的接口直接改到后台,直接后台获取openid后放回,其他都不用变

public void getOpenId() {Map<String, Object> params = getParamsMap();String code = params.get("code").toString();String secret = "ede5a99e35a0c99a1ea61df19a1aeb72";String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";String openid = HttpUtil.doGet(url);renderText(openid);}

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎