【EasyExcel使用两个Java对象来接受一个excel文件】

需求背景:
有时候上传文件想要写一个通用的逻辑,就是说,这个excel前面几个字段是基础字段,后面几个字段是定制字段。
那么为了以后上传不同的文件,就需要编写不同的listener去解析每种不同的excel文件,但是由于基础属性的处理过于复杂,担心别人搞坏。因此将excel文件进行拆分,使用两个listener来接收处理一个excel文件。
2. 目标是使用两个监听器,两个实体类来接收excel文件

一,定义基础属性的listener

@Slf4j
@EqualsAndHashCode(callSuper = true)
@RequiredArgsConstructor
public class CustomerProductUploadListener<E> extends AbsExcelListener<Map<Integer, ReadCellData<?>>> {// 处理拓展属性的监听器父类final AbsExtendListener<E> extListener;

类似普通的easyExcelListener,需要注意的是泛型

public interface AbsExtendListener<E>  {/*** @return 针对不同的项目,使用不同的extend clazz 来接收*/Class<E> getExtClz();void invoke(E data, ProductUploadBaseDTO base ,  AnalysisContext context);void doAfterAllAnalysed(AnalysisContext context);
}

二、定义监听拓展属性的监听器

public class ZTWBExtListener implements AbsExtendListener<ZTWBExtendInfoDTO> {@Getter// 用于接收拓展属性的实体类final Class<ZTWBExtendInfoDTO> extClz;final MachineExtendInfoRepository machineExtendInfoRepository = ApplicationContextUtil.getBean(MachineExtendInfoRepository.class);public ZTWBExtListener(Class<ZTWBExtendInfoDTO> extClz) {this.extClz = extClz;}@Overridepublic void invoke(ZTWBExtendInfoDTO data, ProductUploadBaseDTO machineInfo, AnalysisContext context) {// biz}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {
// biz}private MachineExtendInfo buildExtend(String alias, String name, String content, Long machineId, String machineSn) {// biz}}

三、基础属性监听器的改造


@SneakyThrows@Overridepublic void invoke(Map<Integer, ReadCellData<?>> cellDataMap, AnalysisContext context) {// 将map中的数据读取到基础属性实体类上modelBuildEventListener.invoke(cellDataMap, context);ProductUploadBaseDTO model = (ProductUploadBaseDTO) context.readRowHolder().getCurrentRowAnalysisResult();// 将map中的属性读取到拓展属性实体类上E e1 = readExt(cellDataMap, context);// 校验boolean validate = validate(model);if (!validate) {// 这里为什么要有? 就是因为我们这里如果报错了是需要把错误文件写回到客户端的,cellData2Map 函数就是这个作用// 不需要的话这段也可以删除了val errData = cellData2Map(cellDataMap, model.getErrorMessage(), context);errorData0.add(errData);return;}// 基础属性的业务逻辑处理// ..... biz // 手动调用 拓展属性监听器,进行他自己的业务逻辑处理,三个参数分别是拓展属性实体类、技术属性实体类、easyExcel的上下文对象extListener.invoke(e1, model, context);// 其余的地方视业务需要添加自己的逻辑}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {try {//call 拓展属性监听器的 函数extListener.doAfterAllAnalysed(context);} catch (Exception e) {throw new ExcelCommonException(e);}// 如果有验证不通过的属性,将文件写回客户端if (!CollectionUtils.isEmpty(errorData0)) {errorFile = uploadFile0(errorData0, fileHeadList, ServletUtil.getInstance().currentResponse(), "errFile-");}}

四、easyExcel 自身提供的函数封装、将map拆开读取、将对象合并

private Map<String, Object> cellData2Map(Map<Integer, ReadCellData<?>> cellDataMap, String s, AnalysisContext context) {Map<String, Object> map = new LinkedHashMap<>();Map<Integer, Head> baseHeadMap = context.readSheetHolder().excelReadHeadProperty().getHeadMap();Map<Integer, Head> extHeadMap = buildHeadMap(extListener.getExtClz(), context);List<String> headList = new ArrayList<>();for (int i = 0; i < cellDataMap.size(); i++) {Head head;if (i < baseHeadMap.size()) {head = baseHeadMap.get(i);} else {head = extHeadMap.get(i);}headList.add(CollectionUtils.firstElement(head.getHeadNameList()));ReadCellData<?> readCellData = cellDataMap.get(i);Object value = null;if (Objects.nonNull(readCellData)) {switch (readCellData.getType()) {case STRING:value = readCellData.getStringValue();break;case BOOLEAN:value = readCellData.getBooleanValue();break;case NUMBER:value = readCellData.getNumberValue();break;case DATE:value = readCellData.getDataFormatData().getFormat();break;default:break;}}map.put(CollectionUtils.firstElement(head.getHeadNameList()), value);}if (StringUtils.isNotBlank(s)) {map.put("错误消息", s);}if (CollectionUtils.isEmpty(fileHeadList)) {fileHeadList.addAll(headList);fileHeadList.add("错误消息");}return map;}// 将map中的拓展属性 读取到 拓展监听器所对应的实体类上,并且返回一个实体类对象public E readExt(Map<Integer, ReadCellData<?>> cellDataMap, AnalysisContext context) throwsNoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {E resultModel = extListener.getExtClz().getConstructor().newInstance();ReadSheetHolder readSheetHolder = context.readSheetHolder();Map<Integer, Head> headMap = buildHeadMap(extListener.getExtClz(), context);com.alibaba.excel.support.cglib.beans.BeanMap dataMap = BeanMapUtils.create(resultModel);for (Map.Entry<Integer, Head> entry : headMap.entrySet()) {Integer index = entry.getKey();Head head = entry.getValue();String fieldName = head.getFieldName();if (!cellDataMap.containsKey(index)) {continue;}ReadCellData<?> cellData = cellDataMap.get(index);Object value = ConverterUtils.convertToJavaObject(cellData, head.getField(),ClassUtils.declaredExcelContentProperty(dataMap, readSheetHolder.excelReadHeadProperty().getHeadClazz(),fieldName, readSheetHolder), readSheetHolder.converterMap(), context,context.readRowHolder().getRowIndex(), index);if (value != null) {dataMap.put(fieldName, value);}}return resultModel;}

五、上传功能的接口

如果没有上传需要,可以不实现这个接口


public interface UploadListener {@SneakyThrowsdefault String uploadFile0(List<?> errList,  HttpServletResponse response) {return uploadFile0(errList, response, "上传结果");}@SneakyThrowsdefault String uploadFile0(List<?> errList, HttpServletResponse response, String filePre) {String randName = filePre + UUID.fastUUID() + ".xlsx";String fileName = URLEncoder.encode(randName, "utf-8");response.addHeader("Content-Disposition", "filename=" + fileName);response.setContentType("application/octet-stream");FileItemFactory factory = new DiskFileItemFactory(16, null);FileItem fileItem = factory.createItem("textField", "text/plain", true, fileName);OutputStream os = fileItem.getOutputStream();ExcelWriter excelWriter = EasyExcelFactory.write(os, getGenericClass()).build();WriteSheet writeSheet = EasyExcelFactory.writerSheet("Sheet1").build();excelWriter.write(errList, writeSheet);excelWriter.finish();os.close();MultipartFile multipartFile = new CommonsMultipartFile(fileItem);MinioUtil minioUtil = getBean(MinioUtil.class);minioUtil.putObject(multipartFile, minioUtil.getExceptionPath() + multipartFile.getOriginalFilename());return multipartFile.getOriginalFilename();}@SneakyThrowsdefault String uploadFile0(List<Map<String, Object>> errList, List<String> head,  HttpServletResponse response, String filePre) {if (CollectionUtils.isEmpty(head)){throw new ManagedServiceException("excel head not allowed empty!");}List<List<Object>> sheetData = new ArrayList<>();if (!CollectionUtils.isEmpty(errList)){for (Map<String, Object> stringObjectMap : errList) {List<Object> dl = new ArrayList<>();for (String hk : head) {Object vv = stringObjectMap.get(hk);dl.add(vv);}sheetData.add(dl);}}List<List<String>> heads = new ArrayList<>();for (String h : head) {heads.add(Lists.newArrayList(h)) ;}String randName = filePre + UUID.fastUUID() + ".xlsx";String fileName = URLEncoder.encode(randName, "utf-8");response.addHeader("Content-Disposition", "filename=" + fileName);response.setContentType("application/octet-stream");FileItemFactory factory = new DiskFileItemFactory(16, null);FileItem fileItem = factory.createItem("textField", "text/plain", true, fileName);OutputStream os = fileItem.getOutputStream();EasyExcelFactory.write(os).head(heads).needHead(true).sheet("Sheet1").registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).doWrite(sheetData);os.close();MultipartFile multipartFile = new CommonsMultipartFile(fileItem);MinioUtil minioUtil = getBean(MinioUtil.class);minioUtil.putObject(multipartFile, minioUtil.getExceptionPath() + multipartFile.getOriginalFilename());return multipartFile.getOriginalFilename();}default Class<?> getGenericClass() {Type type = getClass().getGenericSuperclass();if (type instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) type;return (Class<?>) parameterizedType.getActualTypeArguments()[0];} else {throw new IllegalArgumentException("The generic superclass is not a parameterized type.");}}}

六、自己封装通用功能的excelListener抽象类

@EqualsAndHashCode(callSuper = true)
@Data @Slf4j
public abstract class AbsExcelListener<T> extends AnalysisEventListener<T> implements BizListener<BizListener.Ret>, UploadListener {protected String errorFile;protected List<T> successData = new ArrayList<>();protected List<T> errorData = new ArrayList<>();private final List<T> all = new ArrayList<>();@Setterprivate boolean independentTransactions = false;private static final AtomicReference<Validator> validatorAtomicReference = new AtomicReference<>();@Overridepublic Ret getRet() {return new Ret(errorData, successData, getErrorFile());}private static Validator validator() {if (Objects.isNull(validatorAtomicReference.get())) {validatorAtomicReference.set(ApplicationContextUtil.getBean(Validator.class));}return validatorAtomicReference.get();}public static <T> boolean validate(final T obj) {return validate(new ArrayList<>(), obj);}public static <T> boolean validate(final List<ErrorData<T>> errors, final T obj) {return validate(errors, new AtomicReference<>(), obj);}public static <T> boolean validate(final AtomicReference<String> msgRef, final T obj) {return validate(new ArrayList<>(), msgRef, obj);}public static <T> boolean validate(final List<ErrorData<T>> errors, AtomicReference<String> msgRef, final T obj) {if (Objects.isNull(obj)) {log.warn("当前传入的实体对象是Null");return false;}Set<ConstraintViolation<T>> set = requireNonNull(validator()).validate(obj, Default.class);if (!CollectionUtils.isEmpty(set)) {StringJoiner msg = new StringJoiner(",");for (ConstraintViolation<T> cv : set) {Field declaredField;try {declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());} catch (NoSuchFieldException e) {throw new ExcelAnalysisException(e.getMessage());}String errMsg = getErrMsg(cv, declaredField);msg.add(errMsg);}String errMsg = msg.toString();if (obj instanceof ExcelDtoInstance) {ExcelDtoInstance excelDtoInstance = (ExcelDtoInstance) obj;excelDtoInstance.addErrorMsg(errMsg);errors.add(new ErrorData<>(errMsg, obj));} else {Method setErrorMessageMethod = findMethod(obj.getClass(), "setErrorMessage");if (Objects.isNull(setErrorMessageMethod)) {log.error("当前实体[{}]没有 setErrorMessage 函数,跳过.", obj.getClass().getSimpleName());msgRef.set(errMsg);} else {invokeMethod(setErrorMessageMethod, obj, errMsg);}errors.add(new ErrorData<>(errMsg, obj));}return false;} else {return true;}}private static <T> String getErrMsg(ConstraintViolation<T> cv, Field declaredField) {String errMsg = "";if (declaredField.isAnnotationPresent(ExcelProperty.class)) {ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);errMsg = errMsg + annotation.value()[0] + cv.getMessage();} else {errMsg = cv.getPropertyPath().toString() + cv.getMessage();}return errMsg;}Map<Integer, Head> buildHeadMap(Class<?> headClazz,  AnalysisContext context) {val readSheetHolder = context.readSheetHolder();val excelReadHeadProperty = readSheetHolder.excelReadHeadProperty();val baseHeadMap = excelReadHeadProperty.getHeadMap();Map<Integer, Head> headMap = new TreeMap<>();initColumnProperties(context.currentReadHolder(), headClazz, headMap, baseHeadMap.size());return headMap;}private void initColumnProperties(ConfigurationHolder configurationHolder, Class<?> headClazz, Map<Integer, Head> headMap, int pos) {if (headClazz == null) {return;}val fieldCache = ClassUtils.declaredFields(headClazz, configurationHolder);for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {initOneColumnProperty(entry.getKey() + pos, entry.getValue(),fieldCache.getIndexFieldMap().containsKey(entry.getKey()), headMap);}}private void initOneColumnProperty(int index, FieldWrapper field, Boolean forceIndex, Map<Integer, Head> headMap) {List<String> tmpHeadList = new ArrayList<>();boolean notForceName = field.getHeads() == null || field.getHeads().length == 0|| (field.getHeads().length == 1 && com.alibaba.excel.util.StringUtils.isEmpty(field.getHeads()[0]));if (headMap.containsKey(index)) {tmpHeadList.addAll(headMap.get(index).getHeadNameList());} else {if (notForceName) {tmpHeadList.add(field.getFieldName());} else {Collections.addAll(tmpHeadList, field.getHeads());}}Head head = new Head(index, field.getField(), field.getFieldName(), tmpHeadList, forceIndex, !notForceName);headMap.put(index, head);}
}

七、返回结果封装类

封装通用的返回结果

public interface BizListener<T> {/*** 这些数据将会呗返回给前端、*/T getRet();String getErrorFile();@Getterclass Ret {private List<?> errorData;private List<?> successData;private final int total;private final int error;private final int success;private String errorFile;public Ret(List<?> errorData, List<?> successData, String errorFile) {Ret.this.errorData = CollectionUtils.isEmpty(errorData) ? Collections.emptyList() : errorData;Ret.this.successData = CollectionUtils.isEmpty(successData) ? Collections.emptyList() : successData;error = errorData.size();success = successData.size();total = error + success;Ret.this.errorFile = errorFile;}}
}

八、如何调用?

uploadListener 函数再父类中,请先继承父类,或者将父类的函数copy过来

    @ApiOperation(value = "批量导入")@PostMapping(path = {"/import"})public Result<?> customerProductImport(@RequestParam("file") MultipartFile file) {return uploadListener(file, ProductUploadBaseDTO.class, new CustomerProductUploadListener<>(new ZTWBExtListener(ZTWBExtendInfoDTO.class)), false);}

controller的父类,封装了一些基础操作

@Slf4j
public class BaseAction {/*** 抽象 写出 excel 的函数** @param runnable excel 写出代码块,同步调用* @param fileName 导出的文件名字*/@SneakyThrowsprotected void writeExcel(Runnable runnable, String fileName) {HttpServletResponse response = ServletUtil.getInstance().currentResponse();try {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");fileName = URLEncoder.encode(fileName + DateUtil.format(LocalDateTime.now(), PURE_DATETIME_MS_PATTERN), "UTF-8").replace("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");runnable.run();} catch (ManagedServiceException ex) {}}protected Result<?> uploadListener(MultipartFile file, Class<?> dtoClz, ReadListener<?> listener) {return uploadListener(file, dtoClz, listener, true);}// BizExceptionprotected Result<?> uploadListener(MultipartFile file, Class<?> dtoClz, ReadListener<?> listener, boolean useDefaultListener) {try {EasyExcelFactory.read(file.getInputStream(), dtoClz, listener).useDefaultListener(useDefaultListener).sheet().doRead();if (listener instanceof BizListener) {return data(200, ((BizListener<?>) listener).getRet(), "");}return Result.success("");} catch (ManagedServiceException ex) {} catch (Exception ex) {}}protected Result<?> uploadListener(MultipartFile file, ReadListener<?> listener) {return uploadListener(file, listener, Boolean.FALSE);}protected Result<?> uploadListener(MultipartFile file, ReadListener<?> listener, boolean useDefaultListener) {try {EasyExcelFactory.read(file.getInputStream(), listener).useDefaultListener(useDefaultListener).sheet().doRead();if (listener instanceof BizListener) {return data(((BizListener<?>) listener).getRet());}return Result.success(ResultCode.SUCCESS);} catch (ManagedServiceException ex) {} catch (Exception ex) {}}public static <T> PageRecords<T> fromPage(IPage<T> iPage) {PageRecords<T> pageRecords = new PageRecords<>();pageRecords.setRows(iPage.getRecords());pageRecords.setTotal(iPage.getTotal());pageRecords.setTotalPage(iPage.getPages());pageRecords.setCode(HttpStatusEnum.CODE_200.getCode());pageRecords.setMsg(HttpStatusEnum.CODE_200.getMsg());return pageRecords;}}

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

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

相关文章

关于AI Agent、RAG技术揭秘:如何让人工智能更懂你?

人工智能技术正以前所未有的速度改变着我们的世界。从深度学习算法的突破到自动化和机器学习技术的进步。在这个变革的时代&#xff0c;几种前沿技术尤其引人注目&#xff0c;其中包括RAG&#xff08;Retrieval-Augmented Generation&#xff09;、AI Agent以及多模态技术。 近…

工频磁场抗扰度概述及相关注意事项

工频磁场 是指交流输变电设施产生的磁场&#xff0c;工频又称电力频率。 工频的特点是频率低、波长长&#xff1b;我国工频是50赫(Hz)&#xff0c;波长是6000千米(Km&#xff09; 工频磁场的抗扰度试验&#xff08;在有电流流过的地方都会伴生磁场&#xff0c;为了检查设备或系…

vue监听键盘回车事件的三种方法..

方法一&#xff1a; keydown‘show()’ 当然我们传个$event 也可以在函数中获 ev.keyCode if(ev.keyCode13){ alert(‘你按了回车键&#xff01;’) } 方法二&#xff1a; <input type“text” keyup.enter“show()”>回车执行 <input type“text” keydown.up‘sh…

pmp就是智商税?

首先要明白的是&#xff0c;证书的价值并不在于证书本身&#xff0c;而在于学习过程中所获得的知识和经验&#xff0c;这才是证书真正的价值&#xff0c;是无法被复制的个人能力。 学习和考证都是经验的积累&#xff0c;通过这个过程可以不断地获取所需的知识&#xff0c;并加…

基线核查与系统加固:构筑坚实基础防御的双刃剑

引言 网络安全在当今信息社会扮演着不可或缺的角色&#xff0c;而安全基线核查和系统加固作为网络安全防御的基础工作至关重要。本文将深入探讨安全基线核查和系统加固的定义、必要性&#xff0c;以及它们在安全管理中的重要要求。旨在强调这些基础工作在构建健壮网络安全体系…

网络协议学习——IP协议

IP&#xff08;Internet Protocol&#xff0c;互联网协议&#xff09;是网络中最基本的协议之一&#xff0c;负责在互联网中进行数据包的传输。下面是对IP协议的详细讲解&#xff1a; IP协议的作用 IP协议是在网络层&#xff08;第三层&#xff09;上工作的协议&#xff0c;它的…

【Cesium学习笔记】一、加载Cesium并更换天地图底图

【Cesium学习笔记】一、加载Cesium 一、加载Cesium二、用Viewer显示地球三、更换天地图底图 Ps:本教程所有代码于同一个工程中&#xff0c;运行npm run dev默认首页为App.vue&#xff0c;只需替换App.vue的内容即可切换不同页面。 一、加载Cesium 本项目使用nvm管理node版本&…

[xboard]real6410-6.2 移植kernel网络驱动

文章目录 硬件电路软件配置问题1问题2问题3问题4功能测试硬件电路 核心板,使用DM9000A [图片] 软件配置 问题1 / # / # ifconfig ifconfig: /proc/net/dev: No such file or directory ifconfig: socket: Fun

微服务学习2

目录 一.网关路由 1.1.认识网关 1.2网关快速入门 1.2.1.创建项目 1.2.2.引入依赖 1.2.3.启动类 1.2.4.配置路由 1.3.路由过滤 二.网关登录校验 2.1网关请求处理流程 2.2网关过滤器 2.2.2网关过滤器 2.3自定义GlobalFilter 2.4.登录校验 2.4.1.JWT工具 2.4.2.登…

基于springboot的编程训练系统源码数据库

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了编程训练系统的开发全过程。通过分析编程训练系统管理的不足&#xff0c;创建了一个计算机管理编程训练系统的方案。文章介绍了编程训练系统的系统分析部分&…

论文发表|《课外语文》期刊点评_投稿指南

论文发表|《课外语文》期刊点评_投稿指南 《课外语文》 知网 3版3300字符 全包 24年11-12月 可加急9-10月&#xff0c;次月出刊 &#xff08;操作周期2-3个月&#xff0c;文章不是教学类&#xff0c;不要摘要参考文献&#xff09; 《课外语文》杂志创刊于2002年&#xff…

Linux入门常见指令

ls指令 语法&#xff1a; s [ 选项 ] 功能&#xff1a;想查看当前目录的所有子文件与文件夹&#xff0c;直接输入ls然后回车即可&#xff0c;但是ls可以尾接许多选项 例如&#xff1a; ls -a&#xff0c;这个是显示当前目录的所有文件&#xff0c;包括隐藏文件 诸如此类的常用…

SpringCloud集成Skywalking链路追踪和日志收集

1. 下载Agents https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz 2. 上传到服务器解压 在Spring Cloud项目中&#xff0c;每部署一个服务时&#xff0c;就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署…

基于PyAutoGUI图片定位的自动化截图工具--jmeter部分

1、计划 压测完成后需要编写性能测试报告&#xff0c;报告中所需数据截图较多&#xff0c;使用自动化操作方便快捷&#xff0c;就编写一个界面工具以便后续复用。之前编写过loadrunner报告的自动化截图脚本&#xff0c;现在用jmeter也比较多&#xff0c;就编写jmeter部分&#…

3V升9V3串LED驱动恒流WT7012

3V升9V3串LED驱动恒流WT7012 WT7012是一款性能卓越的升压转换器&#xff0c;设计用于驱动多达七串的白光LED。该器件具备宽输入工作电压范围(2-24V)&#xff0c;使其在单节或多节锂电池供电的应用中能够稳定提供背光。WT7012支持从3V起升至6V、9V、12V的恒流输出&#xff0c;通…

sqlserver问题记录

今天在利用sql查询数据时出现如下错误 在执行批处理时出现错误。错误消息为: 引发类型为“System.OutOfMemoryException”的异常。 症状 使用 SSMS 运行返回大量数据的 SQL 查询时&#xff0c;会收到类似于以下内容的错误消息&#xff1a; 执行批处理时出错。 错误消息为&…

Linux基础指令补全,权限问题分析—3

一、命令补全&#xff1a; 1.bc指令&#xff1a; 功能&#xff1a;命令行计算器&#xff0c;使用quit退出语法&#xff1a;bc 算式 2.uname指令&#xff1a; 语法&#xff1a;uname 选项功能&#xff1a;uname原来获取电脑或操作系统的相关信息选项&#xff1a; ①-a选项&am…

【IC前端虚拟项目】验证阶段开篇与知识预储备

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 从这篇开始进入验证阶段&#xff0c;因为很多转方向的小伙伴是转入芯片验证工程师方向的&#xff0c;所以有必要先做一个知识预储备的说明&#xff0c;或者作为验证入门的一个小指导吧。 在最开始&#…

如何做好2024年中央企业内部控制体系建设与监督工作

面对日益复杂的经济环境和全球一体化的挑战&#xff0c;中央企业作为国家经济的中流砥柱&#xff0c;必须不断提升内部控制体系的建设与执行水平。随着2024年的脚步逼近&#xff0c;中央企业需围绕国家宏观政策&#xff0c;积极采纳智能化技术&#xff0c;强化内控体系&#xf…

Redis 的数据结构和内部编码

Redis的 5 种数据类型 Redis 底层在实现上述数据结构的时候&#xff0c;会在源码层面&#xff0c;针对上述实现进行 特定的优化 &#xff0c;来达到节省时间/节省空间效果 特定的优化&#xff1a;内部的具体实现的数据结构&#xff0c;在特定场景下&#xff0c;不是其对应的标准…