Word模板导出时自行分页
word模板导出后存在跨页问题,这样会影响打印纸质排版,需要导出时自动进行分页,避免模板跨页。
需求背景
甲方为了方便对第三方单位人员进行监管,要求根据委外人员信息导出委外人员证件,即word导出。
word模板如下:
问题描述
由于导出后的word是需要用于打印制作实体证件用,且模板高度不能完整整数倍适配页面高度,因此在导出多页数据时会出现单个模板数据跨页的现象,导致打印时个别证件无法完整制作。
解决方案
根据每页能放下的完整模板数代码进行分页(插入分页符)
-
依赖配置
<poi.version>4.1.2</poi.version> <poi-tl.version>1.10.0</poi-tl.version> <!-- 导出工具 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <!-- word模板工具 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>${poi-tl.version}</version> </dependency>
-
java代码
// Controller @ApiOperation("导出委外单位人员证") @ApiOperationSupport(order = 9) @PostMapping("/exportProof") @Log(title = "委外人员", businessType = BusinessType.EXPORT) public void exportProof(HttpServletResponse response, EntrustUserDTO dto) throws IOException { List<EntrustUserVO> expData = entrustUserService.getExpData(dto); for (int i = 0; i < expData.size(); i++) { EntrustUserVO entrustUserVO = expData.get(i); Boolean needPageBreak = i > 0 && ((i + 1) % 4 == 0); entrustUserVO.setNeedPageBreak(needPageBreak); } response.setContentType("application/octet-stream"); response.setHeader("Content-disposition", "attachment"); response.setCharacterEncoding("utf-8"); // 这里绑定了一个自定义的插件到isPageBreak标签 Configure config = Configure.builder().useSpringEL().bind("needPageBreak", new AbstractRenderPolicy<Boolean>() { @Override public void doRender(RenderContext<Boolean> context) throws Exception { XWPFRun where = context.getWhere(); boolean thing = context.getThing(); where.setText("", 0); if (thing) where.addBreak(BreakType.PAGE); } }).build(); // 读取模板流,组装数据 InputStream inputStream = ImageUtils.getOssStream("ucd-oss-priv/template/word/credentials.docx"); XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render( new HashMap<String, Object>() { { put("rows", expData); } } ); template.writeAndClose(response.getOutputStream()); }
// Service @Override public List<EntrustUserVO> getExpData(EntrustUserDTO dto) { List<Long> ids = dto.getIds(); LambdaQueryWrapper<EntrustUser> queryWrapper = new LambdaQueryWrapper<EntrustUser>() .in(EntrustUser::getId, ids) .eq(EntrustUser::getStatus, "2") .select( EntrustUser::getId, EntrustUser::getContractId, EntrustUser::getAgreementId, EntrustUser::getName, EntrustUser::getEntrustNo, EntrustUser::getDeptName, EntrustUser::getStatus, EntrustUser::getAvatar ); List<EntrustUser> entrustUsers = entrustUserMapper.selectList(queryWrapper); if (CollectionUtil.isEmpty(entrustUsers)) { return new ArrayList<>(); } List<EntrustUserVO> collect = entrustUsers.stream().map(e -> { EntrustUserVO entrustUserVO = mapStruct.do2Vo(e); Long contractId = entrustUserVO.getContractId(); Long agreementId = entrustUserVO.getAgreementId(); Contract contract = contractMapper.selectById(contractId); SafeAgreement safeAgreement = safeAgreementMapper.selectById(agreementId); String unitName = contract.getUnitName(); Date endDate = safeAgreement.getEndDate(); entrustUserVO.setUnitName(unitName); Date date = new Date(); int compare = DateUtil.compare(date, endDate); if (compare >= 0) { entrustUserVO.setDate("已失效"); } else { DateTime dateTime = DateUtil.offsetMonth(date, 12); compare = DateUtil.compare(dateTime, endDate); endDate = compare <= 0 ? dateTime : endDate; entrustUserVO.setDate( StringUtils.format("{} ~ {}", DateUtil.format(date, "yyyy-MM-dd"), DateUtil.format(endDate, "yyyy-MM-dd") ) ); } // 处理图片格式 String avatar = e.getAvatar(); if (StringUtils.isNotBlank(avatar)) { byte[] data = ImageUtils.getImage(avatar); String extName = FileNameUtil.extName(avatar); extName = extName.toLowerCase(); PictureType pictureType = FileUtils.getExtension(extName); entrustUserVO.setAvtData(new PictureRenderData(90, 90, pictureType, data)); } return entrustUserVO; }).collect(Collectors.toList()); return collect; }
// VO实体 package com.ucd.outer.domain.vo; import com.deepoove.poi.data.PictureRenderData; import com.fasterxml.jackson.annotation.JsonFormat; import com.ucd.common.annotation.OssFiled; import com.ucd.common.core.domain.BaseVO; import com.ucd.common.annotation.Excel; import com.ucd.outer.domain.entity.EntrustUserDanger; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; import java.util.List; /** * 委外人员对象 outer_entrust_user * * @author javalx * @date 2023-04-10 16:05:59 */ @Data @ApiModel(value = "EntrustUserVO", description = "委外人员VO") public class EntrustUserVO extends BaseVO{ private static final long serialVersionUID = 1L; @Excel(name = "ID", cellType = Excel.ColumnType.NUMERIC, width = 20, needMerge = true) @ApiModelProperty(value = "ID") private Long id; @ApiModelProperty(value = "合同ID") private Long contractId; @ApiModelProperty(value = "安全协议ID") private Long agreementId; @Excel(name = "安全协议编号", needMerge = true) @ApiModelProperty(value = "安全协议编号") private String agreementNo; @Excel(name = "性别", readConverterExp = "0=男,1=女,2=未知", needMerge = true) @ApiModelProperty(value = "性别") private String sex; @Excel(name = "岗位", needMerge = true) @ApiModelProperty(value = "岗位") private String post; @Excel(name = "身份证号", needMerge = true) @ApiModelProperty(value = "身份证号") private String idNumber; @Excel(name = "联系电话", needMerge = true) @ApiModelProperty(value = "联系电话") private String phone; @Excel(name = "地址", needMerge = true) @ApiModelProperty(value = "地址") private String address; @ApiModelProperty(value = "危险作业人员(是:1,否:2)") private String danger; @ApiModelProperty(value = "所属中心ID(中心XXX:1)") private Long deptId; @ApiModelProperty(value = "所属车间ID(车间XXX:1)") private Long workshopId; @Excel(name = "所属车间", needMerge = true) @ApiModelProperty(value = "所属车间") private String workshopName; @Excel(name = "所属工区", needMerge = true) @ApiModelProperty(value = "所属工区") private String workarea; @Excel(name = "作业内容", needMerge = true) @ApiModelProperty(value = "作业内容") private String jobContent; @ApiModelProperty(value = "发证日期结束") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date trainingDate; @ApiModelProperty(value = "培训状态(未通过:1,已通过:2)") private String status; @ApiModelProperty(value = "备注") private String remark; @ApiModelProperty(value = "有效期(截止)") private Date endDate; @OssFiled @ApiModelProperty(value = "照片") private String avatar; @Excel(name = "特种作业证书") @ApiModelProperty(value = "特种作业证书") private List<EntrustUserDangerVO> dangers; // word模板导出数据 @Excel(name = "姓名", needMerge = true) @ApiModelProperty(value = "姓名") private String name; @Excel(name = "委外证号", needMerge = true) @ApiModelProperty(value = "委外证号") private String entrustNo; @Excel(name = "所属部门", needMerge = true) @ApiModelProperty(value = "所属部门") private String deptName; @ApiModelProperty(name = "有效期") private String date; @ApiModelProperty(name = "单位名称") private String unitName; @ApiModelProperty(value = "照片") private PictureRenderData avtData; @ApiModelProperty(value = "是否需要分页") private Boolean needPageBreak; }
-
导出模板
-
导出效果
评论区