一般的な考え方、自由なときに整理する
この方法では、最初にテンプレートという単語を使用してから、テンプレートのコンテンツを置き換えます。テンプレートのコンテンツは2つのブロックに分割され、1つは段落内にあり、もう1つは動的に生成する必要があるフォームであるため、次のようになります。また、2つのバックグラウンドメソッド
1:バックグラウンドメソッド(このメソッドはBaidu用に編成されています)
WordReporterパブリッククラス:
package com.fencer.common.wordUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WordReporter {
private String tempLocalPath;
private XWPFDocument xwpfDocument = null;
private FileInputStream inputStream = null;
private OutputStream outputStream = null;
public WordReporter(){
}
public WordReporter(String tempLocalPath){
this.tempLocalPath = tempLocalPath;
}
/**
* 设置模板路径
* @param tempLocalPath
*/
public void setTempLocalPath(String tempLocalPath) {
this.tempLocalPath = tempLocalPath;
}
/**
* 初始化
* @throws IOException
*/
public void init() throws IOException{
inputStream = new FileInputStream(new File(this.tempLocalPath));
xwpfDocument = new XWPFDocument(inputStream);
}
/**
* 导出方法
* @param
* @param tableIndex
* @return
* @throws Exception
*/
public boolean export( Map<String,Object> map, int tableIndex) throws Exception{
this.insertValueToTable(xwpfDocument,map,tableIndex);
return true;
}
/**
* 循环填充表格内容
* @param xwpfDocument
* @param
* @param tableIndex
* @throws Exception
*/
private void insertValueToTable(XWPFDocument xwpfDocument, Map<String,Object> mapAll, int tableIndex) throws Exception {
List<XWPFTable> tableList = xwpfDocument.getTables();
if(tableList.size()<=tableIndex){
throw new Exception("tableIndex对应的表格不存在");
}
XWPFTable table = tableList.get(tableIndex);
List<XWPFTableRow> rows = table.getRows();
if(rows.size()<2){
throw new Exception("tableIndex对应表格应该为2行");
}
//替换段落里面的变量
this.replaceInPara(xwpfDocument, mapAll);
List<Map<String,String>> params = (List<Map<String, String>>) mapAll.get("list");
//模板的那一行
XWPFTableRow tmpRow = rows.get(1);
List<XWPFTableCell> tmpCells = null;
List<XWPFTableCell> cells = null;
XWPFTableCell tmpCell = null;
tmpCells = tmpRow.getTableCells();
String cellText = null;
String cellTextKey = null;
Map<String,Object> totalMap = null;
for (int i = 0, len = params.size(); i < len; i++) {
Map<String,String> map = params.get(i);
// 创建新的一行
XWPFTableRow row = table.createRow();
// 获取模板的行高 设置为新一行的行高
row.setHeight(tmpRow.getHeight());
cells = row.getTableCells();
for (int k = 0, klen = cells.size(); k < klen; k++) {
tmpCell = tmpCells.get(k);
XWPFTableCell cell = cells.get(k);
cellText = tmpCell.getText();
if (StringUtils.isNotBlank(cellText)) {
//转换为mapkey对应的字段
cellTextKey = cellText.replace("$", "").replace("{", "").replace("}", "");
if (map.containsKey(cellTextKey)) {
// 填充内容 并且复制模板行的属性
setCellText(tmpCell,cell,map.get(cellTextKey));
}
}
}
}
// 删除模版行
table.removeRow(1);
}
/**
* 复制模板行的属性
* @param tmpCell
* @param cell
* @param text
* @throws Exception
*/
private void setCellText(XWPFTableCell tmpCell, XWPFTableCell cell,String text) throws Exception {
CTTc cttc2 = tmpCell.getCTTc();
CTTcPr ctPr2 = cttc2.getTcPr();
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
if (ctPr2.getTcW() != null) {
ctPr.addNewTcW().setW(ctPr2.getTcW().getW());
}
if (ctPr2.getVAlign() != null) {
ctPr.addNewVAlign().setVal(ctPr2.getVAlign().getVal());
}
if (cttc2.getPList().size() > 0) {
CTP ctp = cttc2.getPList().get(0);
if (ctp.getPPr() != null) {
if (ctp.getPPr().getJc() != null) {
cttc.getPList().get(0).addNewPPr().addNewJc()
.setVal(ctp.getPPr().getJc().getVal());
}
}
}
if (ctPr2.getTcBorders() != null) {
ctPr.setTcBorders(ctPr2.getTcBorders());
}
XWPFParagraph tmpP = tmpCell.getParagraphs().get(0);
XWPFParagraph cellP = cell.getParagraphs().get(0);
XWPFRun tmpR = null;
if (tmpP.getRuns() != null && tmpP.getRuns().size() > 0) {
tmpR = tmpP.getRuns().get(0);
}
XWPFRun cellR = cellP.createRun();
cellR.setText(text);
// 复制字体信息
if (tmpR != null) {
if(!cellR.isBold()){
cellR.setBold(tmpR.isBold());
}
cellR.setItalic(tmpR.isItalic());
cellR.setUnderline(tmpR.getUnderline());
cellR.setColor(tmpR.getColor());
cellR.setTextPosition(tmpR.getTextPosition());
if (tmpR.getFontSize() != -1) {
cellR.setFontSize(tmpR.getFontSize());
}
if (tmpR.getFontFamily() != null) {
cellR.setFontFamily(tmpR.getFontFamily());
}
if (tmpR.getCTR() != null) {
if (tmpR.getCTR().isSetRPr()) {
CTRPr tmpRPr = tmpR.getCTR().getRPr();
if (tmpRPr.isSetRFonts()) {
CTFonts tmpFonts = tmpRPr.getRFonts();
CTRPr cellRPr = cellR.getCTR().isSetRPr() ? cellR
.getCTR().getRPr() : cellR.getCTR().addNewRPr();
CTFonts cellFonts = cellRPr.isSetRFonts() ? cellRPr
.getRFonts() : cellRPr.addNewRFonts();
cellFonts.setAscii(tmpFonts.getAscii());
cellFonts.setAsciiTheme(tmpFonts.getAsciiTheme());
cellFonts.setCs(tmpFonts.getCs());
cellFonts.setCstheme(tmpFonts.getCstheme());
cellFonts.setEastAsia(tmpFonts.getEastAsia());
cellFonts.setEastAsiaTheme(tmpFonts.getEastAsiaTheme());
cellFonts.setHAnsi(tmpFonts.getHAnsi());
cellFonts.setHAnsiTheme(tmpFonts.getHAnsiTheme());
}
}
}
}
// 复制段落信息
cellP.setAlignment(tmpP.getAlignment());
cellP.setVerticalAlignment(tmpP.getVerticalAlignment());
cellP.setBorderBetween(tmpP.getBorderBetween());
cellP.setBorderBottom(tmpP.getBorderBottom());
cellP.setBorderLeft(tmpP.getBorderLeft());
cellP.setBorderRight(tmpP.getBorderRight());
cellP.setBorderTop(tmpP.getBorderTop());
cellP.setPageBreak(tmpP.isPageBreak());
if (tmpP.getCTP() != null) {
if (tmpP.getCTP().getPPr() != null) {
CTPPr tmpPPr = tmpP.getCTP().getPPr();
CTPPr cellPPr = cellP.getCTP().getPPr() != null ? cellP
.getCTP().getPPr() : cellP.getCTP().addNewPPr();
// 复制段落间距信息
CTSpacing tmpSpacing = tmpPPr.getSpacing();
if (tmpSpacing != null) {
CTSpacing cellSpacing = cellPPr.getSpacing() != null ? cellPPr
.getSpacing() : cellPPr.addNewSpacing();
if (tmpSpacing.getAfter() != null) {
cellSpacing.setAfter(tmpSpacing.getAfter());
}
if (tmpSpacing.getAfterAutospacing() != null) {
cellSpacing.setAfterAutospacing(tmpSpacing
.getAfterAutospacing());
}
if (tmpSpacing.getAfterLines() != null) {
cellSpacing.setAfterLines(tmpSpacing.getAfterLines());
}
if (tmpSpacing.getBefore() != null) {
cellSpacing.setBefore(tmpSpacing.getBefore());
}
if (tmpSpacing.getBeforeAutospacing() != null) {
cellSpacing.setBeforeAutospacing(tmpSpacing
.getBeforeAutospacing());
}
if (tmpSpacing.getBeforeLines() != null) {
cellSpacing.setBeforeLines(tmpSpacing.getBeforeLines());
}
if (tmpSpacing.getLine() != null) {
cellSpacing.setLine(tmpSpacing.getLine());
}
if (tmpSpacing.getLineRule() != null) {
cellSpacing.setLineRule(tmpSpacing.getLineRule());
}
}
// 复制段落缩进信息
CTInd tmpInd = tmpPPr.getInd();
if (tmpInd != null) {
CTInd cellInd = cellPPr.getInd() != null ? cellPPr.getInd()
: cellPPr.addNewInd();
if (tmpInd.getFirstLine() != null) {
cellInd.setFirstLine(tmpInd.getFirstLine());
}
if (tmpInd.getFirstLineChars() != null) {
cellInd.setFirstLineChars(tmpInd.getFirstLineChars());
}
if (tmpInd.getHanging() != null) {
cellInd.setHanging(tmpInd.getHanging());
}
if (tmpInd.getHangingChars() != null) {
cellInd.setHangingChars(tmpInd.getHangingChars());
}
if (tmpInd.getLeft() != null) {
cellInd.setLeft(tmpInd.getLeft());
}
if (tmpInd.getLeftChars() != null) {
cellInd.setLeftChars(tmpInd.getLeftChars());
}
if (tmpInd.getRight() != null) {
cellInd.setRight(tmpInd.getRight());
}
if (tmpInd.getRightChars() != null) {
cellInd.setRightChars(tmpInd.getRightChars());
}
}
}
}
}
/**
* @方法描述: 替换段落里面的变量
* doc 要替换的文档 params 替换的参数,数据库查询出来的数据
* @return: void
* @Author: carry
*/
private void replaceInPara(XWPFDocument doc, Map<String, Object> params) {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph para;
while (iterator.hasNext()) {
para = iterator.next();
this.replaceInPara(para, params);
}
}
/**
* @方法描述: 替换段落里面的变量
* para 要替换的文档 params 替换的参数,数据库查询出来的数据
* @return: void
* @Author: carry
*/
private void replaceInPara(XWPFParagraph para, Map<String, Object> params) {
List<XWPFRun> runs;
Matcher matcher;
if (this.matcher(para.getParagraphText()).find()) {
runs = para.getRuns();
for (int i = 0; i < runs.size(); i++) {
XWPFRun run = runs.get(i);
String runText = run.toString();
matcher = this.matcher(runText);
if (matcher.find()) {
while ((matcher = this.matcher(runText)).find()) {
runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
}
//直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,
//所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
para.removeRun(i);
para.insertNewRun(i).setText(runText);
}
}
}
}
/**
* @方法描述: 正则匹配字符串
* @return: java.util.regex.Matcher
* @Author: carry
*/
private Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
/**
* 收尾方法
* @param outDocPath
* @return
* @throws IOException
*/
public boolean generate(String outDocPath) throws IOException{
outputStream = new FileOutputStream(outDocPath);
xwpfDocument.write(outputStream);
return true;
}
/**
* @方法描述:
* path 下载的文件路径 projectname 这里意义不大 直接被vue前台替换了 suffix后缀名 这里意义不大 直接被vue前台替换了
* @return: javax.servlet.http.HttpServletResponse
* @Author: carry
*/
public HttpServletResponse download(String downloadPath, HttpServletResponse response) throws Exception {
// path是指欲下载的文件的路径。
File file = new File(downloadPath);
// 以流的形式下载文件。
InputStream fis = new BufferedInputStream(new FileInputStream(downloadPath));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
response.reset();
// 设置response的Header 这里意义不大 直接被vue前台替换了 所以可以删掉
response.addHeader("Content-Disposition", "attachment;filename="
+ new String(("" + "docx").getBytes("gbk"),
"iso-8859-1"));
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(
response.getOutputStream());
//注意这里很重要 vue的回调里根据ContentType类判断是否是下载的操作,这里不要改
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
this.close(fis);
this.close(toClient);
return response;
}
/**
* 关闭输入流
* @param is
*/
private void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 关闭输出流
* @param os
*/
private void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
メソッドを呼び出す
@Test
public void test() throws Exception {
//数据库的字段名,需要与上传模板的变量对应
Map<String ,Object> resultMap=new HashMap<String ,Object>();
SimpleDateFormat sdfYear =new SimpleDateFormat("yyyy年MM月dd日");
SimpleDateFormat sdfMine =new SimpleDateFormat("yyyy年MM月dd日 HH时");
Date date=new Date();
String reportDate=sdfYear.format(date);
String reportTime=sdfMine.format(date);
//后期可以改为动态的适应word模板
resultMap.put("yearid","2018-2019");
resultMap.put("period","1");
resultMap.put("reportDate",reportDate);
resultMap.put("reportTime",reportTime);
resultMap.put("ysll","39.98");
resultMap.put("nsbtrc","30.8");
resultMap.put("dyzrc","9.18");
resultMap.put("szbz","28.4");
resultMap.put("wrbz","26.1");
resultMap.put("sz","11.3");
resultMap.put("qd","14.48");
resultMap.put("qdrps","118.45");
resultMap.put("jhtrk","105.49");
resultMap.put("jhtck","92");
resultMap.put("jhtsw","13.57");
resultMap.put("wfrps","60.03");
resultMap.put("ytrps","48.07");
resultMap.put("whrps","41.96");
// 添加假数据 这里你也可以从数据库里获取数据
List<Map<String, String>> list = new ArrayList<>();
for (int i =0;i < 10; i++){
Map<String,String> map = new HashMap<>();
map.put("stnm", "分水口"+i);
map.put("q", "20");
map.put("w", "30");
map.put("total_w", "50");
list.add(map);
}
resultMap.put("list",list);
// 模板文件输入输出地址
String filePath = "C:\\Users\\叶子\\Desktop\\reportTemplate.docx";
String outPath = "C:\\Users\\叶子\\Desktop\\reportTemplateReal.docx";
WordReporter wordReporter = new WordReporter();
wordReporter.setTempLocalPath(filePath);
wordReporter.init();
wordReporter.export(resultMap,0);
wordReporter.generate(outPath);
}
フロントデスクでhttpメソッドをvueにカプセル化しました:http.js
//导出文件
export(config) {
if (config.data) {
config.responseType="blob";
config.params = {...config.params, ...config.data};
if(config.data.params != undefined){
config.params={ ...config.params,...config.data.params}
}
delete config.data;
}
return this.request(config);
}
と呼ばれる特定のページ:
<el-button type = "text" size = "small" @ click = "exportsWord(scope.row)">ダウンロード</ el-button>
//导出word
exportsWord(row) {
let params = {};
//传参id或者直接传参文件路径也可以到后台
params.id = row.id;
let fileName =
row.deptname +
row.yearid +
"年度" +
row.tm +
"日第" +
row.period +
"期运行日报";
this.$api.exportToWord(params).then(res => {
if (res.code == "0") {
let data = res.result.data;
console.log(data);
let blob = new Blob([data], {
//type mimi类型 可以百度详细类型
//word文档为msword,application/pdfpdf文档为pdf application/vnd.ms-excel
//image/jpeg jpg
type: `application/msword`
});
let objectUrl = URL.createObjectURL(blob);
let link = document.createElement("a");
let fname = fileName;
link.href = objectUrl;
link.setAttribute("download", fname);
document.body.appendChild(link);
link.click();
} else {
this.$message.error(res.msg);
}
});
},