欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-15 14:16:00
...

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

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

条件查询数据并导出到word文档完整功能框架
二、具体功能代码
主要包含: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);
                        }
                    }
                }
            }
        }
    }
}