EasyExcel的导入导出使用

EasyExcel的导入导出使用

/*** @ClassName: CellWidthStyleHandler* @Description: 设置表头的调整宽策略* @Author: * @Date: */
public class CellWidthStyleHandler extends AbstractColumnWidthStyleStrategy {// 可以根据这里的最大宽度,按自己需要进行调整,搭配单元格样式实现类中的,自动换行,效果更好private static final int MAX_COLUMN_WIDTH = 50;private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);/*** 是否设置固定宽度*/private boolean fixed;/*** 固定宽度*/private int fixedWidth;public CellWidthStyleHandler() {}public CellWidthStyleHandler(boolean fixed, int fixedWidth) {this.fixed = fixed;this.fixedWidth = (fixedWidth == 0 ? 15 : fixedWidth);}@Overrideprotected void setColumnWidth(CellWriteHandlerContext context) {boolean needSetWidth = context.getHead() || !CollUtil.isEmpty(context.getCellDataList());if (!needSetWidth) {return;}WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();// 设置固定宽度if (fixed) {Cell cell = context.getCell();writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), fixedWidth * 256);return;}// 设置自动调整宽度Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Cell cell = context.getCell();int columnWidth = this.dataLength(context.getCellDataList(), cell, context.getHead());if (columnWidth >= 0) {if (columnWidth > MAX_COLUMN_WIDTH) {columnWidth = MAX_COLUMN_WIDTH;}Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);}}}private int dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch (type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}
/*** @ClassName: DefaultExcelHeadHandler* @Description: 默认自定义表头样式拦截器* @Author: * @Date: */
public class DefaultExcelHeadHandler extends HorizontalCellStyleStrategy {//设置头样式@Overrideprotected void setHeadCellStyle(CellWriteHandlerContext context) {WriteCellStyle headWriteCellStyle = new WriteCellStyle();headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short) 11);headWriteFont.setColor(IndexedColors.BLACK.getIndex());headWriteCellStyle.setWriteFont(headWriteFont);if (stopProcessing(context)) {return;}WriteCellData<?> cellData = context.getFirstCellData();WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());}
}
/*** @ClassName: EasyExcelUtil* @Description: excel导入导出工具类* @Author: * @Date: */
public class EasyExcelUtil {/*** 导入-读取一页sheet** @param inputStream 文件流* @param clazz       数据对象* @param sheetName   要读取的sheet (不传,默认读取第一个sheet)* @throws Exception*/public static <T> List<T> importExcel(InputStream inputStream, Class<T> clazz, String sheetName, ReadExcelListener readExcelListener) throws Exception {ExcelReaderBuilder builder = EasyExcelFactory.read(inputStream, clazz, readExcelListener);if (StringUtils.isBlank(sheetName)) {builder.sheet().doRead();} else {builder.sheet(sheetName).doRead();}return readExcelListener.getList();}/*** 导入-读取多个sheet** @param inputStream  文件流* @param sheetNum     需要读取的sheet个数(默认0开始,如果传入2,则读取0、1)* @param sheetObjList 每个sheet里面需要封装的对象(如果index为2,则需要传入对应的2个对象)* @param <T>* @return*/public static <T> List<List<T>> importExcels(InputStream inputStream, int sheetNum, List<T> sheetObjList, ReadExcelListener<T> readExcelListener) throws Exception {List<List<T>> resultList = new LinkedList<>();for (int index = 0; index < sheetNum; index++) {Class<T> tClass = (Class<T>) sheetObjList.get(index).getClass();EasyExcelFactory.read(inputStream, tClass, readExcelListener).sheet(index).doRead();List<T> list = readExcelListener.getList();resultList.add(list);}return resultList;}/*** 导出excel表格-列不确定情况;只导出模板【一个处理器】** @param response* @param headList     表头列表* @param dataList     数据列表* @param fileName     文件名称* @param sheetName    sheet名称* @param writeHandler 处理器* @throws Exception*/public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, String fileName, String sheetName, WriteHandler writeHandler) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();// 这里注意如果同一个sheet只要创建一次ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);if (null != writeHandler) {sheetBuilder.registerWriteHandler(writeHandler);}WriteSheet writeSheet = sheetBuilder.build();excelWriter.write(dataList, writeSheet);excelWriter.finish();}/*** 导出excel表格-列不确定情况;只导出模板【多个处理器】** @param response* @param headList      表头列表* @param dataList      数据列表* @param fileName      文件名称* @param sheetName     sheet名称* @param writeHandlers 处理器集合* @throws Exception*/public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, String fileName, String sheetName, List<WriteHandler> writeHandlers) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();// 这里注意如果同一个sheet只要创建一次ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);if (CollUtil.isNotEmpty(writeHandlers)) {for (WriteHandler writeHandler : writeHandlers) {sheetBuilder.registerWriteHandler(writeHandler);}}WriteSheet writeSheet = sheetBuilder.build();excelWriter.write(dataList, writeSheet);excelWriter.finish();}/*** 导出excel表格-不支持设置样式** @param response* @param dataList  数据列表* @param clazz     数据对象* @param fileName  文件名称* @param sheetName sheet名称* @throws Exception*/public static <T> void exportExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());EasyExcelFactory.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);}/*** 导出excel表格-支设置单元格样式** @param response* @param dataList     数据列表* @param clazz        数据对象* @param fileName     文件名称* @param sheetName    sheet名称* @param writeHandler 处理器* @throws Exception*/public static <T> void exportWriteHandlerExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName, WriteHandler writeHandler) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz).build();// 这里注意如果同一个sheet只要创建一次WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).registerWriteHandler(writeHandler).build();excelWriter.write(dataList, writeSheet);excelWriter.finish();}/*** 导出多个sheet** @param response* @param dataList 多个sheet数据列表* @param clazzMap 对应每个sheet列表里面的数据对应的sheet名称* @param fileName 文件名* @param <T>* @throws Exception*/public static <T> void exportExcels(HttpServletResponse response, List<List<?>> dataList, Map<Integer, String> clazzMap, String fileName) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();int sheetNum = dataList.size();for (int i = 0; i < sheetNum; i++) {List<?> objects = dataList.get(i);Class<?> aClass = objects.get(0).getClass();WriteSheet writeSheet0 = EasyExcel.writerSheet(i, clazzMap.get(i)).head(aClass).build();excelWriter.write(objects, writeSheet0);}excelWriter.finish();}/*** 根据模板将集合对象填充表格** @param inputStream 模板文件输入流* @param response    模板文件输出流* @param list        填充对象集合* @param fileName    文件名称* @param sheetName   需要写入的sheet(不传:填充到第一个sheet)* @throws Exception*/public static <T> void exportTemplateExcelList(InputStream inputStream, HttpServletResponse response, List<T> list, String fileName, String sheetName) throws Exception {// 全部填充:全部加载到内存中一次填充if (StringUtils.isBlank(sheetName)) {EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet().doFill(list);} else {EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet(sheetName).doFill(list);}}/*** 根据模板将集合对象填充表格-单个sheet** @param inputStream 模板文件输入流* @param list        填充对象集合-元素对应模板中的.{}* @param object      填充对象-元素对应模板中的{}* @param fileName    文件名称* @throws Exception*/public static <T> void exportTemplateSheet(InputStream inputStream, HttpServletResponse response, List<T> list, Object object, String fileName) throws Exception {FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();// 全部填充:全部加载到内存中一次填充excelWriter.fill(object, fillConfig, writeSheet0);excelWriter.fill(list, fillConfig, writeSheet0);// 可分多次填充,使用文件缓存(省内存)// excelWriter.fill(list1, writeSheet);// excelWriter.fill(list2, writeSheet);excelWriter.finish();}/*** 根据模板将集合对象填充表格-多个sheet** @param inputStream 模板文件输入* @param response    模板文件输出流* @param list1       填充对象集合-元素对应模板中的.{}* @param list2* @param object1     填充对象-元素对应模板中的{}* @param object2* @param fileName    文件名称* @throws Exception*/public static <T> void exportTemplateSheets(InputStream inputStream, HttpServletResponse response, List<T> list1, List<T> list2,Object object1, Object object2, String fileName) throws Exception {FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();WriteSheet writeSheet1 = EasyExcelFactory.writerSheet(1).build();excelWriter.fill(object1, fillConfig, writeSheet0);excelWriter.fill(list1, fillConfig, writeSheet0);excelWriter.fill(object2, fillConfig, writeSheet1);excelWriter.fill(list2, fillConfig, writeSheet1);excelWriter.finish();}/*** 构建输出流** @param fileName 文件名称* @param response 模板文件输出流* @param response* @return* @throws Exception*/private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setHeader("Content-Disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());return response.getOutputStream();}/*** 文件格式校验** @param file*/public static void checkFile(MultipartFile file) {if (file == null) {throw new RuntimeException("文件不能为空!");}String fileName = file.getOriginalFilename();if (StringUtils.isEmpty(fileName)) {throw new RuntimeException("文件名称不能为空!");}if (!fileName.endsWith(FileTypeEnum.TEMPLATE_SUFFIX.getDesc())&& !fileName.endsWith(FileTypeEnum.TEMPLATE_SUFFIX_XLS.getDesc())) {throw new RuntimeException("请上传.xlsx或.xls文件!");}}
}
/*** @ClassName: ExcelHeadStyles* @Description: excel表头颜色定义* @Author: * @Date: */
@Data
public class ExcelHeadStyles {/*** 表头横坐标 - 行*/private Integer rowIndex;/*** 表头纵坐标 - 列*/private Integer columnIndex;/*** 内置颜色*/private Short indexColor;/*** 字体颜色*/private Short fontColor;public ExcelHeadStyles(Integer columnIndex, Short fontColor) {this.columnIndex = columnIndex;this.fontColor = fontColor;}public ExcelHeadStyles(Integer rowIndex, Integer columnIndex, Short fontColor) {this.rowIndex = rowIndex;this.columnIndex = columnIndex;this.fontColor = fontColor;}}
/*** @ClassName: FileTypeEnum* @Description: 文件类型枚举* @Author: * @Date: */
@Getter
public enum FileTypeEnum {/*** 模板格式*/TEMPLATE_SUFFIX("xlsx", ".xlsx"),TEMPLATE_SUFFIX_XLS("xls", ".xls"),TEMPLATE_SUFFIX_DOCX("docx", ".docx");private final String code;private final String desc;FileTypeEnum(String code, String desc) {this.code = code;this.desc = desc;}/*** 通过code获取msg** @param code 枚举值* @return*/public static String getMsgByCode(String code) {if (code == null) {return null;}FileTypeEnum enumList = getByCode(code);if (enumList == null) {return null;}return enumList.getDesc();}public static String getCode(FileTypeEnum enumList) {if (enumList == null) {return null;}return enumList.getCode();}public static FileTypeEnum getByCode(String code) {for (FileTypeEnum enumList : values()) {if (enumList.getCode().equals(code)) {return enumList;}}return null;}
}
/*** @ClassName: ReadExcelListener* @Description: 读取excel文件数据监听器* @Author: * @Date: */
@Slf4j
public abstract class ReadExcelListener<T> extends AnalysisEventListener<T> {private static final int BATCH_COUNT = 10000;/*** 数据集*/private final List<T> list = new ArrayList<>();/*** 表头数据*/private Map<Integer, String> headMap = null;private Map<String, Object> params;// 获取数据集public List<T> getList() {return this.list;}// 获取表头数据public Map<Integer, String> getHeadMap() {return this.headMap;}/*** 每条数据都会进入** @param object* @param analysisContext*/@Overridepublic void invoke(T object, AnalysisContext analysisContext) {this.list.add(object);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}/*** 数据解析完调用** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 读取到的表头信息** @param headMap* @param context*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {this.headMap = headMap;}/*** 异常时调用** @param exception:* @param context:* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {// 数据解析异常if (exception instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;throw new RuntimeException("第" + excelDataConvertException.getRowIndex() + "行" + excelDataConvertException.getColumnIndex() + "列" + "数据解析异常");}// 其他异常...}/*** 数据存储到数据库*/public abstract boolean saveData();
}
/*** @ClassName: RowMergeStrategy* @Description: 自定义行合并策略* @Author: * @Date: */
public class RowMergeStrategy extends AbstractMergeStrategy {/*** 分组,每几行合并一次*/private List<Integer> exportFieldGroupCountList;/*** 目标合并列index*/private Integer targetColumnIndex;// 需要开始合并单元格的首行indexprivate Integer rowIndex;// exportDataList为待合并目标列的值public RowMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {this.exportFieldGroupCountList = getGroupCountList(exportDataList);this.targetColumnIndex = targetColumnIndex;}@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {if (null == rowIndex) {rowIndex = cell.getRowIndex();}// 仅从首行以及目标列的单元格开始合并,忽略其他if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {mergeGroupColumn(sheet);}}private void mergeGroupColumn(Sheet sheet) {int rowCount = rowIndex;for (Integer count : exportFieldGroupCountList) {if (count == 1) {rowCount += count;continue;}// 合并单元格CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);sheet.addMergedRegionUnsafe(cellRangeAddress);rowCount += count;}}// 该方法将目标列根据值是否相同连续可合并,存储可合并的行数private List<Integer> getGroupCountList(List<String> exportDataList) {if (CollUtil.isEmpty(exportDataList)) {return new ArrayList<>();}List<Integer> groupCountList = new ArrayList<>();int count = 1;for (int i = 1; i < exportDataList.size(); i++) {if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {count++;} else {groupCountList.add(count);count = 1;}}groupCountList.add(count);return groupCountList;}
}
/*** @ClassName: ImportDataListener* @Description: 导入数据监听器* @Author: * @Date: */
@Component
public class ImportDataListener extends ReadExcelListener {@Resourceprivate IStudentService studentService;/*** 实现数据保存逻辑-直接操作表头和行数据** @return*/@Overridepublic boolean saveData() {Map<Integer, String> headMap = getHeadMap();List dataList = getList();if (CollUtil.isEmpty(headMap) || CollUtil.isEmpty(dataList)) {return false;}return studentService.batchSaveStudent(dataList, headMap);}
}
/*** @ClassName: ImportStudentListener* @Description: 导入学生excel数据监听器* @Author: * @Date: */
@Component
public class ImportUserListener extends ReadExcelListener {@Resourceprivate IStudentService studentService;@Resourceprivate ITeacherService teacherService;/*** 实现数据保存逻辑** @return*/@Overridepublic boolean saveData() {List dataList = getList();if (CollUtil.isEmpty(dataList)) {return false;}Object obj = dataList.get(0);if (obj instanceof Student) {return studentService.batchSaveStudent(dataList);} else if (obj instanceof Teacher) {return teacherService.batchSaveTeacher(dataList);}return true;}
}
/*** @ClassName: UserExcelHeadHandler* @Description: 用户相关excel处理器* @Author: * @Date: */
public class UserExcelHeadHandler extends HorizontalCellStyleStrategy {private ExcelHeadStyles excelHeadStyle;public UserExcelHeadHandler(ExcelHeadStyles excelHeadStyle) {this.excelHeadStyle = excelHeadStyle;}//设置头样式@Overrideprotected void setHeadCellStyle(CellWriteHandlerContext context) {int columnNo = excelHeadStyle.getColumnIndex();WriteCellStyle headWriteCellStyle = new WriteCellStyle();headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short) 11);if (context.getColumnIndex() <= columnNo) {headWriteFont.setColor(excelHeadStyle.getFontColor());} else {headWriteFont.setColor(IndexedColors.BLACK.getIndex());}headWriteCellStyle.setWriteFont(headWriteFont);if (stopProcessing(context)) {return;}WriteCellData<?> cellData = context.getFirstCellData();WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());}
}
/*** @ClassName: ExportController* @Description: 导出前端控制器* @Author: * @Date: */
@Slf4j
@RestController
public class ExportController {@Resourceprivate IStudentService studentService;@Resourceprivate ITeacherService teacherService;private static final String[] USER_HEAD_FIELDS = new String[]{"序号", "学号", "姓名", "性别"};/*** 导出学生数据-一个sheet** @param response*/@GetMapping("/student/export/sheet")public void exportSheetStudent(HttpServletResponse response) {List<Student> students = studentService.listStudent(10L);log.info("单sheet学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {EasyExcelUtil.exportExcel(response, students, Student.class, "导出学生数据-一个sheet", "第一页");} catch (Exception e) {log.error("单sheet学生数据导出异常!", e);}log.info("单sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 导出学生数据-多个sheet** @param response*/@GetMapping("/student/export/sheets")public void exportSheetsStudent(HttpServletResponse response) {log.info("多sheet学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {List<List<?>> sheetList = new ArrayList<>();List<Student> students1 = studentService.listStudent(10L);List<Student> students2 = studentService.listStudent(20L);sheetList.add(students1);sheetList.add(students2);Map<Integer, String> clazzMap = new HashMap<>();clazzMap.put(0, "sheet1");clazzMap.put(1, "sheet2");EasyExcelUtil.exportExcels(response, sheetList, clazzMap, "导出学生数据-多个sheet");} catch (Exception e) {log.error("多sheet学生数据导出失败!", e);}log.info("多sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 导出学生数据-重复行合并格式** @param response*/@GetMapping("/student/export/mergeRow")public void exportMergeRowStudent(HttpServletResponse response) {log.info("合并格式学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);List<String> mergeDataList = students.stream().map(Student::getSex).collect(Collectors.toList());EasyExcelUtil.exportWriteHandlerExcel(response, students, Student.class, "学生重复数据表格合并", "第一页", new RowMergeStrategy(mergeDataList, 3));} catch (Exception e) {log.error("合并格式学生数据导出失败!", e);}log.info("合并格式学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 下载导入学生数据的模板【一个自定义Handler】** @param response*/@GetMapping("/student/downTemplate001")public void downTemplateStudent001(HttpServletResponse response) {log.info("设置单元格宽度-学生数据模板开始下载...");long startTimeL = System.currentTimeMillis();try {List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).collect(Collectors.toList());CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度", "student", columnWidthHandler);} catch (Exception e) {log.error("设置单元格宽度-学生数据模板下载失败!", e);}log.info("设置单元格宽度-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 下载导入学生数据的模板【多个自定义Handler】** @param response*/@GetMapping("/student/downTemplate002")public void downTemplateStudent002(HttpServletResponse response) {log.info("设置单元格宽度+字体-学生数据模板开始下载...");long startTimeL = System.currentTimeMillis();try {List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).collect(Collectors.toList());// 表头第一行的指定前3列字标红ExcelHeadStyles excelHeadStyle = new ExcelHeadStyles(0, 3, IndexedColors.RED1.getIndex());UserExcelHeadHandler headHandler = new UserExcelHeadHandler(excelHeadStyle);CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度+字体", "student", CollUtil.newArrayList(headHandler, columnWidthHandler));} catch (Exception e) {log.error("设置单元格宽度+字体-学生数据模板下载失败!", e);}log.info("设置单元格宽度+字体-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/**************以下填充模板数据的接口测试说明:可改为get请求,InputStream可使用本地文件输入流,然后变可通过浏览器下载。******************************//*** 根据模板将集合对象填充表格-list** @param template* @param response*/@PostMapping("/student/template/fill-list")public void exportFillTemplateList(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充学生数据,list,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List students = studentService.listStudent(10L);EasyExcelUtil.exportTemplateExcelList(template.getInputStream(), response, students, "填充学生模板数据-list", "students");} catch (Exception e) {log.error("根据模板填充学生数据,list,文件下载失败!", e);}log.info("根据模板填充学生数据,list,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 根据模板将集合对象填充表格-单个sheet** @param template* @param response*/@PostMapping("/student/template/fill-sheet")public void exportFillTemplateSheet(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充学生数据,单个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(3);map.put("startMonth", "2023-8-10");map.put("endMonth", "2023-8-12");EasyExcelUtil.exportTemplateSheet(template.getInputStream(), response, students, map, "填充学生模板数据-sheet");} catch (Exception e) {log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);}log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 根据模板将集合对象填充表格-多个sheet** @param template* @param response*/@PostMapping("/student/template/fill-sheets")public void exportFillTemplateSheets(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充数据,多个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(2);map.put("startMonth", "2023-8-10");map.put("endMonth", "2023-8-12");List teachers = teacherService.listTeacher(10L);Map<String, Object> map2 = new HashMap<>(1);map2.put("illustrate", "老师人员列表");EasyExcelUtil.exportTemplateSheets(template.getInputStream(), response, students, teachers, map, map2, "填充学生模板数据-sheets");} catch (Exception e) {log.error("根据模板填充数据,多个sheet,文件下载失败!", e);}log.info("根据模板填充数据,多个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/********转为get请求测试示例********//*** get请求测试** @param response*/@GetMapping("/student/template/test")public void test(HttpServletResponse response) throws FileNotFoundException {File file = new File("C:\\Users\\Administrator\\Desktop\\test.xlsx");FileInputStream inputStream = new FileInputStream(file);log.info("根据模板填充学生数据,单个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(3);map.put("startMonth", "2023-8-10");map.put("endMonth", "2023-8-12");EasyExcelUtil.exportTemplateSheet(inputStream, response, students, map, "填充学生模板数据-sheet");} catch (Exception e) {log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);}log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}
}
/*** @ClassName: ImportController* @Description: 导入前端控制器* @Author: * @Date: */
@Slf4j
@RestController
public class ImportController {@Resourceprivate ImportUserListener importUserListener;/*** 导入一个sheet学生数据** @param file*/@PostMapping("/student/import/sheet")public boolean importSheetStudent(@RequestParam("file") MultipartFile file) {EasyExcelUtil.checkFile(file);log.info("一个sheet学生数据开始导入...");long startTime = System.currentTimeMillis();List<Student> dataList = null;try {dataList = EasyExcelUtil.importExcel(file.getInputStream(), null, null, importUserListener);// 数据录入Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");} catch (Exception e) {log.error("一个sheet学生数据导入失败!", e);}log.info("一个sheet学生数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));return true;}/*** 导入多个sheet学生数据** @param file*/@PostMapping("/student/import/sheets")public boolean importSheets(@RequestParam("file") MultipartFile file) {EasyExcelUtil.checkFile(file);log.info("多个sheet数据开始导入...");long startTime = System.currentTimeMillis();List<Student> dataList = null;try {List sheetObjList = new ArrayList(2);sheetObjList.add(Student.class);sheetObjList.add(Teacher.class);dataList = EasyExcelUtil.importExcels(file.getInputStream(), 2, sheetObjList, importUserListener);// 数据录入Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");} catch (Exception e) {log.error("多个sheet数据导入失败!", e);}log.info("多个sheet数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));return true;}
}
/*** @ClassName: Student* @Description: 学生* @Author: * @Date: **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {@ExcelProperty("序号")private Integer num;@ExcelProperty("学号")private String sno;@ExcelProperty("学生名字")private String name;@ExcelProperty("性别")private String sex;
}
/*** @ClassName: Teacher* @Description: 老师* @Author: * @Date: **/
@Data
public class Teacher {@ExcelProperty("编号")private String sno;@ExcelProperty("老师名字")private String name;@ExcelProperty("性别")private String sex;
}
/*** @ClassName: TeacherServiceImpl* @Description: 老师相关接口实现* @Author: * @Date: */
@Slf4j
@Service
public class TeacherServiceImpl implements ITeacherService {@Overridepublic List<Teacher> listTeacher(Long limit) {List<Teacher> teachers = new ArrayList<>();for (int i = 0; i < limit; i++) {Teacher teacher = new Teacher();teacher.setSex("女");teacher.setName("老师A" + i);teacher.setSno(UUID.fastUUID().toString());teachers.add(teacher);}return teachers;}@Overridepublic boolean batchSaveTeacher(List<Teacher> teachers) {// 调用dao层接口保存数据...log.info("批量保存老师数据,共:{}条数据", teachers.size());return true;}}
/*** @ClassName: StudentServiceImpl* @Description: 学生相关接口实现* @Author: * @Date: */
@Slf4j
@Service
public class StudentServiceImpl implements IStudentService {@Overridepublic List<Student> listStudent(Long limit) {List<Student> students = new ArrayList<>();for (int i = 0; i < limit; i++) {Student student = new Student();student.setSex("男");student.setNum(i);student.setName("小A" + i);student.setSno(UUID.fastUUID().toString());students.add(student);}return students;}@Overridepublic boolean batchSaveStudent(List<Student> students) {// 调用dao层接口保存数据...log.info("批量保存学生数据,共:{}条数据", students.size());return true;}@Overridepublic boolean batchSaveStudent(List<Map<Integer, String>> dataList, Map<Integer, String> headMap) {// 这里可以针对读取到的表头数据和对应的行数据,这种应用场景适用于导入的excel中数据需要我们自己解析做其他业务处理,或者表头列是动态的,我们// 没有办法使用一个固定的实体做映射log.info("表头列数据:{}", headMap.values());log.info("批量保存学生数据,共:{}条数据", dataList.size());return true;}
}

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

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

相关文章

HTTP和HTTPS区别!

http 是我们几乎天天都要打交道的东西&#xff0c;相关知识点有点多&#xff0c;所以也有不少面试必问的点&#xff0c;这里做了一些整理&#xff0c;帮且大家树立完整的 http 知识体系&#xff0c;对面试官说 so easy HTTP 的特点和缺点 特点&#xff1a;无连接、无状态、灵…

运行vue3项目出现的问题

Mac 系统运行 vue 启动项目时报错: Permission denied 的解决方式 控制台运行 chmod 777 node_modules/.bin/vue-cli-service 如果 npm run dev 还报这个错 控制台运行 node node_modules/esbuild/install.js

day44_jdbc

今日内容 0 复习昨日 1 讲作业 2 数据库连接池(druid) 3 反射 4 改造DBUtil 5 完成CRUD练习 0 复习昨日 1 sql注入 2 预处理语句 3 事务操作 4 DBUtil 1 作业【重要】 利用ORM完成,以下的几个方法非常重要,将来写项目就是这些操作 写项目步骤 搭建环境 创建项目导入依赖工具类数…

Oracle笔记-为表空间新增磁盘(ORA-01691)

如下报错&#xff1a; 原因是Oracle表空间满了&#xff0c;最好是新增一个存储盘。 #查XXX命名空间目前占用了多大的空间 select FILE_NAME,BYTES/1024/1024 from dba_data_files where tablespace_name XXXX #这里的FILE_NAME能查到DBF的存储位置#将对应的datafile设置为30g…

流量控制原理

目的是接收方通过TCP头窗口字段告知发送方本方可接收的最大数据量&#xff0c;用以解决发送速率过快导致接收方不能接收的问题。所以流量控制是点对点控制。 TCP是双工协议&#xff0c;双方可以同时通信&#xff0c;所以发送方接收方各自维护一个发送窗和接收窗。 发送窗&…

ffmpeg命令生成器

FFmpeg 快速入门&#xff1a;命令行详解、工具、教程、电子书 – 码中人的博客FFmpeg 是一个强大的命令行工具&#xff0c;可以用来处理音频、视频、字幕等多媒体文件。本文介绍了 FFmpeg 的基本用法、一些常用的命令行参数&#xff0c;以及常用的可视化工具。https://blog.mzh…

Golang与Erlang有什么差异

Golang和Erlang是两种备受关注的编程语言&#xff0c;它们各自具有独特的特点和优势。下面我将简单的探讨一下Golang和Erlang之间的差异&#xff0c;并且分析它们在并发模型、运行环境、函数式编程和领域特性等多个方面的不同之处。 并发模型 Golang使用goroutines和channels…

Java设计模式大全:23种常见的设计模式详解(二)

本系列文章简介&#xff1a; 设计模式是在软件开发过程中&#xff0c;经过实践和总结得到的一套解决特定问题的可复用的模板。它是一种在特定情境中经过验证的经验和技巧的集合&#xff0c;可以帮助开发人员设计出高效、可维护、可扩展和可复用的软件系统。设计模式提供了一种在…

Vivado用ILA抓波形保存为CSV文件

将ILA观察到的波形数据捕获为CSV文件&#xff0c;抓10次&#xff0c;把文件合并&#xff0c;把源文件删除 运行方法&#xff1a;Vivado的 Tcl console 窗口输入命令 set tcl_dir F:/KLD_FPGA/Code/sim set tcl_filename TCL_ILA_TRIG_V1.2.tcl source $tcl_dir/$tcl_filenam…

计算机是如何工作的

计算机工作 计算机发展史CPU基本工作流程编程语言程序&#xff08;Program&#xff09;编程语言的发展 操作系统进程/任务进程控制块CPU分配&#xff08;进程调度&#xff09;内存分配&#xff08;内存管理&#xff09;进程间通信 计算机发展史 四个发展阶段&#xff1a; 第一…

python创建udf函数步骤

一、目标 实现一个函数&#xff0c;传入两个datetime类型的参数&#xff0c;返回double类型的工作日天数 二、思路 如何计算差值&#xff1f; 如果开始时间和结束时间在同一天&#xff1a;实现同 datediff(end, start, ‘ss’) / 86400.0 如果开始时间和结束时间在不同天&am…

3. ⼤语⾔模型深度学习背景知识

1. LLM⼤语⾔模型⼀般训练过程 #mermaid-svg-8kci1fjEPiVolPue {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8kci1fjEPiVolPue .error-icon{fill:#552222;}#mermaid-svg-8kci1fjEPiVolPue .error-text{fill:#5522…

QML用ListView实现带section的GridView

QML自带的GridView只能定义delegate&#xff0c;没有section&#xff0c;类似手机相册带时间分组标签的样式就没法做。最简单的方式就是组合ListViewGridView&#xff0c;或者ListViewFlow&#xff0c;但是嵌套View时&#xff0c;子级View一般是完全展开的&#xff0c;只显示该…

Mybatis中的sql-xml延迟加载机制

Mybatis中的sql-xml延迟加载机制 hi&#xff0c;我是阿昌&#xff0c;今天记录一下关于Mybatis中的sql-xml延迟加载机制 一、前言 首先mybatis技术本身就不多介绍&#xff0c;说延迟加载机制之前&#xff0c;那要先知道2个概念&#xff1a; 主查询对象关联对象 假设咱们现…

WPF绘制矢量图形并绑定到界面的方法

这里先封装一个方法&#xff0c;使用的时候先创建一个Draw&#xff0c;拿到DrawingContext 之后就可以通过DrawingContext 去绘制想要的图形&#xff0c;绘制完成后通过GetDraw拿到所有绘制的结果 添加一个PrintImage()用于测试当前绘图的样子用于测试 public class DrawVector…

OpenCV 笔记(20):霍夫圆检测

1. 霍夫圆变换 霍夫圆变换(Hough Circle Transform)是一种数字图像处理中的特征提取技术&#xff0c;用于在图像中检测圆形。它将二维图像空间中一个圆转换为该圆半径、圆心横纵坐标所确定的三维参数空间中一个点的过程。因此&#xff0c;圆周上任意三点所确定的圆&#xff0c…

ElasticSearch查询语句用法

查询用法包括&#xff1a;match、match_phrase、multi_match、query_string、term 1.match 1.1 不同字段权重 如果需要为不同字段设置不同权重&#xff0c;可以考虑使用bool查询的should子句来组合多个match查询&#xff0c;并为每个match查询设置不同的权重 {"query&…

二叉树的详解

二叉树 【本节目标】 掌握树的基本概念掌握二叉树概念及特性掌握二叉树的基本操作完成二叉树相关的面试题练习 树型结构&#xff08;了解&#xff09; 概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。…

MySQL深入——18

我们来看看一主多从的情况 比如A是主库&#xff0c;A’ B C D都是副库&#xff0c;但A与A互为备库&#xff0c;当A库出现问题&#xff0c;我现在要将主库转到A’该怎么办。 以下是基于位点的主备切换 CHANGE MASTER TO MASTER_HOST$host_name MASTER_PORT$port MASTER_USER…

JS-本地文件上传

由于不需要原上传文件的样式&#xff0c;所以自己书写了一个按钮触发文件上传&#xff0c;并将原本的样式隐藏 <!doctype html> <html><head><meta charset"utf-8"><title>文件传输</title> </head><body><inpu…