java接入apiv3微信小程序支付(以java的eladmin框架为例)

news2025/1/4 6:08:32

一、需要准备的资料

        1.小程序AppID

                如:wx2e56f5******

        2.商户号

                如:1641******

        3.商户API私钥路径:什么是商户API证书?如何获取商户API证书? 获取文件如下图:

                如:

                本地路径:E:\Env\eladmin\cert\c2\apiclient_key.pem(本地部署写入绝对路径)

                服务器路径:/data/cert/eladmin/c2/apiclient_key.pem(服务器写入相对路径)

        4.商户证书序列号:登录商户平台【API安全】->【API证书】->【查看证书】,可查看商户API证书序列号。

                如:4F24D009CDBC89A**********************

        5.商户APIV3密钥:API v3密钥 - 通用规则 | 微信支付商户文档中心

                如:tYsmXJrIr*****************

                【商户平台】->【账户中心】->【API安全】的页面设置该密钥,请求才能通过微信支付的签名校验。密钥的长度为32个字节。

        6.商户平台证书路径

                如:

                本地路径:E:\Env\eladmin\cert\c2\apiclient_cert.pem(本地部署写入绝对路径)

                服务器路径:/data/cert/eladmin/c2/apiclient_cert.pem(服务器写入相对路径)

        7.商户平台证书路径p12

                如:

                本地路径:E:\Env\eladmin\cert\c2\apiclient_cert.p12(本地部署写入绝对路径)

                服务器路径:/data/cert/eladmin/c2/apiclient_cert.p12(服务器写入相对路径)

二、代码部分

1.pom.xml内加入微信支付扩展
    
<!--     微信支付   -->
    <dependency>
        <groupId>com.github.wechatpay-apiv3</groupId>
        <artifactId>wechatpay-java</artifactId>
        <version>0.2.7</version>
    </dependency>
2.在resources的dev和prod内加入微信支付必填字段
    #微信支付字段
    
      
wx:
      merchantId: 164*******
      privateKeyPath: E:\Env\eladmin\cert\c2\apiclient_key.pem
      certPath: E:\Env\eladmin\cert\c2\apiclient_cert.pem
      certP12Path: E:\Env\eladmin\cert\c2\apiclient_cert.p12
      merchantSerialNumber: 4F24D009CDBC**********************
      apiV3key: tYsmXJr******************
      appId: wx2e56f5******
3.微信支付测试接口
   3-1:测试下单接口
       /api/weChatPay/ceshiJSAPI
   3-2:测试微信支付结果回调地址,当微信支付后,微信方返回支付信息,在回调接口内触发业务逻辑
       注:测试回调接口必须为线上接口,线下无法实现
          可先在线上将微信返回数据打印到txt文件内,然后在本地测试回调接口,触发业务逻辑
       /api/weChatPay/ceshiPayNotify(放入线上的测试回调接口)
       /api/weChatPay/payNotify(本地测试回调接口)--可在postman内测试
       测试时,在Headers内Wechatpay-Serial、Wechatpay-Nonce、Wechatpay-Timestamp、Wechatpay-Signature必填上
       微信返回的json,直接放入raw-json内进行测试
       
4.退款测试接口
   /api/weChatPay/ceshiRefund(回调接口不是必填项,可用可不用)
WeChatPayService.java:可放在Service内
----------------------------------------------------

package me.zhengjie.modules.api.service;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Random;

@Service
@RequiredArgsConstructor
public class WeChatPayService {

    /** 商户API私钥路径 */
    @Value("${wx.privateKeyPath}") //可自己写死路径
    public  String privateKeyPath;

    //=============生成签名=====开始===================================================
    /**
     * 作用:使用字段appId、timeStamp、nonceStr、package计算得出的签名值
     * 场景:根据微信统一下单接口返回的 prepay_id 生成调启支付所需的签名值
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param pack package
     * @return
     * @throws Exception
     */
    public String getSign(String appId, long timestamp, String nonceStr, String pack) throws Exception{
        String message = buildMessage(appId, timestamp, nonceStr, pack);
        String paySign= sign(message.getBytes("utf-8"));
        return paySign;
    }

    private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + pack + "\n";
    }

    private String sign(byte[] message) throws Exception{
        Signature sign = Signature.getInstance("SHA256withRSA");
        //这里需要一个PrivateKey类型的参数,就是商户的私钥。
        sign.initSign(getPrivateKey(privateKeyPath));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 获取私钥。
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {

        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

    /**
     * 获取随机位数的字符串
     * @param length
     * @return
     */
    public static String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    //=============生成签名=====结束===================================================


    /**
     * 获取请求文体
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestBody(HttpServletRequest request) throws IOException {
        ServletInputStream stream = null;
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            throw new IOException("读取返回支付接口数据流出现异常!");
        } finally {
            reader.close();
        }
        return sb.toString();
    }
}
Controller代码如下:

package me.zhengjie.modules.api.rest;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.annotation.Log;
import me.zhengjie.config.FileProperties;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.api.service.WeChatPayService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequiredArgsConstructor
@Api(tags = "1.微信小程序")
@RequestMapping("/api/weChatPay")
public class WeChatPayContoller {

    private final WeChatPayService weChatPayService;
    private final FileProperties fileProperties;
    /**
     * appID
     */
    @Value("${wx.appId}") // 可自己写死--我引用的是自己写的配置内(写死的方式如:appId=wx12345678910)
    public String appId;

    /**
     * 商户号
     */
    @Value("${wx.merchantId}") // 可自己写死
    public String merchantId;

    /**
     * 商户API私钥路径
     */
    @Value("${wx.privateKeyPath}") //可自己写死
    public String privateKeyPath;

    /**
     * 商户证书序列号
     */
    @Value("${wx.merchantSerialNumber}") // 可自己写死
    public String merchantSerialNumber;

    /**
     * 商户APIV3密钥
     */
    @Value("${wx.apiV3key}") //可自己写死
    public String apiV3key;

    /**
     * 商户平台证书路径
     */
    @Value("${wx.certPath}") // 可自己写死
    public String certPath;

    /**
     * 商户平台证书路径p12
     */
    @Value("${wx.certP12Path}") //可自己写死
    public String certP12Path;


    private static Map<String, Config> configMap = new HashMap<>();

    private static Config config = null;
    private static JsapiService service = null;
    private static RefundService refundService = null;


    /**
     * JSAPI 测试下单接口
     */
    @PostMapping(value = "/ceshiJSAPI")
    @Log("JSAPI 测试下单接口")
    @ApiOperation("JSAPI 测试下单接口")
    @AnonymousAccess
    @Transactional(rollbackFor = Exception.class)
    public JSONObject ceshiJSAPI() throws Exception {
        if (config == null) {
            config =
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(merchantId)
                            .privateKeyFromPath(privateKeyPath)
                            .merchantSerialNumber(merchantSerialNumber)
                            .apiV3Key(apiV3key)
                            .build();
        }
        if (service == null) {
            service = new JsapiService.Builder().config(config).build();
        }
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1);//金额,1为0.01元
        request.setAmount(amount);
        request.setAppid(appId);
        request.setMchid(merchantId);
        request.setDescription("测试商品标题");//下单标题
        request.setNotifyUrl("https://www.ceshi123.com/api/weChatPay/ceshiPayNotify");//要求必须为线上接口
        String ddh = weChatPayService.getRandomString(20);
        request.setOutTradeNo(ddh);//订单号
        Payer payer = new Payer();
        payer.setOpenid("oMr**********");//openid
        request.setPayer(payer);
        PrepayResponse response = service.prepay(request);

        JSONObject result = new JSONObject();

        Long date = new Date().getTime();//获取当前时间戳
        String nonceStr = weChatPayService.getRandomString(28);//随机字符串,长度为32个字符以下

        result.put("timeStamp", date.toString());//时间戳
        result.put("nonceStr", nonceStr);//随机字符串,长度为32个字符以下
        result.put("package", "prepay_id=" + response.getPrepayId());//PrepayId
        result.put("signType", "RSA");//签名类型
        result.put("paySign", weChatPayService.getSign(appId, date, nonceStr, "prepay_id=" + response.getPrepayId()));//签名

        return result;
    }

    /**
     * 测试微信支付结果回调地址(放入线上测试)
     *
     * @param
     */
    @PostMapping(value = "/ceshiPayNotify")
    @Log("ceshiPayNotify方法")
    @ApiOperation("ceshiPayNotify方法")
    @AnonymousAccess
    public void ceshi_payNotify(HttpServletRequest request) throws IOException {
        //微信返回的证书序列号
        String serialNo = request.getHeader("Wechatpay-Serial");
        //微信返回的随机字符串
        String nonceStr = request.getHeader("Wechatpay-Nonce");
        //微信返回的时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //微信返回的签名
        String wechatSign = request.getHeader("Wechatpay-Signature");
        String singType = request.getHeader("Wechatpay-Signature-Type");
        String collect = request.getReader().lines().collect(Collectors.joining());
        try {
            FileUtil.writeUtf8String(collect, fileProperties.getPath().getPath() + "/huidiao-collect.txt");//打印看效果
            FileUtil.writeUtf8String(serialNo, fileProperties.getPath().getPath() + "/huidiao-serialNo.txt");//打印看效果
            FileUtil.writeUtf8String(singType, fileProperties.getPath().getPath() + "/huidiao-Signature-Type.txt");//打印看效果
            FileUtil.writeUtf8String(nonceStr, fileProperties.getPath().getPath() + "/huidiao-nonceStr.txt");//打印看效果
            FileUtil.writeUtf8String(timestamp, fileProperties.getPath().getPath() + "/huidiao-timestamp.txt");//打印看效果
            FileUtil.writeUtf8String(wechatSign, fileProperties.getPath().getPath() + "/huidiao-wechatSign.txt");//打印看效果

            //TODO 业务校验---可以写入自己的业务逻辑

        } catch (Exception e) {
            System.out.println("e = " + e);
            FileUtil.writeUtf8String("22222222222222222222", fileProperties.getPath().getPath() + "/huidiao22.txt");//打印看效果
        }
    }

    /**
     * 微信支付结果回调地址(本地)
     *
     * @param request
     * @return
     */
    @PostMapping(value = "/payNotify")
    @AnonymousAccess
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Object> wxCallback(HttpServletRequest request) throws Exception {
        //获取报文
        String body = weChatPayService.getRequestBody(request);
        //随机串
        String nonce = request.getHeader("Wechatpay-Nonce");
        //微信传递过来的签名
        String signature = request.getHeader("Wechatpay-Signature");
        //证书序列号(微信平台)
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String singType = request.getHeader("Wechatpay-Signature-Type");
        //时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        if (configMap.get("config") == null) {
            config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(privateKeyPath)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3key)
                    .build();
            configMap.put("config", config);
        }
        else {
            config = configMap.get("config");
        }
        NotificationParser parser = new NotificationParser((NotificationConfig) config);
        RequestParam.Builder builder = new RequestParam.Builder();
        builder.body(body);
        builder.signature(signature);
        builder.nonce(nonce);
        builder.timestamp(timestamp);
        builder.serialNumber(wechatPaySerial);
        builder.signType(singType);
        RequestParam requestParam = builder.build();

        Transaction parse = parser.parse(requestParam, Transaction.class);
        if ("SUCCESS".equals(parse.getTradeState().toString())) {
            //支付成功,你的业务逻辑

            return new ResponseEntity<>(HttpStatus.OK);

        } else {
            throw new BadRequestException( "支付失败");
        }
    }


    /** 测试退款申请
     * @return*/
    @PostMapping(value = "/ceshiRefund")
    @Log("JSAPI 测试退款接口")
    @ApiOperation("JSAPI 测试退款接口")
    @AnonymousAccess
    @Transactional(rollbackFor = Exception.class)
    public JSONObject ceshiRefund(String No) throws Exception {
        if (config == null) {
            config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(privateKeyPath)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3key)
                    .build();
        }
        if (refundService == null) {
            // 初始化服务
            refundService = new RefundService.Builder().config(config).build();
        }
        CreateRequest request = new CreateRequest();
        request.setOutTradeNo(No);//商户订单号
        request.setOutRefundNo(weChatPayService.getRandomString(16));//商户退款单号,随机生成
        request.setReason("取消订单的退款");//退款原因
        AmountReq amount = new AmountReq();//金额信息
        amount.setRefund(Long.parseLong("1"));//退款金额(0.01元)
        amount.setTotal(Long.parseLong("1"));//原订单退款金额(0.01元)
        amount.setCurrency("CNY");//人民币
        request.setAmount(amount);

//        request.setNotifyUrl("https://https://www.ceshi123.com/api/weChatPay/ceshiRefundNotify");//回调接口,退款时非必填--这里我就没写接口

        JSONObject result = new JSONObject();
        try {
            Refund response = refundService.create(request);
            result.put("code", "SUCCESS");
            result.put("message", "退款成功");
            return result;
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
            return JSONObject.parseObject(e.getResponseBody());
        }
    }

}

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

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

相关文章

计算机提示d3dcompiler43.dll缺失怎么修复,多个解决方法分享

在游戏玩家中&#xff0c;遇到游戏提示找不到 d3dcompiler43.dll 文件的情况并不罕见。这使得许多玩家在启动游戏时感到困扰&#xff0c;因为这意味着他们可能无法正常运行游戏。那么&#xff0c;d3dcompiler43.dll 文件到底是什么呢&#xff1f;为什么游戏会提示找不到它呢&am…

注塑车间是否需要导入MES系统?

判定注塑车间是否需要导入MES系统时&#xff0c;需要谨慎考虑下述几个重要因素&#xff1a; 1.生产加工复杂性和多样化&#xff1a; 倘若注塑车间生产出来的产品品种繁多&#xff0c;涉及到多个工艺过程、不同类型的生产过程和参数设置&#xff0c;那么MES系统能够带去更加精准…

为什么当下MES如此火热,各大制造业工厂都在推行?

MES系统的特点&#xff1a; 1&#xff09;数据采集引擎、整合数据采集渠道&#xff08;RFID、条码设备、PLC、Sensor、IPC、PC等&#xff09;覆盖整个工厂制造现场&#xff0c;保证现场数据的实时、准确、全面的采集&#xff1b; 2&#xff09;打造工厂生产管理系统数据采集基础…

文心一言 VS 讯飞星火 VS chatgpt (90)-- 算法导论8.3 3题

三、用go语言&#xff0c;利用归纳法来证明基数排序是正确的。在你所给出的证明中&#xff0c;在哪里需要假设所用的底层排序算法是稳定的? 文心一言&#xff1a; 基数排序是一种非比较型整数排序算法&#xff0c;其通过在每一位上进行比较来排序。基数排序的一个主要特点是…

不会用手机做二维码?文本、链接码用手机生成的方法

现在很多功能都可以通过手机来实现&#xff0c;用手机制作二维码就是很多小伙伴经常会使用的一个功能&#xff0c;那么在手机上制作文本或者网址二维码是最常见的两种类型。下面就给还会在线制作二维码的小伙伴分享一个工具&#xff0c;通过简单的操作方法就可以快速做出文本码…

华为回击:制裁无法阻挡中国科技创新 | 百能云芯

华为最新推出的Mate 60 Pro手机引发了中国市场的抢购热潮&#xff0c;这一成功的举措为华为带来了信心。华为在这个背景下再度推出两款新机&#xff0c;其中包括高阶版的Mate 60 Pro和折叠式手机Mate X5。这两款手机在首批预购开始后迅速售罄&#xff0c;不仅取得了市场的热烈欢…

【软件测试】Postman中变量的使用

Postman中可设置的变量类型有全局变量&#xff0c;环境变量&#xff0c;集合变量&#xff0c;数据变量及局部变量。区别则是各变量作用域不同&#xff0c;全局变量适用于所有集合&#xff0c;环境变量适用于当前所选环境&#xff08;所有集合中均可使用不同环境变量&#xff09…

3D人脸扫描设备助推元宇宙虚拟人打造

近几年&#xff0c;数字人被广泛应用到文娱、教育、政务、经济、科技等各大领域&#xff0c;如梅兰芳孪生数字人&#xff0c;通过照片采集梅兰芳先生的三维数据&#xff0c;然后依据照片制作1&#xff1a;1无表情头部雕塑&#xff0c;再用扫描设备扫描雕塑&#xff0c;获得梅兰…

SAP MM学习笔记 - 错误 ME092 - Material mainly procured internally(原则上该物料只能内部调达)

购买依赖&#xff0c;购买发注的时候&#xff0c;会出一些错误或警告&#xff0c;碰到的时候&#xff0c;能解决的话&#xff0c;咱们就记录一下。 比如 Msg 番号 ME092 该品目原则上是内部调达。 如下图&#xff0c;本次出这个错误的原因是&#xff0c;ME51N做购买依赖&…

期权权利金计算方法大揭秘!详解期权权利金的计算公式

期权的权利金就是指期权合约市场当时的价格&#xff0c;权利金是会浮动的&#xff0c;跟股票的价格一样&#xff0c;随着市场的波动而波动。权利金是期权费&#xff0c;不是保证金。那么期权权利金计算方法大揭秘&#xff01;详解期权权利金的计算公式。 一、什么是期权的权利金…

IDEA的快捷键大全

快捷键 说明 IntelliJ IDEA 的便捷操作性&#xff0c;快捷键的功劳占了一大半&#xff0c;对于各个快捷键组合请认真对待。IntelliJ IDEA 本身的设计思维是提倡键盘优先于鼠标的&#xff0c;所以各种快捷键组合层出不穷&#xff0c;对于快捷键设置也有各种支持&#xff0c;对…

Java虚拟机(JVM)夺命20连问

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

多线程之基础篇(一)

一、Thread类 1、线程的创建 大家都熟知创建单个线程的三种方式&#xff0c;通过继承Thread类创建线程并重写该类的run()方法&#xff1b;通过实现Runnable接口创建线程一样要重写run()方法&#xff1b;以上的两个run()方法都是线程的执行体&#xff1b;第三&#xff0c;使用…

Matlab学习-自定义函数

Matlab学习-自定义函数 常用自定义函数 文章目录 Matlab学习-自定义函数1. 打印时间2. 计算统计参数3. 画图函数 1. 打印时间 function result calculate_time(time)% Function describe : calculate time% Input : time:N*1% Output : result.hour/min/sec hour/min/sec…

Linux 下静态库与动态库的制作与使用

Linux 下静态库与动态库的制作与使用 文章目录 Linux 下静态库与动态库的制作与使用示例代码&#xff1a;静态库静态库制作静态库使用 动态库动态库制作动态库使用 示例代码&#xff1a; test.c test.h main.c 静态库 静态库制作 以示例代码为例&#xff0c;先执行下面…

FPGA实现“乒乓操作”

一、“乒乓操作”概述 1、结构 “乒乓操作”是一种常用于数据流控制的处理技巧&#xff0c;可以实现无缝高速数据流缓存。首先“乒乓操作”这个名字本身就很吸引人&#xff0c;其结构一般是由数据选择器和数据缓冲器构成的&#xff0c;数据缓冲模块可以为任何存储模块&…

【MySQL数据库原理】MySQL Community 8.0界面工具汉化

尝试以下方法来汉化 MySQL Workbench 8.0 的菜单&#xff1a; 1、使用社区翻译版本&#xff1a;有一些热心的社区成员会将 MySQL Workbench 翻译成不同的语言&#xff0c;包括中文。你可以在一些开源或社区网站上寻找这些翻译版本&#xff0c;并按照他们的说明进行安装。 2、…

抖音外卖平台区域代理怎么拿?送上申请教程!

作为占据庞大流量的短视频平台&#xff0c;它的一举一动都格外引人注意。年初&#xff0c;抖音短视频平台开始大力进军本地生活市场&#xff0c;除了开通团购业务外&#xff0c;还准备做短视频外卖&#xff0c;这一举动&#xff0c;立刻掀起了今年火热的创业浪潮。 要知道&…

sql server服务无法启动怎么办?如何正常启动?

sql server软件是一款关系型数据库管理系统。具有使用方便可伸缩性好与相关软件集成程度高等优点。并且有些应用软件使用过程中是需要sql server数据库的后台支持的&#xff0c;我们在数据编程操作时经常会使用这款编程软件&#xff0c;在编程时系统有时会提示sql server服务无…

pandas读取一个 文件夹下所有excel文件

我这边有个需求&#xff0c;是要求汇总一个文件夹所有的excel文件&#xff0c; 其中有.xls和 .xlsx文件&#xff0c;同时还excel文件中的数据可能还不一致&#xff0c;会有表头数据不一样需要一起汇总。 首先先遍历子文件夹并读取Excel文件&#xff1a; 使用os库来遍历包含子文…