我們先看看需求:
我們要在模板標題插入內容,在多個表格中填充數據
先看東西
這裏我寫了個poi工具類方便操作
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
public class Word2007Util {
/**
* Description: 根據指定的參數值、模板,生成 word 文檔
* @param replaceParamMap 需要替換的參數map
* @param doc 文檔對象
* @return 生成後的 word 文檔對象
*/
public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, XWPFDocument doc) {
try {
if (replaceParamMap != null && replaceParamMap.size() > 0) {
// 處理段落
List<XWPFParagraph> paragraphList = doc.getParagraphs();
processParagraphs1(paragraphList, replaceParamMap, doc);
// 處理表格
Iterator<XWPFTable> it = doc.getTablesIterator();
while (it.hasNext()) {
XWPFTable table = it.next();
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
processParagraphs1(paragraphListTable, replaceParamMap, doc);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
/**
* Description: 根據指定的參數值、模板,生成 word 文檔
* @param replaceParamMap 需要替換的參數map
* @param is 文檔輸入流
* @return 生成後的 word 文檔對象
*/
public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, InputStream is) {
try {
return replaceWord(replaceParamMap, new XWPFDocument(is));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Description: 根據指定的參數值、模板,生成 word 文檔
* @param replaceParamMap 需要替換的參數map
* @param docTemplate 文檔模版路徑
* @return 生成後的 word 文檔對象
*/
public static XWPFDocument replaceWord(Map<String, Object> replaceParamMap, String docTemplate) {
OPCPackage pack;
try {
pack = POIXMLDocument.openPackage(docTemplate);
return replaceWord(replaceParamMap, new XWPFDocument(pack));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Description: 處理段落中的文字和圖片替換
* @param paragraphList 段落集合
* @param replaceParamMap 需要替換的參數map
* @param doc 文檔對象
*/
public static void processParagraphs1(List<XWPFParagraph> paragraphList, Map<String, Object> replaceParamMap, XWPFDocument doc) {
if (paragraphList == null || paragraphList.size() <= 0) {
return;
}
//循環段落
for (XWPFParagraph paragraph : paragraphList) {
List<XWPFRun> runs = paragraph.getRuns();
//循環每個小節,拼接爲一個字符串,避免拆分的時候,誤把替換字段標記 拆分
StringBuffer buffer = new StringBuffer();
for (XWPFRun xwpfRun : runs) {
String text = xwpfRun.getText(0);
if (text == null) {
continue;
}
buffer.append(text);
}
//循環替換字段map,替換內容
String textString = buffer.toString();
for (Entry<String, Object> entry : replaceParamMap.entrySet()) {
String key = entry.getKey();
if (textString.indexOf(key) != -1) {
//isSetText = true;
Object value = entry.getValue();
if(value == null) {
textString = textString.replace(key, "");
}
if (value instanceof Map) {// 圖片替換
// TODO 待實現
} else {//非map,則將值轉換爲string類型
textString = textString.replace(key, StringUtil.isNotEmpty(String.valueOf(value)) ? String.valueOf(value) : "");
}
}
}
//再次循環 把替換後的字符串 賦值給每個段落的最後一個小節,前面的小節全部設爲空
for(int i=0;i<runs.size();i++){
XWPFRun run = runs.get(i);
if(i<(runs.size()-1)){
run.setText(null, 0);
}else{
//如果內容裏面有換行標籤 需要替換掉換行標籤 並加入換行功能
if(textString.indexOf("<br>") !=-1){
String s[] = textString.split("<br>");
for (int j = 0; j < s.length; j++) {
run.setText(s[j],j);
if(j<s.length-1){
run.addBreak(); //換行
}
}
}else{
run.setText(textString, 0);
}
}
}
}
}
/**
* Description: 處理段落中的文字和圖片替換
* @param paragraphList 段落集合
* @param replaceParamMap 需要替換的參數map
* @param doc 文檔對象
*/
public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> replaceParamMap, XWPFDocument doc) {
if (paragraphList == null || paragraphList.size() <= 0) {
return;
}
for (XWPFParagraph paragraph : paragraphList) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text == null) {
continue;
}
boolean isSetText = false;
for (Entry<String, Object> entry : replaceParamMap.entrySet()) {
String key = entry.getKey();
if (text.indexOf(key) != -1) {
isSetText = true;
Object value = entry.getValue();
if(value == null) {
text = text.replace(key, "");
}
if (value instanceof String
|| value instanceof Integer
|| value instanceof Float
|| value instanceof Double) {// 文本替換
text = text.replace(key, StringUtil.isNotEmpty(value.toString()) ? value.toString() : "-");
}
if (value instanceof Map) {// 圖片替換
// TODO 待實現
}
}
}
if (isSetText) {
run.setText(text, 0);
}
}
}
}
/**
* Description: 將輸入流中的數據寫入字節數組
* @param in 輸入流
* @param isClose 是否關閉輸入流
* @return 字節數組
*/
public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
byte[] byteArray = null;
try {
int total = in.available();
byteArray = new byte[total];
in.read(byteArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (isClose) {
try {
in.close();
} catch (Exception e2) {
System.out.println("關閉流失敗");
}
}
}
return byteArray;
}
/**
* 取消表格邊框
*/
public static void removeTableBroder(XWPFTable table){
/**************************************/
CTTblBorders borders=table.getCTTbl().getTblPr().addNewTblBorders();
CTBorder hBorder=borders.addNewInsideH();
hBorder.setVal(STBorder.Enum.forString("none"));
hBorder.setSz(new BigInteger("1"));
hBorder.setColor("0000FF");
CTBorder vBorder=borders.addNewInsideV();
vBorder.setVal(STBorder.Enum.forString("none"));
vBorder.setSz(new BigInteger("1"));
vBorder.setColor("00FF00");
CTBorder lBorder=borders.addNewLeft();
lBorder.setVal(STBorder.Enum.forString("none"));
lBorder.setSz(new BigInteger("1"));
lBorder.setColor("3399FF");
CTBorder rBorder=borders.addNewRight();
rBorder.setVal(STBorder.Enum.forString("none"));
rBorder.setSz(new BigInteger("1"));
rBorder.setColor("F2B11F");
CTBorder tBorder=borders.addNewTop();
tBorder.setVal(STBorder.Enum.forString("none"));
tBorder.setSz(new BigInteger("1"));
tBorder.setColor("C3599D");
CTBorder bBorder=borders.addNewBottom();
bBorder.setVal(STBorder.Enum.forString("none"));
bBorder.setSz(new BigInteger("1"));
bBorder.setColor("F7E415");
}
/**
* 設置單元格樣式
*/
public static void setCellStyle(XWPFTableCell cell,String text,String fontFamily){
cell.removeParagraph(0);
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中
XWPFParagraph paragraphX = cell.addParagraph();
paragraphX.setFontAlignment(2);
XWPFRun run = paragraphX.createRun();
run.setFontFamily(fontFamily);
run.setText(text);
}
}
調用Controller
public class ExportController {
@Autowired
private ProjectApplyFlowService projectApplyFlowService;
@Autowired
private SpecialInfoService specialInfoService;
@Autowired
private StartSpecialInfoService startSpecialInfoService;
/***
* @Param [id, request, response]
* @return void
* @Description 導出項目彙總表
* @author liuzonghua
* @date 2020/6/30 17:48
**/
@RequestMapping("exportSpecialProject")
public void expertSpecialProject(String id, HttpServletRequest request, HttpServletResponse response){
try {
InputStream in = ResourceUtil.getResourceAsStream("/doc/applyCollectTable.docx");
XWPFDocument doc = null;
//數據
SearchCondition jqGridSearch = new JQGridSearch();
User currentUser = (User) this.getCurrentUser(request, response);
ConditionGroupsBuilder conditionGroupsBuilder = new ConditionGroupsBuilder();
conditionGroupsBuilder.addConditionField(new ConditionField("", "areaDepartmentId", ConditionFieldOp.BASE_EQUAL, currentUser.getDepartmentId()));
if(StringUtils.isNotBlank(id)) {
conditionGroupsBuilder.addConditionField(new ConditionField("", "projectBatchId", ConditionFieldOp.BASE_EQUAL, id));
}
jqGridSearch.addExtraConditionGroups(conditionGroupsBuilder.build());
//word多表結構(可再封裝方法)
List<List<Map<String, Object>>> data = new ArrayList<>();
List<Map<String, Object>> list = projectApplyFlowService.findCollectByProjectBatchIdAndAreaDepartmentId(id,currentUser.getDepartmentId());
data.add(list);
StartSpecialInfo startSpecialInfo = startSpecialInfoService.findById(id);
if(CollectionUtil.isNotEmpty(startSpecialInfo)){
SpecialInfo specialInfo = specialInfoService.findById(startSpecialInfo.getSpecialId());
if(CollectionUtil.isNotEmpty(specialInfo)){
doc = this.exportListDoc(in, data,specialInfo.getSpecialName());
}
}
String fileName = "項目申報彙總表"+ ".docx";
response.reset();
this.setDownloadResponse(request, response, fileName);
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
ServletOutputStream servletOS = response.getOutputStream();
doc.write(ostream);
servletOS.write(ostream.toByteArray());
servletOS.flush();
servletOS.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Param [in, data, specialName]
* @return org.apache.poi.xwpf.usermodel.XWPFDocument
* @Description 導出doc
* @author liuzonghua
* @date 2020/6/30 17:49
**/
public XWPFDocument exportListDoc(InputStream in, List<List<Map<String, Object>>> data,String specialName) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("${special}", specialName);
XWPFDocument doc = Word2007Util.replaceWord(map, in);
docList(data, doc);
return doc;
}
/**
* 導出列表
* @param data
* @param doc
* Description:
* Date: 2019年9月27日
* Time: 上午10:27:47
* @author liu.zonghua
*/
private void docList(List<List<Map<String, Object>>> data,XWPFDocument doc){
//得到表格對象列表
List<XWPFTable> tables = doc.getTables();
for(int j=0;j<data.size();j++) {
if(CollectionUtil.isNotEmpty(data.get(j))){
int i = 0;
for(Map<String, Object> map : data.get(j)){
//取第j+1個列表
XWPFTable table = tables.get(j);
//獲取表格行對象
XWPFTableRow row = null;
row = table.createRow();
XWPFTableCell cell0 = row.getCell(0);
Word2007Util.setCellStyle(cell0, StringUtil.parseString(i + 1),"仿宋");
XWPFTableCell cell1 = row.getCell(1);
Word2007Util.setCellStyle(cell1, MapUtils.getString(map, "title","") ,"仿宋");
XWPFTableCell cell2 = row.getCell(2);
Word2007Util.setCellStyle(cell2,MapUtils.getString(map, "startNum",""),"仿宋");
XWPFTableCell cell3 = row.getCell(3);
Word2007Util.setCellStyle(cell3,MapUtils.getString(map, "projectLeader",""),"仿宋");
XWPFTableCell cell4 = row.getCell(4);
Word2007Util.setCellStyle(cell4, MapUtils.getString(map, "phone",""),"仿宋");
XWPFTableCell cell5 = row.getCell(5);
Word2007Util.setCellStyle(cell5, MapUtils.getString(map, "enterpriseStartTime",""),"仿宋");
XWPFTableCell cell6 = row.getCell(6);
Word2007Util.setCellStyle(cell6, MapUtils.getString(map, "enterpriseEndTime",""),"仿宋");
i++;
}
}else {
//取第j+1個列表
XWPFTable table = tables.get(j);
//獲取表格行對象
XWPFTableRow row = null;
row = table.createRow();
XWPFTableCell cell0 = row.getCell(0);
Word2007Util.setCellStyle(cell0,"","仿宋");
XWPFTableCell cell1 = row.createCell();
Word2007Util.setCellStyle(cell1, "","仿宋");
XWPFTableCell cell2 = row.createCell();
Word2007Util.setCellStyle(cell2, "","仿宋");
XWPFTableCell cell3 = row.createCell();
Word2007Util.setCellStyle(cell3, "","仿宋");
XWPFTableCell cell4 = row.createCell();
Word2007Util.setCellStyle(cell4, "","仿宋");
XWPFTableCell cell5 = row.createCell();
Word2007Util.setCellStyle(cell5, "","仿宋");
}
}
}
/***
* @Param [request, response, fileName]
* @return void
* @Description 下載相關
* @author liuzonghua
* @date 2020/6/30 17:49
**/
public void setDownloadResponse(HttpServletRequest request, HttpServletResponse response,
String fileName) throws Exception {
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
String downloadFileName = "";
if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) {
downloadFileName = URLEncoder.encode(fileName, "UTF-8");
} else {
downloadFileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
}
response.setHeader("Content-disposition", "attachment; filename=" + downloadFileName);
}
}
解析
public XWPFDocument exportListDoc(InputStream in, List<List<Map<String, Object>>> data,String specialName) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("${special}", specialName);
XWPFDocument doc = Word2007Util.replaceWord(map, in);
docList(data, doc);
return doc;
}
這塊來替換word中${}數據
得到多個表格對象
List<XWPFTable> tables = doc.getTables();
通過List<List<Map<String, Object>>數據來與表格對應
然後獲取表格,填充內容,設置樣式。
//獲取表格行對象
XWPFTableRow row = null;
row = table.createRow();
XWPFTableCell cell0 = row.getCell(0);
Word2007Util.setCellStyle(cell0, StringUtil.parseString(i + 1),"仿宋");