Java中使用EasyExcel
Java中使用EasyExcel
文章目录
- Java中使用EasyExcel
- 一:EasyExcel介绍
- 1.1、核心函数
- 导入数据
- 导出数据
- 1.2、项目实际应用
- 导入数据
- 导出数据
- 1.3、相关注解
- @ExcelProperty
- 作用
- 示例
- 二:EasyExcel使用
- 2.1、导入功能
- 2.2、导出功能
- 三:EasyExcel完整代码,异步导入导出+任务管理
- 3.1、异步导入+记录导入失败文件导出+模版检查+模版参数检查
- 1、controller层:
- 2、serviceImpl层:
- 3、枚举方法
- 4.检查模板Listener
- 3.2、下载导出文件
- 3.3、异常情况处理
- 1、字符库缺失:Mac或者Windows正常,Linux报错
一:EasyExcel介绍
- EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。它能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能,主体由阿里团队封装并维护。
- 本文示例所呈现的主体功能为导入,其中涵盖导入过程中自动记录解析的数据错误,并以 excel 的形式返回给前端,以及 excel 模板校验错误等情况;
<!-- easyexcel -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version>
</dependency>
对于简单使用:EasyExcel简单Demo,查看基础Demo示例
官网链接:EasyExcel官网
1.1、核心函数
导入数据
String filePath = "C:\\Users\\fkjas\\Desktop\\lixl\\test.xlsx";
EasyExcel.read(filePath, User.class, new ExcelListener()).sheet().doRead();
导出数据
String filePath = "C:\\Users\\fkjas\\Desktop\\lixl\\test.xlsx";
EasyExcel.write(filePath, User.class).sheet("学生信息表").doWrite(list);
1.2、项目实际应用
导入数据
List<User> userList = EasyExcel.read(newBufferedInputStream(file.getInputStream())).head(User.class).sheet().doReadSync();
导出数据
EasyExcel.write(httpServletResponse.getOutputStream(), User.class).sheet("用户信息").doWrite(userList);
1.3、相关注解
@ExcelProperty
作用
标注列名以及各列的前后顺序
示例
@ExcelProperty(index = 0, value = "姓名")
private String userName;
二:EasyExcel使用
2.1、导入功能
思路:读取文件-》创建ExcelListener-》在Listener中封装处理数据-》批量处理
/*** 文件上传* <p>* 1. 创建excel对应的实体对象 参照{@link UploadData}* <p>* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}* <p>* 3. 直接读即可*/@PostMapping("upload")@ResponseBodypublic String upload(MultipartFile file) throws IOException {EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();return "success";}
2.2、导出功能
思路1:创建导出数据集-》调用EasyExcel的能力-》批量处理–》将结果传递到浏览器请求中,直接响应到浏览器下载
/*** 文件下载(失败了会返回一个有部分数据的Excel)* <p>* 1. 创建excel对应的实体对象 参照{@link DownloadData}* <p>* 2. 设置返回的 参数* <p>* 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大*/@GetMapping("download")public void download(HttpServletResponse response) throws IOException {// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());}
思路2:创建导出数据集-》调用EasyExcel的能力-》批量处理–》将结果保存成为一个文件,记录任务,通过接口调用任务id进行下载文件
//5.开始保存错误日志,将错误信息导出excel表格//本地文件全路径String fileExportPath = fileFolderPath + File.separator + taskCodeEnum.getDesc() + "-失败-" + DateUtil.getUniqueIdentifier() + "." + fileNamePrefix;try (ExcelWriter excelWriter = EasyExcel.write(fileExportPath, WarehouseGoodsPriceErrorWriteReq.class).build()) {// 这里注意 如果同一个sheet只要创建一次WriteSheet writeSheet = EasyExcel.writerSheet("失败数据1").build();excelWriter.write(failList, writeSheet);} catch (Exception e) {//如果Linux中出现null,https://easyexcel.opensource.alibaba.com/qa/#%E6%88%91%E5%9C%A8%E6%9C%AC%E5%9C%B0%E5%8F%AF%E4%BB%A5%E5%8F%91%E5%B8%83%E5%88%B0%E7%BA%BF%E4%B8%8A%E7%8E%AF%E5%A2%83%E6%80%8E%E4%B9%88%E4%B8%8D%E5%8F%AF%E4%BB%A5%E4%BA%86//Linux下执行:yum install dejavu-sans-fonts fontconfig -y /或者重装: sudo yum reinstall fontconfig -y//确认: find /usr -name libfontconfig.so.1log.error("easyExcel:导出excel失败", e);puTaskRepo.updateTaskStatus(taskId, ExcelHandlerStatusEnum.FAILED.getCode());}
三:EasyExcel完整代码,异步导入导出+任务管理
3.1、异步导入+记录导入失败文件导出+模版检查+模版参数检查
1、controller层:
@ApiOperation(value = "导入excel模版,根据模版code来创建任务")@Valid@PostMapping("/importFile")public Result<Long> importFile(@ApiParam(name = "file", value = "文件") @RequestParam("file") MultipartFile file,@ApiParam(name = "templateCode", value = "模版templateCode") @NotBlank(message = "模版templateCode不能为空") String templateCode) {Long taskId= excelFileService.importFile(file, templateCode);return Result.ok(taskId);}
2、serviceImpl层:
@Overridepublic Long importFile(MultipartFile multipartFile, String templateCode) {Map<String, String> map = ExcelImportTaskEnum.getMap();Long currentUserId = UserContext.getCurrentUserId();if (ObjectUtil.isEmpty(map)) {throw new ServiceException("任务不存在");}if (ObjectUtil.isNotEmpty(map)) {if (!map.containsKey(templateCode)) {throw new ServiceException("不支持此类任务,请联系管理员");}}Template template = templateRepo.getByCode(templateCode);if (ObjectUtil.isEmpty(template)) {throw new ServiceException("模板不存在");}String originalFilename = multipartFile.getOriginalFilename();String fileNamePrefix = FileUtil.getFileNamePrefix(originalFilename);ExcelImportTaskEnum taskCodeEnum = ExcelImportTaskEnum.getEnum(template.getCode());Long taskId;switch (taskCodeEnum) {//批量仓库门店价格修改case WAREHOUSE_GOODS_PRICE:taskId = handlerImportWarehouseGoodsPrice(currentUserId, multipartFile, taskCodeEnum, fileNamePrefix, template);break;default:throw new ServiceException("不支持此类型模版code");}return taskId;}/*** 获取文件名只获取后缀** @param fileName* @return*/public static String getFileNamePrefix(String fileName) {String extName = fileName.substring(fileName.lastIndexOf(".") + 1);return ObjectUtil.isEmpty(extName) ? "" : extName;}
3、枚举方法
package com.kkd.web.admin.model.enums;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;import java.util.EnumSet;
import java.util.Map;
import java.util.stream.Collectors;/*** @beLongProjecet: kkd-all* @beLongPackage: com.kkd.web.admin.model.enums* @author: xiaoxiangyuan* @createTime: 2024/08/23 15:05* @description:* @version: v1.0*/
@Getter
@AllArgsConstructor
@Slf4j
public enum ExcelImportTaskEnum {//模版任务WAREHOUSE_GOODS_PRICE("warehouseGoodsPrice", "批量修改仓库商品价格"),;private String code;private String desc;public static ExcelImportTaskEnum getEnum(String code) {for (ExcelImportTaskEnum thirdTypeEnum : ExcelImportTaskEnum.values()) {if (thirdTypeEnum.getCode().equals(code)) {return thirdTypeEnum;}}return null;}public static String getDesc(String code) {for (ExcelImportTaskEnum thirdTypeEnum : ExcelImportTaskEnum.values()) {if (thirdTypeEnum.getCode().equals(code)) {return thirdTypeEnum.getDesc();}}return null;}public static boolean checkCodeExist(String code) {for (ExcelImportTaskEnum thirdTypeEnum : ExcelImportTaskEnum.values()) {if (thirdTypeEnum.getCode().equals(code)) {return true;}}return false;}public static Map<String, String> getMap() {Map<String, String> map = EnumSet.allOf(ExcelImportTaskEnum.class).stream().collect(Collectors.toMap(ExcelImportTaskEnum::getCode, ExcelImportTaskEnum::getDesc));return map;}public static void main(String[] args) {log.info("getMap()的值为:{}", getMap());}
}
/*** 批量仓库门店价格修改** @param currentUserId* @param multipartFile* @param taskCodeEnum* @param fileNamePrefix* @param template*/private Long handlerImportWarehouseGoodsPrice(Long currentUserId, MultipartFile multipartFile, ExcelImportTaskEnum taskCodeEnum, String fileNamePrefix, Template template) {//1.校验模版头信息try {CheckHeaderListener headerValidationListener = new CheckHeaderListener(WarehouseGoodsPriceReadReq.class);EasyExcel.read(new BufferedInputStream(multipartFile.getInputStream()), WarehouseGoodsPriceReadReq.class, headerValidationListener).headRowNumber(1).sheet().doRead();} catch (IOException e) {throw new ServiceException("导入文件失败,请稍后重试");}//2.将导入文件临时存入服务器String fileFolderPath = getFileFolderPath();FileUtil.createFolder(fileFolderPath);//本地文件全路径String fileImportPath = fileFolderPath + File.separator + taskCodeEnum.getDesc() + "-" + DateUtil.getUniqueIdentifier() + "." + fileNamePrefix;try {//将文件保存到指定路径multipartFile.transferTo(new File(fileImportPath));} catch (IOException e) {log.error("保存文件异常", e);throw new ServiceException("保存文件异常");}//3.创建任务PuTask puTask = new PuTask();puTask.setFunctionType(ExcelFunctionTypeEnum.IMPORT_FILE.getCode());puTask.setOrgId(UserContext.getCurrentOrgId());puTask.setOperatorId(currentUserId);puTask.setTemplateCode(template.getCode());puTask.setStatus(ExcelHandlerStatusEnum.IN_PROGRESS.getCode());puTaskRepo.save(puTask);Long taskId = puTask.getId();try {//4.提交异步任务CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {puTaskRepo.updateTaskStatus(taskId, ExcelHandlerStatusEnum.IN_PROGRESS.getCode());WarehouseGoodsPriceListener listener = new WarehouseGoodsPriceListener();listener.setCurrentUserId(currentUserId);EasyExcel.read(fileImportPath, WarehouseGoodsPriceReadReq.class, listener).sheet().doRead();Integer successCount = listener.getSuccessCount();Integer allCount = listener.getAllCount();List<WarehouseGoodsPriceErrorWriteReq> failList = listener.getFailList();Integer errorCount = ObjectUtil.isEmpty(failList) ? 0 : failList.size();String handlerResult = "总条数:" + allCount + ",成功条数:" + successCount + ",失败条数:" + errorCount;puTask.setHandleResult(handlerResult);if (ObjectUtil.isNotEmpty(failList)) {//5.开始保存错误日志,将错误信息导出excel表格//本地文件全路径String fileExportPath = fileFolderPath + File.separator + taskCodeEnum.getDesc() + "-失败-" + DateUtil.getUniqueIdentifier() + "." + fileNamePrefix;try (ExcelWriter excelWriter = EasyExcel.write(fileExportPath, WarehouseGoodsPriceErrorWriteReq.class).build()) {// 这里注意 如果同一个sheet只要创建一次WriteSheet writeSheet = EasyExcel.writerSheet("失败数据1").build();excelWriter.write(failList, writeSheet);} catch (Exception e) {//如果Linux中出现null,https://easyexcel.opensource.alibaba.com/qa/#%E6%88%91%E5%9C%A8%E6%9C%AC%E5%9C%B0%E5%8F%AF%E4%BB%A5%E5%8F%91%E5%B8%83%E5%88%B0%E7%BA%BF%E4%B8%8A%E7%8E%AF%E5%A2%83%E6%80%8E%E4%B9%88%E4%B8%8D%E5%8F%AF%E4%BB%A5%E4%BA%86//Linux下执行:yum install dejavu-sans-fonts fontconfig -y /或者重装: sudo yum reinstall fontconfig -y//确认: find /usr -name libfontconfig.so.1log.error("easyExcel:导出excel失败", e);puTaskRepo.updateTaskStatus(taskId, ExcelHandlerStatusEnum.FAILED.getCode());}puTask.setErrorData(JSON.toJSONString(failList));puTask.setErrorUrl(fileExportPath);}puTaskRepo.updateById(puTask);}, poolExecutor);//6.同步数据库状态,删除临时文件completableFuture.thenRun(() -> {//修改状态已完成puTaskRepo.updateTaskStatus(taskId, ExcelHandlerStatusEnum.COMPLETED.getCode());//删除临时文件FileUtil.deleteTempFile(new File(fileImportPath));});} catch (Exception e) {log.error("处理失败,taskId:{},失败原因:{}", taskId, e.getMessage(), e);puTaskRepo.updateTaskStatus(taskId, ExcelHandlerStatusEnum.FAILED.getCode());}return taskId;}
4.检查模板Listener
package com.kkd.web.admin.model.excel.base;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.kkd.web.admin.model.util.EasyExcelUtil;
import lombok.extern.slf4j.Slf4j;import java.util.Map;@Slf4j
public class CheckHeaderListener extends AnalysisEventListener<Object> {private final Class<?> clazz;private boolean position = true;public CheckHeaderListener(Class<?> clazz) {this.clazz = clazz;}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {EasyExcelUtil.checkExcelHeader(headMap, clazz);position = false;}@Overridepublic void invoke(Object data, AnalysisContext context) {}/*** 通过该方法控制是否继续解析* @param context* @return*/@Overridepublic boolean hasNext(AnalysisContext context) {return position;}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {}
}
package com.kkd.web.admin.model.excel.warehouse.goodsPrice.read.req;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;/*** @beLongProjecet: kkd-all* @beLongPackage: com.kkd.web.admin.test.excel* @author: xiaoxiangyuan* @createTime: 2024/12/17 17:28* @description:* @version: v1.0*/
@Data
public class WarehouseGoodsPriceReadReq {@ExcelProperty(index = 0,value = "*组织ID")private String orgId;@ExcelProperty(index = 1,value = "*SKU编码")private String sku;@ExcelProperty(index = 2,value = "*门店编码")private String qnhStoreId;@ExcelProperty(index = 3,value = "*商品零售价(元)")private String onLinePrice;
}
/*** 创建文件夹** @param path*/public static void createFolder(String path) {File folder = new File(path);if (!folder.exists()) {folder.mkdirs();}}/*** 获取存储文件夹路径** @return*/private String getFileFolderPath() {//获取本地文件夹地址String savePath = null;if (SystemUtil.SystemNameEnum.TYPE1.getDesc().equals(SystemUtil.getSystemName())) {savePath = windowsPath;} else if (SystemUtil.SystemNameEnum.TYPE2.getDesc().equals(SystemUtil.getSystemName())) {savePath = linuxPath;} else {savePath = macPath;}return savePath;}
package com.kkd.common.model.util;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;/*** @beLongProjecet: ai_ability_gateway* @beLongPackage: com.wondertek.util* @author: xiaoxiangyuan* @createTime: 2022/09/26 9:53* @description:* @version: v1.0*/
@Slf4j
public class SystemUtil {/*** desc: 获取当前运行系统名称** @param* @return*/public static String getSystemName() {String os = System.getProperty("os.name");//Windows操作系统if (os != null && os.toLowerCase().startsWith("windows")) {log.debug("当前系统版本是:{}", os);return SystemNameEnum.TYPE1.getDesc();} else if (os != null && os.toLowerCase().startsWith("linux")) {//Linux操作系统log.debug("当前系统版本是:{}", os);return SystemNameEnum.TYPE2.getDesc();} else { //其它操作系统log.debug("当前系统版本是:{}", os);return SystemNameEnum.TYPE3.getDesc();}}@AllArgsConstructor@Getterpublic enum SystemNameEnum {//TYPE1("windows"),TYPE2("linux"),TYPE3("mac");private String desc;}
}
package com.kkd.web.admin.model.excel.warehouse.goodsPrice.write.req;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.kkd.web.admin.model.excel.warehouse.goodsPrice.read.req.WarehouseGoodsPriceReadReq;
import lombok.Data;/*** @beLongProjecet: kkd-all* @beLongPackage: com.kkd.web.admin.test.excel* @author: xiaoxiangyuan* @createTime: 2024/12/17 17:28* @description:* @version: v1.0*/
@Data
@HeadRowHeight(35)
@ColumnWidth(30)
@ContentRowHeight(20)
public class WarehouseGoodsPriceErrorWriteReq extends WarehouseGoodsPriceReadReq {@ExcelProperty(index = 4,value = "失败原因")@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 10)private String errorMsg;}
/*** 删除本地临时文件** @param file :删除file对象*/public static void deleteTempFile(File file) {if (file != null) {File del = new File(file.toURI());del.delete();}}
CREATE TABLE `pu_task` (`id` bigint NOT NULL AUTO_INCREMENT,`org_id` bigint NOT NULL DEFAULT '0' COMMENT '组织id',`function_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '功能 0:导入 1:导出',`operator_id` bigint NOT NULL COMMENT '操作人',`template_code` varchar(64) NOT NULL COMMENT '模版code',`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '执行状态 0:未执行 1:执行中 2:执行完成 3:执行失败',`handle_result` varchar(64) NOT NULL DEFAULT '' COMMENT '执行结果',`success_url` varchar(255) DEFAULT '' COMMENT '处理导出成功数据文件路径',`error_url` varchar(255) DEFAULT '' COMMENT '处理失败数据文件路径',`error_data` text COMMENT '处理失败数据',`redundancy` varchar(255) DEFAULT NULL COMMENT '冗余字段',`is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除状态 0:未删除 1:已删除',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`id`),KEY `idx_org_id` (`org_id`),KEY `idx_template_code` (`template_code`),KEY `idx_operator_id` (`operator_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='导入导出任务表';
CREATE TABLE `pu_template` (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(64) NOT NULL DEFAULT '' COMMENT '模版名称',`code` varchar(64) NOT NULL DEFAULT '' COMMENT '模版code',`url` varchar(255) NOT NULL DEFAULT '' COMMENT '模板链接',`is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除状态 0:未删除 1:已删除',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',`create_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建者',`update_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '更新者',PRIMARY KEY (`id`),KEY `idx_code` (`code`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='导入导出模板管理';
3.2、下载导出文件
@ApiOperation(value = "下载处理异常的excel,根据任务id")
@Valid
@GetMapping("/downloadFile")
public Result<String> downloadFile(HttpServletResponse httpServletResponse,@ApiParam(name = "taskId", value = "任务ID") @NotNull(message = "任务id不能为空") Long taskId,@ApiParam(name = "functionType", value = "功能 0:导入 1:导出") @NotNull(message = "任务类型functionType不能为空") @Min(value = 0,message = "最小为0") @Max(value = 1,message = "最大为1")Integer functionType,@ApiParam(name = "downloadType", value = "下载成功/失败文件,导入类型只有失败文件 0:成功 1:失败") @NotNull(message = "下载类型downloadType不能为空") @Min(value = 0,message = "最小为0") @Max(value = 1,message = "最大为1")Integer downloadType) {excelFileService.downloadFile(httpServletResponse, taskId,functionType,downloadType);return Result.ok();
}
@Override
public void downloadFile(HttpServletResponse httpServletResponse, Long taskId, Integer functionType, Integer downloadType) {PuTask puTask = puTaskRepo.getById(taskId);if (ObjectUtil.isEmpty(puTask)) {throw new ServiceException("任务不存在");}String path = getFileUrl(functionType, downloadType, puTask);String fileName = Paths.get(path).getFileName().toString();try {// 将数据用户信息导出成Excel文件并以流的形式返回httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// 设置字符集httpServletResponse.setCharacterEncoding("utf-8");// 设置文件名,并且进行编码fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");// 告诉浏览器将以下载的方式处理响应,而不是在浏览器中直接打开(attachment表示下载、filename*=utf-8''" + fileName + ".xlsx"表示下载的文件名)httpServletResponse.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);File file = new File(path);if (!file.exists()) {throw new ServiceException("文件不存在:" + path);}// 将文件内容写入到响应流中try (InputStream inputStream = new FileInputStream(file); OutputStream outputStream = httpServletResponse.getOutputStream()) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}outputStream.flush();}} catch (Exception e) {throw new ServiceException("导出文件失败,请联系管理员");}
}
3.3、异常情况处理
1、字符库缺失:Mac或者Windows正常,Linux报错
java.lang.NullPointerException: nullat sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)at sun.awt.FontConfiguration.init(FontConfiguration.java:107)at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)at sun.font.SunFontManager$2.run(SunFontManager.java:441)at java.security.AccessController.doPrivileged(Native Method)at sun.font.SunFontManager.<init>(SunFontManager.java:386)at sun.awt.FcFontManager.<init>(FcFontManager.java:35)at sun.awt.X11FontManager.<init>(X11FontManager.java:57)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.lang.Class.newInstance(Class.java:442)at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)at java.security.AccessController.doPrivileged(Native Method)at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)at java.awt.Font.getFont2D(Font.java:491)at java.awt.Font.canDisplayUpTo(Font.java:2064)at java.awt.font.TextLayout.singleFont(TextLayout.java:470)at java.awt.font.TextLayout.<init>(TextLayout.java:531)at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidthAsFloat(SheetUtil.java:352)at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.<init>(AutoSizeColumnTracker.java:117)at org.apache.poi.xssf.streaming.SXSSFSheet.<init>(SXSSFSheet.java:106)at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:694)at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:712)at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:104)at com.alibaba.excel.util.WorkBookUtil.createSheet(WorkBookUtil.java:86)at com.alibaba.excel.context.WriteContextImpl.createSheet(WriteContextImpl.java:223)at com.alibaba.excel.context.WriteContextImpl.initSheet(WriteContextImpl.java:203)at com.alibaba.excel.context.WriteContextImpl.currentSheet(WriteContextImpl.java:135)at com.alibaba.excel.write.ExcelBuilderImpl.addContent(ExcelBuilderImpl.java:54)at com.alibaba.excel.ExcelWriter.write(ExcelWriter.java:73)at com.alibaba.excel.ExcelWriter.write(ExcelWriter.java:50)at com.kkd.web.admin.service.impl.ExcelFileServiceImpl.handlerExcelWarehouseGoodsPrice(ExcelFileServiceImpl.java:209)at com.kkd.web.admin.service.impl.ExcelFileServiceImpl.importFile(ExcelFileServiceImpl.java:142)at com.kkd.web.admin.controller.excel.ExcelFileController.importFile(ExcelFileController.java:43)at com.kkd.web.admin.controller.excel.ExcelFileController$$FastClassBySpringCGLIB$$1c09eef6.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:123)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)at com.kkd.web.admin.controller.excel.ExcelFileController$$EnhancerBySpringCGLIB$$5472f61d.importFile(<generated>)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)at javax.servlet.http.HttpServlet.service(HttpServlet.java:696)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:750)
文档:EasyExcel官方解释
异常原因:Linux上安装的jdk是openjdk,其中字体库缺失导致方法一:更换jdk版本,将openjdk更换为sun下的jdk即可解决
方法二:Linux下执行:yum install dejavu-sans-fonts fontconfig -y 或者重装: sudo yum reinstall fontconfig -y确认: find /usr -name libfontconfig.so.1最后:重新启动项目即可
相关文章:

Java中使用EasyExcel
Java中使用EasyExcel 文章目录 Java中使用EasyExcel一:EasyExcel介绍1.1、核心函数导入数据导出数据 1.2、项目实际应用导入数据导出数据 1.3、相关注解ExcelProperty作用示例 二:EasyExcel使用2.1、导入功能2.2、导出功能 三:EasyExcel完整代…...
前沿科技改变生活新趋势
纳米技术在电子设备制造中的应用越来越广泛。这种技术能够帮助制造更小、更快、更耐用的电子产品。 举个例子,手机的处理器是其核心部件。随着纳米技术的进步,现在的处理器比以前小得多,但功能却更强。这样不仅让手机变得更轻薄,…...
不到一个月,SQLite 3.49.0来了
距离 SQLite 3.48.0 发布不到一个月,SQLite 开发团队于 2025 年 2 月 6 日发布了 SQLite 3.49.0 版本。这更新速度的确让人感动,那么这个版本又有哪些更新呢? 查询优化器 新版本改进了自动索引(query-time index)优化…...
Android车机DIY开发之软件篇(十四)编译i.mx8mplus官方kernel
1.下载 下载地址 2.安装依赖 sudo apt-get update sudo apt-get install build-essential git libncurses5-dev libssl-dev bc sudo apt-get install gcc-aarch64-linux-gnu export CROSS_COMPILEaarch64-linux-gnu- 3.配置 make ARCHarm64 defconfig 4.编译 make ARCHa…...

Mac上搭建宝塔环境并部署PHP项目
安装Docker Desktop》搭建Centos版本的宝塔环境》部署PHP项目 1. 下载Docker for mac 软件:https://www.docker.com/ 或使用终端命令:brew install --cask --appdir/Applications docker 2. 使用命令安装宝塔环境的centos7系统: docker pul…...

3.3.3 VO-O语法- 语法算子(二)
循环遍历 由于VO语言是面向数据集的,其所有隐含的语义中都已经带有了遍历并计算的数据逻辑。因此,VO语言只提供了一种支持循环语法的算子--Loop算子。 Loop算子 Loop算子是一个容器算子,其可以实现对其内部子流程的循环迭代运行。但Loop算…...
安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)
安装 Ollama 的步骤根据操作系统不同会有所差异,以下是针对不同操作系统的详细安装指南: Windows 系统 下载安装包:访问 Ollama 官方下载页面,下载适用于 Windows 的安装程序 OllamaSetup.exe。运行安装程序:双击下载的安装包,按照提示完成安装。默认安装路径为 C:\User…...

HCIA项目实践--静态路由的综合实验
八 静态路由综合实验 (1)划分网段 # 192.168.1.0 24#分析:每个路由器存在两个环回接口,可以把两个环回接口分配一个环回地址,所以是四个环回,一个骨干,这样分配,不会出现路由黑洞#19…...

Electron视图进程和主进程通讯
快速创建基于vue的electron项目:quick-start/create-electron - npm 视图线程也就index.html是无法直接访问这个api的(如果没有开启视图层访问nodejs的功能,现在几乎没法直接开启,开启了一堆警告提示) 所以需要通过r…...

Vript-Hard——一个基于高分辨率和详细字幕的视频理解算法
一、概述 多模态学习的最新进展促进了对视频理解和生成模型的研究。随之而来的是,对高分辨率视频和详细说明所建立的高质量数据集的需求激增。然而,由于时间因素的影响,视频与文本的配对不像图像那样容易。准备视频和文本配对是一项困难得多…...
react脚手架搭建react项目使用scss
1.create-react-app 创建的项目,webpack配置默认是隐藏的 ,如果要查看 或修改用npm run eject命令,因为create-react-app脚手架默认已经配置了scss、sass所以不用改webpack配置。如果用less 就需要自己添加配置 2.如果直接使用scss的文件会直接报错&…...

Vue.js 状态管理库Pinia
Pinia Pinia :Vue.js 状态管理库Pinia持久化插件-persist Pinia :Vue.js 状态管理库 Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。 要使用Pinia ,先要安装npm install pinia在main.js中导入Pinia 并使用 示例…...
【Stable Diffusion部署至GNU/Linux】安装流程
以下是安装Stable Diffusion的步骤,以Ubuntu 22.04 LTS为例子。 显卡与计算架构介绍 CUDA是NVIDIA GPU的专用并行计算架构 技术层级说明CUDA Toolkit提供GPU编译器(nvcc)、数学库(cuBLAS)等开发工具cuDNN深度神经网络加速库(需单独下载)GPU驱动包含CUDA Driver(需与CUDA …...

【C/C++算法】从浅到深学习---滑动窗口(图文兼备 + 源码详解)
绪论:冲击蓝桥杯一起加油!! 每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章是算法训练的第二章----滑动窗口,它的本质是双指针算法的衍生所以我将…...

计算机毕业设计SpringBoot+Vue.js房源推荐系统 房价预测 房源大数据分析可视化(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
开源机器人+具身智能 解决方案+AI
开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...

通过 VBA 在 Excel 中自动提取拼音首字母
在excel里面把表格里的中文提取拼音大写缩写怎么弄 在Excel中,如果你想提取表格中的中文字符并转换为拼音大写缩写(即每个汉字的拼音首字母的大写形式),可以通过以下步骤来实现。这项工作可以分为两个主要部分: 提取拼…...

华硕笔记本怎么一键恢复出厂系统_华硕笔记本一键恢复出厂系统教程
华硕笔记本怎么一键恢复出厂系统? 华硕一键恢复出厂系统是一个安全、高效、方便的恢复方式,让您轻松还原出厂设置,以获得更好的系统性能。如果您的华硕电脑遇到问题,可以使用华硕一键恢复出厂系统功能。下面小编就教大家华硕笔记本…...

Ubuntu 如何安装Snipaste截图软件
在Ubuntu上安装Snipaste-2.10.5-x86_64.AppImage的步骤如下: 1. 下载Snipaste AppImage 首先,从Snipaste的官方网站或GitHub Releases页面下载Snipaste-2.10.5-x86_64.AppImage文件。 2. 赋予执行权限 下载完成后,打开终端并导航到文件所在…...
【离散数学上机】T235,T236
T235题目:输入集合A和B,输出A到B上的所有单射函数。 问题描述 给定非空数字集合A和B,求出集合A到集合B上的所有单射函数。 输入格式 第一行输入m和n(空格间隔),分别为集合A和集合B中的元素个数;…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...

未授权访问事件频发,我们应当如何应对?
在当下,数据已成为企业和组织的核心资产,是推动业务发展、决策制定以及创新的关键驱动力。然而,未授权访问这一隐匿的安全威胁,正如同高悬的达摩克利斯之剑,时刻威胁着数据的安全,一旦触发,便可…...