条件查询数据并导出到word文档完整功能框架

一、概述
导出到word文档功能,主要以下步骤:

  1. 引入Apache POI、args4j、docx4j、xdocreport等 jar包
  2. 在服务器安装目录下保存模板word文档
  3. 点击导出后,查询数据
  4. 读取服务器模板word文档
  5. 替换文档内容
  6. 导出写入response对象

在这里插入图片描述
二、具体功能代码
主要包含:pom配置、实体类、接口、service类等

  1. pom配置
	
		<properties>
			<xdocreport.version>1.0.6</xdocreport.version>
			<apache-poi-version>3.15</apache-poi-version>
		</properties>
	
		<!-- Apache POI -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${apache-poi-version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>${apache-poi-version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>${apache-poi-version}</version>
		</dependency>

		<!--qcx add word2pdf start-->
		<dependency>
			<groupId>args4j</groupId>
			<artifactId>args4j</artifactId>
			<version>2.32</version>
			<exclusions>
				<exclusion>
					<artifactId>slf4j-log4j12</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.docx4j</groupId>
			<artifactId>docx4j</artifactId>
			<version>6.1.2</version>
			<exclusions>
				<exclusion>
					<artifactId>slf4j-log4j12</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itextpdf</artifactId>
			<version>5.5.13.1</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
			<version>${xdocreport.version}</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>org.odftoolkit.odfdom.converter.pdf</artifactId>
			<version>${xdocreport.version}</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.itext.extension</artifactId>
			<version>2.0.2</version>
		</dependency>
  1. 实体类
/**
 * 导出报告参数字段
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ReportContentDto {
    /**
     * 报告唯一键
     */
    private String uuid = "";

    /**
     * 报告日期(yyyy年MM月dd日)
     */
    private String reportDate = "";

    /**
     * 报告开始事件(MM月dd日hh时mm分)
     */
    private String reportStartTime = "";
    /**
     * 报告截至时间(MM月dd日hh时mm分)
     */
    private String reportEndTime = "";

    /**
     * 报告内容字段
     */
    private String reportParam = "";
}
  1. 服务器中保存的word文档模板样式,文档名称 template.docx,文档内容如下:
工作情况报告
${current_time}
${start_time} 至 ${end_time} 时间中,工作内容如下:
${report_param}
  1. service类,包括MakeReport(word文档生成类)和 ExportReportServiceImpl(Service类)
/**
 * @Title: 导出word报告业务逻辑处理服务层
 */
@Service
public class ExportReportServiceImpl{
    private static final AriesJcLogger LOGGER = AriesJcLoggerFactory.getLogger(OnlineReportServiceImpl.class);

    public void onlineReport(HttpServletResponse response, String timeType, String currentTime, Timestamp startTime,
                             Timestamp endTime, String reportType) {
        try {
            //查询文档上的相关信息
            ReportContentDto dto = getReportInfo(timeType, currentTime, startTime, endTime, regionIndexCode, reportType);

            //组装段落
            Map<String, String> params = assemblyParagraph(reportType, dto);
            
            String path = FileUploadUtils.getWebInfoFileRootPath();
            //服务器查组件目录资源
            String resourcePath = path + "/resource/word/";

            String templateFileName = "template.docx";
            String template = resourcePath + templateFileName;
            String fileName = "工作情况报告.docx";
            //在服务器组件资源包内生成word后导出
            MakeReport report = new MakeReport();
            report.replaceAndExportWord(null, template, response, params, fileName);

        } catch (Exception e) {
            LOGGER.errorWithErrorCode(ConstParamErrorCode.BS_COMMON_ERROR.name(),"exportReport ", e);
        }
    }

    /**
     * 查询报告内容
     */
    public ReportContentDto getReportInfo(String timeType, String currentTime, Timestamp startTime, Timestamp endTime)
    {
        ReportContentDto reportContentDto = new ReportContentDto();
        reportContentDto.setReportDate(currentTime);
        reportContentDto.setReportStartTime(startTime.toString());
        reportContentDto.setReportEndTime(endTime.toString());
        reportContentDto.setReportParam("export report");
        return null;
    }


    /**
     * 将报告内容组装成替换字段map
     * 后续支持自定义配置模板时需优化
     */
    private Map<String, String> assemblyParagraph(String reportType, ReportContentDto dto) {
        Map<String, String> params = new HashMap<>();
        params.put("${current_time}", dto.getReportDate());
        params.put("${report_param}", dto.getReportParam());
        params.put("${start_time}", StringUtils.isEmpty(dto.getReportStartTime()) ? " " : dto.getReportStartTime());
        params.put("${end_time}", StringUtils.isEmpty(dto.getReportEndTime()) ? " " : dto.getReportEndTime());
        return params;
    }
}
/**
 * word文档生成
 */
public class MakeReport {

    private static final AriesJc Logger LOGGER = AriesJcLoggerFactory.getLogger(MakeReport.class);
    
    /**
     * 内容格式docx
     */
    public static final String CONTENT_TYPE_DOCX
            = "application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8";

    /**
     * 将模板里的关键字替换并导出
     *
     * @param fileName
     * @param srcPath
     * @param map
     * @param fileName
     * @return
     * @throws Exception
     */
    public boolean replaceAndExportWord(List<Map<String, String>> tableParams, String srcPath,
                                        HttpServletResponse response, Map<String, String> map,
                                        String fileName) throws Exception {
        String[] sp = srcPath.split("\\.");
        OutputStream out;
        String docName = "docx";
        // 比较文件扩展名
        if (docName.equalsIgnoreCase(sp[sp.length - 1])) {
            try (FileInputStream fi = new FileInputStream(srcPath);
                 XWPFDocument document = new XWPFDocument(fi)) {
                // 处理段落
                List<XWPFParagraph> paragraphList = document.getParagraphs();
                processParagraphs(paragraphList, map);
                //进行换行和缩进
                handleDocParaTabAndWrap(paragraphList);
                //导出文档
                response.reset();
                //文件上传类型限制为docx文件
                response.setContentType(CONTENT_TYPE_DOCX);
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
                out = response.getOutputStream();
                document.write(out);
                out.flush();
                out.close();
                return true;
            } catch (Exception e) {
                LOGGER.errorWithErrorCode(ConstParamErrorCode.BS_COMMON_ERROR.code(), "can't export word", e);
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 处理docx中换行和缩进
     * @param paragraphList
     * @return
     * @throws Exception
     */
    public void handleDocParaTabAndWrap(List<XWPFParagraph> paragraphList) throws Exception
    {
        for(XWPFParagraph p : paragraphList) {
            List<XWPFRun> runs = p.getRuns();
            if (runs != null) {
                for (XWPFRun r : runs) {
                    //需要替换的文本
                    String text = r.getText(0);
                    if (text.indexOf("\n") != -1)
                    {
                        r.setText("", 0);
                        String[] split = text.split("\n");
                        //进行换行和缩进
                        if(split != null && split.length > 0)
                        {
                            for (int i = 0; i < split.length; i++)
                            {
                                r.setText(split[i]);
                                if(i < (split.length - 1))
                                {
                                    //实现换行
                                    r.addBreak();
                                    //实现缩进
                                    r.addTab();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换段落中的数据
     *
     * @param paragraphList
     * @param param         段落数据
     * @throws Exception
     */
    public void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, String> param) throws Exception {
        if (paragraphList != null && paragraphList.size() > 0) {
            for (XWPFParagraph paragraph : paragraphList) {
                boolean addReplace = false;
                List<XWPFRun> runs = paragraph.getRuns();
                //每个需要替换的key的run的位置的集合
                List<Integer> replaceRuns = new ArrayList<>();
                //每个段落的所有的key run的集合
                List<List<Integer>> perReplaceRunList = new ArrayList<>();
                for (int i = 0; i < runs.size(); i++) {
                    String text = runs.get(i).getText(0);
                    if (addReplace) {
                        replaceRuns.add(i);
                    }
                    if (text != null && text.contains("$")) {
                        addReplace = true;
                        replaceRuns.add(i);
                    }
                    if (text != null && text.contains("}")) {
                        addReplace = false;
                        perReplaceRunList.add(replaceRuns);
                        replaceRuns = new ArrayList<Integer>();
                    }
                }

                for (List<Integer> runsList : perReplaceRunList) {
                    StringBuilder textSb = new StringBuilder();
                    for (Integer aRunsList : runsList) {
                        textSb.append(runs.get(aRunsList).getText(0));
                    }
                    String replaceStr = textSb.toString();
                    for (int j = 0; j < runsList.size(); j++) {
                        for (Map.Entry<String, String> entry : param.entrySet()) {
                            String key = entry.getKey();
                            if (replaceStr.contains(key)) {
                                Object value = entry.getValue();
                                //文本替换
                                if (value != null) {
                                    replaceStr = replaceStr.replace(key, value.toString());
                                }
                            }
                        }
                    }

                    for (int j = 0; j < runsList.size(); j++) {
                        if (j == 0) {
                            runs.get(runsList.get(j)).setText(replaceStr, 0);
                        } else {
                            runs.get(runsList.get(j)).setText("", 0);
                        }
                    }
                }
            }
        }
    }
}
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页