微信支付

news2024/12/26 10:42:03

文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 

 封装的工具类

package com.qf.fmall.utils;

import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
import org.apache.shiro.crypto.hash.Md5Hash;

import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

public class WeixinPayUtils {

    public static final  String orderSubmit="https://api.mch.weixin.qq.com/pay/unifiedorder";
    public static final  String orderQueryUrl="https://api.mch.weixin.qq.com/pay/orderquery";

    public static final String appkey="sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC";

    public static void main(String[] args) {

        String s = weixinPay("sadsadasa", "wqeqweqeq");
        System.out.println(s);

    }


    public static String weixinPay(String oid,String describe){
        //1. 组织请求map,必传字段如下
        //这里可有序可以无序,但是计算签名的时候必须有序,规定!按Key排序
        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("appid","wx632c8f211f8122c6");//商户的应用ID
        treeMap.put("mch_id","1497984412"); //商户号
        treeMap.put("notify_url","http://47.118.45.73:8080/pay/callback"); // 商户提供的回调地址

        String randomstr = UUID.randomUUID().toString().replaceAll("-", ""); //生成随机数
        treeMap.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项


        treeMap.put("body",describe); // 订单描述信息
        treeMap.put("out_trade_no",oid); // 订单编号
        treeMap.put("total_fee","1");  // 1 分钱
        treeMap.put("trade_type","NATIVE"); // 支付类型
        treeMap.put("fee_type","CNY"); // 币种

        treeMap.put("sign_type","MD5"); // 签名算法

        //计算签名
        String tempString = treeMap.toString().replace("{", "").replace("}", "").replace(", ","&")+"&key="+appkey;
        String sign = new Md5Hash(tempString).toHex().toUpperCase();

        treeMap.put("sign",sign);


        //map转XML字符串
        String xml = XmlUtil.mapToXmlStr(treeMap);

        //用Hutool工具类发送post请求
        String result = HttpRequest.post(orderSubmit).body(xml).execute().body();


        // xml str ----> map
        Map<String, Object> resultMap = XmlUtil.xmlToMap(result);
        String url = (String) resultMap.get("code_url");
        return  url;


    }


    public static String queryStatus(String orderId) {
        //1. 组织请求map,必传字段如下
        //这里可有序可以无序,但是计算签名的时候必须有序,规定!按Key排序
        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("appid","wx632c8f211f8122c6");//商户的应用ID
        treeMap.put("mch_id","1497984412"); //商户号
        String randomstr = UUID.randomUUID().toString().replaceAll("-", ""); //生成随机数
        treeMap.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项

        treeMap.put("out_trade_no",orderId); // 订单编号

        treeMap.put("sign_type","MD5"); // 签名算法

        //计算签名
        String tempString = treeMap.toString().replace("{", "").replace("}", "").replace(", ","&")+"&key="+appkey;
        String sign = new Md5Hash(tempString).toHex().toUpperCase();

        treeMap.put("sign",sign);


        //map转XML字符串
        String xml = XmlUtil.mapToXmlStr(treeMap);

        //用Hutool工具类发送post请求
        String result = HttpRequest.post(orderQueryUrl).body(xml).execute().body();


        // xml str ----> map
        Map<String, Object> resultMap = XmlUtil.xmlToMap(result);
        String trade_state = (String) resultMap.get("trade_state");
        return  trade_state;
    }
}

controller

package com.qf.fmall.controller;

import com.qf.fmall.common.ResultVo;
import com.qf.fmall.entity.Orders;
import com.qf.fmall.service.IOrdersService;
import com.qf.fmall.utils.FmallConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.HashMap;

/**
 * <p>
 * 订单  前端控制器
 * </p>
 *
 * @author jmj
 * @since 2023-08-24
 */
@RestController
@RequestMapping("/order")
@CrossOrigin
@Slf4j
public class OrdersController {

    @Autowired
    private IOrdersService ordersService;

    @PostMapping("/add")
    public ResultVo add(Integer[] cids,@RequestBody Orders orders) throws Exception {
        log.info("入参为:cid={},orders={}", Arrays.toString(cids),orders);

      HashMap<String,Object> map= ordersService.addOrder(cids,orders);


        return ResultVo.vo(FmallConstants.SUCCESS_CODE,FmallConstants.SUCCESS_MSG,map);
    }

    @GetMapping("/status/{orderId}")
    public ResultVo status(@PathVariable("orderId") String orderId){
        log.info("入参为:orderId={}",orderId);

     String s=   ordersService.status(orderId);
    log.info("传回来的状态:{}",s);
        return ResultVo.vo(FmallConstants.SUCCESS_CODE,FmallConstants.SUCCESS_MSG,s);
    }

}

service

package com.qf.fmall.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.fmall.entity.*;
import com.qf.fmall.mapper.OrdersMapper;
import com.qf.fmall.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.fmall.utils.WeixinPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 订单  服务实现类
 * </p>
 *
 * @author jmj
 * @since 2023-08-24
 */
@Service
@Slf4j
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {

    @Autowired
    private IShoppingCartService shoppingCartService;

    @Autowired
    private IProductSkuService iProductSkuService;

    @Autowired
    private IProductService iProductService;

    @Autowired
    private IOrderItemService iOrderItemService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized HashMap<String, Object> addOrder(Integer[] cids, Orders orders) throws Exception {
        //1. 查询用户购物车中的对应的商品套餐库存量是否还足够
        List<Map<String, Object>> shoppingcars = shoppingCartService.listMaps(new QueryWrapper<ShoppingCart>().select("sku_id  skuId, SUM(`cart_num`) `sum`").in("cart_id", cids).groupBy("sku_id"));
        log.info("查出来的购物车按ID分类计算的集合为{}",shoppingcars);
        TreeSet<String> productIds = new TreeSet<>();//查出购物车中所有的productId
        for (Map<String, Object> shoppingcar : shoppingcars) {
             ProductSku one = iProductSkuService.getOne(new QueryWrapper<ProductSku>().eq("sku_id", shoppingcar.get("skuId")));
            productIds.add(one.getProductId());
             Integer stock = one.getStock();
             Double cartNum = (Double) shoppingcar.get("sum");
             if (cartNum>stock){
                 throw new Exception("库存不足,购买失败");
             }
//             减少库存
             one.setStock((stock-cartNum.intValue()));
             iProductSkuService.updateById(one);
         }
         //过了这个循环没有抛异常,就可以往下走,说明库存够


        //2. 生成唯一的订单编号
        String orderId = UUID.randomUUID().toString().replace("-", "");
          orders.setOrderId(orderId);
        //3. 生成订单主表(orders表)中的数据
       orders.setCreateTime(new Date());//创建时间
       orders.setUpdateTime(new Date());//修改时间
        // 产品名称:untitled用逗号隔开
        //先查Product产品ID
        StringBuilder builder = new StringBuilder();
        for (String productId : productIds) {
            //查出每个产品中的名字,放到字符串缓冲流中,并用逗号拼接
            builder.append(iProductService.getOne(new QueryWrapper<Product>().eq("product_id",productId)).getProductName());
            builder.append(",");
        }
        //删除最后一个逗号,拼接转化为字符串
        String untitled = builder.deleteCharAt(builder.length() - 1).toString();
        orders.setUntitled(untitled);
        // 订单的状态,初始值1,待付款 status
        orders.setStatus("1");//待付款
        // 逻辑删除状态,初始值为0 delete_status
        orders.setDeleteStatus(0);

        log.info("生成的order对象为:{}",orders);
        //将对象添加到订单表里

            this.save(orders);

        //4. 生成订单明细表的数据 (OrderItem表)
        //有几个cid就有几个定单

        ArrayList<OrderItem> orderItems = new ArrayList<>();

        for (Integer cartId : cids) {
            OrderItem orderItem = new OrderItem();
            String orderItemId = UUID.randomUUID().toString().replace("-", "");
            //设置32位随机数作为ItemId 放入orderItem对象里
            orderItem.setItemId(orderItemId);
            //订单Id注入
            orderItem.setOrderId(orders.getOrderId());
            //查一下购物车 id
            ShoppingCart shoppingCart = shoppingCartService.getOne(new QueryWrapper<ShoppingCart>().eq("cart_id", cartId));
            ProductSku productSku = iProductSkuService.getOne(new QueryWrapper<ProductSku>().eq("sku_id", shoppingCart.getSkuId()));
            Product product = iProductService.getOne(new QueryWrapper<Product>().eq("product_id", productSku.getProductId()));
            //查一下产品对象
            //注入产品ID
            orderItem.setProductId(productSku.getProductId());
            orderItem.setProductName(product.getProductName());
            orderItem.setProductImg(productSku.getSkuImg());
            orderItem.setSkuId(productSku.getSkuId());
            orderItem.setSkuName(productSku.getSkuName());
            orderItem.setProductPrice(new BigDecimal(productSku.getSellPrice()));
            orderItem.setBuyCounts(Integer.parseInt(shoppingCart.getCartNum()));
            orderItem.setTotalAmount(new BigDecimal(productSku.getSellPrice()*Integer.parseInt(shoppingCart.getCartNum())));

            //转换时间
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            orderItem.setBasketDate(format.parse(shoppingCart.getCartTime()));

            orderItem.setIsComment(0);
            log.info("每个订单详情对象:{}",orderItem);

            //保存到集合
            orderItems.add(orderItem);


        }

        //5. 保存订单到数据库
        log.info("添加到数据库的订单集合对象:{}",orderItems);
        iOrderItemService.saveBatch(orderItems);


        //清空购物车
        List<Integer> list = Arrays.asList(cids);
       shoppingCartService.removeBatchByIds(list);


        //6. 跟微信支付平台交互,获取可以支付的url

        String url = WeixinPayUtils.weixinPay(orders.getOrderId(),orders.getUntitled());
        log.info("url:{}",url);
        //7. 组织返回的map数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId",orders.getOrderId());
        map.put("productNames",orders.getUntitled());
        map.put("payUrl",url);


        return map;
    }

    @Override
    public String status(String orderId) {
        //1.掉微信支付的查询订单状态接口,获取订单状态
     String status= WeixinPayUtils.queryStatus(orderId);

        //2.如果支付成功了,需要修改订单表中的订单状态和支付时间
        if (status.equals("SUCCESS")){
         Orders orders = new Orders();
         orders.setOrderId(orderId);
         orders.setStatus("2");
         updateById(orders);
         return "2";
        }
        return "-1";
    }




}

封装工具类

pom

<!--   微信支付 sdk (sdk用来简化调用的工具包)   -->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
    </dependencies>

 WxSdkUtils

package com.qf.fmall2302.wxpay;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class WxSdkUtils {


    public String getPayUrl(String orderid,String desc,Long amount) throws Exception {
        // 创建sdk的核心对象
        WXPay wxPay = new WXPay(new MyWxConfig());

        HashMap<String, String> map = new HashMap<>();
        String randomstr = UUID.randomUUID().toString().replaceAll("-", "");
        map.put("nonce_str",randomstr); // 长度32个字符的随机字符串,干扰项
        map.put("body",desc); // 订单描述信息

        map.put("out_trade_no",orderid); // 订单编号
        map.put("total_fee","1");  // 1 分钱
        map.put("trade_type","NATIVE"); // 支付类型
        map.put("fee_type","CNY"); // 币种
        map.put("notify_url","http://47.118.45.73:8080/pay/callback"); // 商户提供的回调地址
        map.put("sign_type","MD5"); // 签名算法

        Map<String, String> result = wxPay.unifiedOrder(map);
        return result.get("code_url");
    }

    public static String queryStatus(String orderid) throws Exception {
        WXPay wxPay = new WXPay(new MyWxConfig());
        HashMap<String, String> map = new HashMap<>();
        map.put("out_trade_no",orderid);
        Map<String, String> result = wxPay.orderQuery(map);
        return result.get("trade_state");
    }


    public static void main(String[] args) throws Exception {

        String orderid = "202308241617987";
        WXPay wxPay = new WXPay(new MyWxConfig());
        HashMap<String, String> map = new HashMap<>();
        map.put("out_trade_no",orderid);
        Map<String, String> result = wxPay.orderQuery(map);
        System.out.println(result);

    }

}

MyWxConfig implements WXPayConfig 

package com.qf.fmall2302.wxpay;

import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;

public class MyWxConfig implements WXPayConfig {

    public static final String appid = "wx632c8f211f8122c6";
    public static final String mch_id = "1497984412";
    public static final String appkey = "sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC";

    @Override
    public String getAppID() {
        return appid;
    }

    @Override
    public String getMchID() {
        return mch_id;
    }

    @Override
    public String getKey() {
        return appkey;
    }

    @Override
    public InputStream getCertStream() {
        return null;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 0;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 0;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/928664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

海运费查询国际海运费知识-箱讯科技

在国际贸易中&#xff0c;海运是一种常见且重要的货物运输方式。了解海运费用及其查询方法以及国际海运费的相关知识对于进出口商和物流从业人员来说至关重要。本文将介绍海运费查询的方法和国际海运费的相关知识&#xff0c;帮助读者更好地理解和应用于实际业务中。 一、海运费…

话说SLAM中的点云上采样

目录 1 什么是点云上采样,为什么需要点云上采样 2 以LIO-SAM为例进行方法1的讲解 2.1 IMU预积分代码解析 + 点云加密思想 2.1.1 收到IMU信息的回调函数 2.2.2 优化函数置位 resetOptimization 2.2.3 TF类 2.3.3.1 流程图 2.3.3.2 代码详细注释 2.2.4 总结 2.2 图像…

windows下cmd快速生成大文件命令

fsutil file createnew [文件名] [文件大小]

Ubuntu安装RabbitMQ

一、安装 更新系统软件包列表&#xff1a; sudo apt update安装RabbitMQ的依赖组件和GPG密钥&#xff1a; sudo apt install -y curl gnupg curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo gpg --dearmo…

实验九 根文件系统移植

【实验目的】 熟悉根文件系统的目录结构&#xff0c;构建自己的根文件系统 【实验环境】 ubuntu 14.04 发行版FS4412 实验平台交叉编译工具&#xff1a;arm-none-linux-gnueabi- 【注意事项】实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行 【实验步骤】 一、构建自…

jconsole查看JVM虚拟机使用情况 JDK1.8

首先需要在启动命令加上如下配置命令 -Djava.rmi.server.hostname服务运行ip -Dcom.sun.management.jmxremotetrue-Dcom.sun.management.jmxremote.port端口号-Dcom.sun.management.jmxremote.sslfalse-Dcom.sun.management.jmxremote.authenticatefalse 打开jdk自带的jsonso…

如何利用易查分快速发布学生分班结果?

在即将开学之际&#xff0c;负责分班工作的老师们通常会感到非常辛苦。他们不仅要制作分班情况表格&#xff0c;还需要想方设法将其发布出来&#xff0c;但又不能直接公开&#xff0c;以免无关人员随意加入。为了解决这个问题&#xff0c;一种快捷的发布学生分班情况的方法是自…

文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题

六、如果用go语言&#xff0c;考虑对 PARTITION 过程做这样的修改:从数组 A 中随机选出三个元素&#xff0c;并用这三个元素的中位数(即这三个元素按大小排在中间的值)对数组进行划分。求以a 的函数形式表示的、最坏划分比例为 a:(1-a)的近似概率&#xff0c;其中 0<a<1。…

【复制带随机指针的链表】

题目来源 1、将每个 拷贝节点 都 插入 在原来的节点的后面 2、链接每个拷贝结点的 random 注意&#xff1a; 3、将拷贝结点 解 下来&#xff0c;尾插到一起&#xff0c;恢复原来链表。 /*** Definition for a Node.* struct Node {* int val;* struct Node *nex…

Windows平台Unity下播放RTSP或RTMP如何开启硬解码?

我们在做Windows平台Unity播放RTMP或RTSP的时候&#xff0c;遇到这样的问题&#xff0c;比如展会、安防监控等场景下&#xff0c;需要同时播放多路RTMP或RTSP流&#xff0c;这样对设备性能&#xff0c;提出来更高的要求。 虽然我们软解码&#xff0c;已经做的资源占有非常低了…

数据库优化:读写分离,并在SpringBoot项目中代码实现

什么要对数据库做读写分离优化。 存在下面两个问题&#xff0c;所以要进行数据库优化 单表不能太大&#xff1a;mysql官方说法:单表2000万数据&#xff0c;就到达瓶颈了。&#xff0c;所以说为了保证查询效率&#xff0c;得让每张表的大小得到控制。查询压力大&#xff1a;在…

开源微服务如何选型?Spring Cloud、Dubbo、gRPC、Istio 详细对比

作者&#xff1a;刘军 不论您是一名开发者、架构师、CTO&#xff0c; 如果您曾深度参与在微服务开发中&#xff0c;那么相信您一定有过开源微服务框架或体系选型的疑问&#xff1a;Apache Dubbo、Spring Cloud、gRPC 以及 Service Mesh 体系产品如 Istio&#xff0c;到底应该选…

《扩散模型 从原理到实战》Hugging Face (一)

文章目录 前言第一章 扩散模型简介1.1 扩散模型的原理1.1.1 生成模型1.1.2 扩散过程 前言 Hugging Face最近出版了第一本中文书籍《扩散模型 从原理到实战》&#xff0c;其中内容关于扩散模型&#xff08;Diffusion Model&#xff09;&#xff0c;和AIGC相关的内容较多&#x…

Search Ads Toggle有效推广:结合IPIDEA代理IP的TikTok营销策略

TikTok 本月22日推出了一个搜索广告切换(Search Ads Toggle)的新功能&#xff0c;这个功能对于广告商来说&#xff0c;更容易触达有明确搜索意向的目标受众。谷歌有研究显示&#xff0c;现在的年轻用户群体更倾向于把Tik Tok这样的社交媒体软件当做搜索引擎来使用&#xff0c;比…

Redis问题集合(三)在Redis容器里设置键值对

前言 前提是已经拉取了Redis镜像并创建了对应的容器做个记录&#xff0c;方便后续查看 步骤 查看Redis容器的ID&#xff1a;docker ps -a 进入容器&#xff1a;docker exec -it 容器ID /bin/bash进入redis命令行&#xff1a;redis-cli输入密码&#xff1a;auth 配置密码 查看…

L1-033 出生年(Python实现) 测试点全过

题目 以上是新浪微博中一奇葩贴&#xff1a;“我出生于1988年&#xff0c;直到25岁才遇到4个数字都不相同的年份。”也就是说&#xff0c;直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求&#xff0c;自动填充“我出生于y年&#xff0c;直到x岁才遇到n个数字都不…

使用EF Core更新与修改生产数据库

使用EF Core的Code First&#xff0c;在设计阶段&#xff0c;直接使用Database.EnsureCreated()和EnsureDeleted()可以快速删除、更新最新的数据结构。由于没有什么数据&#xff0c;删除的风险非常低。但是对于已经投入生产的数据库&#xff0c;这个方法就绝对不可行了。 考虑…

vue3学习源码笔记(小白入门系列)------ 组件是如何渲染成dom挂载到指定位置的?

文章目录 os准备组件如何被挂载到页面上第一步 createApp 做了哪些工作&#xff1f;ensureRendererbaseCreateRenderercreateAppAPImountrenderpatchprocessComponentprocessElement 总结 os 学习一下vue3 源码&#xff0c;顺便记录分享下 使用vitest 插件调试源码 辅助阅读 …

0825|C++day5 运算符重载+静态成员+类的基础【Xmind+实例】

一、运算符重载 实例&#xff1a;&#xff08;赋值运算符、自增自减运算符、插入提取运算符&#xff09; #include <iostream>using namespace std;class Person {friend Person & operator(Person &L,const Person &R);friend Person & operator(Perso…

RabbitMQ 集群

clustering 最开始我们介绍了如何安装及运行 RabbitMQ 服务&#xff0c;不过这些是单机版的&#xff0c;无法满足目前真实应用的要求。如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等情况&#xff0c;该怎么办&#xff1f;单台 RabbitMQ服务器可以满足每秒 100…