通联支付API集成(适用于SpringBoot)

目标:

  • 学习如何使用Java与通联支付API进行交互

  • 实现一个简单的支付下单和查询订单状态的示例

所需材料:

  • 通联支付API文档

官方文档icon-default.png?t=N7T8https://aipboss.allinpay.com/know/devhelp/main.php?pid=38#mid=313

  • 通联支付加签代码SybUtil

package com.allinpay.common;

import net.sf.json.JSONObject;
import org.apache.tomcat.util.codec.binary.Base64;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;


@SuppressWarnings("all")
public class SybUtil {
    /**
     * js转化为实体
     *
     * @param <T>
     * @param jsonstr
     * @param cls
     * @return
     */
    public static <T> T json2Obj(String jsonstr, Class<T> cls) {
        JSONObject jo = JSONObject.fromObject(jsonstr);
        T obj = (T) JSONObject.toBean(jo, cls);
        return obj;
    }

    /**
     * md5
     *
     * @param b
     * @return
     */
    public static String md5(byte[] b) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.reset();
            md.update(b);
            byte[] hash = md.digest();
            StringBuffer outStrBuf = new StringBuffer(32);
            for (int i = 0; i < hash.length; i++) {
                int v = hash[i] & 0xFF;
                if (v < 16) {
                    outStrBuf.append('0');
                }
                outStrBuf.append(Integer.toString(v, 16).toLowerCase());
            }
            return outStrBuf.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return new String(b);
        }
    }

    /**
     * 判断字符串是否为空
     *
     * @param s
     * @return
     */
    public static boolean isEmpty(String s) {
        if (s == null || "".equals(s.trim()))
            return true;
        return false;
    }

    /**
     * 生成随机码
     *
     * @param n
     * @return
     */
    public static String getValidatecode(int n) {
        Random random = new Random();
        String sRand = "";
        n = n == 0 ? 4 : n;// default 4
        for (int i = 0; i < n; i++) {
            String rand = String.valueOf(random.nextInt(10));
            sRand += rand;
        }
        return sRand;
    }



    public static boolean validSign(TreeMap<String, String> param,
                                    String appkey, String signType) throws Exception {
        if (param != null && !param.isEmpty()) {
            if (!param.containsKey("sign"))
                return false;
            String sign = param.remove("sign");
            if ("MD5".equals(signType)) {// 如果是md5则需要把md5的key加入到排序
                param.put("key", appkey);
            }
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : param.entrySet()) {
                if (entry.getValue() != null && entry.getValue().length() > 0) {
                    sb.append(entry.getKey()).append("=")
                            .append(entry.getValue()).append("&");
                }
            }
            if (sb.length() > 0) {
                sb.deleteCharAt(sb.length() - 1);
            }
            if ("MD5".equals(signType)) {
                return sign.toLowerCase().equals(
                        md5(sb.toString().getBytes("UTF-8")).toLowerCase());
            } else {
                return rsaVerifyPublickey(sb.toString(), sign, appkey, "UTF-8");
            }
        }
        return false;
    }

    public static boolean rsaVerifyPublickey(String content, String sign,
                                             String publicKey, String charset) throws Exception {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    Base64.decodeBase64(publicKey.getBytes()));
            return rsaVerifyPublickey(content, sign, pubKey, charset);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("RSAcontent = " + content + ",sign=" + sign
                    + ",charset = " + charset, e);
        }
    }

    public static boolean rsaVerifyPublickey(String content, String sign,
                                             PublicKey pubKey, String charset) throws Exception {
        try {
            java.security.Signature signature = java.security.Signature
                    .getInstance("SHA1WithRSA");

            signature.initVerify(pubKey);

            if (charset == null || "".equals(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            return signature.verify(Base64.decodeBase64(sign.getBytes()));
        } catch (Exception e) {
            throw e;
        }
    }
    public static String unionSign(TreeMap<String, String> params,String appkey,
                                   String signType) throws Exception {
        // TODO Auto-generated method stub

        params.remove("sign");
        if ("MD5".equals(signType)) {// 如果是md5则需要把md5的key加入到排序
            params.put("key", appkey);
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (entry.getValue() != null && entry.getValue().length() > 0) {
                sb.append(entry.getKey()).append("=").append(entry.getValue())
                        .append("&");
            }
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        String sign = "";
        if ("MD5".equals(signType)) {
            System.out.println(sb.toString());
            sign = md5(sb.toString().getBytes("UTF-8"));// 记得是md5编码的加签
            params.remove("key");
        } else {
            sign = rsaSign(sb.toString(), appkey, "UTF-8");
        }
        return sign;
    }

    public static String rsaSign(String content, String privateKey,
                                 String charset) throws Exception {
        PrivateKey priKey = getPrivateKeyFromPKCS8("RSA",
                Base64.decodeBase64(privateKey.getBytes()));
        return rsaSign(content, priKey, charset);
    }

    public static String rsaSign(String content, byte[] privateKey,
                                 String charset) throws Exception {
        PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", privateKey);
        return rsaSign(content, priKey, charset);
    }

    public static String rsaSign(String content, PrivateKey priKey,
                                 String charset) throws Exception {
        java.security.Signature signature = java.security.Signature
                .getInstance("SHA1WithRSA");
        signature.initSign(priKey);
        if (charset == null || "".equals(charset)) {
            signature.update(content.getBytes());
        } else {
            signature.update(content.getBytes(charset));
        }
        byte[] signed = signature.sign();

        return new String(Base64.encodeBase64(signed));
    }

    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
                                                    byte[] encodedKey) throws Exception {

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    public static PublicKey getPublicKeyFromX509(String algorithm,
                                                 byte[] encodedKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }
}
  • IDE(如IntelliJ IDEA或Eclipse)

  • JDK 8 或更高版本

  • 需要的maven
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.43</version>
        </dependency>

        <!-- SybUtil文件需要用到 -->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
  •  辅助类
  1. 通联支付需要的请求数据格式(Allinpay.java)
package com.allinpay.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.math.BigDecimal;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Allinpay {

    private String cusid;

    private String appid;

    private int version;

    private BigDecimal trxamt;

    /*
        当指定为F02时,交易仅限分期交易。
        分期交易金额必须大于500元。
     */
    // ?
    private String paytype;

    /*
        3  花呗分期3期
        6  花呗分期6期
        12  花呗分期12期
        3-cc 支付宝信用卡分期3期
        6-cc 支付宝信用卡分期6期
        12-cc 支付宝信用卡分期12期
        暂只支持支付宝花呗分期,支付宝信用卡分期,仅支持A01/A02
     */
    // 可空参数
    private String fqnum;

    //订单号,商户唯一订单号
    private String reqsn;

    /*
        商户网站使用的编码格式,支持
        UTF-8、GBK
        跟商户网站的编码一致

    */
    //
    private String charset;

    /*
     必须为https协议地址,且不允许带参数
     页面跳转同步通知页面路径
    */
    private String returl;

    // 异步通知地址
    // ?
    private String notify_url;

    // 商品描述,长度最大100
    private String body;


    //? 通知会原样带上, 订单备注信息
    private String remark;

    // 随机字符串,自己生成,最大32位
    private String randomstr;

    //订单有效时间,以分为单位,默认为15
    private String validtime;

    // ? 支付限制(no_credit--指定不能使用信用卡支付)
    private String limit_pay;

    // 签名类型,目前支持RSA2和RSA
    private String signtype;

    // 签名 32位
    private String sign;

    // 关闭订单的时候需要
    private String oldreqsn;



}

 2. 由于本案列采用了多商家,所以暂时把配置也建成了一个类(PayConfig.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class PayConfig {

    private String cusid;

    private String appid;

    private String privateKey;

}

 3.本案列设置了多方支付方式,所以还有一个支付载荷(PayLoad.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.math.BigDecimal;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class PayLoad {

    private String orderId;

    private BigDecimal amount;

    private String payConfigKey;

    private String remark;

    private String title;

    private int payType;

    private String returnUrl;

    private String notifyUrl;


}
  •  H5支付下单代码

    //这个是PayService的Impl实现层
    private final String order = "https://syb.allinpay.com/apiweb/h5unionpay/unionorder";
    private final String rsaPrivateKey = "xxx";
    @SneakyThrows
    @Override
    public String h5Pay(PayLoad payLoad) {
        // String payConfigKey = payLoad.getPayConfigKey();
        PayConfig payConfig = new PayConfig()
            .setAppid("xxx")
            .setCusid("xxx")
            .setPrivateKey(rsaPrivateKey);
        Allinpay allinpay = new Allinpay()
                .setSigntype("RSA")
                .setTrxamt(new BigDecimal(2))
                .setReqsn(payLoad.getOrderId())
                .setRandomstr(SybUtil.getValidatecode(8))
                .setBody(payLoad.getTitle())
                .setRemark(payLoad.getRemark())
                .setCharset("UTF-8")
                .setAppid(payConfig.getAppid())
                .setCusid(payConfig.getCusid())
                .setReturl(payLoad.getReturnUrl());
        allinpay.setSign(URLEncoder.encode(SybUtil.unionSign(objectToTreeMap(allinpay), payConfig.getPrivateKey() , "RSA"), StandardCharsets.UTF_8));
        return order + "?" + treeMapToUrlParams(objectToTreeMap(allinpay));
    }
    //Controller代码
    @SneakyThrows
    @GetMapping("pay")
    public String pay(HttpServletResponse response) {
        String paymentUrl = (String) payService.h5Pay(new PayLoad()
                .setPayType(2)
                .setPayConfigKey("")
                .setReturnUrl("https://blog.csdn.net")
                .setOrderId(IdUtil.getSnowflakeNextIdStr())
                .setAmount(new BigDecimal(2))
                .setRemark("测试支付备注")
                .setTitle("测试H5支付")
        );
        String htmlResponse = "<!DOCTYPE html><html><head></head><body>"
                + "<script>window.location.href='" + paymentUrl + "'</script>"
                + "</body></html>";

        // 设置响应内容类型为HTML
        response.setContentType("text/html;charset=UTF-8");
        return htmlResponse;
    }

  • 关闭订单 

    // 关闭接口
    private final String close = "https://vsp.allinpay.com/apiweb/tranx/close";

    @SneakyThrows
    @Override
    public String closeOrder(PayLoad payLoad) {
        PayConfig payConfig = new PayConfig()
                .setAppid("xxx")
                .setCusid("xxxx")
                .setPrivateKey(rsaPrivateKey);
        Allinpay allinpay = new Allinpay()
                .setCusid(payConfig.getCusid())
                .setAppid(payConfig.getAppid())
                .setRandomstr(SybUtil.getValidatecode(8))
                .setVersion(11)
                .setOldreqsn(payLoad.getOrderId())
                .setSigntype("RSA");
        allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));
        return HttpUtil.post(close, BeanUtil.beanToMap(allinpay));
    }
 
     /**
     * 关闭订单
     * @param outTradeNo 下单的订单号,也就是你支付下单类Allinpay的reqsn
     * @return {@link String}
     ***/
    @SneakyThrows
    @GetMapping("closeOrder/{outTradeNo}")
    public Map<String,String> closeOrder(@PathVariable Long outTradeNo) {
        return handleResult(payService.closeOrder(new PayLoad().setOrderId(outTradeNo.toString())));
    }
  •  查询订单

    // 查询接口
    private final String query = "https://vsp.allinpay.com/apiweb/tranx/query";

    @SneakyThrows
    @Override
    public String query(PayLoad payLoad) {
        PayConfig payConfig = new PayConfig()
                .setAppid("xxx")
                .setCusid("xxxx")
                .setPrivateKey(rsaPrivateKey);
        Allinpay allinpay = new Allinpay()
                .setCusid(payConfig.getCusid())
                .setAppid(payConfig.getAppid())
                .setRandomstr(SybUtil.getValidatecode(8))
                .setVersion(11)
                .setReqsn(payLoad.getOrderId())
                .setSigntype("RSA");
        allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));
        return HttpUtil.post(query, BeanUtil.beanToMap(allinpay));
    }


    /**
     * 查询订单
     * @param outTradeNo 下单的订单号
     * @return {@link String}
     ***/
    @SneakyThrows
    @GetMapping("query/{outTradeNo}")
    public Map<String, String> query(@PathVariable Long outTradeNo) {
        return handleResult(payService.query(new PayLoad().setOrderId(outTradeNo.toString())));
    }
  • 退款接口,这个是只能退当天的交易 (全额退实时返回退款结果)

    // 取消当天交易退款接口
    private final String cancelDayUrl = "https://vsp.allinpay.com/apiweb/tranx/cancel";

    @SneakyThrows
    @Override
    public String cancelDay(PayLoad payLoad) {
        PayConfig payConfig = new PayConfig()
                .setAppid("xxx")
                .setCusid("xxxx")
                .setPrivateKey(rsaPrivateKey);
        Allinpay allinpay = new Allinpay()
                .setCusid(payConfig.getCusid())
                .setAppid(payConfig.getAppid())
                .setRandomstr(SybUtil.getValidatecode(8))
                .setVersion(11)
                .setTrxamt(new BigDecimal(2))
                .setReqsn(payLoad.getOrderId())
                .setOldreqsn(payLoad.getOrderId())
                .setSigntype("RSA");
        allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));
        return HttpUtil.post(cancelDayUrl, BeanUtil.beanToMap(allinpay));
    }


    /**
     * 退款接口,只能退今天的,全额退款,实时返回退款结果
     * @return {@link String}
     */
    @SneakyThrows
    @GetMapping("cancelDay/{outTradeNo}")
    public Map<String, String> cancelDay(@PathVariable Long outTradeNo) {
        return handleResult(payService.cancelDay(new PayLoad().setOrderId(outTradeNo.toString())));
    }
  • 退款接口 ,可以退部分

    
    // 退款接口
    private final String refundUrl = "https://vsp.allinpay.com/apiweb/tranx/refund";

    @SneakyThrows
    @Override
    public String refund(PayLoad payLoad) {
        PayConfig payConfig = new PayConfig()
                .setAppid("xxx")
                .setCusid("xxxx")
                .setPrivateKey(rsaPrivateKey);
        Allinpay allinpay = new Allinpay()
                .setCusid(payConfig.getCusid())
                .setAppid(payConfig.getAppid())
                .setRandomstr(SybUtil.getValidatecode(8))
                .setVersion(11)
                .setTrxamt(new BigDecimal(2))
                .setReqsn(payLoad.getOrderId())
                .setOldreqsn(payLoad.getOrderId())
                .setSigntype("RSA");
        allinpay.setSign(SybUtil.unionSign(objectToTreeMap(allinpay), rsaPrivateKey, "RSA"));
        return HttpUtil.post(refundUrl, BeanUtil.beanToMap(allinpay));
    }

     // 可以和上面的接口进行整合处理

    /**
     * 退款接口,可以退部分
     * @return {@link String}
     */
    @SneakyThrows
    @GetMapping("refund/{outTradeNo}")
    public Map<String, String> refund(@PathVariable Long outTradeNo) {
        return handleResult(payService.refund(new PayLoad().setOrderId(outTradeNo.toString())));
    }

提示: 可以和上面的接口进行整合处理

  • 其中签名需要用到的转map方法 

    private TreeMap<String, String> objectToTreeMap(Object obj) {
        TreeMap<String, String> treeMap = new TreeMap<>();
        Class<?> clazz = obj.getClass();
        while (clazz != null) {
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                try {
                    Object fieldValue = field.get(obj);
                    if (fieldValue != null) {
                        treeMap.put(field.getName(), fieldValue.toString());
                    }
                } catch (IllegalAccessException e) {
                    log.error("Error accessing field " + field.getName() + ": " + e.getMessage());
                }
            }
            clazz = clazz.getSuperclass();
        }
        return treeMap;
    }
  •  其中map转路径参数方法

  private static String treeMapToUrlParams(TreeMap<String, String> treeMap) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : treeMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(key).append("=").append(value);
        }
        return sb.toString();
    }
  • 其中通联返回验签代码

    /**
     * 验签
     * @param result
     * @return {@link Map}<{@link String},{@link String}>
     * @throws Exception
     */
    @SuppressWarnings({ "rawtypes", "all" })
    public static Map<String,String> handleResult(String result) throws Exception{
        Map map = SybUtil.json2Obj(result, Map.class);
        if(map == null){
            throw new Exception("返回数据错误");
        }
        if("SUCCESS".equals(map.get("retcode"))) {
            TreeMap tmap = new TreeMap();
            tmap.putAll(map);
            if(SybUtil.validSign(
                     tmap,
                    "xxxxx",
                    "RSA")
            ){
                return map;
            }else{
                throw new Exception("验证签名失败");
            }
            // 验签成功,返回数据
        }else{
            throw new Exception(map.get("retmsg").toString());
        }
    }

提示:如果不考虑多商户,多支付通道,可以再方法中Allinpay类直接填参数请求,不用通过PayLoad和PayConfig类  

  • 完整代码克隆地址:

git clone https://gitee.com/byte1026/allin-pay.git

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从GPT-4o和Google I/O看AI技术变革与未来趋势

引言 在科技界的激烈竞争中&#xff0c;OpenAI 和 Google 这两大巨头不断推出新技术&#xff0c;引领着人工智能的发展。最近&#xff0c;OpenAI 发布了 GPT-4o&#xff0c;恰逢 Google I/O 大会前一天&#xff0c;这一发布会似乎有意“截胡” Google I/O。今天&#xff0c;我…

python实现520表白图案

今天是520哦&#xff0c;作为程序员有必要通过自己的专业知识来向你的爱人表达下你的爱意。那么python中怎么实现绘制520表白图案呢&#xff1f;这里给出方法&#xff1a; 1、使用图形库&#xff08;如turtle&#xff09; 使用turtle模块&#xff0c;你可以绘制各种形状和图案…

go 爬虫之 colly 简单示例

1. 背景 colly 是 Go 实现的比较有名的一款爬虫框架&#xff0c;而且 Go 在高并发和分布式场景的优势也正是爬虫技术所需要的。它的主要特点是轻量、快速&#xff0c;设计非常优雅&#xff0c;并且分布式的支持也非常简单&#xff0c;易于扩展。 2. 官方文档 https://go-col…

大模型的实践应用24-LLaMA-Factory微调通义千问qwen1.5-1.8B模型的实例

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用24-LLaMA-Factory微调通义千问qwen1.5-1.8B模型的实例, LLaMA-Factory是一个专门用于大语言模型微调的框架,它支持多种微调方法,如LoRA、QLoRA等,并提供了丰富的数据集和预训练模型,便于用户进行模型微调。通义千问…

15:00面试,15:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

mysql 慢查询

一、开启mysql自己的慢查询日志 1、查看慢日志参数设置 show VARIABLES like %query% 2、修改配置文件 vim /etc/my.cnf [mysqld] slow_query_log 1 #是否开启慢查询日志记录 long_query_time 1 #慢查询时间&#xff0c;单位秒 #log_outputtable,file #慢查询…

学习Thymeleaf时遇到的问题

使用idea创建web项目&#xff0c;启动服务器后无法访问页面 原因是tomcat 新版本引用包名改变 由javax变为jakarta 解决办法1 把项目的poe.xml文件由 改为 解决办法2 新建项目时选择新版本&#xff0c;但是新版本不支持thymeleaf

基础2 JAVA图形编程桌面:探索图形程序的抽象实现

嘿&#xff0c;大家好&#xff01;我非常高兴又一次有机会与大家相聚&#xff0c;分享新的知识和经验。对于热爱编程和探索新技术的朋友们来说&#xff0c;今天的内容绝对不容错过。我为大家准备了一个详尽的视频教程&#xff1a;《基础2 JAVA 图形编程&#xff1a;主程序调用…

word-表格疑难杂症诊治

一、用表格进行排版图片、制作公文头 可以在插入图片时固定列宽 二、表格中的疑难杂症 问题一&#xff1a;表格超过页面&#xff0c;右侧文字看不见 解决&#xff1a;表格窗口-布局-自动调整-根据窗口自动调整表格 问题二&#xff1a;表格底部文字被遮挡 解决&#xff1a;布…

sheng的学习笔记-AI-EM算法

AI学习笔记目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 基础知识 什么是EM算法 EM算法简介 数学知识 极大似然估计 问题描述 用数学知识解决现实问题 最大似然函数估计值的求解步骤 Jensen不等式 定义 EM算法详解 问题描述 EM算法推导流程 EM算法流程…

Java——内部类

内部类概念 当一个事物的内部&#xff0c;还有一个部分需要一个完整的结构进行描述&#xff0c;而这个内部的完整的结构又只为外部事物提供服 务&#xff0c;那么这个内部的完整结构最好使用内部类。在 Java 中&#xff0c;可以将一个类定义在另一个类或者一个方法的内部&…

CustomTkinter:便捷美化Tkinter的UI界面(附模板)

CustomTkinter是一个基于Tkinter的Python用户界面库。 pip3 install customtkinter它提供了各种UI界面常见的小部件。这些小部件可以像正常的Tkinter小部件一样创建和使用&#xff0c;也可以与正常的Tkinter元素一起使用。 它的优势如下&#xff1a; CustomTkinter的小部件和…

Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明

Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明 目录 Python 机器学习 基础 之 数据表示与特征工程 【单变量非线性变换 / 自动化特征选择/利用专家知识】的简单说明 一、简单介绍 二、单变量非线性变换 三、自…

C语言游戏实战(12):植物大战僵尸(坤版)

植物大战僵尸 前言&#xff1a; 本游戏使用C语言和easyx图形库编写&#xff0c;通过这个项目我们可以深度的掌握C语言的各种语言特性和高级开发技巧&#xff0c;以及锻炼我们独立的项目开发能力&#xff0c; 在开始编写代码之前&#xff0c;我们需要先了解一下游戏的基本规则…

倍思/西圣/UHB电容笔怎么选?2024热门电容笔全面性能测评大PK

​在这个追求速度和效率的时代&#xff0c;ipad以其便携性和高性能成为很多上班族、学生党提高生产力和学习效率的重要工具&#xff0c;很多人更是会搭配一支电容笔来进一步发挥ipad的使用价值&#xff0c;可原装的电容笔毕竟价格较高&#xff0c;于是很多人将目光转向平替&…

Day35 代码随想录打卡|二叉树篇---二叉树的层序遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 方法&#xff1a;二叉树的层序遍历感觉是相对简单的&#xff0c;只需要定义一个队列&#xff0c;从根节点开始放入队列…

SQL靶场搭建

概述 简单介绍一下SQL靶场的搭建&#xff0c;以及在搭建过程中遇到的一些问题。使用该软件搭建靶场相对简单&#xff0c;适合新手小白。当然&#xff0c;也可以在自己的虚拟机下进行搭建&#xff0c;相对来说就较为复杂。本章主要讲解使用Phpstudy进行SQL靶场搭建。 这里我推…

【安装笔记-20240519-Windows-安装测试 Optimizer】

安装笔记-系列文章目录 安装笔记-20240519-Windows-安装测试 Optimizer 文章目录 安装笔记-系列文章目录安装笔记-20240519-Windows-安装测试 Optimizer 前言一、软件介绍名称&#xff1a;Optimizer主页官方介绍 二、安装步骤测试版本&#xff1a;16.5下载链接功能界面 三、应…

Redis篇 有关Redis的认识和Redis的特性应用场景

Redis 一. Redis的基本概念1.1 应用/系统1.2 模块/组件1.3 分布式1.4 集群1.5 主/从1.6 中间件1.7 可用性1.8 响应时长1.9 吞吐 二.Redis的特性三.使用场景 一. Redis的基本概念 1.1 应用/系统 一个应用就是一个组,一个服务器程序 1.2 模块/组件 一个应用,里面有很多功能,每个…

Java开发工具类(JDK、Hutool、Guava)

目录 Java开发常用的工具类1、JDK自带程序读取控制台输入内容&#xff08;调试程序或者学习的时候比较有用&#xff09;Arrays工具类 数组转集合Collections 集合工具类 排序Collections 集合工具类 查找Lambda表达式 操作集合 收集、转map、分组 2、Apache 的 commons-lang3 和…