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

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

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

2023美赛A题完整数据!思路代码数据数学建模
选取内蒙古河套灌区(典型干旱区)2010-2020年气温,降雨,蒸散发和水汽压月数据 包括四种主要作物及其占比 内容截图如下: 链接为:https://www.jdmm.cc/file/2708703 同时还提供参考代码和参考文章的选项~…...

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

k8s(存储)数据卷与数据持久卷
为什么需要数据卷? 容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题问题1:当容器升级或者崩溃时,kubelet会重建容器,容器内文件会丢失问题2:一个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(也就是小皮v8.1版本)&…...

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

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

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

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

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

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

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

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

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

[ vulhub漏洞复现篇 ] Drupal Core 8 PECL YAML 反序列化任意代码执行漏洞(CVE-2017-6920)
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...
如何将数据库结构导入到word
在navicat执行查询语句 SELECT COLUMN_NAME 备注, COLUMN_COMMENT 名称, COLUMN_TYPE 数据类型, false as 是键 FROM INFORMATION_SCHEMA.COLUMNS where -- wx 为数据库名称,到时候只需要修改成你要导出表结构的数据库即可 table_schema yuncourt_ai AND -- articl…...

FreeRTOS内存管理 | FreeRTOS十五
目录 说明: 一、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…...

【数字电路】数字电路的学习核心
文章目录前言一、电子电路知识体系二、数电的学习目标三、数字电路分析例子四、数字电路设计例子总结前言 用数字信号完成对数字量进行算术运算和逻辑运算的电路称为数字电路,或数字系统。由于它具有逻辑运算和逻辑处理功能,所以又称数字逻辑电路。现代…...

day45【代码随想录】动态规划之完全平方数、单词拆分、打家劫舍、打家劫舍 II
文章目录前言一、完全平方数(力扣279)二、单词拆分(力扣139)三、打家劫舍(力扣198)四、打家劫舍 II前言 1、完全平方数 2、单词拆分 3、打家劫舍 4、打家劫舍 II 一、完全平方数(力扣279&#…...

java程序,springboot程序 找不到主类,找不到符号解决思路
文章目录问题解决方案一.可以尝试clean掉maven依赖,然后重新启动二.右键工程,选择maven然后重新加载工程,接着再启动试试三.删掉工程中的services.iml文件,重新配置后接着再启动试试四. 终极方案清除idea缓存,重启idea…...

AntD-tree组件使用详析
目录 一、selectedKeys与onSelect 官方文档 代码演示 onSelect 注意事项 二、expandedKeys与onExpand 官方文档 代码演示 onExpand 注意事项 三、loadedKeys与onLoad和onExpand 官方文档 代码演示 onExpand与onLoad: 注意事项 四、loadData …...

spring的事务控制
1.调用这个方法的对象是否是spring的代理对象($CGLIB结尾的) 2.这个方法是否是加了Transactional注释 都符合才可以被事物控制 如果调用方法的对象没有被事物控制,那么被调用的方法即便是加了Transactional也是没用的 事务失效情况…...

4.如何靠IT逆袭大学?
学习的动力不止于此: IT逆袭 这两天利用工作空余时间读了贺利坚老师的《逆袭大学——传给 IT 学子的正能量》,感触很多,有些后悔没有好好利用大学时光。 不过人都是撞了南墙再回头的,吃一堑长一智。 这本书无论你是工作了还是…...

提供网络可测试的接口【公共Webservice】
提供网络可测试的接口 1、腾讯QQ在线状态 WEB 服务 Endpoint: qqOnlineWebService Web 服务 Disco: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?disco WSDL: http://www.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl 腾讯QQ在线状态 WEB 服…...

【深入理解计算机系统】库打桩 - 阅读笔记
文章目录库打桩机制1. 编译时打桩2. 链接时打桩3. 运行时打桩库打桩机制 Linux 链接器支持一个很强大的技术,称为库打桩 (library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以…...

RocketMQ高性能原理分析
目录一、读队列与写队列1.概念介绍2.读写队列个数关系分析二、消息持久化1.持久化文件介绍2.持久化结构介绍:三、过期文件删除1.如何判断文件过期2.什么时候删除过期文件四、高效文件写1.零拷贝技术加速文件读写2.文件顺序写3.刷盘机制五、 消息主从复制六、负载均衡…...

前端面试当中CDN会问啥------CDN详细教程来啦
⼀、CDN 1. CDN的概念 CDN(Content Delivery Network,内容分发⽹络)是指⼀种通过互联⽹互相连接的电脑⽹络系统,利 ⽤最靠近每位⽤户的服务器,更快、更可靠地将⾳乐、图⽚、视频、应⽤程序及其他⽂件发送给⽤户&…...