当前位置: 首页 > news >正文

Java Excel的数据导入导出

引入依赖

<!-- EasyExcel -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.7</version>
</dependency><!--csv文件操作-->
<dependency><groupId>net.sourceforge.javacsv</groupId><artifactId>javacsv</artifactId><version>2.0</version>
</dependency>

数据读取监听

导入数据时,程序解析和读取数据用,必须要!!!

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** Excel数据解析监听器, 数据解析方法异步执行* @param <T>   Excel中数据的类型*/
@Getter
@Setter
@NoArgsConstructor
public class ExcelListener<T> extends AnalysisEventListener<T> {// 加入一个判断标签,判断数据是否已经读取完private volatile boolean retryLock = false;// 解析完成后的数据集合, 监听对象初始化之后,立即初始化集合对象private final List<T> dataList = new ArrayList<>();// 每次最多导入条数private final int batchSize = 2000;/*** 获取解析后的数据集合, 如果数据还没有被解析完成,会对读取该集合的线程进行阻塞,直到数据读取完成之后,进行解锁。* 如果一次导入数据超过batchSize条,则以抛异常的形式阻止导入数据* @return  解析后的数据集合*/public List<T> getDataList() {while (true){if (retryLock){if (dataList.size() > batchSize){// 手动清空数据内存数据,减少内存消耗dataList.clear();throw new RuntimeException("一次最多导入"+ batchSize +"条数据");} else {return dataList;}}}}/*** Excel每解析一行数据,就会调用一次该方法* @param data*            one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*            analysis context*/@Overridepublic void invoke(T data, AnalysisContext context) {dataList.add(data);}/*** 读取表头内容* @param headMap   表头部数据* @param context   数据解析上下文*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {//System.out.println("表头:" + headMap);}/*** 流中的数据解析完成之后,就会调用此方法* @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 数据解析完成,解锁retryLock = true;}/*** 解析过程如果发生异常,会调用此方法* @param exception* @param context*/@Overridepublic void onException(Exception exception, AnalysisContext context){throw new RuntimeException("Excel数据异常,请检查或联系管理员!");}
}

Excel工具类

根据EasyExcel Model 导出工具类,CSV支持easyexcel获取ExcelProperty

package net.demo.excel.common.util;import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.csvreader.CsvWriter;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;/*** @desc: 根据EasyExcel Model 导出工具类* @Author: Swift* @Date: 2019-08-26 15:18*/
public class ExportUtil {/*** 获取ExcelProperty Value* @return*/public static <T extends BaseRowModel> String[] getFieldNames(Class<T> tClass) {Field[] fields = tClass.getDeclaredFields();List<String> headers = new ArrayList<>();for (Field field: fields) {ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (property != null) {String[] s = property.value();if (s.length > 0) {headers.add(s[0]);}}}String[] strings = new String[headers.size()];headers.toArray(strings);return strings;}/*** 获取filedName* @param vo* @param <T>* @return*/public static <T extends BaseRowModel>  String[] getFields(T vo) {Field[] fields = vo.getClass().getDeclaredFields();List<String> columns = new ArrayList<>();for (Field field: fields) {ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (property != null) {try {field.setAccessible(true);columns.add(field.get(vo)==null ? "" : field.get(vo).toString());} catch (IllegalAccessException e) {e.printStackTrace();throw new RuntimeException("写入内容到csv失败!");}}}String[] strings = new String[columns.size()];columns.toArray(strings);return strings;}public static <T extends BaseRowModel> void export(String type, List<T> vos, HttpServletResponse response, Class<T> t) throws IOException {Boolean isCsv = "csv".equals(type);String fileName = "data" + CalendarUtils.getCurrentTime();response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");if (isCsv) {fileName += ".csv";} else {fileName += ".xlsx";}response.setHeader("Content-disposition", "attachment;filename=" + fileName);ServletOutputStream outputStream = response.getOutputStream();if (isCsv) {CsvWriter csvWriter = new CsvWriter(outputStream, ',', Charset.forName("GBK"));csvWriter.writeRecord(getFieldNames(t));for (T vo : vos) {String[] fields = getFields(vo);csvWriter.writeRecord(fields);}csvWriter.close();} else {ExcelWriter excelWriter = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true);Sheet sheet = new Sheet(1, 0, t);excelWriter.write(vos, sheet);sheet.setAutoWidth(true);excelWriter.finish();}outputStream.flush();}public static <T extends BaseRowModel> void export(String type,String fileName, List<T> vos, HttpServletResponse response, Class<T> t) throws IOException {Boolean isCsv = "csv".equals(type);
//        String fileName = "data" + CalendarUtils.getCurrentTime();response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");if (isCsv) {fileName += ".csv";} else {fileName += ".xlsx";}response.setHeader("Content-disposition", "attachment;filename=" + fileName);ServletOutputStream outputStream = response.getOutputStream();if (isCsv) {CsvWriter csvWriter = new CsvWriter(outputStream, ',', Charset.forName("GBK"));csvWriter.writeRecord(getFieldNames(t));for (T vo : vos) {String[] fields = getFields(vo);csvWriter.writeRecord(fields);}csvWriter.close();} else {ExcelWriter excelWriter = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true);Sheet sheet = new Sheet(1, 0, t);excelWriter.write(vos, sheet);sheet.setAutoWidth(true);excelWriter.finish();}outputStream.flush();}/*** 根据Excel模板,批量导入数据* @param file  导入的Excel* @param clazz 解析的类型* @return  解析完成的数据*/public static List<?> importExcel(MultipartFile file, Class<?> clazz){if (file == null || file.isEmpty()){throw new RuntimeException("没有文件或者文件内容为空!");}List<Object> dataList = null;BufferedInputStream ipt = null;try {InputStream is = file.getInputStream();// 用缓冲流对数据流进行包装ipt = new BufferedInputStream(is);// 数据解析监听器ExcelListener<Object> listener = new ExcelListener<>();// 读取数据EasyExcel.read(ipt, clazz,listener).sheet().doRead();// 获取去读完成之后的数据dataList = listener.getDataList();} catch (Exception e){log.error(String.valueOf(e));throw new RuntimeException("数据导入失败!" + e);}return dataList;}
}

WriterFactory

导出工厂实现了xlsx与csv 两种方式

package net.demo.excel.common.export;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.demo.excel.common.constants.Constants;
import net.demo.excel.common.constants.ExportTypeEnum;
import net.demo.excel.common.export.csv.CsvExport;
import net.demo.excel.common.export.excel.ExcelExport;/*** 导出工厂*/
@Data
@Slf4j
public class WriterFactory {/*** 返回文件流方式** @param key* @param fileName* @param response* @return*/public static ExportWriter getExportWriter(String key, String fileName,HttpServletResponse response) {ExportWriter exportWriter = null;try {OutputStream os = response.getOutputStream();ExportTypeEnum exportTypeEnum = ExportTypeEnum.findByType(key);fileName = fileName + exportTypeEnum.getSuffix();exportWriter = generateExportWriter(exportTypeEnum, os);response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));} catch (UnsupportedEncodingException e) {log.error("UnsupportedEncoding:", e);} catch (IOException e) {log.error("IOException:", e);}return exportWriter;}/*** 输出到文件方式** @param key* @param fileName* @return*/public static ExportWriter getExportWriter(String key, String fileName)throws FileNotFoundException {ExportTypeEnum exportTypeEnum = ExportTypeEnum.findByType(key);String filePath =Constants.EXPORT_TMP_DIR + File.separator + fileName + exportTypeEnum.getSuffix();File file = new File(filePath);OutputStream os = new FileOutputStream(file);ExportWriter exportWriter = generateExportWriter(exportTypeEnum, os);exportWriter.setFilePath(filePath);return exportWriter;}private static ExportWriter generateExportWriter(ExportTypeEnum exportTypeEnum, OutputStream os) {ExportWriter exportWriter = null;switch (exportTypeEnum) {case EXCEL:exportWriter = new ExcelExport(os);break;case CSV:exportWriter = new CsvExport(os);break;default:}return exportWriter;}
}

ExportModel抽象类

package net.demo.excel.common.export.model;import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.csvreader.CsvWriter;/*** 抽象实体*/
public abstract class ExportModel {public abstract ExcelWriter getExcelWriter();public abstract Sheet getSheet();public abstract CsvWriter getCsvWriter();
}

CsvModel 实体类 

package net.demo.excel.common.export.csv.model;import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.csvreader.CsvWriter;
import lombok.Data;
import net.demo.excel.common.export.model.ExportModel;/*** csv相关实体*/
@Data
public class CsvModel extends ExportModel {private CsvWriter csvWriter;@Overridepublic ExcelWriter getExcelWriter() {return null;}@Overridepublic Sheet getSheet() {return null;}@Overridepublic CsvWriter getCsvWriter() {return csvWriter;}public CsvModel(CsvWriter csvWriter) {this.csvWriter = csvWriter;}
}

ExcelModel 实体类 

package net.demo.excel.common.export.excel.model;import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.csvreader.CsvWriter;
import lombok.Data;
import net.demo.excel.common.export.model.ExportModel;/*** excel,csv相关实体*/
@Data
public class ExcelModel extends ExportModel {private ExcelWriter excelWriter;private Sheet sheet;@Overridepublic ExcelWriter getExcelWriter() {return excelWriter;}@Overridepublic Sheet getSheet() {return sheet;}@Overridepublic CsvWriter getCsvWriter() {return null;}public ExcelModel(ExcelWriter excelWriter, Sheet sheet) {this.excelWriter = excelWriter;this.sheet = sheet;}
}

ExportWriter接口

package net.demo.excel.common.export;import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.fastjson.JSONArray;
import java.util.List;
import net.demo.excel.common.bean.Column;/*** 导出接口*/
public interface ExportWriter {public static final int EXPORT_PAGE_SIZE = 5000;/*** 写入表头 结构为{"code":"字段名","title":"显示名"}** @param columnList*/public void writeTitle(List<Column> columnList);public <T extends BaseRowModel> void writeTitle(Class<T> t);/*** 添加内容 data的Map结构为{"字段名":"字段值"}** @param dataList* @param columnList*/public void appendContent(JSONArray dataList, List<Column> columnList);public <T extends BaseRowModel> void appendContent(List<T> vos, Class<T> t);/*** 关闭文件流*/public void close();public String getFilePath();public void setFilePath(String filePath);}

Column

package net.demo.excel.common.bean;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Column {/*** 英文名称*/private String code;/*** 中文名称*/private String title;
}

ExcelExport实现类

model.getSheet() 的sheet的初始化在ExcelExport中完成。new sheet(1, 0, ExcelProperty)第3个参数com.alibaba.excel.annotation.ExcelProperty通过注解来生成表头。

package net.demo.excel.common.export.excel;import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.demo.excel.common.bean.Column;
import net.demo.excel.common.export.ExportWriter;
import net.demo.excel.common.export.excel.model.ExcelModel;
import net.demo.excel.common.export.model.ExportModel;
import net.demo.excel.common.util.ExportUtil;import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** excel具体实现*/
@Slf4j
@Data
public class ExcelExport implements ExportWriter {private ExportModel model;private OutputStream os;private String filePath;/*** 初始化** @param os*/public ExcelExport(OutputStream os) {ExcelWriter writer = new ExcelWriter(os, ExcelTypeEnum.XLSX);Sheet sheet = new Sheet(1, 0);sheet.setSheetName("1");this.model = new ExcelModel(writer, sheet);this.os = os;}/*** 写标题** @param columnList*/@Overridepublic void writeTitle(List<Column> columnList) {List<List<String>> dataList = new ArrayList<List<String>>();//组装标题行for (int i = 0; i < columnList.size(); i++) {List<String> titleList = new ArrayList<String>();Column column = columnList.get(i);String title = column.getTitle();titleList.add(title);dataList.add(titleList);}model.getSheet().setHead(dataList);}/*** 写标题*/@Overridepublic <T extends BaseRowModel> void writeTitle(Class<T> t) {List<List<String>> dataList = new ArrayList<List<String>>();String[] columns = ExportUtil.getFieldNames(t);//组装标题行for (int i = 0; i < columns.length; i++) {List<String> titleList = new ArrayList<String>();String title = columns[i];titleList.add(title);dataList.add(titleList);}model.getSheet().setHead(dataList);}/*** 内容追加** @param dataList* @param columnList*/@Overridepublic void appendContent(JSONArray dataList, List<Column> columnList) {List<List<String>> dataArray = new ArrayList<List<String>>();//组装数据行for (Object obj : dataList) {JSONObject json = (JSONObject) JSONObject.toJSON(obj);List<String> rowList = new ArrayList<>();for (int j = 0; j < columnList.size(); j++) {Column columnMap = columnList.get(j);String code = columnMap.getCode();Object value = json.get(code);String valueStr = value == null ? "" : value.toString();rowList.add(valueStr);}dataArray.add(rowList);}model.getExcelWriter().write1(dataArray, model.getSheet());}/*** 追加内容** @param vos* @param t* @param <T>*/@Overridepublic <T extends BaseRowModel> void appendContent(List<T> vos, Class<T> t) {//--start 修复sheet行数据为null时,列对齐错位--List<List<Object>> dataArray = new ArrayList<List<Object>>();for (T vo : vos) {Field[] fields = vo.getClass().getDeclaredFields();List<Object> rowList = new ArrayList<>();for (Field field : fields) {ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (property != null) {try {field.setAccessible(true);Object fieldValue = field.get(vo) == null ? "" : field.get(vo);rowList.add(fieldValue);} catch (IllegalAccessException e) {e.printStackTrace();throw new RuntimeException("写入内容到xlsx失败!");}}}dataArray.add(rowList);}model.getExcelWriter().write(dataArray, model.getSheet());//--end 修复api行数据为null时,列对齐错位--model.getSheet().setClazz(t); //注解来生成表头//model.getExcelWriter().write(vos, model.getSheet());model.getSheet().setAutoWidth(true);}/*** 关闭流*/@Overridepublic void close() {ExcelWriter writer = model.getExcelWriter();try {if (writer != null) {writer.finish();}os.close();} catch (IOException e) {log.error("os close error", e);}}@Overridepublic String getFilePath() {return filePath;}@Overridepublic void setFilePath(String filePath) {this.filePath = filePath;}
}

CsvExport实现类

package net.demo.excel.common.export.csv;import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.csvreader.CsvWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.demo.excel.common.bean.Column;
import net.demo.excel.common.export.ExportWriter;
import net.demo.excel.common.export.csv.model.CsvModel;
import net.demo.excel.common.export.model.ExportModel;
import net.demo.excel.common.util.ExportUtil;/*** csv具体实现*/
@Slf4j
@Data
public class CsvExport implements ExportWriter {private ExportModel model;private OutputStream os;private String filePath;/*** 初始化** @param os*/public CsvExport(OutputStream os) {CsvWriter csvWriter = new CsvWriter(os, ',', Charset.forName("GBK"));this.model = new CsvModel(csvWriter);this.os = os;}/*** 写标题** @param columnList*/@Overridepublic void writeTitle(List<Column> columnList) {String[] headers = new String[columnList.size()];for (int i = 0; i < columnList.size(); i++) {Column tmp = columnList.get(i);headers[i] = tmp.getTitle();}try {model.getCsvWriter().writeRecord(headers);} catch (IOException e) {log.error("写入标题到csv失败!", e);throw new RuntimeException("写入标题到csv失败!");}}@Overridepublic <T extends BaseRowModel> void writeTitle(Class<T> t){try {model.getCsvWriter().writeRecord(ExportUtil.getFieldNames(t));} catch (IOException e) {log.error("写入标题到csv失败!", e);throw new RuntimeException("写入标题到csv失败!");}}/*** 内容追加** @param dataList* @param columnList*/@Overridepublic void appendContent(JSONArray dataList, List<Column> columnList) {String[] content = null;List<String> codeList = new ArrayList<String>();for (int i = 0; i < columnList.size(); i++) {Column tmp = columnList.get(i);String code = tmp.getCode();codeList.add(code);}try {for (Object obj : dataList) {JSONObject json = (JSONObject) JSONObject.toJSON(obj);content = new String[codeList.size()];for (int i = 0; i < codeList.size(); i++) {String code = codeList.get(i);Object value = json.get(code);content[i] = value == null ? "" : value.toString();}model.getCsvWriter().writeRecord(content);}} catch (Exception e) {log.error("写入内容到csv失败!", e);throw new RuntimeException("写入内容到csv失败!");}}@Overridepublic <T extends BaseRowModel> void appendContent(List<T> vos, Class<T> t) {try {for (T vo : vos) {String[] fields = ExportUtil.getFields(vo);model.getCsvWriter().writeRecord(fields);}} catch (IOException e) {log.error("写入内容到csv失败!", e);throw new RuntimeException("写入内容到csv失败!");}}/*** 关闭*/@Overridepublic void close() {CsvWriter csvWriter = model.getCsvWriter();if (csvWriter != null) {csvWriter.close();}try {os.close();} catch (IOException e) {log.error("os close error", e);}}@Overridepublic String getFilePath() {return filePath;}@Overridepublic void setFilePath(String filePath) {this.filePath = filePath;}
}

创建导入数据模板类

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
import lombok.experimental.Accessors;import javax.validation.constraints.NotEmpty;
import java.io.Serializable;/*** 数据导入的Excel模板实体*/
@Data
public class ImportExcelVo implements Serializable {private static final long serialVersionUID = 1L;@ColumnWidth(20)@ExcelProperty(value = "公司名称", index = 0)private String name;@ColumnWidth(20)@ExcelProperty(value = "公司联系电话", index = 1)private String phone;@ColumnWidth(28)@ExcelProperty(value = "公司统一社会信用代码", index = 2)private String creditCode;@ColumnWidth(15)@ExcelProperty(value = "区域", index = 3)private String province;@ColumnWidth(15)@ExcelProperty(value = "公司法人", index = 4)private String legalPerson;@ExcelProperty(value = "备注", index = 5)private String remark;
}

创建数据导出模板

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
import lombok.experimental.Accessors;import java.io.Serializable;/*** 资质信息导出实体*/
@Data   // Lombok注解,用于生成getter setter
@Accessors(chain = true) //Lombok注解,链式赋值使用
public class ExportExcelVo extends BaseRowModel {private static final long serialVersionUID = 1L;@ColumnWidth(25)@ExcelProperty(value = "企业名称", index = 0)private String name;@ColumnWidth(25)@ExcelProperty(value = "社会统一信用代码", index = 1)private String creditCode;@ColumnWidth(15)@ExcelProperty(value = "曾用名", index = 2, converter = NullConverter.class)private String formerName;@ColumnWidth(15)@ExcelProperty(value = "公司法人", index = 3)private String legalPerson;@ExcelProperty(value = "区域", index = 4)private String province;@ExcelProperty(value = "录入时间", index = 5)private String createTime;@ColumnWidth(15)@ExcelProperty(value = "公司股东", index = 6)private String stockholder;@ExcelProperty(value = "企业联系方式", index = 7)private String contact;}

使用方法

/*** Excel批量导入数据** @param file 导入文件*/
@RequestMapping(value = "/import", method = RequestMethod.POST)
public CommonResponse<String> importEvents(MultipartFile file) {try {List<?> list = ExportUtil.importExcel(file, ImportExcelVo.class);System.out.println(list);return CommonResponse.success("数据导入完成");} catch (Exception e) {return CommonResponse.error("数据导入失败!" + e.getMessage());}
}//生成excel文件
try {exportWriter = WriterFactory.getExportWriter(dto.getExportType() == null ? "csv" : dto.getExportType(), fileName);exportWriter.writeTitle(PhoneExportVO.class);exportWriter.appendContent(list, PhoneExportVO.class);
} catch (Exception e) {log.error("导出失败", e);throw new BaseException("导出失败");
} finally {if (exportWriter != null) {exportWriter.close();}
}ExportWriter exportWriter = WriterFactory.getExportWriter(exportType, fileName);
List<Column> columns = trunkAreaVOResp.getColumns();
exportWriter.writeTitle(columns);
JSONArray dataList = (JSONArray) JSON.toJSON(trunkAreaVOResp.getTrunkArea());
exportWriter.appendContent(dataList, columns);
exportWriter.close();

EasyExcel自定义转换器Converter

Timestamp 转换器

package com.yandype.util.easyExcel;import java.sql.Timestamp;
import java.text.SimpleDateFormat;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;public class TimestampConverter implements Converter<Timestamp>{@Overridepublic Class<Timestamp> supportJavaTypeKey() {return Timestamp.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic WriteCellData<String> convertToExcelData(Timestamp timestamp, ExcelContentProperty contentProperty,GlobalConfiguration globalConfiguration) throws Exception {return new WriteCellData<String>(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp));}}

NullConverter

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;public class NullConverter implements Converter<String> {/*** 回到 Java 中的对象类型** @return 支持 Java 类*/@Overridepublic Class supportJavaTypeKey() {return String.class;}/*** * 返回 excel 中的对象枚举* * @return 支持 {@link Cell DataTypeEnum}* */@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}/*** 将excel对象转换为Java对象** @param cellData* Excel 单元格数据。NotNull。* @param contentProperty* 内容属性。可空。* @param globalConfiguration* 全局配置。NotNull。* @return 要放入 Java 对象的数据* @抛出异常*             例外。*/@Overridepublic String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return "-".equals(cellData.getStringValue()) ? null : cellData.getStringValue();}/*** 将 Java 对象转换为 excel 对象** @参数值* Java 数据.NotNull。* @param contentProperty* 内容属性。可空。* @param globalConfiguration* 全局配置。NotNull。* @return 数据放入 Excel* @抛出异常*             例外。*/@Overridepublic CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new CellData<>(null == value ? "-" : value);}
}

使用方法一

每个字段都要添加@ExcelProperty(converter = NullConverter.class)代码,如果遇到大量的数据字段去填充处理会增加很多工作量。转换器仅支持需要被处理的数据字段,也就是适用于从数据库查询出来已有的数据,如日期格式或性别字段做转换时才生效

使用方法二

File uploadFile = File.createTempFile("export", ".xlsx");
String templateFilePath = systemUrl + "/template/exportPublishShop.xlsx";ExcelWriterSheetBuilder excelWriterSheetBuilder = 
EasyExcel.write(uploadFile).registerConverter(new TimestampConverter()).withTemplate(templateFilePath).sheet();List<Map<String, String>> productList = 查询数据数据// productList 如果数据量很大一定要做分页查询,避免占用内存过大
excelWriterSheetBuilder.doFill(productList);

相关文章:

Java Excel的数据导入导出

引入依赖 <!-- EasyExcel --> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.7</version> </dependency><!--csv文件操作--> <dependency><groupId>n…...

OceanBase 4.0解读:兼顾高效与透明,我们对DDL的设计与思考

关于作者 谢振江&#xff0c;OceanBase 高级技术专家。 2015年加入 OceanBase, 从事存储引擎相关工作&#xff0c;目前在存储-索引与 DDL 组&#xff0c;负责索引&#xff0c;DDL 和 IO 资源调度相关工作。 回顾关系型数据库大规模应用以来的发展&#xff0c;从单机到分布式无…...

Qt线程池

目录1、线程池是什么&#xff1f;2、Qt线程池2.1、用法例程2.2、线程池对性能的提升2.3、运行算法单线程写法线程池写法1、线程池是什么&#xff1f; 线程池是一种线程使用模式&#xff0c;它管理着一组可重用的线程&#xff0c;可以处理分配过来的可并发执行的任务。 线程池设…...

设置table中的tbody

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>设置table中的tbody</title> </head> <body> <script> // 这里有json数据&#xff0c;是jav…...

2023美赛A题完整数据!思路代码数据数学建模

选取内蒙古河套灌区&#xff08;典型干旱区&#xff09;2010-2020年气温&#xff0c;降雨&#xff0c;蒸散发和水汽压月数据 包括四种主要作物及其占比 内容截图如下&#xff1a; 链接为&#xff1a;https://www.jdmm.cc/file/2708703 同时还提供参考代码和参考文章的选项~…...

Node.js安装与配置

Node.js安装与配置 前言 本篇博文记录了Node.js安装与环境变量配置的详细步骤&#xff0c;旨在为将来再次配置Node.js时提供指导方法。 另外&#xff1a;Node.js版本请根据自身系统选择&#xff0c;安装位置、全局模块存放位置和环境变量应根据自身实际情况进行更改。 Node…...

k8s(存储)数据卷与数据持久卷

为什么需要数据卷&#xff1f; 容器中的文件在磁盘上是临时存放的&#xff0c;这给容器中运行比较重要的应用程序带来一些问题问题1&#xff1a;当容器升级或者崩溃时&#xff0c;kubelet会重建容器&#xff0c;容器内文件会丢失问题2&#xff1a;一个Pod中运行多个容器并需要共…...

php5.6.9安装sqlsrv扩展(windows)

报错:Marning: PHP Startup: Unable to load dynamic 1library D:lphpstudy_prolExtensionslphpl(phps.6.9ntslextphp_ pdo_sqlsry 56 nts′找不到指定的模块。in Unknown on line 0 整整搞了一天才终于解决 我用的是phpstudy_pro&#xff08;也就是小皮v8.1版本&#xff09;&…...

URL黑名单 扫描工具ua特征 GET(args)参数检查 cookie黑名单 POST参数检查参考代码

资源宝分享www.httple.net 文章目录URL黑名单扫描工具ua特征GET(args)参数检查cookie黑名单POST参数检查注&#xff1a;请先检查是否已设置URL白名单&#xff0c;若已设置URL白名单&#xff0c;URL黑名单设置将失效 多个URL配置需换行&#xff0c;一行只允许填写一个。可直接填…...

【软考系统架构设计师】2022下论文写作历年真题

【软考系统架构设计师】2022下论文写作历年真题 试题四 论湖仓一体架构及其应用&#xff08;75分&#xff09; 试题四 论湖仓一体架构及其应用 随着5G、大数据、人工智能、物联网等技术的不断成熟&#xff0c;各行各业的业务场景日益复杂&#xff0c;企业数据呈现出大规模、多…...

推荐3个好用的scrum敏捷项目管理工具

结合对工具的了解和使用心得&#xff0c;介绍在管理scrum中常见的一些工具基础的scrum工具&#xff1a;1、物理白板物理白板是实施scrum最简单直接的方式。之前我也说过&#xff0c;一些利弊。数据不能够沉淀等等。2、Excel表格表格的形式就是如果多人编辑时&#xff0c;不能实…...

每日学术速递2.17

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.LG 1.Decoupled Model Schedule for Deep Learning Training 标题&#xff1a;深度学习训练的解耦模型时间表 作者&#xff1a;Hongzheng Chen, Cody Hao Yu, Shuai Zheng, Zhen Zhang,…...

ElementUI`resetFields()`方法避坑

使用ElementUI中的resetFields()方法有哪些注意点 场景一 场景一&#xff1a;当编辑弹出框和新增弹出框共用时&#xff0c;编辑数据后关闭编辑弹出框时调用this.$refs.form.resetFields()无法清空弹出框 问题代码&#xff1a; // 点击新增按钮handleAdd() {this.dialogVi…...

如何保证数据库和缓存双写一致性?

前言 数据库和缓存&#xff08;比如&#xff1a;redis&#xff09;双写数据一致性问题&#xff0c;是一个跟开发语言无关的公共问题。尤其在高并发的场景下&#xff0c;这个问题变得更加严重。 我很负责的告诉大家&#xff0c;该问题无论在面试&#xff0c;还是工作中遇到的概率…...

Hinge Loss 和 Zero-One Loss

文章目录Hinge Loss 和 Zero-One LossHinge LossZero-One LossHinge Loss 和 Zero-One Loss 维基百科&#xff1a;https://en.wikipedia.org/wiki/Hinge_loss 图表说明&#xff1a; 纵轴表示固定 t1t1t1 的 Hinge loss&#xff08;蓝色&#xff09;和 Zero-One Loss&#xff…...

Linux下zabbix_proxy实施部署

简介 zabbix proxy 可以代替 zabbix server 收集性能和可用性数据,然后把数据汇报给 zabbix server,并且在一定程度上分担了zabbix server 的压力. zabbix-agent可以指向多个proxy或者server zabbix-proxy不能指向多个server zabbix proxy 使用场景: 1&#xff0c;监控远程区…...

Rust之错误处理(二):带结果信息的可恢复错误

开发环境 Windows 10Rust 1.67.1VS Code 1.75.1项目工程 这里继续沿用上次工程rust-demo 带结果信息的可恢复错误 大多数错误并没有严重到需要程序完全停止的程度。有时&#xff0c;当一个函数失败时&#xff0c;它的原因是你可以很容易地解释和应对的。例如&#xff0c;如…...

[ vulhub漏洞复现篇 ] Drupal Core 8 PECL YAML 反序列化任意代码执行漏洞(CVE-2017-6920)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

如何将数据库结构导入到word

在navicat执行查询语句 SELECT COLUMN_NAME 备注, COLUMN_COMMENT 名称, COLUMN_TYPE 数据类型, false as 是键 FROM INFORMATION_SCHEMA.COLUMNS where -- wx 为数据库名称&#xff0c;到时候只需要修改成你要导出表结构的数据库即可 table_schema yuncourt_ai AND -- articl…...

FreeRTOS内存管理 | FreeRTOS十五

目录 说明&#xff1a; 一、FreeRTOS内存管理 1.1、动态分配与用户分配内存空间 1.2、标准C库动态分配内存缺点 1.3、FreeRTOS的五种内存管理算法优缺点 1.4、heap_1内存管理算法 1.5、heap_2内存管理算法 1.6、heap_3内存管理算法 1.7、heap_4内存管理算法 1.8、hea…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...