excel导入导出

1. 导入依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.easyexcel</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.5</version>
</dependency>

2. 定义实体类

java 复制代码
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class ImportConfigDTO {

    @ExcelProperty("类型")
    @ColumnWidth(15)
    private String type;

    @ExcelProperty("故障名")
    @ColumnWidth(15)
    private String name;

    @ExcelProperty("故障码")
    @ColumnWidth(15)
    private String faultCode;

    @ExcelProperty("描述")
    @ColumnWidth(15)
    private String description;
}

3. Controller类

java 复制代码
@Slf4j
@RestController
public class ExportConfigController {

    @Autowired
    private ImportConfigService importConfigService;

    @PostMapping("/api/v1/importConfigTemplate")
    public ResponseEntity<String> importConfigTemplate(MultipartFile file) {
        importDtcConfigService.importDtoConfigTemplate(file);
        return ResponseEntity.ok("success");
    }

    @PostMapping("/api/v1/import-config")
    public ResponseEntity<String> importConfig(MultipartFile file) {
        String filename = file.getOriginalFilename();
        if (StringUtil.isBlank(filename)) {
            throw new RuntimeException("请上传文件!");
        }
        if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
            throw new RuntimeException("请上传正确的excel文件!");
        }
        InputStream inputStream;
        try {
            ConfigImportListener importListener = new ConfigImportListener(importConfigService);
            inputStream = new BufferedInputStream(file.getInputStream());
            ExcelReaderBuilder builder = EasyExcel.read(inputStream, ImportConfigDTO.class, importListener);
            builder.doReadAll();
        } catch (IOException e) {
            throw new RuntimeException("excel文件上传出现错误" + e.getMessage());
        }
        return ResponseEntity.ok("操作成功");
    }

    @SneakyThrows
    @GetMapping("/api/v1/export-config")
    public void exportConfig(HttpServletResponse response) {
        List<ImportConfigDTO> list = importConfigService.findAll();
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = URLEncoder.encode("配置数据导出", StandardCharsets.UTF_8);
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), ImportConfigDTO.class).sheet("配置数据表").doWrite(list);
    }

    @SneakyThrows
    @GetMapping("/api/v1/export-template")
    public void exportTemplate(HttpServletResponse response) {
        List<ImportConfigDTO> list = new ArrayList<>();
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = URLEncoder.encode("配置数据模板", StandardCharsets.UTF_8);
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), ImportConfigDTO.class).sheet("配置数据表").doWrite(list);
    }
}

4. 两种监听类定义方式

  • 方式一:调用保存方法
java 复制代码
@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class ConfigImportListener extends AnalysisEventListener<ImportConfigDTO> {

	/**
	 * 默认每隔3000条存储数据库
	 */
	private int batchCount = 3000;
	/**
	 * 缓存的数据列表
	 */
	private List<ImportConfigDTO> list = new ArrayList<>();

	private final ImportConfigService importConfigService;

	@Override
	public void invoke(ImportConfigDTO data, AnalysisContext context) {
		list.add(data);
		// 达到BATCH_COUNT,则调用importer方法入库,防止数据几万条数据在内存,容易OOM
		if (list.size() >= batchCount) {
			// 调用importer方法
			importConfigService.uploadExcelDtoConfig(list);
			// 存储完成清理list
			list.clear();
		}
	}

	@Override
	public void doAfterAllAnalysed(AnalysisContext analysisContext) {
		// 调用importer方法
		importConfigService.uploadExcelDtoConfig(list);
		// 存储完成清理list
		list.clear();
	}

}
  • 方式二:只做数据接收
java 复制代码
@Data
@EqualsAndHashCode(callSuper = true)
public class ConfigListener extends AnalysisEventListener<ImportConfigDTO> {

    List<ImportConfigDTO> list = Lists.newLinkedList();

    List<ExcelDataConvertException> listException = new ArrayList<>();

    Map<Integer, String> excelHeadMap = new HashMap<>(10);

    @Override
    public void invoke(ImportConfigDTO data, AnalysisContext analysisContext) {
        list.add(data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        excelHeadMap = headMap;
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) {
    }
}

5. Excel工具类

java 复制代码
@Slf4j
public class ExcelUtils {

    public static final long MAX_SIZE = 10 * 1024 * 1024;


    /**
     * 用于读取excel
     * @param file                  文件参数
     * @param importClass           导入对象class
     * @param analysisEventListener 分析事件监听器
     */
    public static void readExcel(MultipartFile file, Class<?> importClass, AnalysisEventListener<?> analysisEventListener) {
        // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        try(InputStream inputStream = file.getInputStream()) {
            if (file.getSize() > MAX_SIZE) {
                throw new RuntimeException("The maximum file size allowed for upload is 10MB 上传文件最大允许上传10MB");
            }
            String fileName = file.getOriginalFilename();
            if (fileName == null || !(fileName.endsWith(".xls") || fileName.endsWith(".xlsx"))) {
                throw new RuntimeException("The uploaded file format is incorrect, it must be in. xls or. xlsx format 上传文件格式不正确,必须是.xls或.xlsx格式");
            }
            EasyExcel.read(inputStream, importClass, analysisEventListener).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException("excel文件上传出现错误" + e.getMessage());
        }
    }
}

6. Service类

java 复制代码
@Slf4j
@Service
public class ImportConfigService {

    @Autowired
    private ConfigMapper configMapper;

    public void importDtoConfigTemplate(MultipartFile multipartFile) {
        ConfigListener configListener = new ConfigListener();
        //读取excel
        ExcelUtils.readExcel(multipartFile, ImportConfigDTO.class, configListener);

        List<ImportConfigDTO> configImportList = configListener.getList();

        if (CollectionUtil.isEmpty(configImportList)) {
            throw new RuntimeException("Upload file is empty 上传文件为空");
        }
        List<ExcelDataConvertException> listException = configListener.getListException();
        Set<String> infoSet = listException.stream()
                .map(e -> "第" + (e.getRowIndex() + 1) + "行,第" + (e.getColumnIndex() + 1) + "列")
                .collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(infoSet)) {
            uploadExcelDtoConfig(configImportList);
        } else {
            throw new RuntimeException(String.join(";", infoSet));
        }
    }

    public void uploadExcelDtoConfig(List<ImportConfigDTO> importConfigDTOList) {
        List<ConfigPO> configPOList = new ArrayList<>();
        for (ImportConfigDTO importConfigDTO : importConfigDTOList) {
            ConfigPO configPO = new ConfigPO();
            configPO.setId(IdWorker.nextId());
            configPO.setType(importConfigDTO.getType());
            configPO.setName(importConfigDTO.getName());
            configPO.setFaultCode(importConfigDTO.getFaultCode());
            configPO.setDescription(importConfigDTO.getDescription());
            configPO.setCreatedAt(LocalDateTime.now());
            configPO.setCreatedBy("system");
            configPO.setUpdatedAt(LocalDateTime.now());
            configPO.setUpdatedBy("system");
            configPOList.add(configPO);
        }
        if (CollectionUtil.isNotEmpty(configPOList)) {
            configMapper.batchInsert(configPOList);
        }
    }

    public List<ImportConfigDTO> findAll() {
        return configMapper.findAll();
    }
}
相关推荐
用户9083246027311 小时前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840821 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解1 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解1 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记1 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者2 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840822 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解2 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者3 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺3 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端