导入导出Excel
Springboot + Easyexcel导入导出excel
- EasyExcel 的导出导入支持两种方式进行处理
- *easyexcel 导出不用监听器,导入需要写监听器*
- 一、导入:简单实现
- 1. 导入依赖,阿里的easyexcel插件
- 2. 程序
- 2-1. 实体类:
- 2-2. 定义一个 监听类:
- 2-3. service:
- 2-4. Controller 上传文件接口
- 3. Postman测试
- 二、导入:多头行数,多sheet,复杂表头
- 1. 两sheet表头数据不一致
- *思路:需要定义各自的excel接收数据的实体类,然后创建各自的监听类,重写方法*
- 具体实现
- 监听类
- controller层
- service实现层
- 多行头
- 读取时设置头行数即可
- 读取表头数据
- 三、导出:简单简单实现
- 1. 模拟数据 10条数据
- 3. 程序
- 3. 过滤导出列
- 五、导入:复杂头 合并表头
- 1. 实体类
- 六、动态自由导出导入
- 1. 导出
- 1-1. 编写一个动态导出工具类
- 1-2. 测试: *easyexcel-export-user1.xlsx*
- 接上面同一个类里 方法二
- 2. 导入: EasyExcel 导入需要一个监听器,导出不需要
- 2-1. 编写一个动态导入监听器
- 2-2. 编写动态导入工具类
EasyExcel 的导出导入支持两种方式进行处理
easyexcel 导出不用监听器,导入需要写监听器
- 第一种是通过实体类注解方式来生成文件和反解析文件数据映射成对象
- 第二种是通过动态参数化生成文件和反解析文件数据
下面我们以用户信息的导出导入为例,分别介绍两种处理方式。
一、导入:简单实现
1. 导入依赖,阿里的easyexcel插件
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.6</version>
</dependency
创建一个用来 读取 excel的实体类
实体类的属性可以用
-
@ExcelProperty(index = 0),index=0,找的是上图 A列(第一列)
-
@ExcelProperty(value = “标号”)
两种都可以用,但是不要两个一起用
2. 程序
2-1. 实体类:
实体类中可以使用@DateFormat(阿里包下的)注解:
要使用String类型来接收数据才有用
@Data
public class TemplateEntity {@ExcelProperty("标号")private Integer label;@ExcelProperty("字符串")private String str;@ExcelProperty("数字")private Integer num;@ExcelProperty("时间")// 这里需要用string接收才会格式化@DateTimeFormat("yyyy-MM-dd")private String date;}
————————————————
2-2. 定义一个 监听类:
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {private List<TemplateEntity> list = new ArrayList<>();// 一条一条读取数据,全部添加到list集合里@Overridepublic void invoke(TemplateEntity data, AnalysisContext analysisContext) {list.add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}public List<TemplateEntity> getData() {return list;}
}
2-3. service:
public interface TemplateService {/*** 导入excel*/Result importExcel(MultipartFile file) throws IOException;
}@Service
public class TemplateServiceImpl implements TemplateService {@Overridepublic Result importExcel(MultipartFile file) throws IOException{List<TemplateEntity> entities = getTemplateEntities(file);// 处理数据System.out.println(entities);return Result.success(entities);}// 读取 excel 数据private List<TemplateEntity> getTemplateEntities(MultipartFile file) throws IOException {TemplateListener listener = new TemplateListener(); // 定义的 listenerEasyExcel.read(file.getInputStream(), TemplateEntity.class, listener).sheet().doRead();// 返回 所有数据return listener.getData();}
}
2-4. Controller 上传文件接口
@RestController
@RequestMapping("/sys")
public class TemplateController {@Autowiredprivate TemplateService templateService;@RequestMapping("/import")public Result importData(@RequestPart("file") MultipartFile file) throws IOException{return templateService.importExcel(file);}
}
3. Postman测试
{"code": 200,"msg": "处理成功","data": [{"label": 1,"str": "a","num": 20},{"label": 2,"str": "b","num": 30},{"label": 3,"str": "c","num": 40},...
}
————————————————
二、导入:多头行数,多sheet,复杂表头
1. 两sheet表头数据不一致
这里为了演示效果,sheet1和sheet3是不同表头的,sheet2目前是空的数据表
思路:需要定义各自的excel接收数据的实体类,然后创建各自的监听类,重写方法
读取时,指定不同的监听类,excel接收数据的实体类对象,然后放入map中返回即可
具体实现
实体类
TemplateEntity接收sheet1
@Data
public class TemplateEntity {@ExcelProperty("标号")private Integer label;@ExcelProperty("字符串")private String str;@ExcelProperty("数字")private Integer num;@ExcelProperty(value = "时间")@DateTimeFormat("yyyy-MM-dd")private String date;
}
OtherTemplateEntity接收sheet3
@Data
public class OtherTemplateEntity {@ExcelProperty("标号")private String label;@ExcelProperty("名称")private String name;@ExcelProperty("类型")private String type;@ExcelProperty(value = "时间")@DateTimeFormat("yyyy-MM-dd")private String date;
}
监听类
同上,只是写两个各自的
controller层
@PostMapping("/importMany")
public R importMany(@RequestPart("file") MultipartFile file) throws IOException {return easyExcelService.importManyExcel(file);
}
service实现层
public R importManyExcel(MultipartFile file) throws IOException {Map<String, Object> map = getTemplateEntitiesMany(file);List<TemplateEntity> data1 = (List<TemplateEntity>) map.get("data1");List<OtherTemplateEntity> data2 = (List<OtherTemplateEntity>) map.get("data2");log.info("data1数据=={}", data1);log.info("data2数据=={}", data2);return R.success(map);
}private Map<String, Object> getTemplateEntitiesMany(MultipartFile file) throws IOException {Map<String,Object> map = new HashMap<>();TemplateListener listener = new TemplateListener(); // 定义的 listenerOtherTemplateListener otherListener = new OtherTemplateListener();ExcelReader excelReader = EasyExcel.read(file.getInputStream()).build();// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener// readSheet参数设置读取sheet的序号// 读取sheet1ReadSheet readSheet1 =EasyExcel.readSheet(0).head(TemplateEntity.class).registerReadListener(listener).build();// 读取sheet3ReadSheet readSheet2 =EasyExcel.readSheet(2).head(OtherTemplateEntity.class).registerReadListener(otherListener).build();excelReader.read(readSheet1, readSheet2);// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的excelReader.finish();// 取出数据放入map中,然后返回List<TemplateEntity> data1 = listener.getData();List<OtherTemplateEntity> data2 = otherListener.getData();map.put("data1", data1);map.put("data2", data2);return map;}
{"code": 200,"msg": "OK","message": null,"data": {"data2": [{"label": "a","name": "a1","type": "t1","date": "2022-01-07"},{"label": "b","name": "b1","type": "t2","date": "2022-01-07"}......],"data1": [{"label": 1,"str": "a","num": 20,"date": "2021-12-20"},{"label": 2,"str": "b","num": 30,"date": "2021-12-20"}......]}
}
多行头
读取时设置头行数即可
headRowNumber是头行数,如下是设置头行数2,那么读取时会从第三行开始读取数据
private List<TemplateEntity> getTemplateEntities(MultipartFile file) throws IOException {TemplateListener listener = new TemplateListener(); // 定义的 listenerEasyExcel.read(file.getInputStream(), TemplateEntity.class, listener).sheet(0).headRowNumber(2).doRead();// 返回 所有数据return listener.getData();}
读取表头数据
在监听类中重写invokeHeadMap方法,将表头数据也添加即可
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {private List<TemplateEntity> list = new ArrayList<>();@Overridepublic void invoke(TemplateEntity data, AnalysisContext context) {list.add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {}public List<TemplateEntity> getData() {return list;}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {// 读取到头数据LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap))}
————————————————
三、导出:简单简单实现
实体类省略,还是上面的TemplateEntity
导出excel数据,这里有两种写法,拟定好文件名称直接传入方法,会自动创建一个文件
1. 模拟数据 10条数据
// 模拟数据
private List<TemplateEntity> exportData() {List<TemplateEntity> entities = new ArrayList<>();for (int i = 0; i< 10; i++) {TemplateEntity entity = new TemplateEntity();entity.setStr("字符串" + i);entity.setDate("数据" + i);entity.setLabel(i+1);entity.setNum(i);entities.add(entity);}return entities;
}
3. 程序
public R export() {String path = "C:\\Users\\EDZ\\Desktop\\";// 写法1String fileName = path + System.currentTimeMillis() + ".xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭// 如果这里想使用03 则 传入excelType参数即可EasyExcel.write(fileName, TemplateEntity.class).sheet("模板").doWrite(exportData());// 写法2// 这里 需要指定写用哪个class去写ExcelWriter excelWriter = EasyExcel.write(fileName, TemplateEntity.class).build();WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();excelWriter.write(exportData(), writeSheet);// 千万别忘记finish 会帮忙关闭流excelWriter.finish();return R.success();
}
————————————————
3. 过滤导出列
public R export() {String path = "C:\\Users\\EDZ\\Desktop\\";String fileName = path + System.currentTimeMillis() + ".xlsx";// 加入要忽略date字段Set<String> excludeColumnFiledNames = new HashSet<String>();excludeColumnFiledNames.add("date");EasyExcel.write(fileName,TemplateEntity.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板").doWrite(exportData()); }
五、导入:复杂头 合并表头
1. 实体类
@Data
public class TemplateEntity {@ExcelProperty({"主标题", "标号"})private Integer label;@ExcelProperty({"主标题", "字符串"})private String str;@ExcelProperty({"主标题", "数字"})private Integer num;@ExcelProperty({"主标题", "时间"})@DateTimeFormat("yyyy-MM-dd")private String date;
}
六、动态自由导出导入
在实际使用开发中,我们不可能每来一个 excel 导入导出需求,就编写一个实体类,很多业务需求需要根据不同的字段来动态导入导出,没办法基于实体类注解的方式来读取文件或者写入文件。
因此,基于EasyExcel提供的动态参数化生成文件和动态监听器读取文件方法,我们可以单独封装一套动态导出导出工具类,省的我
们每次都需要重新编写大量重复工作,我在实际使用过程,封装出来的工具类如下:
<!-- guava 工具类 集合各种处理 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.5</version></dependency>
1. 导出
1-1. 编写一个动态导出工具类
package com.ltkj.common.excel;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ltkj.common.utils.JsonUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** 动态导出工具类测试** @author wangl* @date 2023-10-10*/
public class DynamicEasyExcelExportUtilTest {private static final Logger log = LoggerFactory.getLogger(DynamicEasyExcelExportUtilTest.class);private static final String DEFAULT_SHEET_NAME = "sheet1";/*** 动态生成导出模版(单表头)** @param headColumns 列名称* @return excel文件流*/public static byte[] exportTemplateExcelFile(List<String> headColumns) {List<List<String>> excelHead = Lists.newArrayList();byte[] stream = createExcelFile(excelHead, new ArrayList<>());return stream;}/*** 动态生成模版(复杂表头)** @param excelHead 列名称* @return*/public static byte[] exportTemplateExcelFileCustomHead(List<List<String>> excelHead) {byte[] stream = createExcelFile(excelHead, new ArrayList<>());return stream;}/*** 动态导出文件(通过map方式计算)** @param headColumnMap 有序列头部* @param dataList 数据体* @return*/public static byte[] exportExcelFile(LinkedHashMap<String, String> headColumnMap, List<Map<String, Object>> dataList) {//获取列名称List<List<String>> excelHead = new ArrayList<>();if (MapUtils.isNotEmpty(headColumnMap)) {//key为匹配符,value为列名,如果多级列名用逗号隔开headColumnMap.entrySet().forEach(entry -> {excelHead.add(Lists.newArrayList(entry.getValue().split(",")));});}List<List<Object>> excelRows = new ArrayList<>();if (MapUtils.isNotEmpty(headColumnMap) && CollectionUtils.isNotEmpty(dataList)) {for (Map<String, Object> dataMap : dataList) {List<Object> rows = new ArrayList<>();headColumnMap.entrySet().forEach(headColumnEntry -> {if (dataMap.containsKey(headColumnEntry.getKey())) {Object data = dataMap.get(headColumnEntry.getKey());rows.add(data);}});excelRows.add(rows);}}byte[] stream = createExcelFile(excelHead, excelRows);return stream;}/*** 生成文件(自定义头部排列)** @param rowHeads* @param excelRows* @return*/public static byte[] customerExportExcelFile(List<List<String>> rowHeads, List<List<Object>> excelRows) {//将行头部转成easyexcel能识别的部分List<List<String>> excelHead = transferHead(rowHeads);return createExcelFile(excelHead, excelRows);}/*** 生成文件** @param excelHead* @param excelRows* @return*/private static byte[] createExcelFile(List<List<String>> excelHead, List<List<Object>> excelRows) {try {if (CollectionUtils.isNotEmpty(excelHead)) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();EasyExcel.write(outputStream).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).head(excelHead).sheet(DEFAULT_SHEET_NAME).doWrite(excelRows);return outputStream.toByteArray();}} catch (Exception e) {log.error("动态生成excel文件失败,headColumns:" + JsonUtils.toJsonString(excelHead) + ",excelRows:" + JsonUtils.toJsonString(excelRows), e);}return null;}/*** 将行头部转成easyexcel能识别的部分** @param rowHeads* @return*/public static List<List<String>> transferHead(List<List<String>> rowHeads) {//将头部列进行反转List<List<String>> realHead = new ArrayList<>();if (CollectionUtils.isNotEmpty(rowHeads)) {Map<Integer, List<String>> cellMap = new LinkedHashMap<>();//遍历行for (List<String> cells : rowHeads) {//遍历列for (int i = 0; i < cells.size(); i++) {if (cellMap.containsKey(i)) {cellMap.get(i).add(cells.get(i));} else {cellMap.put(i, Lists.newArrayList(cells.get(i)));}}}//将列一行一行加入realHeadcellMap.entrySet().forEach(item -> realHead.add(item.getValue()));}return realHead;}/*** 导出文件测试** @param args* @throws IOException*/public static void main(String[] args) throws IOException {//导出包含数据内容的文件(方式一)LinkedHashMap<String, String> headColumnMap = Maps.newLinkedHashMap();headColumnMap.put("name", "姓名");headColumnMap.put("sex", "性别");headColumnMap.put("titleName", "职称信息一, 职称名称");headColumnMap.put("titleLevel", "职称信息一, 职称等级");headColumnMap.put("titleName_2", "职称信息二, 职称名称");headColumnMap.put("titleLevel_2", "职称信息二, 职称等级");List<Map<String, Object>> dataList = new ArrayList<>();for (int i = 0; i < 5; i++) {Map<String, Object> dataMap = Maps.newHashMap();dataMap.put("name", "张三" + i);dataMap.put("sex", "男");dataMap.put("titleName", "会计师");dataMap.put("titleLevel", i + " 级");dataMap.put("titleName_2", "律师");dataMap.put("titleLevel_2", i * 10 + " 级");dataList.add(dataMap);}byte[] stream1 = exportExcelFile(headColumnMap, dataList);FileOutputStream outputStream1 = new FileOutputStream(new File("easyexcel-export-user1.xlsx"));outputStream1.write(stream1);outputStream1.close();}
}
1-2. 测试: easyexcel-export-user1.xlsx
接上面同一个类里 方法二
//导出包含数据内容的文件(方式二)//头部,第一层List<String> head1 = new ArrayList<>();head1.add("第1行头部列1-序号");head1.add("第1行头部列2-缴纳单位");head1.add("第1行头部列3-姓名");head1.add("第1行头部列4-身份证号");// 第一行:一直是列1 列1 列1:就是合并列的意思head1.add("第1行头部列5-五险一金信息");head1.add("第1行头部列5-五险一金信息");head1.add("第1行头部列5-五险一金信息");head1.add("第1行头部列5-五险一金信息");head1.add("第1行头部列5-五险一金信息");head1.add("第1行头部列5-五险一金信息");//头部,第二层List<String> head2 = new ArrayList<>();// 2行 和 1行 行头相同: 就是合并行的意思head2.add("第1行头部列1-序号");head2.add("第1行头部列2-缴纳单位");head2.add("第1行头部列3-姓名");// 2-3行合并,不和1行合并head2.add("第1行头部列3-身份证号");head2.add("第2行头部列5-养老保险");head2.add("第2行头部列5-养老保险");head2.add("第2行头部列5-养老保险");head2.add("第2行头部列8-医疗保险");head2.add("第2行头部列8-医疗保险");head2.add("第2行头部列8-医疗保险");//头部,第三层List<String> head3 = new ArrayList<>();// 3行 和 2行 行头相同: 就是合并行的意思head3.add("第1行头部列1-序号");head3.add("第1行头部列2-缴纳单位");head3.add("第1行头部列3-姓名");// 2-3行合并,不和1行合并head3.add("第1行头部列3-身份证号");head3.add("第3行头部列5-缴费基数");head3.add("单位缴纳比例");head3.add("第3行头部列7-个人缴纳比例");head3.add("第3行头部列8-缴费基数");head3.add("单位缴纳比例");head3.add("第3行头部列10-个人缴纳比例");//封装头部List<List<String>> allHead = new ArrayList<>();allHead.add(head1);allHead.add(head2);allHead.add(head3);//封装数据体//第一行数据List<Object> data1 = Lists.newArrayList("001", "旅投科技", "赵一", "130xxx1", 5000, 5, 6, 6000, 7, 8);//第二行数据List<Object> data2 = Lists.newArrayList("002", "三药集团", "孙二", "232xxx2", 8000, 8, 9, 9000, 10, 12);List<List<Object>> allData = Lists.newArrayList(data1, data2);byte[] stream2 = customerExportExcelFile(allHead, allData);FileOutputStream outputStream2 = new FileOutputStream(new File("easyexcel-export-user2.xlsx"));outputStream2.write(stream2);outputStream2.close();
2. 导入: EasyExcel 导入需要一个监听器,导出不需要
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.1</version></dependency><!-- guava 工具类 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version></dependency></dependencies>
2-1. 编写一个动态导入监听器
package com.ltkj.common.excel;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson2.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** EasyExcel 导入需要一个监听器,导出不需要** @author wangl* @date 2023-10-14*/
public class DynamicEasyExcelListener extends AnalysisEventListener<Map<Integer, String>> {private static final Logger LOGGER = LoggerFactory.getLogger(DynamicEasyExcelListener.class);/*** 表头数据(存储所有的表头数据)*/private List<Map<Integer, String>> headList = new ArrayList<>();/*** 数据体*/private List<Map<Integer, String>> dataList = new ArrayList<>();/*** 这里会一行行的返回头** @param headMap* @param context*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {LOGGER.info("解析到一条标题头数据:{}", JSON.toJSONString(headMap));//存储全部表头数据headList.add(headMap);}/*** 这个每一条数据解析都会来调用** @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(Map<Integer, String> data, AnalysisContext context) {// 解析一条 放到 dataList里,最后返回 dataList 即可 LOGGER.info("解析到一条data数据:{}", JSON.toJSONString(data));dataList.add(data);}/*** 所有数据解析完成了 都会来调用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库LOGGER.info("所有数据解析完成!");}public List<Map<Integer, String>> getHeadList() {return headList;}public List<Map<Integer, String>> getDataList() {return dataList;}
}
2-2. 编写动态导入工具类
package com.ltkj.common.excel;import com.ali
baba.excel.EasyExcelFactory;
import com.alibaba.excel.util.IoUtils;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** 编写导入工具类** @author wangl* @date 2023-10-14*/
public class DynamicEasyExcelImportUtils {private static final Logger LOGGER = LoggerFactory.getLogger(DynamicEasyExcelListener.class);/*** 动态获取全部列和数据体,默认只有1行标题** @param stream* @return*/public static List<Map<String, String>> parseExcelToView(byte[] stream) {return parseExcelToView(stream, 1);}/*** 动态获取全部列和数据体,指定有几行标题** @param stream excel文件流* @param parseRowNumber 指定有几行标题* @return*/public static List<Map<String, String>> parseExcelToView(byte[] stream, Integer parseRowNumber) {LOGGER.info("指定有[" + parseRowNumber + "]行标题");DynamicEasyExcelListener readListener = new DynamicEasyExcelListener();EasyExcelFactory.read(new ByteArrayInputStream(stream)).registerReadListener(readListener).headRowNumber(parseRowNumber).sheet("sheet1").doRead();List<Map<Integer, String>> headList = readListener.getHeadList();if (CollectionUtils.isEmpty(headList)) {throw new RuntimeException("Excel未包含表头");}List<Map<Integer, String>> dataList = readListener.getDataList();if (CollectionUtils.isEmpty(dataList)) {throw new RuntimeException("Excel未包含数据");}//获取头部,取最后一次解析的列头数据Map<Integer, String> excelHeadIdxNameMap = headList.get(headList.size() - 1);//封装数据体List<Map<String, String>> excelDataList = Lists.newArrayList();for (Map<Integer, String> dataRow : dataList) {Map<String, String> rowData = new LinkedHashMap<>();excelHeadIdxNameMap.entrySet().forEach(columnHead -> {rowData.put(columnHead.getValue(), dataRow.get(columnHead.getKey()));});excelDataList.add(rowData);}return excelDataList;}/*** 文件导入测试** @param args* @throws IOException*/public static void main(String[] args) throws IOException {FileInputStream inputStream = new FileInputStream(new File("easyexcel-export-user1.xlsx"));byte[] stream = IoUtils.toByteArray(inputStream);List<Map<String, String>> dataList = parseExcelToView(stream, 2);// 打印最后结果 全部数据 不含标题System.out.println(JSONArray.toJSONString(dataList));inputStream.close();}
}
所有数据解析完成!
[{"姓名":"张三0","性别":"男","职称名称":"律师","职称等级":"0 级"},
{"姓名":"张三1","性别":"男","职称名称":"律师","职称等级":"10 级"},
{"姓名":"张三2","性别":"男","职称名称":"律师","职称等级":"20 级"},
{"姓名":"张三3","性别":"男","职称名称":"律师","职称等级":"30 级"},
{"姓名":"张三4","性别":"男","职称名称":"律师","职称等级":"40 级"}]
为了方便后续的操作流程,在解析数据的时候,会将列名作为key!
三、小结
在实际的业务开发过程中,根据参数动态实现 Excel 的导出导入还是非常广的。
相关文章:

导入导出Excel
Springboot Easyexcel导入导出excel EasyExcel 的导出导入支持两种方式进行处理*easyexcel 导出不用监听器,导入需要写监听器* 一、导入:简单实现1. 导入依赖,阿里的easyexcel插件2. 程序2-1. 实体类:2-2. 定义一个 监听类&#…...

C# Thread.Sleep(0)有什么用?
一、理论分析 回答这个要先从线程时间精度(时间片)开始说起。很多参考书说,默认情况下,时间片为15ms 左右,但是这是已经过时的知识。在老的 Windows 操作系统里,应用程序模式时时间片 15ms 左右࿰…...

二十四、【参考素描三大面和五大调】
文章目录 三种色面(黑白灰)五种色调 这个可以参考素描对物体受光的理解:素描调子的基本规律与素描三大面五大调物体的明暗规律 三种色面(黑白灰) 如下图所示,我们可以看到光源是从亮面所对应的方向射过来的,所以我们去分析图形的时候,首先要…...

【Python 千题 —— 基础篇】进制转换:十进制转二进制
题目描述 题目描述 计算机底层原理中常使用二进制来表示相关机器码,学会将十进制数转换成二进制数是一个非常重要的技能。现在编写一个程序,输入一个十进制数,将其转换成二进制数。 输入描述 输入一个十进制数。 输出描述 程序将输入的…...

[ spring boot入门 ] java: 错误: 无效的源发行版:17
因为我目前idea中使用的是jdK8,而在pom.xml文件里是17,所以我需要将所有地方修改为jdk8 pom.xml的jdk版本为8 maven的setting.xml文件 jdk为8 还有Java Compiler 还有Project Structure 里面的project 和 module...

【计算机组成体系结构】电路基本原理与加法器设计
一、算术逻辑单元—ALU 1.基本的逻辑运算(1bit的运算) 基本逻辑运算分为,与、或、非。大家应该很熟悉了,与:全1为1,否则为0。或:全0为0,否则为1。非:取反。三个基本的逻…...

MyBatisPlus之基本CRUD、常用注解
文章目录 前言一、MyBatisPlus简介1.简介2.特性 二、基本CRUD1.依赖2.搭建基本结构3.BaseMapper4.使用插入删除(1)通过id删除记录(2)通过id批量删除记录(3)通过map条件删除记录 修改查询(1&…...

采集EtherNET/IP转Profinet在西门子plc中的应用
远创智控网关YC-EIPM-PN,让你的设备和云平台实时连接! 远创智控YC-EIPM-PN网关产品支持各种数据接口,无论是工业领域的仪表、PLC、计量设备,还是设备数据,都能实时采集并整合。它将这些设备中的运行数据、状态数据等信…...

Paddle build_cinn_pass_test源码阅读(fluid目录下)
代码位置在 paddle\fluid\framework\paddle2cinn\build_cinn_pass_test.cc ,因为paddle CINN和PIR部分依旧在高频更新,所以各位看到的可能和我的不一样 inline bool CheckNodeExisted(const std::unordered_set<Node*>& nodes,const std::str…...

函数调用:为什么会发生stack overflow?
在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站,Stack Overflow 的名字来自于一个常见的报错,就是栈溢出(stack ove…...

git log
git log -p 是一个用于显示git commit历史的命令,它会展示每个commit的详细信息,包括每个修改文件的清单、添加/删除的行所在的位置以及具体的实际更改。这个命令能够让用户深入了解仓库的历史记录。 与git log相比,git log -p 提供了更多的…...

在面试提问环节应该问那些内容
在面试提问环节应该问那些内容 薪资和福利: 你可以询问关于薪资、福利和其他福利待遇的细节,包括工资结构、健康保险、退休计划、带薪休假等。 了解关于加班、绩效奖金和涨薪机会的信息。 工作时间和灵活性: 询问工作时间、工作日和工作日…...

【vb.net】轻量JSON序列及反序列化
这个代码写的有点时间了,可能有点小bug,欢迎评论区反馈 作用是将Json文本转化成一个HarryNode类进行相关的Json对象处理或者读取,也可以将一个HarryNode对象用ToString变为Json文本。 举例: 1、读取节点数据 dim harryNode N…...

【Vue】vue2与netcore webapi跨越问题解决
系列文章 C#底层库–记录日志帮助类 本文链接:https://blog.csdn.net/youcheng_ge/article/details/124187709 文章目录 系列文章前言一、技术介绍二、问题描述三、问题解决3.1 方法一:前端Vue修改3.2 方法二:后端允许Cors跨越访问 四、资源…...

SpringSecurity + jwt + vue2 实现权限管理 , 前端Cookie.set() 设置jwt token无效问题(已解决)
问题描述 今天也是日常写程序的一天 , 还是那个熟悉的IDEA , 还是那个熟悉的Chrome浏览器 , 还是那个熟悉的网站 , 当我准备登录系统进行登录的时候 , 发现会直接重定向到登录页 , 后端也没有报错 , 前端也没有报错 , 于是我得脸上又多了一张痛苦面具 , 紧接着在前端疯狂debug…...

【21】c++设计模式——>装饰模式
装饰模式的定义 装饰模式也可以称为封装模式,所谓的封装就是在原有行为之上进行扩展,并不会改变该行为; 例如网络通信: 在进行网络通信的时候,数据是基于IOS七层或四层网络模型(某些层合并之后就是四层模型…...

【博客707】模版化拆解并获取victoriametrics的metricsql各个元素
golang解析victoriametrics的metricsql 场景: 需要拆解metricsql中的部分元素,比如:rollup function,label filter等需要对语法合法性进行判断,同时拒绝某些查询函数我们需要拆解metricsql并进行改造 使用victoriam…...

nodejs + express 实现 http文件下载服务程序
nodejs express 实现 http文件下载服务程序, 主要包括两个功能:指定目录的文件列表,某个文件的下载。 假设已经安装好 nodejs ; cd /js/node_js ; 安装在当前目录的 node_modules/ npm install express --save npm install express-gene…...

Qt多文本编辑器项目实战
0x00 引言 本文将详细讲解如何使用Qt实现一个多文本编辑器。涉及的话题包括:Qt框架基础、窗体布局、文本编辑、拓展功能等等。 在阅读本文之前,你需要掌握基本的C编程知识和Qt框架的使用方法。 0x01 新建Qt项目 在Qt Creator中,新建一个Q…...

CVE-2017-7529 Nginx越界读取内存漏洞
漏洞概述 当使用Nginx标准模块时,攻击者可以通过发送包含恶意构造range域的header请求,来获取响应中的缓存文件头部信息。在某些配置中,缓存文件头可能包含后端服务器的IP地址或其它敏感信息,从而导致信息泄露。 影响版本 Ngin…...

力扣每日一题136:只出现一次的数字
题目描述: 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 示例 1 &#…...

导航栏参考代码
导航栏参考代码 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>导航栏参考代码</title> </head> <body> <table width"858" border"0" align"center"><tr&g…...

区块链(11):java区块链项目之页面部分实现
addPeer.html <!DOCTYPE html> <html> <head><meta charset="utf-8"> <title>java区块链</title><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="styles…...

RootSIFT---SIFT图像特征的扩展
RootSIFT是论文 Three things everyone should know to improve object retrieval - 2012所提出的 A Comparative Analysis of RootSIFT and SIFT Methods for Drowsy Features Extraction - 2020 当比较直方图时,使用欧氏距离通常比卡方距离或Hellinger核时的性能…...

ChatGPT角色扮演教程,Prompt词分享
使用指南 1、可直复制使用 2、可以前往已经添加好Prompt预设的AI系统测试使用 https://ai.idcyli.comhttps://ai.idcyli.com 雅思写作考官 我希望你假定自己是雅思写作考官,根据雅思评判标准,按我给你的雅思考题和对应答案给我评分,并且按…...

zabbix监控——自定义监控内容
目录 自定义监控项步骤 案例 1、明确需要执行的命令 2、创建 zabbix 的监控项配置文件,用于自定义 key,并重启zabbix-agent2 3、.在服务端验证新建的监控项 4、在 Web 页面创建自定义监控项模板 1)创建模板 2)创建监控项 …...

中断机制-中断协商机制、中断方法
4.1 线程中断机制 4.1.1 从阿里蚂蚁金服面试题讲起 Java.lang.Thread下的三个方法: 4.1.2 什么是中断机制 首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,自己来决定自己的命运,所以,…...

three.js入门 —— 实现第一个3D案例
前言: three.js入门,根据文档实现第一个3D案例 效果图: 代码实现: const scene new THREE.Scene();//创建一个长方体几何对象Geometryconst geometry new THREE.BoxGeometry(100, 100, 100);//创建一个网络基础材质的材质对象…...

《动手学深度学习 Pytorch版》 8.4 循环神经网络
8.4.1 无隐状态的神经网络 对于无隐藏装态的神经网络来说,给定一个小批量样本 X ∈ R n d \boldsymbol{X}\in\mathbb{R}^{n\times d} X∈Rnd,则隐藏层的输出 H ∈ R n h \boldsymbol{H}\in\mathbb{R}^{n\times h} H∈Rnh 通过下式计算: …...

什么是物联网阀控水表?
物联网阀控水表是一种新型的水表,结合了物联网技术和传统水表的功能,可以实现对水的计量、控制和管理。随着人们对水资源的日益重视,物联网阀控水表的应用越来越广泛,为水资源的合理利用和管理提供了有效手段。 物联网阀控水表是由…...