【苍穹外卖】Day2 手把手敲完细节

目录

1. 新增员工

1.1 需求分析和设计

1.2 代码开发

①定义DTO类:(在sky-pojo里)

②EmployeeController中创建新增员工方法save()

③EmployeeService里声明save方法(alt+enter)

④EmployeeServiceImpl中实现save方法

⑤在EmployeeMapper中声明insert方法,插入数据库

1.3 功能测试

1.4 代码完善

1.5 代码提交

1.6 遇到的问题

2. 员工的分页查询

2.1 需求分析和设计

2.2 代码开发

①定义DTO类

②EmployeeController中创建员工分页查询方法page()

③EmployeeService里声明pageQuery方法

④ EmployeeServiceImpl中实现pageQuery方法

⑤在EmployeeMapper中声明pageQuery方法,插入数据库

2.3 功能测试

2.4 代码完善

2.5 代码提交

3. 启用禁用员工账号

3.1 需求分析和设计​编辑

3.2 代码开发

3.3 功能测试

 4. 编辑员工

4.1 需求分析和设计

 4.2 代码开发

 4.3 功能测试-成功

5. 导入分类模块功能

5.1 需求分析和设计

5.2 代码导入

5.3 功能测试


1. 新增员工

步骤:需求分析和设计(产品原型→接口设计→数据库设计)→代码开发

1.1 需求分析和设计

产品原型:

当填写完表单信息, 点击"保存"按钮后, 会提交该表单的数据到服务端, 在服务端中需要接受数据, 然后将数据保存至数据库中。

请求方式:post,由于需要提交员工信息,post可以携带json数据

请求参数:json数据

返回数据:响应码,数据,携带错误信息等..

接口设计:

 其实就是把页面中录入的员工数据打包成json格式插入emplyee表。

数据库设计(emplyee表)

红框中就是页面输入的数据 

1.2 代码开发

当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据。

①定义DTO类:(在sky-pojo里)
 @Data
public class EmployeeDTO implements Serializable {private Long id;private String username;private String name;private String phone;private String sex;private String idNumber;}
EmployeeController中创建新增员工方法save()

Springboot是面向注解开发,所以注意添加如下注解

EmployeeService里声明save方法(alt+enter)

/**后面直接回车补全注释

.var快捷创建一个对象

/*** 新增员工* @param employeeDTO*/void save(EmployeeDTO employeeDTO);
④EmployeeServiceImpl中实现save方法

使用了对象属性拷贝的方式进行了强制对象转换。

具体来说,这里使用了Spring框架中的BeanUtils类的静态方法copyProperties来将EmployeeDTO对象的属性值复制到Employee对象中。这种方式可以视作一种强制对象转换,因为它将两个不同类的对象之间的属性进行了映射和复制,从而实现了数据的传递和转换。

    public void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();//对象属性拷贝,除了拷贝的属性相同,其他的属性都要自己设置BeanUtils.copyProperties(employeeDTO, employee);//设置账号的状态,默认正常状态 1表示正常 0表示锁定(放在常量类里方便维护可复用)employee.setStatus(StatusConstant.ENABLE);//设置密码,默认密码123456(md5加密后再存储)employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));//设置当前记录的创建时间和修改时间employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//设置当前记录创建人id和修改人id//TODO 后期需要修改为当前登录用户的idemployee.setCreateUser(10L);//目前写个假数据,后期修改employee.setUpdateUser(10L);employeeMapper.insert(employee);//后续步骤定义}
⑤在EmployeeMapper中声明insert方法,插入数据库
/*** 插入员工数据* @param employee*/@Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +"values " +"(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")void insert(Employee employee);

表的字段和属性是一一对应,表的属性采用驼峰命名法(在server的配置文件application.yml中)

mybatis:#mapper配置文件mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.sky.entityconfiguration:#开启驼峰命名map-underscore-to-camel-case: true

1.3 功能测试

两种方法:接口文档(主要)、前后端联调(需要前端开发好)

我们上期讲到,接口文档是由Swagger规范生成,由注解来修饰具有更好可读性的文档。

首先开启启动类SkyAppication.java

然后打开localhost:8081/doc.html——接口文档,开始调试,返回401

原来是存在jwt令牌校验的拦截器

所以我们先到登录页面获取令牌

 添加为全局参数

然后发送,这个时候遇到了一个500问题 ,反复确定insert SQL语句没有错误后,修改发送请求与参考视频里的一致,重新调试,成功添加

前后端联调:登录一直在加载,最终报了一个错(504),怀疑是因为连接着接口文档或者没有往下运行到登录

所以加载不出来,重新debug,成功登陆界面,添加数据成功!

1.4 代码完善

1、要捕获username不唯一的异常

 

debug停在获取jwt令牌的一行,原因是2小时以后原来的token失效,重新获取

在server的handler文件中添加exceptionhandler:

    @ExceptionHandlerpublic Result exceptionHandler(SQLIntegrityConstraintViolationException ex){//Duplicate entry 'zhangsan' for key 'employee.idx_username'//我们希望当重复时,提示xx重复String message = ex.getMessage();if(message.contains("Duplicate entry")){String[] sp = message.split(" ");String username = sp[2];//String msg = username + "已存在";String msg = username + MessageConstant.ALREADY_EXISTS;return Result.error(msg);}else {return Result.error(MessageConstant.UNKNOWN_ERROR);}}

修改之后,异常被捕获,作出响应 

2、创建员工save方法里的创建人和修改人是固定写死的,即

        //TODO 后期需要修改为当前登录用户的idemployee.setCreateUser(10L);//目前写个假数据,后期修改employee.setUpdateUser(10L);

我们需要的user_id就在拦截的token里面,需要进行解析

        //1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}

问题是解析得到了empId后,我们要如何传递给service的save方法 

● ThreadLocal

并不是一个线程(Thread),他是一个线程的局部变量

为每个线程提供单独一份存储空间,起到线程隔离的作用,只有线程内才能获取对应的值

那么我们客户端发出的每次请求是否对应一个线程呢?在不同的地方添加语句

System.out.println("当前线程的id:" + Thread.currentThread().getId());

可以看到都对应线程:44 

重新请求对应线程46,说明:一次请求确实对应一个线程。所以可以把id存入ThreadLocal,再在server里取出来.

ThreadLocal常用方法:set(T value), get(), remove()

我们使用ThreadLocal时往往会进行一个简单的封装,包装成一个工具类common-BaseContext

public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}

添加两句,interceptor(拦截器)里

BaseContext.setCurrentId(empId);

serviceimpl实现类里

employee.setCreateUser(BaseContext.getCurrentId());employee.setUpdateUser(BaseContext.getCurrentId());

debug时可以右键-evalueate expression得到里面的值为empId

1.5 代码提交

commit + push即可

1.6 遇到的问题

1、没有自动补全SQL语句功能

net start MYSQL80后可以测试数据库连接

这篇文章非常有用:IDEA设置MYSQL语句自动提示补全

最后发现是因为安装的社区版本很多功能都没有,所以重新安装Utimate版本

2、Cannot resolve symbol 'SQLIntegrityConstraintViolationException'

import java.sql.SQLIntegrityConstraintViolationException;(导入这个包)


2. 员工的分页查询

2.1 需求分析和设计

分析产品原型——

请求方式:get方式请求,

查询参数:页码,每页记录数,员工姓名(不同于增加员工查询参数是json格式,这里使用Query)

后端相应数据:响应码,错误信息,总的数据数total,和这一页展示的员工数据集合records

接口设计:

2.2 代码开发

根据接口设置对应的DTO

后面所有的分页查询都封装成PageResult对象,再+code+msg封装成统一的result

具体来说,Result<Object>接口传入PageResult对象

①定义DTO类
@Data
public class EmployeePageQueryDTO implements Serializable {//员工姓名private String name;//页码private int page;//每页显示记录数private int pageSize;}
EmployeeController中创建员工分页查询方法page()

路径等于@RequestMapping+下面的路径

@RequestMapping("/admin/employee")@PostMapping("/login")
@PostMapping("/logout")
@GetMapping("/page")
    @GetMapping("/page")@ApiOperation("员工分页查询")public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){Log.info("员工分页查询,参数为:{}", employeePageQueryDTO);PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);    //service存储分页查询的方法return Result.success(pageResult);}
EmployeeService里声明pageQuery方法
    /*** 分页查询方法* @param employeePageQueryDTO* @return*/PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
④ EmployeeServiceImpl中实现pageQuery方法

一般来说通过从数据库中导入分页数据

select * from employee limit 0,10(limit关键字查询第0-10条)

mybatis框架提供插件pagehelper,简化分页操作 (在pom.xml中增加配置)

        <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId></dependency>

 page和pageSize已知,直接用pagehelper

    /*** 分页查询* @param employeePageQueryDTO* @return*/public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {//select * from employee limit 0,10(limit关键字查询第0-10条)//实现原理:将page封装后存入threadlocal,在分页查询前取出来,动态拼接实现SQLPageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);   //返回pagehelper格式的对象long total = page.getTotal();List<Employee> records = page.getResult();return new PageResult(total, records);}
⑤在EmployeeMapper中声明pageQuery方法,插入数据库

由于是动态SQL,要使用动态标签,注解不太方便,

所以我们将SQL写入映射配置文件,在server-resources-mapper-EmployeeMapper.xml里

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.EmployeeMapper">
</mapper>

ctrl+点击EmployeeMapper可以进入EmployeeMapper.java文件说明映射已经建立好了

同时为了确保xml文件被扫描到,在application.xml中增加配置

mybatis:#mapper配置文件mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.sky.entityconfiguration:#开启驼峰命名map-underscore-to-camel-case: true

下载mybatisx插件:

红色头绳的表示映射配置文件,蓝色头绳的表示mapper接口。在mapper接口点击红色头绳的小鸟图标会自动跳转到对应的映射配置文件,在映射配置文件中点击蓝色头绳的小鸟图标会自动跳转到对应的mapper接口。也可以在mapper接口中定义方法,自动生成映射配置文件中的 statement 

alt+enter-select自动生成配置文件,在自动生成的基础上编写动态SQL

<mapper namespace="com.sky.mapper.EmployeeMapper"><select id="pageQuery" resultType="com.sky.entity.Employee">select * from  employee<where><if test="name != null and name !=’‘">and name like concat('%',#{name},'%')   //模糊搜索+字符串拼接</if></where>order by create_time desc   //降序排序</select>
</mapper>

2.3 功能测试

①接口文档:

返回401,说明token又过期了,在application.yml中

返回两条json(报了500看了一下是因为xml文件里加中文注释)

 ②前后端联调

功能一:分页查询,前端已经显示了

功能二:模糊查询调用name like语句

2.4 代码完善

刚刚在测试时已经发现了问题,红框里的最后操作时间不是规范格式

第一种方式需要一个一个地处理,第二种方式则可以统一处理

通过server-config-WebMvcConfiguration里重写Spring框架里自带的一个方法extendHandlerExceptionResolvers,扩展消息转换器((对后端返回给前端的数据做统一处理)

通过实现WebMvcConfigurer接口,你可以按需选择性地覆盖接口中的方法,只实现你需要的配置,而不需要处理所有配置。

    /*** 扩展Spring MVC框架的消息转换器* @param exceptionResolvers*/protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){log.info("扩展消息转换器...");//创建一个消息转换器对象MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();//需要为消息转换器设置一个对象转换器,将java对象序列化为json数据converter.setObjectMapper(new JacksonObjectMapper());//将自己的消息转换器converter加入容器converters里,并优先使用converters.add(0, converter);}

2.5 代码提交


3. 启用禁用员工账号

3.1 需求分析和设计

POST请求是因为启用禁用 本质是修改

一般来说,状态用路径参数传,id用请求参数传

3.2 代码开发

EmployeeController中创建方法

    /*** 启用禁用员工账号* @param status* @param id* @return*/@PostMapping("/status/{status}")@ApiOperation("启用禁用员工账号")public Result startOrStop(@PathVariable Integer status, Long id){log.info("启用禁用员工账号,参数为:{},{}", status, id);employeeService.startOrStop(status, id);return Result.success();}

 EmployeeService里声明

    /*** 启用禁用员工账号* @param status* @param id*/void startOrStop(Integer status, Long id);

EmployeeServiceImpl中实现

    public void startOrStop(Integer status, Long id) {//根据id改status,动态更新所以传实体类比较合适//update employee set status =? where id = ?Employee employee = new Employee();employee.setStatus(status);employee.setId(id);employeeMapper.update(employee);}

也可以通过@Builder构建器获得一个构件器对象

    public void startOrStop(Integer status, Long id) {//根据id改status,动态更新所以传实体类比较合适//update employee set status =? where id = ?Employee employee = Employee.builder().status(status).id(id).build();employeeMapper.update(employee);}

在EmployeeMapper中

    /*** 根据主键动态修改属性* @param employee*/void update(Employee employee);

既然是动态的,SQL语句也要放在映射配置文件里写

    <update id="update">update employee<set><if test="name != null">name = #{name},</if><if test="username != null">username = #{username},</if><if test="password != null">password = #{password},</if><if test="phone != null">phone = #{phone},</if><if test="sex != null">sex = #{sex},</if><if test="idNumber != null">id_Number = #{idNumber},</if><if test="updateTime != null">update_Time = #{updateTime},</if><if test="updateUser != null">update_User = #{updateUser},</if><if test="status != null">status = #{status},</if></set>where id = #{id}</update>

3.3 功能测试

修改成功!

前后端联调也成功! 

最后记得提交!


 4. 编辑员工

4.1 需求分析和设计

点击修改,就会跳转修改界面

 接口设计:

涉及到两个接口:一个是根据id查询员工信息(GET),一个是修改员工信息(PUT)

还有提交用POST,删除用DELETE

 4.2 代码开发

①根据id查询员工信息比较简单,这里只放具体实现了

    /*** 根据id查询员工信息* @param id* @return*/@Select("select * from employee where id = #{id}")Employee getById(Long id);

前后端联调成功,并且可以从开发者工具-网络看到响应格式

② 编辑员工信息

利用mapper之前定义好的update语句更新员工信息

    /*** 编辑员工信息* @param employeeDTO*/public void update(EmployeeDTO employeeDTO) {Employee employee = new Employee();BeanUtils.copyProperties(employeeDTO, employee);employee.setUpdateTime(LocalDateTime.now());employee.setUpdateUser(BaseContext.getCurrentId());employeeMapper.update(employee);}

 4.3 功能测试-成功

5. 导入分类模块功能

5.1 需求分析和设计

 设计包括6个接口,和员工管理类似

5.2 代码导入

mapper-xml-service-imple-controller倒序导入,这样不会报错

maven编译一遍无误

5.3 功能测试


两天终于敲完了 Day2,进度有点慢啊T^T

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

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

相关文章

顶刊文献阅读及代码复现

前提:每个无人机都有 (i)自己的机载计算机,用于执行控制其自身动作所需的计算 (ii)自己的传感器系统,用于测量相对位置和速度, (iii)自己的通信设备,用于与相邻代理进行数据交换。 模型:短期的排斥力、中间范围的速度一致性和长距离的吸引力

通过PLC地址来切换威纶通触摸屏界面

Step 1 元件-PLC控制 Step 2 新增 选择设备 选择切换基本窗口功能 选择触发地址 Step 3 离线仿真测试 在数值框中输入对应的页面号 可以看到页面可以正常切换 分享创作不易&#xff0c;请多多支持&#xff0c;点赞、收藏、关注&#xff01; Ending~

昇思Mindspore25天学习打卡Day20:DCGAN生成漫画头像

昇思Mindspore25天学习打卡Day20&#xff1a;DCGAN生成漫画头像 1 GAN基础原理2 DCGAN原理3 数据准备与处理数据处理 4 构造网络4.1 生成器4.2 判别器 5 模型训练损失函数优化器训练模型 6 结果展示7 训练结束打上标签和时间 在下面的教程中&#xff0c;我们将通过示例代码说明…

基于STM主题模型的主题提取分析-完整代码数据

直接看结果: 代码: import re from collections import defaultdict import random import matplotlib.pyplot as plt import numpy as npimport pandas as pd import numpy as np import re from sklearn.feature_extraction.text import CountVectorizer from nltk.corpus…

在Morelogin中使用IPXProxy海外代理IP的设置指南

Morelogin指纹浏览器是市场上较受欢迎的指纹浏览器&#xff0c;允许用户管理多个账号并进行自动化操作。它提供免费环境供用户进行体验&#xff0c;并且操作起来非常简单。大多数人都会将Morelogin指纹浏览器和海外代理IP进行使用&#xff0c;来应用于多种场景&#xff0c;如电…

用ce修改植物大战僵尸杂交版银币

第一步打开游戏 用ce打开图中进程 第二步 输入你原始银币 点首次搜索 第三步 找到这个地址 把地址拖下来 第四步 双击直接修改下面数值即可 金币 钻石 都和这个方法一样 不一样的是首次搜索可能会有很多地址 我们改变游戏里面的值 然后再次搜索游戏被改变的值即可准确找到地址

新加坡工作和生活指北:租房篇

本文首发于公众号 Keegan小钢 前段时间已经分享了工作篇&#xff0c;现在接着聊聊生活篇。因为生活这块涉及到多个方面&#xff0c;内容比较多&#xff0c;所以我再细分了一下&#xff0c;本篇先聊聊租房。 先来看看新加坡的地区分布图&#xff0c;如下&#xff1a; 上图将新加…

使用Python绘制累积直方图并分析数据

使用Python绘制累积直方图并分析数据 在这篇博客中&#xff0c;我们将探讨如何使用Python中的pandas库和matplotlib库来绘制累积直方图&#xff0c;并分析数据文件中的内容。累积直方图是一种常用的图表类型&#xff0c;用于展示数据的累积分布情况。 数据&#xff1a; 链接…

vue缓存页面,当tab切换时保留原有的查询条件

需求&#xff1a; 切换tab时&#xff0c;查询条件不变 路由页面&#xff1a; 单个页面上加这句话&#xff1a;

bert-base-chinese模型离线使用案例

import torch import torch.nn as nn from transformers import BertModel, BertTokenizer# 通过torch.hub(pytorch中专注于迁移学的工具)获得已经训练好的bert-base-chinese模型 # model torch.hub.load(huggingface/pytorch-transformers, model, bert-base-chinese) model…

超过35岁的网工,你该何去何从?

在网络工程师这个职业中&#xff0c;35岁往往被视为一个重要的门槛&#xff0c;这个年龄段的工程师&#xff0c;既拥有丰富的经验和技能&#xff0c;也面临着职业发展的诸多挑战。 随着技术的飞速发展和年轻一代的不断涌入&#xff0c;不少35岁以上的网工都在迷茫的路口&#x…

拖地机检测液位的原理-管道液位传感器

在现代洗地机中&#xff0c;确保水箱液位充足是保证清洁效率和质量的关键之一。为了实现这一功能&#xff0c;洗地机通常配备了管道光电液位传感器&#xff0c;这种传感器利用先进的光学感应原理来准确检测水箱中的液位情况。 管道光电液位传感器的工作原理基于光学传感技术&a…

VOS历史话单的非法呼叫话单解决方案,IPSS模块安装到VOS服务器,可大幅度提高安全性!

由于VOS的普及性&#xff0c;不得不承认VOS确实是非常优秀的软交换&#xff0c;但是很多客户在使用过程中都会遇到各种安全问题&#xff0c;比如话费被盗用了&#xff0c;历史话单一堆的非法呼叫话单&#xff0c;严重的影响到了话务安全&#xff0c;并不是那点话费的事了&#…

Flutter【组件】标签

简介 flutter 标签组件。标签组件是一种常见的 UI 元素&#xff0c;用于显示和管理多个标签&#xff08;或标签集合&#xff09;。 github地址&#xff1a; https://github.com/ThinkerJack/jac_uikit pub地址&#xff1a;https://pub.dev/packages/jac_uikit 使用方式&…

中科驭数HADOS 3.0:以四大架构革新,全面拥抱敏捷开发理念,引领DPU应用生态

一家成功的大算力芯片公司&#xff0c;其核心壁垒必须是软硬兼备的&#xff0c;既要有芯片架构的强大技术壁垒&#xff0c;更要有持久投入的、生态兼容完备的软件护城河。HADOS&#xff0c;就是中科驭数的软件护城河。 ——中科驭数高级副总裁 张宇 近日&#xff0c;在DPU基础…

关于MySQL mvcc

innodb mvcc mvcc 多版本并发控制 在RR isolution 情况下 trx在启动的时候就拍了个快照。这个快照是基于整个数据库的。 其实这个快照并不是说拷贝整个数据库。并不是说要拷贝出这100个G的数据。 innodb里面每个trx有一个唯一的trxID 叫做trx id .在trx 开始的时候向innodb系…

嵌入式音频处理技术的现在发展及未来的方向

嵌入式音频处理技术&#xff1a;从音频流媒体到声音识别 嵌入式音频处理技术的迅猛发展正在改变我们的生活方式&#xff0c;从音频流媒体到声音识别&#xff0c;这个领域为人们的生活和工作带来了巨大的影响。本文将探讨嵌入式音频处理技术的最新趋势和应用&#xff0c;以及提…

逻辑回归模型(非回归问题,而是解决二分类问题)

目录&#xff1a; 一、Sigmoid激活函数&#xff1a;二、逻辑回归介绍&#xff1a;三、决策边界四、逻辑回归模型训练过程&#xff1a;1.训练目标&#xff1a;2.梯度下降调整参数&#xff1a; 一、Sigmoid激活函数&#xff1a; Sigmoid函数是构建逻辑回归模型的重要激活函数&am…

openlayers更改点坐标

我现在的需求是无人机点位根据ws传输的经纬度改变位置&#xff0c;在网上查了很多资料&#xff0c;终于是做出来了&#xff0c;如果有问题请指出。 效果图&#xff0c;无人机可以来回移动 这里是核心代码 // 添加飞机点位图层let vectorLayerpointfunction DronepointLayer()…

Kafka(三)Producer第二篇

一&#xff0c;生产者架构 生产者客户端由两个线程协调运行&#xff0c;分别为主线程和Sender线程&#xff08;发送线程&#xff09;。 主线程&#xff1a;KafkaProducer创建消息&#xff0c;通过拦截器、序列化器和分区器之后缓存到消息收集器RecordAccumulator中&#xff1b;…