微信支付文档传送门:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3

1.开发工具:
idea+springcloud+微信web开发工具

2.开发环境:
java+maven

3.开发前准备:
3.1 所需材料
小程序的appid,APPsecret,支付商户号(mch_id),商户密钥(key),付款用户的openid。

申请接入微信商户地址:https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_miniapp.shtml

3.2 开发模式
本次开发采用的开发模式是:普通模式,适用于有自己开发团队或外包开发商的直连商户收款。开发者申请自己的appid和mch_id,两者需具备绑定关系,以此来使用微信支付提供的开放接口,对用户提供服务。

开发 java

一、控制层 PaymentController.java

/*** 微信预支付Api* 统一下单接口* @param openId* @return*/
@ApiOperation("微信预支付1")
@ApiImplicitParams({@ApiImplicitParam(name = "openId",value = "用户openId")
})
@PostMapping(value = {"jsapipays"})
public ResponseEntity jsapipays(@RequestParam String openId) {Condition usercondition = new Condition(User.class);usercondition.createCriteria().andEqualTo("wxId",openId);User user=userService.findByCondition(usercondition,null).get(0);//通过用户ID查询蓝牙订单Condition bizBluetoothOrderC=new Condition(BizBluetoothOrder.class);bizBluetoothOrderC.createCriteria().andEqualTo("uId",user.getId());List<BizBluetoothOrder> bizBluetoothOrderlist = bizBluetoothOrderService.findByCondition(bizBluetoothOrderC,null);if(bizBluetoothOrderlist.isEmpty()){return failResult("订单不存在!");}BizBluetoothOrder bizBluetoothOrder = bizBluetoothOrderlist.get(0);Map jsapi = wxPayService.jsapi2(bizBluetoothOrder.getOrderSn(),"18.0" ,openId);return successResult(jsapi);
}

二、service层

/*** 微信小程序支付* @param orderNum* @param openId* @return*/
Map jsapi2(String orderNum , String total_fee, String openId);

三、实现类

/*** 统一下单开始 方法1* @param orderNum* @param total_fee* @param openId* @return*/
@Override
public Map jsapi2(String orderNum , String total_fee, String openId) {try {log.info("订单号=="+orderNum);//拼接统一下单地址参数SortedMap<String,String> paraMap = new TreeMap();paraMap.put("appid", WXConstEnum.appId);paraMap.put("body", "支付订单");paraMap.put("mch_id", WXConstEnum.mch_id);paraMap.put("nonce_str", WxPayUtils.makeUUID(32).toUpperCase());paraMap.put("signType",WXConstEnum.SIGNTYPE);paraMap.put("openid", openId);paraMap.put("out_trade_no",orderNum);//订单号  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一paraMap.put("spbill_create_ip", WxPayUtils.getLocalIp());paraMap.put("total_fee", total_fee);paraMap.put("timeStamp", WxPayUtils.getCurrentTimeStamp());paraMap.put("trade_type",WXConstEnum.TRADETYPE);paraMap.put("notify_url",WXConstEnum.notify_url);// 此路径是微信服务器调用支付结果通知路径随意写String sign =  WXPayUtil.generateSignature(paraMap, WXConstEnum.key).toUpperCase();paraMap.put("sign", sign);String xml = WxPayUtils.mapToXml(paraMap);//将所有参数(map)转xml格式log.info("xml源串 = " + xml);// 统一下单地址 https://api.mch.weixin.qq.com/pay/unifiedorderString xmlStr = HttpUtils.sendPost(WXConstEnum.pay_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_idlog.info("返回xmlStr = " + xmlStr);//以下内容是返回前端页面的json数据String prepay_id = "";//预支付idif (xmlStr.indexOf("SUCCESS") != -1) {Map<String, String> map = WxPayUtils.xmlToMap(xmlStr);prepay_id = map.get("prepay_id");}Map<String, String> payMap = new HashMap<String, String>();payMap.put("appId", WXConstEnum.appId);payMap.put("timeStamp", WxPayUtils.getCurrentTimeStamp());payMap.put("nonceStr", WxPayUtils.makeUUID(32));payMap.put("signType", "MD5");String paySign =  WXPayUtil.generateSignature(paraMap, WXConstEnum.key).toUpperCase();payMap.put("paySign", paySign);payMap.put("package", "prepay_id=" + prepay_id);return payMap;} catch (Exception e) {e.printStackTrace();}return null;
}四、调用统一下单的接口 参数类WXConstEnum.java
/*** TODO 替换成自己的参数*/
//微信小程序appid
public static String appId = "wx34118d54080e5555";
//微信商户号
public static String mch_id="1612911113";
//微信支付的商户密钥
public static final String key = "50c01580a2824d48a48d94e9f6b046fb";
//支付成功后的服务器回调url
public static final String notify_url="http://shopdev.lyproduct.cn/lyshop-app/app/orderapi/miniNotify";
//签名方式
public static final String SIGNTYPE = "MD5";
//交易类型
public static final String TRADETYPE = "JSAPI";
//微信统一下单接口地址
public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信支付返回状态码
public static final String SUCCESS = "SUCCESS";

五、WxPayUtils.java 需要用到的工具类 官方文档会有提供SDK

/*** XML格式字符串转换为Map** @param strXML XML字符串* @return XML数据转换后的Map* @throws Exception*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {try {Map<String, String> data = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));org.w3c.dom.Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}try {stream.close();} catch (Exception ex) {// do nothing}return data;} catch (Exception ex) {throw ex;}}/*** 将Map转换为XML格式的字符串** @param data Map类型数据* @return XML格式的字符串* @throws Exception*/
public static String mapToXml(SortedMap<String, String> data) throws Exception {DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//防止XXE攻击documentBuilderFactory.setXIncludeAware(false);documentBuilderFactory.setExpandEntityReferences(false);DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();org.w3c.dom.Document document = documentBuilder.newDocument();org.w3c.dom.Element root = document.createElement("xml");document.appendChild(root);for (String key: data.keySet()) {String value = data.get(key);if (value == null) {value = "";}value = value.trim();org.w3c.dom.Element filed = document.createElement(key);filed.appendChild(document.createTextNode(value));root.appendChild(filed);}TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer = tf.newTransformer();DOMSource source = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");StringWriter writer = new StringWriter();StreamResult result = new StreamResult(writer);transformer.transform(source, result);String output = writer.getBuffer().toString();try {writer.close();}catch (Exception ex) {}return output;
}/*** 生成签名** @param data 待签名数据* @param key API密钥* @return 签名*/
public static String generateSignature(final Map<String, String> data, String key) throws Exception {return generateSignature(data, key, WXPayConstants.SignType.MD5);
}/*** 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。** @param data 待签名数据* @param key API密钥* @param signType 签名方式* @return 签名*/
public static String generateSignature(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {Set<String> keySet = data.keySet();String[] keyArray = keySet.toArray(new String[keySet.size()]);Arrays.sort(keyArray);StringBuilder sb = new StringBuilder();for (String k : keyArray) {if (k.equals(WXPayConstants.FIELD_SIGN)) {continue;}if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名sb.append(k).append("=").append(data.get(k).trim()).append("&");}sb.append("key=").append(key);if (WXPayConstants.SignType.MD5.equals(signType)) {return MD5(sb.toString()).toUpperCase();}else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {return HMACSHA256(sb.toString(), key);}else {throw new Exception(String.format("Invalid sign_type: %s", signType));}
}
/*** 生成 MD5** @param data 待处理数据* @return MD5结果*/
public static String MD5(String data) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");byte[] array = md.digest(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();
}/*** 生成 HMACSHA256* @param data 待处理数据* @param key 密钥* @return 加密结果* @throws Exception*/
public static String HMACSHA256(String data, String key) throws Exception {Mac sha256_HMAC = Mac.getInstance("HmacSHA256");SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");sha256_HMAC.init(secret_key);byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();
}/*** 获取有序map* @param map* @return*/
public static SortedMap<String,String> getSortedMap(Map<String,String> map){SortedMap<String, String> sortedMap = new TreeMap<>();Iterator<String> it =  map.keySet().iterator();while (it.hasNext()){String key  = (String)it.next();String value = map.get(key);String temp = "";if( null != value){temp = value.trim();}sortedMap.put(key,temp);}return sortedMap;
}/*** 生成随机数** @return*/
public static String makeUUID(int len) {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
}/*** 获取当前的Timestamp** @return*/
public static String getCurrentTimeStamp() {return Long.toString(System.currentTimeMillis()/1000);
}/*** 获取当前的时间* @return*/
public static long getCurrentTimestampMs() {return System.currentTimeMillis();
}
/*** 获取当前机器的ip** @return String*/
public static String getLocalIp(){InetAddress ia=null;String localip = null;try {ia=ia.getLocalHost();localip=ia.getHostAddress();} catch (Exception e) {e.printStackTrace();}return localip;}/*** 转换金额型到整型* @param money* @return*/
public static String moneyToIntegerStr(Double money){BigDecimal decimal = new BigDecimal(money);int amount = decimal.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();return String.valueOf(amount);
}/*** 生成订单号** @return*/
public static String generateOrderNo() {SimpleDateFormat sdf  = new SimpleDateFormat("yyMMdd");return sdf.format(new Date())+makeUUID(16);
}/*** 获取当前工程url** @param request* @return*/
public static String getCurrentUrl(HttpServletRequest request){return request.getScheme() +"://" + request.getServerName()  + ":" +request.getServerPort() +request.getContextPath();
}/*** 转换double 为 int string* @param payAmount* @return*/
public static String moneyToIntegerStr(double payAmount){String money = String.valueOf(payAmount);return money;
}

传递的xml参数必须按照官方接口文档(https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1),如果出现sing签名错误的问题,试试修改商户密钥(本人修改了三次才成功)。

control层调用接口时 我是值传递了openId 可以根据下单的需要去其他参数(注意大小写)

所有的参数都有,应该不会看不懂吧。直接复制粘贴!

微信小程序支付(java后端)相关推荐

  1. 微信小程序支付 Java后端代码详解

    微信小程序发起支付 Java后台处理代码---- 直接上代码吧! 我把自己的业务逻辑代码删了,但是都有注释的 莫慌! package com.mvc.controller;import java.io ...

  2. 微信小程序篇_01 微信小程序与Java后端接口交互

    微信小程序与Java后端接口交互 准备 创建后端项目 创建小程序项目 本文主要介绍小程序前后端数据的交互,实践演示. 准备 创建后端项目 我这里就创建一个SpringBoot项目作为演示. 在创建项目 ...

  3. 微信小程序支付 java

    话不多说,直接开撸. 支付流程步骤: 1)首先调用wx.login方法获取code,通过code获取openid: 2)java后台调用统一下单支付接口(这里会进行第一次签名),用来获取prepay_ ...

  4. 微信小程序支付java服务端集成采坑总结

    先上个微信小程序支付官方文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8 重点看 ...

  5. 微信小程序支付-java对接微信

    一共是两个方法: 一个方法后台生成预支付订单,得到预支付交易会话标识prepay_id,传给前端,让前端调起小程序支付: 一个是支付回调 目录 一.生成预支付订单 注意: 二. 支付回调 一.生成预支 ...

  6. 微信小程序向java后端发送对象时 ,后端接收不到

    微信小程序前端向后端发送对象接收不到 这里时请求头 这里时data中做的假数据 这是封装好的 post请求 后端的Controller代码 返回的结果 接收结果为null  但是可以接到可以用过 加@ ...

  7. 微信小程序结合Java后端实现登录注册

    微信小程序登录 微信用户,授权信息,相关实体类 微信用户表 实体类 获取微信的token 常量抽取 httpClient工具,用于发送请求获取token nbplus pom 工具类 请求微信后台,获 ...

  8. 小程序支付php客户源码,微信小程序支付-PHP后端

    一.前端代码: 1.先写一个可以点击支付的按钮支付 2.开始js代码pay: function(){ //下订单并唤起微信支付 var price = '0.01'; //支付金额 var openi ...

  9. 微信小程序支付java端apiv3版

    背景 :网上支付这块资料比较多也比较杂,有些是基于老版本接口的文章,虽然说明很详细写的很好阅读量很大, 但是不是那么适用.现在最新版本apiv3,基于此基础上做的支付开发. 官方文档地址:https: ...

  10. 微信小程序支付java视频_【原创】微信小程序支付(普通模式,公众号支付同适用)java后台案例...

    /*** * 支付回调接口*/@RequestMapping("/userpaycallback")publicString wxUserPaycallback(HttpServl ...

最新文章

  1. Android chromium 1
  2. golang中的strings.HasSuffix
  3. 大熊君学习html5系列之------History API(SPA单页应用的必备------重构完结版)
  4. response.setStatus的时机
  5. 上世纪八九十年代的收录放音机拆解
  6. 黄聪:PHP去掉转义后字符串中的反斜杠\函数stripslashes
  7. 中小卖家需要避开的三个坑
  8. html onblur 函数执行了2次,JavaScript“onblur事件”调用函数失效 原因与解决方法
  9. WPF自定义LED风格数字显示控件
  10. flutter 弹幕插件_Flutter 实现虎牙/斗鱼 弹幕效果
  11. win10 安装MASM32 遇到的问题DELETE operation of EXE file has failed
  12. 宫颈癌风险的智能诊断
  13. eact Native开发IDE安装及配置
  14. java+添加分割符_如何给数字添加分隔符
  15. Redis--集群-Cluster-真正的/终极版的集群
  16. 【松鼠科学会】头脑练功房:冥想真的有效吗?
  17. php把buffer转化为图片_长微博生成(将html转化为图片)原理浅析
  18. 利用 Openai Gpt-3 实现下一代自动化测试
  19. 我用python搞了一个杀毒软件(菜)
  20. html table表头升序 降序,jquery实现表格根据字段进行升序降序

热门文章

  1. 自媒体账号如何注册?手把手教你只需四步
  2. DPR-Dense Passage Retrieval for Open-Domain Question Answering 论文阅读
  3. 公司管理混乱,沟通不便导致我熬夜加班怎么办
  4. 码奴们,给大家推荐个电影网站-大家学影视网
  5. 【编程科普】为何电脑的时间有时候走不准?一秒到底有多长?
  6. BIOS14: Multiple Regression(多元回归) using R
  7. 管理高效优秀团队的,都懂这3条天规,请静下心感悟!
  8. 计算机音乐谱刚好遇见你,刚好遇见你 (完整版)
  9. 在线文档技术揭秘开篇 - 富文本编辑器
  10. 致2020 : 蜗牛学院迎难而上的一年!