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();
    }
}
相关推荐
yangminlei1 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot
+VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue小型房屋租赁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
进阶的小名7 小时前
[超轻量级延时队列(MQ)] Redis 不只是缓存:我用 Redis Stream 实现了一个延时MQ(自定义注解方式)
java·数据库·spring boot·redis·缓存·消息队列·个人开发
y***n6148 小时前
springboot项目架构
spring boot·后端·架构
qq_318121598 小时前
互联网大厂Java面试故事:支付与金融服务微服务架构、消息队列与AI风控全流程解析
java·spring boot·redis·微服务·kafka·支付系统·金融服务
亲爱的非洲野猪9 小时前
SpringBoot启动流程深度剖析:从@SpringBootApplication到Servlet容器就绪
hive·spring boot·servlet
vortex59 小时前
【小技巧】用 VLOOKUP 实现表格合并
excel
OpenTiny社区9 小时前
TinyPro v1.4.0 正式发布:支持 Spring Boot、移动端适配、新增卡片列表和高级表单页面
java·前端·spring boot·后端·开源·opentiny
宫瑾9 小时前
Excel常用操作记录
excel
计算机毕设指导610 小时前
基于微信小程序民宿预订管理系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·tomcat·maven