最近在开发中有按照模板导出word的需求,并且把echarts图例附到word里,我开始使用freework取ftl模板的,不过由于转换麻烦,需定义好格式xml再转为ftl文件所以改为使用poi取word模板直接赋值的方式,并且通过拼接标签实现图片的附带和定义宽度高度。
1、controller代码
package com.springboot.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
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.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import net.sf.json.JSONObject;
@Controller
public class WordTest {
@RequestMapping("/exportSellPlan")
public @ResponseBody void exportSellPlan(Long id, HttpServletRequest request, HttpServletResponse response)throws Exception{
String rpName=request.getParameter("rpName")==null?"":request.getParameter("rpName");
rpName=java.net.URLDecoder.decode(rpName,"UTF-8") ;
String title = rpName;
OutputStream out = null;
String path="C:\\Users\\Administrator\\Desktop\\demo.docx";
//String path = request.getSession().getServletContext().getRealPath("/efficiency/EnergyCellReport/中能瑞通模板.docx");
try {
out = response.getOutputStream();
/**
* 读取word
*/
XWPFDocument docx = PropertiesUtil.importWord(path);
//docx = mFaultReportManageService.fillWordDataByList(docx, maps);
/**
* 数据组装
*/
//获取所有需要填充的数据
//List<Map<String,String>> codeList = energyUnitService.queryEnergyReportDiList(rpId, consId);
Map<String, String> wdmap = new HashMap<String, String>();
com.alibaba.fastjson.JSONObject json=new com.alibaba.fastjson.JSONObject();
// String appId=UserUtil.getAppId();
// json.put("appId", appId);
// TenantAppClone app=energyUnitService.selectObjectByID(json);
wdmap.put("Title-N01","aaa");
Map<String,Object> map = new HashMap<>();
map.put("filepath", "C:\\Users\\Administrator\\Desktop\\50a6dcc7ly1g2g62aqxzpj22re1ulx6p.jpg");
map.put("width", "100");
map.put("height", "100");
wdmap.put("img-scoreimg",String.valueOf(JSONObject.fromObject(map)));
replaceInPara(docx,wdmap);
/*boolean flag_cp=false;
if(codeList!=null&&codeList.size()>0){
for(Map<String,String> map:codeList){
if(map.get("CODE_VALUE").equals("the-cpname")){
flag_cp=true;
}
}
}
//填充word中的产品表格
if(flag_cp){
this.queryProduct(docx,rpTime);
}
//填充值
//this.writeInWord(codeList,docx,rpTime);
Map<String, String> wdmap = new HashMap<String, String>();
if(codeList!=null&&codeList.size()>0){
for(int i=0;i<codeList.size();i++){
Map map = codeList.get(i);
wdmap.put(map.get("CODE_VALUE").toString(),map.get("RP_VALUE").toString()); //公司名称
}
}
//修改word中的值
replaceInPara(docx,wdmap);*/
/**
* 生成word
*/
PropertiesUtil.exportWord(docx, title, out, request, response);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* word中 的文字填入
* @param docx
* @param params
*/
public void replaceInPara(XWPFDocument docx, Map<String, String> params) {
Iterator<XWPFParagraph> itPara = docx.getParagraphsIterator();
while (itPara.hasNext()) {
XWPFParagraph paragraph = (XWPFParagraph) itPara.next();
Set<String> set = params.keySet();
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
List<XWPFRun> run = paragraph.getRuns();
for (int i = 0; i < run.size(); i++) {
System.out.println(run.get(i).getText(run.get(i).getTextPosition())+"-------------------------");
if (run.get(i).getText(run.get(i).getTextPosition()) != null&& run.get(i).getText(run.get(i).getTextPosition()).equalsIgnoreCase(key)) {
if (!(key.startsWith("img-"))) {
run.get(i).setText(params.get(key), 0);
} else {
run.get(i).setText("", 0);
Map<String, String> pic = new HashMap<String, String>();
System.err.println(params.get(key));
JSONObject jsonObject = JSONObject.fromObject(params.get(key));
for (Iterator<?> iter = jsonObject.keys(); iter.hasNext();)
{
String k = (String) iter.next();
String v = jsonObject.get(k).toString();
pic.put(k, v);
}
int width = Integer.parseInt(pic.get("width").toString());
int height = Integer.parseInt(pic.get("height").toString());
byte[] byteArray = null;
FileInputStream in = null;
try {
in = new FileInputStream(pic.get("filepath").toString());
int total = in.available();
byteArray = new byte[total];
in.read(byteArray);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
in.close();
} catch (Exception e2) {
System.out.println("关闭流失败");
}
}
int picType = XWPFDocument.PICTURE_TYPE_PNG;
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
try {
String ind = docx.addPictureData(byteInputStream,picType);
//docx.createPicture(width , height,paragraph);
final int EMU = 9525;
width *= EMU;
height *= EMU;
String blipId = ind;
CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();
String picXml = ""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ 1
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>";
inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(1);
docPr.setName("图片" + 1);
docPr.setDescr("测试");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
2、PropertiesUtil代码:
package com.springboot.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
/**
* @Description 加载属性配置文件工具类
*/
public class PropertiesUtil {
/**
* 导出word
* @param docx
* @param title
* @param out
* @param request
* @param response
* @throws Exception
*/
public static void exportWord(XWPFDocument docx, String title, OutputStream out, HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 兼容浏览器
String userAgent = request.getHeader("USER-AGENT");
if (!StringUtils.contains(userAgent, "Mozilla")) {// 火狐浏览器
title = URLEncoder.encode(title, "UTF-8");// 其他浏览器
} else {
title = new String(title.getBytes("UTF-8"), "ISO8859-1");
}
response.setContentType("application/msword");
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Content-Disposition", "attachment;filename=" + title + ".doc");
// 创建word文档
try {
docx.write(out);
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
}
}
/**
* 读取word
* @param fileName
* @return
* @throws Exception
*/
public static XWPFDocument importWord(String fileName) throws Exception {
InputStream in = null;
XWPFDocument docx = null;
try {
in = new FileInputStream(new File(fileName));
docx = new XWPFDocument(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
in.close();
}
return docx;
}
/**
* 表格填充值
* @param table
* @return
*/
public static int getNullValuePos(XWPFTable table) {
List<XWPFTableRow> rows = null;
List<XWPFTableCell> cells = null;
XWPFTableRow row = null;
rows = table.getRows();
// 至少第一行是标题行 从表题行的下一行进行查询
int t = -1;
for (int i = 0; i < rows.size(); i++) {
// 获取当前行
row = rows.get(i);
// 获取当前行的所有cell
cells = row.getTableCells();
// 获取cell的size
int cellSize = cells.size();
// 获取最后一个cell的内容
XWPFTableCell cell = cells.get(cellSize - 1);
String text = cell.getText().trim();
if (StringUtils.isBlank(text)) {
t = i;
break;
}
}
return t;
}
}
3、excel模板:(根据代码我只示例了一个赋值的参数一个图片的参数)
填充值:
填充图片:
代码赋值示例:(图片需要三个参数地址、宽度、高度)
3、效果
值效果:
图片效果: