跨境电商支付平台-PingPong Pay(实现收银台模式沙箱支付)

news2025/7/18 4:05:43

介绍

PingPongCheckout 跨境支付的 API 接口文档,商户服务器和 PingPongCheckout 服务器进行交互。 供商户/平台服务方的技术开发及测试相关人员使用。 本文档分别从交互流程、通讯方式、签名方 案、交易接口、注意事项等⻆度详细介绍了 PingPongCheckout 跨境支付 API 接口的工作方式和开发过 程,可以帮助开发人员快速接入支付系统,同时也可以作为后续接口参数以及参数类型的速查手册。

Pingpong商户接入指南

收银台模式系统交互流程介绍

通俗一点收银台的付款方式就像现实生活中我们去饭店吃饭时一样,我们只需要去饭店的收银台给他钱然后至于如何扣款怎么扣款我们都不需要过多关心,而收银台付款也是这样,我们只需要把付款的参数交给对方至于具体扣款第三方支付平台会给我们返回一个他们的支付界面,然后我们引导用户过去进行支付操作,支付支付之后的结果我们需要提供一个回调函数,用于第三方支付平台告诉我们支付结果

image-20230505163716276

对于整一个收银台的支付流程借鉴一下官方的图,说的很详细

JS-SDK交互流程

步骤

  1. 客户端提交订单给商户服务端处理
  2. 商户服务端返回PingPongCheckout JS-SDK需要的参数(包含订单信息,签名和JS-SDK初始化需要的参数)
  3. 客户端初始化PingPongCheckout SDK,并且调用createPayment,传入订单信息。
  4. SDK自动开始和PingPongCheckout服务端交互,成功之后将会渲染PingPongCheckout收银台
  5. 买家填写卡号和cvv等支付信息
  6. 提交支付信息
  7. 如果是3D交易,还需要3D验证,否则直接展示交易结果
  • 图例:

  • 7.1 3D流程

  • 7.2 非3D流程

  1. 异步通知详见如何获取交易状态
  2. 收到异步通知需要响应OK给PingPongCheckout

此次对接的是“统一下单-本地支付&信用卡”方式支付,他与“获取跳转收银台”方式两者都是在请求完pingpong支付之后生成收银台的跳转链接,但是后者是由我们开发者控制界面跳转只返回支付的界面URL,而后者是由pingpong直接跳转过去,我们采用的是前者也就是统一下单-本地支付&信用卡方式

image-20230506102830885

Coding

沙箱环境获取收银台VO类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;


/**
 * PingPong支付充值获取支付收银台地址所需参数对象
 * SDK address:<a href="https://acquirer-api-docs-v3.pingpongx.com/pages/a2c224/#%E5%85%AC%E5%85%B1%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0">...</a>
 * 参数上没有写选传或者条件必传则代表字段为必传字段
 *
 * @author Czw
 * @date 2023/05/05
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CoinRechargePingPongRequest implements Serializable {

    /**
     * 唯一请求号
     */
    private String requestId;
    /**
     * PingPong 商户店铺编号
     */
    private String accId;
    /**
     * MD5-使用MD5算法加签
     * SHA256-使用SHA256算法加签
     */
    private String signType;
    /**
     * 签名,签名秘钥(salt)放入签名串的位置为: 签名串的开头 , 即{salt}key1=val2&key2=val2&key3=val3
     * <a href="https://acquirer-api-docs-v3.pingpongx.com/pages/77ae52/#%E8%AF%B7%E6%B1%82%E7%AD%BE%E5%90%8D%E8%8C%83%E5%9B%B4">...</a>
     */
    private String sign;
    /**
     * 收单方式
     * CHECKOUT-返回收银台地址
     * PAY-直接支付
     */
    private String acquirerType;
    /**
     * 交易金额,精确位数和币种有关,请查询附录交易币种
     */
    private String amount;
    /**
     * 交易币种,ISO 4217 三位币种,具体支持币种⻅附录交易币种
     */
    private String currency;
    /**
     * 商户网站交易流水号,每次请求的唯一标识,可用于后续订单查询和对账
     */
    private String merchantTransactionId;
    /**
     * 商户自定义接收重定向的结果 URL;如 3DS验证,银行在线转账或虚拟钱包之类支付方式时,最后需要重定向到商户指定的⻚面地址
     */
    private String shopperResultUrl;
    /**
     * 收银台页面取消支付操作时页面跳转地址,acquirerType=CHECKOUT,并且没有传送paymentBrand时候必传,条件必传
     */
    private String shopperCancelUrl;
    /**
     * 异步通知地址,可选
     */
    private String notificationUrl;
    /**
     * 商户扩展字段,可用于指定特定参数,会在响应体中原样返回(暂不可用),可选
     */
    private String remark;
    /**
     * 建站平台标识,建站平台接入必传。作用是标识这笔交易的是从哪个建站平台发起的,条件必传
     */
    private String merchantSource;
    /**
     * 用户ID,用户在HC的用户ID
     */
    private String customerId;
    /**
     * 用户注册邮箱
     */
    private String email;
    /**
     * 商品名称,例如钻石
     */
    private String name;
    /**
     * 商品数量
     */
    private String number;
}

沙箱环境获取收银台DTO类

import lombok.Data;
import java.io.Serializable;


/**
 * PingPong支付获取收银台地址时返回值dto
 *
 * @author Czw
 * @date 2023/05/06
 */
@Data
public class PingPongPayCheckoutDto implements Serializable {
    private static final long serialVersionUID = 7575136778850419334L;
    /**
     * PingPong 商户店铺编号
     */
    private String accId;
    /**
     * 交易金额
     */
    private String amount;
    /**
     * PingPong 商户店商户号
     */
    private String clientId;
    /**
     * 结果状态码
     */
    private String code;
    /**
     * 交易币种,ISO 4217 三位币种,参考https://acquirer-api-docs-v3.pingpongx.com/pages/3c0bdf/
     */
    private String currency;
    /**
     * 结果描述
     */
    private String description;
    /**
     * 商户网站的的交易流水号
     */
    private String merchantTransactionId;
    /**
     * 由商户自定义本次交易结果通知的地址,一旦填写该参数,PingPongCheckout 将通过 Post 方式异步推送交易结果到该地址
     */
    private String notificationUrl;
    /**
     * 当前交易关联的 PingPong 交易流水号
     */
    private String relateTransactionId;
    /**
     * 签名内容
     */
    private String sign;
    /**
     * MD5、SHA256
     */
    private String signType;
    /**
     * SUCCESS-成功
     * FAILED-失败
     * PROCESSING-进行中
     * PENDING-处理中
     * REVIEW-待审核
     */
    private String status;
    /**
     * PingPong 交易流水号
     */
    private String transactionId;
    /**
     * 交易发起时间,yyyyMMddHHmmss
     */
    private String transactionTime;
    /**
     * 本次结账请求的唯一标示,用于初始化JS-SDK
     */
    private String token;
    /**
     * 仅在收银台模式下返回,JS-SDK的加载地址
     */
    private String innerJsUrl;
    /**
     * 仅在收银台模式下返回,PingPong 支付收银台地址
     */
    private String paymentUrl;
}

参数加密PingPongSignUtil

package com.hc.app.user.server.util.pingpong;


import com.google.common.collect.Maps;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;

import com.hc.app.user.model.request.CoinRechargePingPongRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.util.Map;
import java.util.TreeMap;

/**
 * @description: PingPong支付签名工具类
 * @author: Czw
 * @create: 2023-05-05 12:02
 **/
@Slf4j
public class PingPongSignUtil {

    /**
     * 签名方法-sha256
     */
    public static final String SIGN_TYPE_SHA256 = "SHA256";
    /**
     * 签名方法-md5
     */
    public static final String SIGN_TYPE_MD5 = "MD5";

    /**
     * 测试环境异步通知支付状态地址
     */
    public static final String NOTIFICATION_URL_TEST = "";
    /**
     * 取消支付时跳转的界面
     */
    public static final String SHOPPER_CANCEL_URL_TEST = "http://52.221.156.209/pay/pay_success.html?orderId=orderNum&status=4";
    /**
     * 支付的网站发起地址
     */
    public static final String MERCHANT_SOURCE_URL = "";


    //------------------沙箱参数信息开始------------------------

    public static final String SANDBOX_ACCID = "2018092714313010016291";
    /**
     * 生成签名时的盐
     */
    public static final String SANDBOX_SALT = "F78BC96A55548B2319EE68E0";


    //------------------沙箱参数信息结束------------------------


    /**
     * 部分参数签名,参与签名的字段
     */
    private static final String[] includeFields = {"accId", "amount", "clientId", "cardNum", "currency", "merchantTransactionId",
            "requestId", "signType", "transactionId"};

    /**
     * 签名秘钥
     */
    private String salt = null;


    public PingPongSignUtil(String salt) {
        this.salt = salt;
    }

    public static void main(String[] args) {
        TreeMap<String, Object> signMap = new TreeMap<>();
        signMap.put("clientId", "2018092714313010016");
        signMap.put("accId", "2018092714313010016291");
        signMap.put("order", "2018092J7Y1K4U313010016291");
        String sha256 = signature("SHA256", SANDBOX_SALT, signMap);
        System.out.println(sha256);
    }

    /**
     * 执行签名
     *
     * @param signType 签名类型 SHA256/MD5
     * @param salt     盐
     * @param signMap  待签名串
     * @return {@link String }
     * @author Czw
     * @date 2023/05/05
     */
    public static String signature(String signType, String salt, TreeMap<String, Object> signMap) {
        String signContent = getPartSignParams(signMap);
        System.out.println("signContent=" + signContent);

        if (StringUtils.equalsIgnoreCase("MD5", signType)) {
            return md5Sign(salt, signContent);
        } else if (StringUtils.equalsIgnoreCase("SHA256", signType)) {
            return sha256(signContent, salt);
        }
        return null;
    }

    /**
     * 转换为符号映射
     *
     * @param request 请求
     * @param signMap 标志地图
     * @author Czw
     * @date 2023/05/08
     */
    public static void convertToSignMap(CoinRechargePingPongRequest request, TreeMap<String, Object> signMap) {
        // 获取对象的所有字段
        Field[] fields = request.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 设置字段可访问
            field.setAccessible(true);
            // 获取字段的值
            Object value = null;
            try {
                value = field.get(request);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            if (value != null) {
                // 将字段名和值作为键值对添加到TreeMap中
                signMap.put(field.getName(), value);
            }
        }
    }


    /**
     * 获取待签名串(部分字段签名)
     */
    private static String getPartSignParams(TreeMap<String, Object> signMap) {
        //添加需要签名的字段
        TreeMap<String, Object> resultMap = Maps.newTreeMap();
        for (String param : includeFields) {
            String value = (String) signMap.get(param);
            if (StringUtils.isNotBlank(value)) {
                //应SDK要求对参数进行trim操作
                resultMap.put(param, value.trim());
            }
        }
        return getSignParams(resultMap);
    }

    /**
     * 获取待签名串
     */
    private static String getSignParams(TreeMap<String, Object> resultMap) {
        StringBuilder stringBuilder = new StringBuilder();
        int paramNum = 0;
        for (Map.Entry<String, Object> signEntry : resultMap.entrySet()) {
            paramNum++;
            stringBuilder.append(signEntry.getKey());
            stringBuilder.append("=");
            stringBuilder.append(signEntry.getValue());
            if (paramNum < resultMap.size()) {
                stringBuilder.append("&");
            }
        }
        log.debug("content:【{}】", stringBuilder);
        return stringBuilder.toString();
    }


    private static String md5Sign(String salt, String content) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(salt.getBytes());
            md.update(content.getBytes());
            byte[] digest = md.digest();
            return byteToHexString(digest);
        } catch (Exception e) {
            log.error("md5签名失败", e);
        }
        return null;
    }


    private static String sha256(String content, String salt) {
        try {
            if (StringUtils.isBlank(salt)) {
                throw new RuntimeException("salt is null");
            }
            String contentStr = salt.concat(content);
            return DigestUtils.sha256Hex(contentStr.getBytes(StandardCharsets.UTF_8)).toUpperCase();
        } catch (Exception e) {
            log.error("sha256", e);
        }

        return null;
    }


    public static String byteToHexString(byte[] b) {
        StringBuilder hexString = new StringBuilder();
        for (byte value : b) {
            String hex = Integer.toHexString(value & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            hexString.append(hex.toUpperCase());
        }
        return hexString.toString();
    }
}

沙箱环境收银台代码

    //------------------沙箱参数信息开始------------------------

    public static final String SANDBOX_ACCID = "2018092714313010016291";
    /**
     * 生成签名时的盐
     */
    public static final String SANDBOX_SALT = "F78BC96A55548B2319EE68E0";
    /**
     * 收单方式-直接支付
     */
    public static final String ACQUIRER_TYPE_CHECKOUT = "CHECKOUT";

@GetMapping("/pingPongPay")
    public String pingPongPay() {
        CoinRechargePingPongRequest pingPongRequest = new CoinRechargePingPongRequest();
        String uid = UUID.randomUUID().toString();
        pingPongRequest.setRequestId(uid);
        pingPongRequest.setAccId(SANDBOX_ACCID);
        pingPongRequest.setSignType(SIGN_TYPE_SHA256);
        pingPongRequest.setAcquirerType(ACQUIRER_TYPE_CHECKOUT);
        pingPongRequest.setAmount("1.99");
        pingPongRequest.setCurrency("USD");
        String merchantTransactionId = UUID.randomUUID().toString();
        pingPongRequest.setMerchantTransactionId(merchantTransactionId);
        //URL是自定义的支付结果显示页,pingpongpay接收到后会在后面拼接订单ID"?orderId=123"
        pingPongRequest.setShopperResultUrl("http://52.221.156.209/pay/pay_success.html");
        //取消支付的URL
        pingPongRequest.setShopperCancelUrl("http://52.221.156.209/pay/pay_success.html?orderId=orderNum&status=4".replace("orderNum", merchantTransactionId));
        //这个URL是我们自定义的回调订单回调接口地址,参考文档:https://acquirer-api-docs-v3.pingpongx.com/pages/d0ddb3/#%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%E4%BA%A4%E4%BA%92%E6%B5%81%E7%A8%8B
        pingPongRequest.setNotificationUrl("http://52.221.156.209/pay/callback");
        pingPongRequest.setRemark("");
        pingPongRequest.setMerchantSource("");
        pingPongRequest.setCustomerId("10028");
        pingPongRequest.setEmail("19**790****@163.com");
        pingPongRequest.setName("Token充值");
        pingPongRequest.setNumber("67499");

        TreeMap<String, Object> signMap = new TreeMap<>();
        // 将pingPongRequest对象字段放入map中
        convertToSignMap(pingPongRequest, signMap);
        pingPongRequest.setSign(PingPongSignUtil.signature("SHA256", SANDBOX_SALT, signMap));
        String url;
        if (envConfig.isProd()) {
            //生产
            url = "https://acquirer-payment.pingpongx.com/acquirer/payment";
        } else {
            //沙箱
            url = "https://sandbox-acquirer-payment.pingpongx.com/acquirer/payment";
        }
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 构造请求实体
        HttpEntity<String> requestEntity = new HttpEntity<>(JSONObject.toJSONString(pingPongRequest), headers);
        //设置超时时间
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        //请求pingpong支付
        ResponseEntity<JSONObject> result = restTemplate.postForEntity(url, requestEntity, JSONObject.class);
	    System.out.println(result);

        JSONObject body = result.getBody();
        SysLogger.info(this.getClass(), "payermax 创建订单结果" + body.toJSONString());
        PingPongPayCheckoutDto payCheckoutDto = JsonFieldUtil.jsonToObj(body, PingPongPayCheckoutDto.class);
        System.out.println(payCheckoutDto);	
        return responseEntity.toString();
    }

需要说明的是,请求地址URL在sdk中是一个使用了占位符的地址:https://{host}/acquirer/payment,其中的{host}代表的是对接流程(必读)对应的资源,所以完整url是代码中的https://sandbox-acquirer-payment.pingpongx.com/acquirer/payment地址,包括salt以及accid都是该界面中的资源;我们在设置获取收银台URL时一定要设置NotificationUrl参数,它的作用时让pingpong支付支付的过程中以这样的频率 2s/5s/10s/30s/1m/10m/30m/1h/2h/1d/2d访问这个NotificationUrl,我们可以在这个接口中更新支付订单的状态以及对应状态下的业务,另外回调函数NotificationUrl的接口中为了保证安全需要做IP访问限制,只允许pingpongpay的服务器IP访问

image-20230506103217619

官方服务器ip
image-20230509095547434

沙箱的测试效果

image-20230506103311579

apifox测试界面

image-20230506105348137

可以看一下返回参数paymentUrl,它就是我们需要的支付界面,在浏览器中访问查看,与apifox中的paymentUrl地址一致

image-20230508182805614

支付结果页

image-20230508182815753

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

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

相关文章

【C++】类和对象(中篇)

几个成员函数 类的6个默认成员函数构造函数引例特点 析构函数概念特点 拷贝构造函数概念特征 赋值运算符重载赋值运算符重载赋值运算符只能重载成类的成员函数不能重载成全局函数前置和后置重载 日期类的实现const成员函数取地址及const取地址操作符重载 类的6个默认成员函数 …

Web缓存利用分析(二)

导语&#xff1a;在上一篇文章中&#xff0c;大致介绍了一些关于Web Cache的攻击方式及CTF中的一些出现。而本篇文章则会聚焦于Web Cache在学术前沿的一些攻击利用方式的探究。 前言 在上一篇文章中&#xff0c;大致介绍了一些关于Web Cache的攻击方式及CTF中的一些出现。而本…

Web缓存利用分析(一)

导语&#xff1a;最近看到一些Web Cache方面的攻击&#xff0c;于是总结了一下&#xff0c;内容如下。 前言 最近看到一些Web Cache方面的攻击&#xff0c;于是总结了一下&#xff0c;内容如下。 背景知识 Cache是一种经典的用空间换时间的做法&#xff0c;其应用场景非常广…

Htop使用说明

目录 引言 什么是htop htop安装 htop界面介绍 htop功能介绍 引言 我们使用服务器的时候常常需要关注下自己的程序资源占用情况&#xff0c;htop就是一种互动式的进程查查看器&#xff0c;整齐用下来感觉比top的逼格高&#xff0c;造作可视化都更方便些&#xff0c;我觉得还…

《Vue.js 设计与实现》—— 02 框架设计核心要素

框架设计并非仅仅实现功能那么简单&#xff0c;里面有很多学问。例如&#xff1a; 框架应该给用户提供哪些构建产物&#xff1f;产物的模块格式如何&#xff1f; 当用户没有以预期的方式使用框架时&#xff0c;是否应该打印合适的警告信息从而提供更好的开发体验&#xff0c;让…

优化性能测试分析:如何科学利用CPU异常曲线

性能测试为保证软件质量起到重要作用&#xff0c;对于交易量较大的应用系统&#xff0c;性能测试更是一个必不可少的环节。 测试人员通常通过监测响应时间、吞吐量、应用服务器和数据库服务器的CPU及内存来衡量系统的性能是否达标&#xff0c;那么&#xff0c;在性能测试过程中…

LabVIEWCompactRIO 开发指南13 网络发布的共享变量

LabVIEWCompactRIO 开发指南13 网络发布的共享变量 跨网络共享标签的一种方法是网络共享变量。术语网络变量是指网络上可以在程序、应用程序、远程计算机和硬件之间进行通信的软件项。网络共享变量非常适合1:N或N:1设置&#xff0c;因为它们有一个内置的连接管理器来管理传入…

《Netty》从零开始学netty源码(五十六)之RecvByteBufAllocator

RecvByteBufAllocator 在创建channel的过程中会创建一个相应的配置类&#xff0c;该类存储了一些关于channel的属性&#xff0c;包括分配内存的ByteBufAllocator和预估大小的RecvByteBufAllocator&#xff0c;通过前面的学习我们知道ByteBufAllocator分配内存的时候最终会委托…

Consensus洞察|2023,Web3“脱虚向实”元年

前言 2023年对于Web3来说&#xff0c;是一个被推到主流社会前台的关键时期。 出品&#xff5c;欧科云链研究院 作者&#xff5c;毕良寰 Web3作为新兴科技&#xff0c;其发展路径在近几年尤为艰难&#xff0c;充斥着“丑闻”的2022年&#xff0c;以Luna/UST的崩溃为起点开启了…

c++类与对象(二)——赋值运算符重载与取地址操作符重载

文章目录 一.运算符重载1.运算符重载的概念2.实现Date类&#xff08;1&#xff09;> < > < ! 重载&#xff08;2&#xff09; - - 重载&#xff08;3&#xff09;前置与后置重载&#xff08;4&#xff09;日期-日期的实现&#xff08;5&#xff09;<< 与 &g…

代码随想录之额外题目

数组 1207 独一无二的出现次数 看数组的大小和长度都没有很大&#xff0c;所以可以直接用数组来做哈希表&#xff0c;用一个数组来记录出现次数&#xff0c;再用一个数组来标记出现次数的值是否出现过。就是O(n) class Solution {public boolean uniqueOccurrences(int[] arr…

Spring IOC:IOC在Spring底层中如何实现?

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 spring版本&#xff1a;5.3.1 文章目录 Spring系列专栏文章目录一. 什么是IOC?二. IOC在spring中的实现2.1…

java 基础

第一章 计算机认识 1 概述 计算机包括**硬件&#xff08;hardware&#xff09;和软件&#xff08;software&#xff09;**两部分。硬件包括计算机可以看得见的物理部分&#xff0c;而软件提供看不见的指令。 2 计算机硬件介绍 3 计算机硬件——中央处理器 中央处理器&#xff0…

PyQGIS 加载单个shp文件到图层面板

打开QGIS Desktop 3.22.16&#xff0c;点击菜单栏 【设置】——>【Python控制台】 在Python控制台中点击【显示编辑器】按钮&#xff0c;打开Python编辑器 点击第一个按钮 【打开脚本文件】&#xff0c;选择加载图层列表到图层面板源码 # 加载图层列表到图层面板中 from qgi…

DataGridXL中快速搜索单元格和底部全屏模式区域隐藏

DataGridXL表格是在2020年发布&#xff0c;DataGridXL在设计时就考虑到了性能。提供最快、最简单、最可靠的数据网格。DataGridXL支持所有常用所有的浏览器&#xff0c;为 Web 应用程序提供类似于 Microsoft Excel 的体验&#xff0c;它支持前端框架有Vue、React、Angular等。 …

Acid burn(★★)

运行程序 先是弹出一个neg 然后是真正的程序界面 有一个输入Serial和Name的判断 还有一个只输入Serial的判断 查壳 没有壳&#xff0c;是Delphi程序 先除去一个Neg 找到Neg弹出的程序&#xff0c;在程序头下个断&#xff0c;运行程序&#xff0c;此时栈顶是调用此功能的…

希亦、米家、必胜家用洗地机测评,洗地机十年老用户告诉你哪款好用

如今&#xff0c;各种清洁设备早已进入我们的生活。其中&#xff0c;各种扫地机和洗地机更是出现在各大商场、酒店、餐饮、医院等领域。 洗地机是一种集洗地、吸尘于一体的清洗设备&#xff0c;它适合清扫如粉尘、烟头、纸屑、厨余、毛发等垃圾。它的工作效率高&#xff0c;可…

如何解决 :libstdc++.so.6: version `GLIBCXX_3.4.30‘ not found

在使用 python 以下的命令时&#xff0c; from scipy.signal import convolve出现报错&#xff1a; /home/anaconda3/envs/norm/lib/python3.9/site-packages/scipy/linalg/../../../../libstdc.so.6: version GLIBCXX_3.4.30 not found (required by /home/anaconda3/envs/no…

上海车展有哪些让人过目不忘的电驱技术?

前言 2023年的第二十届上海国际汽车工业展览会&#xff08;以下简称“上海车展”&#xff09;中&#xff0c;扁线、SiC、800V、油冷成为了大多数车企电驱动力总成的标配。下面选取几家非常有特色的电驱技术进行解析&#xff0c;并探讨下电驱技术的发展方向。 舍弗勒对标件电驱…

前几天面了个32岁的测试员,年薪50w问题基本都能回答上,应该刷了不少八股文···

互联网行业竞争是一年比一年严峻&#xff0c;作为测试工程师的我们唯有不停地学习&#xff0c;不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水&#xff0c;进入心仪的企业&#xff08;阿里、字节、美团、腾讯等大厂.....&#xff09; 所以&#xff0c;大家就迎来了…