条件查询数据并导出到word文档完整功能框架
程序员文章站
2022-06-15 14:16:00
...
一、概述
导出到word文档功能,主要以下步骤:
- 引入Apache POI、args4j、docx4j、xdocreport等 jar包
- 在服务器安装目录下保存模板word文档
- 点击导出后,查询数据
- 读取服务器模板word文档
- 替换文档内容
- 导出写入response对象
二、具体功能代码
主要包含:pom配置、实体类、接口、service类等
- 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>
- 实体类
/**
* 导出报告参数字段
*/
@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 = "";
}
- 服务器中保存的word文档模板样式,文档名称 template.docx,文档内容如下:
工作情况报告
${current_time}
${start_time} 至 ${end_time} 时间中,工作内容如下:
${report_param}
- 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);
}
}
}
}
}
}
}
上一篇: Fiber 树的构建