我们先看看需求: 我们要在模板标题插入内容,在多个表格中填充数据
先看东西
这里我写了个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),"仿宋");