微信电脑版二维码( NATIVE 扫码支付)

news2024/10/4 21:54:22

后端代码

/**
* 微信支付->扫码支付(模式二)->统一下单->微信二维码
* @return
*/
@PostMapping (value = “/qrcode”)
@RequestLog(“微信支付二维码”)
@ApiOperation(“微信支付二维码”)
@AnonAccess
public ResponseEntity wxpayPay(@Validated @RequestBody SysMemberRecordVo sysMemberRecordVo,
HttpServletRequest request,HttpServletResponse response) {

    String urlCode = null;

// String out_trade_no = UUID.randomUUID().toString().replace(“-”, “”);
String out_trade_no=getCurrentTimeStamp();
// 账号信息
String currTime = PayToolUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = String.valueOf(PayToolUtil.buildRandom(4));
String nonce_str = strTime + strRandom;
String total_fee = String.valueOf(Integer.parseInt(sysMemberRecordVo.getType().getValue()) * 100);
// (Double.parseDouble(sysMemberRecordVo.getType().getValue()) * 100)

    SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
    packageParams.put("appid", WXConstants.appid);//公众账号ID
    packageParams.put("mch_id", WXConstants.mchid);//商户号
    packageParams.put("nonce_str", nonce_str);//随机字符串
    packageParams.put("body", "开通会员");  //商品描述
    packageParams.put("out_trade_no", out_trade_no);//商户订单号
    packageParams.put("total_fee", total_fee); //标价金额 订单总金额,单位为分
    packageParams.put("spbill_create_ip", WxChatPayCommonUtil.getIp(request));//终端IP APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
    packageParams.put("notify_url", WXConstants.NOTIFY_URL);//通知地址 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数
    packageParams.put("trade_type", "NATIVE");//交易类型 NATIVE 扫码支付
    // 签名
    String sign = PayToolUtil.createSign("UTF-8", packageParams, WXConstants.key);
    packageParams.put("sign", sign);

    // 将请求参数转换为xml格式的string
    String requestXML = PayToolUtil.getRequestXml(packageParams);
    logger.info("requestXML:{}", requestXML);

    // 调用微信支付统一下单接口
    String resXml = HttpUtils.postData(PayConfigUtil.UFDODER_URL, requestXML);
    logger.info("resXml: {}", resXml);

    // 解析微信支付结果
    Map map = null;
    try {
        map = XMLUtil4jdom.doXMLParse(resXml);
        logger.info("map: {}", map);
    } catch (JDOMException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    // 返回微信支付的二维码连接
    urlCode = (String) map.get("code_url");
    logger.info("urlCode:{}", urlCode);
    if (!"".equals(urlCode)){
        sysMemberRecordVo.setOutTradeNo(Long.valueOf(out_trade_no));
        sysMemberRecordVo.setPayState((long)0);
        sysMemberRecordFacade.createSysMemberRecord(sysMemberRecordVo);
    }
    map.put("out_trade_no",out_trade_no);
    map.remove("appid");
    map.remove("mch_id");
    map.remove("sign");
    map.remove("trade_type");
    return new ResponseEntity<>(map,HttpStatus.OK);

}

/**
* 微信支付-回调
* @param request
* @param response
*/
@PostMapping(“/wxNotify”)
@RequestLog(“微信支付回调”)
@ApiOperation(“微信支付回调”)
@AnonAccess
public String wxpayNotify(HttpServletRequest request, HttpServletResponse response) {
//读取参数
InputStream inputStream ;
StringBuffer sb = null;
try {
sb = new StringBuffer();
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, “UTF-8”));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

    //解析xml成map
    Map<String, String> map = new HashMap<String, String>();
    try {
        map = XMLUtil4jdom.doXMLParse(sb.toString());
    } catch (JDOMException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    //过滤空 设置 TreeMap
    SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
    Iterator it = map.keySet().iterator();
    while (it.hasNext()) {
        String parameter = (String) it.next();
        String parameterValue = map.get(parameter);
        String v = "";
        if(null != parameterValue) {
            v = parameterValue.trim();
        }
        packageParams.put(parameter, v);
    }
    //判断签名是否正确
    if(PayToolUtil.isTenpaySign("UTF-8", packageParams, WXConstants.key)) {
        //------------------------------
        //处理业务开始
        //------------------------------
        String resXml = "";
        if("SUCCESS".equals((String)packageParams.get("result_code"))){
            // 这里是支付成功
            //执行自己的业务逻辑
            String mch_id = (String)packageParams.get("mch_id");
            String openid = (String)packageParams.get("openid");
            String is_subscribe = (String)packageParams.get("is_subscribe");
            String out_trade_no = (String)packageParams.get("out_trade_no");
            String total_fee = (String)packageParams.get("total_fee");

            //执行自己的业务逻辑
            //暂时使用最简单的业务逻辑来处理:只是将业务处理结果保存到session中
            //(根据自己的实际业务逻辑来调整,很多时候,我们会操作业务表,将返回成功的状态保留下来)
            String code =sysMemberRecordFacade.wxpayNotify(out_trade_no);

            //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
            resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                    + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            return ("fail");
        }
        //------------------------------
        //处理业务完毕
        //------------------------------
        try {
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    } else{
        logger.info("通知签名验证失败");
    }
    return ("success");
}

//生成订单号方法
public static String getCurrentTimeStamp(){
SimpleDateFormat sdf = new SimpleDateFormat(“yyyyMMddHHmmss”);
return sdf.format(new Date());
}

//PayToolUtil类
package com.zohokeyes.les.bootstrap.utils;

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

public class PayToolUtil {

/**
 * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
 * @return boolean
 */
public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
    StringBuffer sb = new StringBuffer();
    Set es = packageParams.entrySet();
    Iterator it = es.iterator();
    while(it.hasNext()) {
        Map.Entry entry = (Map.Entry)it.next();
        String k = (String)entry.getKey();
        String v = (String)entry.getValue();
        if(!"sign".equals(k) && null != v && !"".equals(v)) {
            sb.append(k + "=" + v + "&");
        }
    }

    sb.append("key=" + API_KEY);

    //算出摘要
    String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
    String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();

    //System.out.println(tenpaySign + "    " + mysign);
    return tenpaySign.equals(mysign);
}

/**
 * 创建sign签名
 * @param characterEncoding 编码格式
 * @param packageParams 请求参数
 * @param API_KEY API密钥
 * @return
 */
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
    StringBuffer sb = new StringBuffer();
    Set es = packageParams.entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
            sb.append(k + "=" + v + "&");
        }
    }
    sb.append("key=" + API_KEY);
    String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
    return sign;
}

/**
 * 将请求参数转换为xml格式的string
 * @param parameters 请求参数
 * @return 转换后的字符串
 */
public static String getRequestXml(SortedMap<Object, Object> parameters) {
    StringBuffer sb = new StringBuffer();
    sb.append("<xml>");
    Set es = parameters.entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
            sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
        } else {
            sb.append("<" + k + ">" + v + "</" + k + ">");
        }
    }
    sb.append("</xml>");
    return sb.toString();
}

/**
 * 取出一个指定长度大小的随机正整数
 * @param length int 设定所取出随机数的长度。length小于11
 * @return int 返回生成的随机数。
 */
public static int buildRandom(int length) {
    int num = 1;
    double random = Math.random();
    if (random < 0.1) {
        random = random + 0.1;
    }
    for (int i = 0; i < length; i++) {
        num = num * 10;
    }
    return (int) ((random * num));
}

/**
 * 获取当前时间 yyyyMMddHHmmss
 * @return
 */
public static String getCurrTime() {
    Date now = new Date();
    SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    return outFormat.format(now);
}

}

//WxChatPayCommonUtil类
package com.zohokeyes.les.bootstrap.utils;

import org.springframework.util.StringUtils;

import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;

import java.io.*;
import java.net.URL;

/**

  • 自定义微信支付工具类
    /
    public class WxChatPayCommonUtil {
    /
    *

    • 发送 http 请求
    • @param requestUrl 请求路径
    • @param requestMethod 请求方式(GET/POST/PUT/DELETE/…)
    • @param outputStr 请求参数体
    • @return 结果信息
      */
      public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
      try {
      URL url = new URL(requestUrl);
      HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
      conn.setDoOutput(true);
      conn.setDoInput(true);
      conn.setUseCaches(false);
      // 设置请求方式(GET/POST)
      conn.setRequestMethod(requestMethod);
      conn.setRequestProperty(“content-type”, “application/x-www-form-urlencoded”);
      // 当outputStr不为null时向输出流写数据
      if (null != outputStr) {
      OutputStream outputStream = conn.getOutputStream();
      // 注意编码格式
      outputStream.write(outputStr.getBytes(“UTF-8”));
      outputStream.close();
      }
      // 从输入流读取返回内容
      InputStream inputStream = conn.getInputStream();
      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, “utf-8”);
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      String str = null;
      StringBuffer buffer = new StringBuffer();
      while ((str = bufferedReader.readLine()) != null) {
      buffer.append(str);
      }
      // 释放资源
      bufferedReader.close();
      inputStreamReader.close();
      inputStream.close();
      inputStream = null;
      conn.disconnect();
      return buffer.toString();
      } catch (Exception e) {
      e.printStackTrace();
      }
      return null;
      }

    /**

    • 获取ip
    • @param request 请求
    • @return ip 地址
      */
      public static String getIp(HttpServletRequest request) {
      if (request == null) {
      return “”;
      }
      String ip = request.getHeader(“X-Requested-For”);
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getHeader(“X-Forwarded-For”);
      }
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getHeader(“Proxy-Client-IP”);
      }
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getHeader(“WL-Proxy-Client-IP”);
      }
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getHeader(“HTTP_CLIENT_IP”);
      }
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getHeader(“HTTP_X_FORWARDED_FOR”);
      }
      if (StringUtils.isEmpty(ip) || “unknown”.equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
      }
      return ip;
      }

    /**

    • 从流中读取微信返回的xml数据

    • @param httpServletRequest

    • @return

    • @throws IOException
      */
      public static String readXmlFromStream(HttpServletRequest httpServletRequest) throws IOException {
      InputStream inputStream = httpServletRequest.getInputStream();
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
      final StringBuffer sb = new StringBuffer();
      String line = null;
      try {
      while ((line = bufferedReader.readLine()) != null) {
      sb.append(line);
      }
      } finally {
      bufferedReader.close();
      inputStream.close();
      }

      return sb.toString();
      }

    /**

    • 设置返回给微信服务器的xml信息
    • @param returnCode
    • @param returnMsg
    • @return
      */
      public static String setReturnXml(String returnCode, String returnMsg) {
      return “<return_code><![CDATA[" + returnCode + "]]></return_code><return_msg><![CDATA[" + returnMsg + "]]></return_msg>”;
      }

}

//http工具类,负责发起post请求并获取的返回
//HttpUtils
package com.zohokeyes.les.bootstrap.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

/**

  • http工具类,负责发起post请求并获取的返回
    */
    public class HttpUtils {

    private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
    private final static String DEFAULT_ENCODING = “UTF-8”;

    public static String postData(String urlStr, String data){
    return postData(urlStr, data, null);
    }

    public static String postData(String urlStr, String data, String contentType){
    BufferedReader reader = null;
    try {
    URL url = new URL(urlStr);
    URLConnection conn = url.openConnection();
    conn.setDoOutput(true);
    conn.setConnectTimeout(CONNECT_TIMEOUT);
    conn.setReadTimeout(CONNECT_TIMEOUT);
    if(contentType != null)
    conn.setRequestProperty(“content-type”, contentType);
    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
    if(data == null)
    data = “”;
    writer.write(data);
    writer.flush();
    writer.close();

         reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
         StringBuilder sb = new StringBuilder();
         String line = null;
         while ((line = reader.readLine()) != null) {
             sb.append(line);
             sb.append("\r\n");
         }
         return sb.toString();
     } catch (IOException e) {
         logger.error("Error connecting to " + urlStr + ": " + e.getMessage());
     } finally {
         try {
             if (reader != null)
                 reader.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
     return null;
    

    }

}

前端代码vue
引入import QRCode from ‘qrcode’ // 引入生成二维码插件qrcode
在data中的return定义qrCodeImgUrl存放微信二维码用的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

算了,具体可看https://blog.csdn.net/fat_shady/article/details/12841091这个帖子.

总结:后端代码中的APPID啥的用自己的就行,然后那几个工具类可以合到一起。我因为项目忙实现了就没整理。很多工具类的方法没用到后期可以删除。

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

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

相关文章

GreatSQL 8.0.32-24 今日发布

1.新增特性 1.1 SQL兼容性1.2 MGR1.3 性能优化1.4 安全 2.稳定性提升 3.其他调整 4.bug修复 5.GreatSQL VS MySQL 6.GreatSQL Release Notes GreatSQL 8.0.32-24版本发布&#xff0c;增加并行load data、&#xff08;逻辑 & CLONE&#xff09;备份加密、MGR读写节点可绑定…

MyBatis的创建和单表使用

前言&#xff1a; 之前我们了解到MySQL。接下来了解一下MyBatis&#xff0c;它不是一种数据库&#xff0c;那是什么呢和数据库有什么联系了&#xff1f; 目录 一&#xff1a;MyBatis的定义 二&#xff1a;MyBatis的创建 三&#xff1a;MyBatis的简单使用 3.1:准备工作 3.…

后端服务架构高性能设计之道

“N 高 N 可”&#xff0c;高性能、高并发、高可用、高可靠、可扩展、可维护、可用性等是后台开发耳熟能详的词了&#xff0c;它们中有些词在大部分情况下表达相近意思。本序列文章旨在探讨和总结后台架构设计中常用的技术和方法&#xff0c;并归纳成一套方法论。 前言 本文主…

视频采集到录制 - MP4生成

录制最终格式是MP4&#xff0c;视频流是采用H264编码流&#xff0c;音频是aac编码流 最终需要将两个流合并到一个文件里 采用的方案&#xff0c;是通过mp4v2的库&#xff0c;进行合并 原理很简单&#xff1a; 先创建文件&#xff0c;输入编码参数 需要创建视频流初始 也需要…

制造业在数字化时代如何应对挑战和机遇?

随着数字化时代的到来&#xff0c;制造业不可避免地会受到一些对应的挑战和机遇。以下是一些关键部分&#xff1a; 数字化转型&#xff1a;制造商已经采用数字技术来转变他们的运营。包括采用高级分析、自动化、人工智能 (AI) 和物联网 (IoT)。这些技术可以提高生产力、质量控制…

2.项目数仓、项目工具

项目数仓 数仓(Data Warehouse)是指用于存储和管理企业数据的一种大型数据库系统,以支持企业的决策分析活动。它采用了ETL(抽取、转化、加载)等技术来集成和清洗数据,并提供了灵活的查询和报表功能,使得分析师和决策者可以更好地理解企业的业务情况和趋势。 项目工…

基于三相坐标系状态方程的感应电动机起动动态计算(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

DataGrip使用技巧总结

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

照片怎么拼图?简单好用的拼图方法分享

照片的拼接不仅能够让我们将多张照片合成一张大图&#xff0c;还能够发挥我们的想象和创意&#xff0c;例如&#xff0c;我们可以将不同的照片拼接在一起&#xff0c;创造出一个全新的场景&#xff0c;或者将同一个场景的不同角度的照片拼接在一起&#xff0c;制作出一个完整的…

一个网站建设公司如何保障提供优质的服务

网站建设公司提供的服务是否优质&#xff0c;直接影响到客户的口碑&#xff0c;也会影响到公司的口碑。 一个好的网站建设公司&#xff0c;不仅会提供优质的服务&#xff0c;还会有专业的技术人员对客户进行跟踪服务。这是一项重要的工作&#xff0c;需要一个网站建设公司不断…

《神奇的连接组》读后

人类大脑被戏称为“三磅的宇宙”&#xff0c;或许可以从科学上解释关于“意识”的问题&#xff0c;大脑的神经科学可能是人类科学的最终前沿。 任何真正先进的科技&#xff0c;看起来都与魔法无异。 要解释大脑如何运转&#xff0c;单凭基因无法解释大脑为什么这样工作&#xf…

Java——Java易错选择题复习(2)(计算机网络)

1. 下面关于源端口地址和目标端口地址的描述中&#xff0c;正确的是&#xff08; &#xff09; A. 在TCP/UDP传输段中&#xff0c;源端口地址和目的端口地址是不能相同的 B. 在TCP/UDP传输段中&#xff0c;源端口地址和目的端口地址必须是相同的 C. 在TCP/UDP传输段中&#xff…

chatgpt赋能python:Python声音处理之变声

Python声音处理之变声 随着科技的发展&#xff0c;人们对于声音处理越来越感兴趣。变声技术就是其中的一种&#xff0c;它可以将一个人的声音变成其他的人或动物的声音&#xff0c;非常有趣。 Python作为一种广泛使用的编程语言&#xff0c;可以在声音处理中发挥重要作用。本…

如何在食品行业运用IPD?

食品是我国重要的民生产业之一&#xff0c;是保障和满足人民群众不断增长消费需求的重要支撑。食品指各种供人食用或者饮用的成品和原料以及按照传统既是食品又是药品的物品&#xff0c;包括加工食品&#xff0c;半成品和未加工食品&#xff0c;不包括烟草或只作药品用的物质。…

为数据可视化增添戏剧性

Python 中的视觉叙事&#xff1a;让数据说话的 5 个创新技巧 为数据可视化增添戏剧性 数据可视化 - 这是一个现在经常被抛出的短语。但我们谈论的不仅仅是普通的旧图表和图形。 不 不 不。我们谈论的是讲故事。我们正在谈论将这些行和列的数字变成令人着迷的叙述。 现在是我们从…

Elasticsearch:数据是如何被写入的?

在我之前的文章 “Elasticsearch&#xff1a;索引数据是如何完成的”&#xff0c;我详述了如何索引 Elasticsearch 的数据的。在今天的文章中&#xff0c;我将从另外一个视角来诠释如何写入数据到 Elasticsearch。更多关于 Elasticsearch 数据操作&#xff0c;请阅读文章 “Ela…

PowerShell install 一键部署postgres15

postgres 前言 PostgreSQL 是一个功能强大的开源对象关系数据库系统&#xff0c;拥有超过 35 年的积极开发经验 这为其赢得了可靠性、功能稳健性和性能的良好声誉。 通过官方文档可以找到大量描述如何安装和使用 PostgreSQL 的信息。 开源社区提供了许多有用的地方来熟悉Postg…

08 【生命周期 组件】

1. 生命周期 1.1 引出生命周期 生命周期 又名生命周期回调函数,生命周期函数、生命周期钩子是什么,Vue在关键时刻帮我们调用的一些特殊名称函数生命周期函数的名字不可更改,但函数的具体内容是根据程序员需求编写的生命周期函数中的this指向的是vm或组件实例对象 <div i…

贺斌教授团队:多少冥想训练才能提高脑机接口的性能?

冥想训练可以帮助人们学会更好地控制脑机接口。但是一项新的研究发现&#xff0c;单次的冥想练习不足以提高表现。发表在《Frontiers in Human Neuroscience》的一项研究结果表明&#xff0c;人们需要更长时间的冥想才能体验到明显的改善。 # 脑机接口性能如何提高&#xff1f;…

kafka 集群是如何选择 leader,你知道吗?

前言 kafka集群是由多个broker节点组成&#xff0c;这里面包含了许多的知识点&#xff0c;以下的这些问题你都知道吗? 你知道topic的分区leader是怎么选举的吗&#xff1f; 你知道zookeeper中存储了kafka的什么信息吗&#xff1f;起到什么做呢&#xff1f; 你知道kafka消息…