微信小程序实现拉起微信支付功能-最简单版

里面有很多逻辑需要大家自己写啊,比如订单获取啊,生成订单啊,变更订单状态,退款啊,等等的,我这里就实现了一个基本的功能,就是拉起支付,支付到账这样的,大家根据需求自己编写就行。我这里提供的基本上都是复制了直接就能用的那种啊,前提是你要有商户号,要生成秘钥证书这些啊

首先需要去注册商户号啊,这个过程比较复杂啊,然后微信平台上有引导的,大家跟着做就行

就是这个位置啊,然后需要提交的材料准备好就行,基本上当天就会批下来,费率的话每个行业都是不一样的啊,然后在小程序里关联到商户号就行,

代码编写 只附部分核心程序,他是需要拿着openid去后台获取相应的参数的啊,这里的orderId我直接前端随机了,正常应该写在后端的啊,大家额注意一下。有些参数没明白的,可以去微信平台的文档里看一下啊,都是一一对应的啊,然后我这个也不需要下载什么jdk,maven的话也是springboot那一套啊,没什么特殊的

data: {
    phoneNumber: '', // 存储手机号
    openid: '', // 用户的 openid
    orderId: '', // 订单 ID
    paymentData: null, // 存储从后端获取的支付参数
    statu:'点击支付',
    isButtonDisabled: false // 默认按钮是可点击的
  },
  generateOrderId: function() {
    // 获取当前时间戳
    const timestamp = new Date().getTime();
    // 生成一个随机数
    const randomNum = Math.floor(Math.random() * 100000);
    // 拼接时间戳和随机数生成订单号
    return timestamp.toString() + randomNum.toString();
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    const orderId = this.generateOrderId();
    const openId = wx.getStorageSync('openId')
    this.setData({
      openid: openId,
      orderId: orderId
     
    });
  },
 // 发起支付函数
 startPayment: function () {
  const that = this;
  // 先从后端获取支付参数
  wx.request({
    url: url+'api/getPaymentParams',
    method: 'POST',
    data: {
      openid: this.data.openid,
      orderId: this.data.orderId
    },
    success: function (res) {
      if (res.data && res.data.success) {

        const paymentData = res.data.paymentData;
        console.log(res.data.paySign)
        // 调用微信支付接口
        wx.requestPayment({
          timeStamp: paymentData.timeStamp,
          nonceStr: paymentData.nonceStr,
          package: paymentData.package,
          signType: paymentData.signType,
          paySign: res.data.paySign,
          success: (res) => { // 使用箭头函数
           that.setData({
              statu: '已支付',
              isButtonDisabled: true // 将按钮设置为不可点击
            });
            console.log('支付成功', res);
            wx.request({
              url: url + 'api/setOrder?orderId=' + that.data.orderId, //仅为示例,并非真实的接口地址
              method: 'GET',
              header: { 'content-type': 'application/json' },
              success: (res) => {
                // 处理成功请求的回调
              }
            });
        
            // 支付成功后的操作,如跳转页面或其他逻辑
          },
          fail: (res) => { // 使用箭头函数
            console.log('支付失败', res);
            // 支付失败后的操作,如提示用户重新支付
          }
        });
      } else {
        wx.showToast({
          title: '此订单已支付',
          icon: 'none'
        });
        console.error('获取支付参数失败', res);
      }
    },
    fail: function (err) {
      wx.showToast({
        title: '此订单已支付', 
        icon: 'none'
      });
      console.error('请求支付参数失败', err);
    }
  });
},

Java:服务器端

private static final String APPID = "";
private static final String APPSECRET = "";
private  static  final String MCHID="";//商户号
private  static  final String NOTIFYURL="";//回执地址
private  static  final String  MCHKEY="";//秘钥



@PostMapping("/getPaymentParams")
public @ResponseBody Map<String, Object> getPaymentParams(@RequestBody Map<String, String> request) {
    String openid = request.get("openid");
    String orderId = request.get("orderId");
    String money="1";//目前模拟数据,后续需要通过支付金额表或者是通过第三方获取支付金额,通过OPENID去user表找到手机号,然后通过手机号查询金额表

    // 创建统一下单请求参数
    Map<String, String> params = new HashMap<>();
    params.put("appid", APPID);
    params.put("mch_id",MCHID );
    params.put("nonce_str", WXPayUtil.generateNonceStr());
    params.put("body", "订单支付");
    params.put("out_trade_no", orderId);
    params.put("total_fee", money); // 单位为分
    params.put("spbill_create_ip", "127.0.0.1");
    params.put("notify_url", NOTIFYURL);
    params.put("trade_type", "JSAPI");
    params.put("openid", openid);

    try {
        String sign = WXPayUtil.generateSignature(params, MCHKEY);
        params.put("sign", sign);

        String xml = WXPayUtil.mapToXml(params);
        String response = HttpUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);

        Map<String, String> result = WXPayUtil.xmlToMap(response);

        if ("SUCCESS".equals(result.get("return_code")) && "SUCCESS".equals(result.get("result_code"))) {
            String prepayId = result.get("prepay_id");

            Map<String, String> payMap = new HashMap<>();
            payMap.put("appId", APPID);
            payMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            payMap.put("nonceStr", WXPayUtil.generateNonceStr());
            payMap.put("package", "prepay_id=" + prepayId);
            payMap.put("signType", "MD5");

            String paySign = WXPayUtil.generateSignature(payMap, MCHKEY);

            Map<String, Object> responseMap = new HashMap<>();
            responseMap.put("success", true);
            responseMap.put("paymentData", payMap);
            responseMap.put("paySign", paySign);

            Order order=new Order();
            order.setOrderId(orderId);
            order.setOpenId(openid);
            order.setPayTime(new Date());
            order.setMoney(money);
            orderService.add(order);
            return responseMap;
        } else {
            Map<String, Object> responseMap = new HashMap<>();
            responseMap.put("success", false);
            responseMap.put("errMsg", result.get("err_code_des"));
            return responseMap;
        }
    } catch (Exception e) {
        e.printStackTrace();
        Map<String, Object> responseMap = new HashMap<>();
        responseMap.put("success", false);
        responseMap.put("errMsg", e.getMessage());
        return responseMap;
    }
}

util类,用来生成随机字符串,加密,验证签名等作用的

public class WXPayUtil {

public static String generateNonceStr() {

return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);

}

public static String generateSignature(Map<String, String> data, String key) throws Exception {

// 1. Sort the parameters in dictionary order

Map<String, String> sortedData = new TreeMap<>(data);

// 2. Concatenate the parameters as per the format: key1=value1&key2=value2...

String stringA = sortedData.entrySet().stream()

.map(entry -> entry.getKey() + "=" + entry.getValue())

.collect(Collectors.joining("&"));

// 3. Append the key

String stringSignTemp = stringA + "&key=" + key;

// 4. Sign the concatenated string using MD5

return MD5(stringSignTemp).toUpperCase();

}

public static String mapToXml(Map<String, String> data) {

StringBuilder xml = new StringBuilder();

xml.append("<xml>");

for (Map.Entry<String, String> entry : data.entrySet()) {

xml.append("<").append(entry.getKey()).append(">");

xml.append(entry.getValue());

xml.append("</").append(entry.getKey()).append(">");

}

xml.append("</xml>");

return xml.toString();

}

public static Map<String, String> xmlToMap(String strXML) throws Exception {

SAXBuilder builder = new SAXBuilder();

Document doc = builder.build(new StringReader(strXML));

Element root = doc.getRootElement();

List<Element> children = root.getChildren();

Map<String, String> data = new HashMap<>();

for (Element child : children) {

data.put(child.getName(), child.getTextNormalize());

}

return data;

}

private 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 b : array) {

sb.append(String.format("%02x", b));

}

return sb.toString();

}

/**

* 验证签名

* @param data 通知数据

* @param key 密钥

* @return 签名是否有效

* @throws Exception

*/

public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {

if (!data.containsKey("sign")) {

return false;

}

String sign = data.get("sign");

return generateSignature(data, key).equals(sign);

}

}

相关推荐
zquwei6 分钟前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
TT哇13 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦35 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_31234541 小时前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安1 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
sdaxue.com1 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
真滴book理喻1 小时前
Vue(四)
前端·javascript·vue.js