开发技巧之Excel的导入导出操作

我爱海鲸 2024-11-13 10:40:22 暂无标签

简介Easy Excel

官方文档

Easy Excel

1、pom文件

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.10</version>
        </dependency>

2、相关代码:

	public String BatchImport(MultipartFile file) {
		InputStream is;
		try {
			is = file.getInputStream();
		} catch (IOException e) {
			throw new ServerException(“异常”);
		}
		EasyExcel.read(is, ExcelTest.class, new ReadExcelListener(this)).sheet().headRowNumber(2).doRead();
		return null;
	}

ExcelTest:

@Data
@EqualsAndHashCode
public class ExcelTest {
    /**
     * 姓名
     */
//    @ExcelProperty(value = "*身份证号", index = 0)
    private String name;
    /**
     * 身份证号
     */
//    @ExcelProperty(value = "*身份证号", index = 1 )
    private String idNo;

    /**
     * 手机号
     */
//    @ExcelProperty(value = "*手机号", index = 2 )
    private String phone;

    /**
     * 邮箱
     */
//    @ExcelProperty(value = "*邮箱", index = 3)
    private String email;

}

ReadExcelListener:

@Slf4j
public class ReadExcelTestListener implements ReadListener<ExcelTest> {

    private IReadExcelTestService readExcelTestService;

    // 读取的excel的最大行数
    private static final int ROW_COUNT = 500;

    // 是否存在错误
    private Boolean isExitError = false;

    // 解析的Excel数据
    private List<ExcelTest> excelTests = new ArrayList<>();

    // 校验的Excel数据的错误信息
    private List<ExcelTestError> excelTestErrors = new ArrayList<>();


    public ReadExcelTestListener(IReadExcelTestService readExcelTestService) {
        this.readExcelTestService = readExcelTestService;
    }



    @Override
    public void onException(Exception e, AnalysisContext analysisContext) throws Exception {

    }

    @Override
    public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
        Integer rowIndex = context.readRowHolder().getRowIndex();
        log.info("ReadExcelTestListener-invokeHead-校验行数【{}】",rowIndex);
        if (rowIndex == 1) {
            String[] headList = {"*姓名", "*身份证号", "*手机号", "*邮箱"};
            // 校验表头的数量
            if (headMap.size() != headList.length) {
                throw new ServerException("异常");
            }
            for (int i = 0 ; i < headList.length ; i++) {
                if (!headList[i].equals(headMap.get(i).getStringValue())) {
                 throw new ServerException("异常");
                }
            }
        }
    }

    @Override
    public void invoke(ExcelTest excelTest, AnalysisContext analysisContext) {
        // excel读取到哪一行了
        Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
        log.info("ReadExcelTestListener-invoke-读取数据的行数【{}】",rowIndex);
        if (!"示例:张三".equals(excelTest.getName())) {
            if (rowIndex < 2) {
                throw new ServerException("异常");
            }
            if (rowIndex > ROW_COUNT) {
                throw new ServerException("异常");
            }
            readExcelTestService.checkImportExcelTest(excelUser,excelTestErrors);
            excelTests.add(excelTest);
        }
    }

    @Override
    public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {

    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        List<String> errorDescList = excelUserErrors.stream().map(ExcelTestError::getErrorDesc).collect(Collectors.toList());
        if (errorDescList.stream().anyMatch(StringUtil::isNotBlank)){
            isExitError = true;
        }
        log.info("ReadExcelTestListener-doAfterAllAnalysed-是否有错误【{}】",isExitError);
        if (isExitError) {
            // 存在错误,生成错误报告
            log.info("ReadExcelTestListener-doAfterAllAnalysed-错误报告【{}】",excelTestErrors);
            readExcelTestService.uploadErrorReport(excelTestErrors);
        } else {
            // 不存在错误,入库
            excelTests = excelTests.stream().distinct().collect(Collectors.toList());
            readExcelTestService.saveExcelTest(excelTests);
        }
    }

    @Override
    public boolean hasNext(AnalysisContext analysisContext) {
        return true;
    }
}
IReadExcelService:
public interface IReadExcelUserService {

    /**
     * 保存批量导入
     * @param excelTests
     * @return
     */
    boolean saveExcelTest(List<ExcelTest> excelTests);

    /**
     * 校验批量导入信息
     * @param excelTest 当前行的信息
     * @param excelTestErrors excel解析的错误信息
     */
    void checkImportExcelUser(ExcelTest excelTest , List<ExcelTestError> excelTestErrors);

    /**
     * 上传错误报告
     * @param excelTestErrors 错误信息集合
     */
    void uploadErrorReport(List<ExcelTestError> excelTestErrors );

}

IReadExcelService实现:

	@Override
	public String downloadErrorReport(String ticket) {
		List<Long> attachIdList = new ArrayList<>();
		Long attachId  = redis.get(ticket);
		attachIdList.add(attachId);
		Map<Long, String> map = getDownloadUrlMap(attachIdList);
		return map.get(attachId);
	}	

        @Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveExcelTest(List<ExcelUser> excelTests) {
		log.info("OperateUserServiceImpl-saveExcelUser-导入员工的数量【{}】",excelTests.size());
		if (CollectionUtil.isEmpty(excelUsers)) {
			throw new ServerException("异常");
		}
		List<ExcelTestDTO> excelTestDTOList = BeanUtil.copyProperties(excelTests, ExcelTestDTO.class);
		List<UserDept> userDepts = new ArrayList<>();
		ticket = "";
		excelUserDTOList.forEach(test->{
			this.save(test);
		});
		return userDeptService.saveBatch(userDepts);
	}

	@Override
	public void checkImportExcelTest(ExcelTest excelTest, List<ExcelTestError> excelTestErrors) {
		//  校验批量导入的员工信息
		StringBuilder errorDesc = new StringBuilder();
		ExcelTestError excelTestError = BeanUtil.copyProperties(excelTest, ExcelTestError.class);
		if (StringUtil.isBlank(excelTestError.getName())) {
			errorDesc.append("姓名不能为空#");
		}
		if (StringUtil.isBlank(excelTestError.getPhone())) {
			errorDesc.append("手机号不能为空#");
		}
		if (StringUtil.isBlank(excelTestError.getEmail())) {
			errorDesc.append("邮箱不能为空#");
		}
		if (StringUtil.isBlank(excelTestError.getIdNo())) {
			errorDesc.append("身份证号不能为空#");
		}
		String error = errorDesc.toString();
		excelTestError.setErrorDesc(error);
		excelTestErrors.add(excelTestError);
	}

	@Override
	public void uploadErrorReport(List<ExcelTestError> excelTestErrors) {
		String fileName =   "errorReport" + System.currentTimeMillis()+ ".xlsx";
		String filePath = alignmentProperties.getTemplatePath() + File.separator + fileName;
		String errorTemplatePath = alignmentProperties.getTemplatePath()+ File.separator + ERROR_TEMPLATE_NAME;
		EasyExcel.write(filePath, ExcelUserError.class)
				.withTemplate(errorTemplatePath)
				.excelType(ExcelTypeEnum.XLSX)
				.sheet("批量导入员工信息模板")
				.doFill(excelUserErrors);
		File f = new File(filePath);
		byte[] bytes = FileUtil.File2byte(f);
		MultipartFile file = new SicpayMultipartFile(fileName,fileName,bytes);
		Attach attach = uploadFile(fileName, file);
		log.info("OperateUserServiceImpl-uploadErrorReport-上传错误报告de文件【{}】",attach);
		// 删除本地临时文件
		FileUtil.deleteTempFile(f);
		// 将错误报告保存到redis,并设置超时时间为两小时
		ticket = UUID.randomUUID().toString();
		redis.setEx(ticket,attach.getId(), 2);
	}

2024-11-11 start:

导出:

    @PostMapping("/export")
    public Result export(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = URLEncoder.encode("导出的名称"+".", StandardCharsets.UTF_8);
        response.setHeader(“xlsx”, "attachment;filename=" + fileName + “xlsx”);
        // TODO 查询的数据 假设返回为list


        ExcelWriter writer = EasyExcel.write(response.getOutputStream()).build();
        WriteSheet sheet = EasyExcel.writerSheet(0).head(TestVo.class).build();
        writer.write(list, sheet).finish();
        return Result.success();
    }

TestVo:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class TestVo {

    /**
     *名称
     */
    @ColumnWidth(10)
    @ExcelProperty("名称")
    private String name;

    /**
     * 时间
     */
    @ColumnWidth(20)
    @ExcelProperty("时间")
   @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    private Date time;


}

end

你好:我的2025