1.添加依赖
org.freemarker
freemarker
2.3.28
org.docx4j
docx4j
6.1.2
org.apache.poi
poi
${poi.version}
org.apache.poi
poi-scratchpad
${poi.version}
org.apache.poi
poi-ooxml
${poi.version}
org.apache.poi
poi-ooxml-schemas
${poi.version}
fr.opensagres.xdocreport
xdocreport
1.0.6
org.apache.poi
ooxml-schemas
1.3
2.新建word
添加内容
项目编号:${projectCode!}
${ title!}
表2 -列表
${list!}
另存为mht文件
修改为ftl
修改内容,去掉${}间的样式文字
如果有图片需要添加 ${imagesBase64String}和${imagesXmlHrefString}
添加工具类
public class RichHtmlHandler {
private static final Logger logger = LoggerFactory.getLogger(RichHtmlHandler.class);
private String handledDocBodyBlock; //富文本所在doc中的区域
private List docBase64BlockResults = new ArrayList(); //文档中图片64位编码的结果区
private List xmlImgRefs = new ArrayList(); //图片在xml中的短路径
private RichObject richObject = null; //富文本对象
private Document doc = null; //默认文档为空
public RichHtmlHandler() {
super();
}
public RichHtmlHandler(RichObject richObj) throws IOException {
this.richObject = richObj;
doc = Jsoup.parse(wrappHtml(richObject.getHtml()));
handledHtml(richObject.getWebAppliction());
}
/**
* 处理html
*
* @param isWebApplication
* @throws IOException
*/
public void handledHtml(boolean isWebApplication)
throws IOException {
logger.debug("RichHtmlHandler handledHtml isWebApplication:" + isWebApplication);
Elements imags = doc.getElementsByTag("img");
if (imags == null || imags.size() == 0) {
// 返回编码后字符串
return;
//handledDocBodyBlock = WordHtmlGeneratorHelper.string2Ascii(html);
}
// 转换成word mht 能识别图片标签内容,去替换html中的图片标签
for (Element item : imags) {
// 把文件取出来
String src = item.attr("src");
String srcRealPath = src;
if (isWebApplication) {
String contentPath = RequestResponseContext.getRequest().getContextPath();
if (!StringUtils.isEmpty(contentPath)) {
if (src.startsWith(contentPath)) {
src = src.substring(contentPath.length());
}
}
srcRealPath = RequestResponseContext.getRequest().getSession()
.getServletContext().getRealPath(src);
}
File imageFile = new File(srcRealPath);
String imageFielShortName = imageFile.getName();
String fileTypeName = FileUtils.getFileSuffix(srcRealPath);
String docFileName = "image" + UUIDUtils.get32UUID() + "."
+ fileTypeName;
String srcLocationShortName = richObject.getDocSrcParent() + "/" + docFileName;
String styleAttr = item.attr("style"); // 样式
//高度
String imagHeightStr = item.attr("height");
;
if (StringUtils.isEmpty(imagHeightStr)) {
imagHeightStr = getStyleAttrValue(styleAttr, "height");
}
//宽度
String imagWidthStr = item.attr("width");
;
if (StringUtils.isEmpty(imagHeightStr)) {
imagHeightStr = getStyleAttrValue(styleAttr, "width");
}
imagHeightStr = imagHeightStr.replace("px", "");
imagWidthStr = imagWidthStr.replace("px", "");
if (StringUtils.isEmpty(imagHeightStr)) {
//去得到默认的文件高度
imagHeightStr = "0";
}
if (StringUtils.isEmpty(imagWidthStr)) {
imagWidthStr = "0";
}
int imageHeight = Integer.parseInt(imagHeightStr);
int imageWidth = Integer.parseInt(imagWidthStr);
//得到文件的word mht的body块
String handledDocBodyBlock = WordImageConvertor.toDocBodyBlock(srcRealPath,
imageFielShortName, imageHeight, imageWidth, styleAttr,
srcLocationShortName, richObject.getShapeidPrex(), richObject.getSpidPrex(), richObject.getTypeid());
item.after(handledDocBodyBlock);
//item.parent().append(handledDocBodyBlock);
item.remove();
// 去替换原生的html中的imag
String base64Content = WordImageConvertor
.imageToBase64(srcRealPath);
String contextLocation = richObject.getDocSrcLocationPrex() + "/" + richObject.getDocSrcParent()
+ "/" + docFileName;
String docBase64BlockResult = WordImageConvertor
.generateImageBase64Block(richObject.getNextPartId(), contextLocation,
fileTypeName, base64Content);
docBase64BlockResults.add(docBase64BlockResult);
String imgXMLHref = " ";
xmlImgRefs.add(imgXMLHref);
}
}
/**
* 获取样式的属性值
*
* @param style
* @param attributeKey
* @return
*/
private String getStyleAttrValue(String style, String attributeKey) {
if (StringUtils.isEmpty(style)) {
return "";
}
// 以";"分割
String[] styleAttrValues = style.split(";");
for (String item : styleAttrValues) {
// 在以 ":"分割
String[] keyValuePairs = item.split(":");
if (attributeKey.equals(keyValuePairs[0])) {
return keyValuePairs[1];
}
}
return "";
}
/**
* 给html添加必须的标签
*
* @param html
* @return
*/
private String wrappHtml(String html) {
// 因为传递过来都是不完整,需要添加以下标签
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append("");
sb.append(html);
sb.append("");
sb.append("");
return sb.toString();
}
public String getHandledDocBodyBlock() {
String raw = WordHtmlGeneratorHelper.string2Ascii(doc.getElementsByTag("body").html());
return raw.replace("=3D", "=").replace("=", "=3D");
//return handledDocBodyBlock;
}
public void setHandledDocBodyBlock(String handledDocBodyBlock) {
this.handledDocBodyBlock = handledDocBodyBlock;
}
public List getDocBase64BlockResults() {
return docBase64BlockResults;
}
public void setDocBase64BlockResults(List docBase64BlockResults) {
this.docBase64BlockResults = docBase64BlockResults;
}
public List getXmlImgRefs() {
return xmlImgRefs;
}
public void setXmlImgRefs(List xmlImgRefs) {
this.xmlImgRefs = xmlImgRefs;
}
public RichObject getRichObject() {
return richObject;
}
public void setRichObject(RichObject richObject) {
this.richObject = richObject;
}
}
public class WordGeneratorWithFreemarker {
private static final Logger logger = LoggerFactory.getLogger(WordGeneratorWithFreemarker.class);
/**
* 创建doc文件
*
* @param templatePath 模板所在路径 xxx/xxx/template
* @param templateName 模板名字 xxx.ftl
* @param dataMap 数据集合
* @param outPath 输出文件路径 xxx/xxx/xxx.doc
*/
public static void createDoc(String templatePath, String templateName, Map dataMap, String outPath) throws Exception {
logger.debug("WordGeneratorWithFreemarker createDoc()");
Freemarker.fprint(templatePath, templateName, dataMap, new FileOutputStream(new File(outPath)));
}
/**
* 创建doc文件
*
* @param templatePath 模板所在路径 xxx/xxx/template
* @param templateName 模板名字 xxx.ftl
* @param dataMap 数据集合
* @param response 文件流
*/
public static void createDoc(String templatePath, String templateName, Map dataMap, HttpServletResponse response) throws Exception {
logger.debug("WordGeneratorWithFreemarker createDoc()");
String fileName = "招标方案";
OutputStream out = response.getOutputStream();
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".doc");
Freemarker.fprint(templatePath, templateName, dataMap, response.getOutputStream());
out.flush();
out.close();
}
/**
* 创建富文本Html处理器,主要处理图片及编码
*
* @param richObject 需要的参数
* @return
*/
public static RichHtmlHandler createRichHtmlHandler(RichObject richObject) throws Exception {
logger.debug("WordGeneratorWithFreemarker createRichHtmlHandler()");
RichHtmlHandler richHtmlHandler = new RichHtmlHandler(richObject);
return richHtmlHandler;
}
/**
* 获取图片的64位字符串
*
* @param richHtmlHandlerList
* @return
*/
public static String getImagesBase64String(List richHtmlHandlerList) {
logger.debug("WordGeneratorWithFreemarker getImagesBase64String()");
String imagesBase64String = "";
for (RichHtmlHandler richHtmlHandler : richHtmlHandlerList) {
if (!CollectionUtils.isEmpty(richHtmlHandler.getDocBase64BlockResults())) {
for (String item : richHtmlHandler.getDocBase64BlockResults()) {
imagesBase64String += item + "\n";
}
}
}
logger.debug("WordGeneratorWithFreemarker getImagesBase64String() result:" + imagesBase64String);
return imagesBase64String;
}
/**
* 获取图片在xml中的端路径
*
* @param richHtmlHandlerList
* @return
*/
public static String getXmlImgHref(List richHtmlHandlerList) {
logger.debug("WordGeneratorWithFreemarker getXmlImgHref()");
String xmlImgHref = "";
for (RichHtmlHandler richHtmlHandler : richHtmlHandlerList) {
if (!CollectionUtils.isEmpty(richHtmlHandler.getXmlImgRefs())) {
for (String item : richHtmlHandler.getXmlImgRefs()) {
xmlImgHref += item + "\n";
}
}
}
logger.debug("WordGeneratorWithFreemarker getXmlImgHref() result:" + xmlImgHref);
return xmlImgHref;
}
}
public class RichObject {
private String html; //富文本html文件
//指doc转成mht之后的一些基础配置
private String docSrcParent = ""; //文档父类
private String docSrcLocationPrex = ""; //文档本地前缀
private String nextPartId; //下一个父类
private String shapeidPrex; //文档中shapeid前缀
private String spidPrex; //文档中spid的前缀
private String typeid; //类型ID
private Boolean isWebAppliction; //是不是web应用
public String getHtml() {
return html;
}
public void setHtml(String html) {
this.html = html;
}
public String getDocSrcParent() {
return docSrcParent;
}
public void setDocSrcParent(String docSrcParent) {
this.docSrcParent = docSrcParent;
}
public String getDocSrcLocationPrex() {
return docSrcLocationPrex;
}
public void setDocSrcLocationPrex(String docSrcLocationPrex) {
this.docSrcLocationPrex = docSrcLocationPrex;
}
public String getNextPartId() {
return nextPartId;
}
public void setNextPartId(String nextPartId) {
this.nextPartId = nextPartId;
}
public String getShapeidPrex() {
return shapeidPrex;
}
public void setShapeidPrex(String shapeidPrex) {
this.shapeidPrex = shapeidPrex;
}
public String getSpidPrex() {
return spidPrex;
}
public void setSpidPrex(String spidPrex) {
this.spidPrex = spidPrex;
}
public String getTypeid() {
return typeid;
}
public void setTypeid(String typeid) {
this.typeid = typeid;
}
public Boolean getWebAppliction() {
return isWebAppliction;
}
public void setWebAppliction(Boolean webAppliction) {
isWebAppliction = webAppliction;
}
@Override
public String toString() {
return "RichObject{" +
"html='" + html + '\'' +
", docSrcParent='" + docSrcParent + '\'' +
", docSrcLocationPrex='" + docSrcLocationPrex + '\'' +
", nextPartId='" + nextPartId + '\'' +
", shapeidPrex='" + shapeidPrex + '\'' +
", spidPrex='" + spidPrex + '\'' +
", typeid='" + typeid + '\'' +
", isWebAppliction=" + isWebAppliction +
'}';
}
}
编写测试类
public class ClientExample {
private static final Logger logger = LoggerFactory.getLogger(ClientExample.class);
public static void main(String[] agrs) throws Exception {
//用map存放数据
HashMap data = new HashMap();
//创建富文本
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append("");
sb.append("wesley 演示 导出富文本!@@#######¥¥%%%%………………&&&**~~~~~~&&&&&&&&、、、、、、、、");
sb.append("----多图分割线---");
sb.append("");
sb.append("中国梦,幸福梦!");
sb.append("");
RichObject richObject = new RichObject();
richObject.setHtml(sb.toString());
//--------------------此处可以spring配置文件配置,也可以直接读取属性文件获取------------------
//从mht文件中找
richObject.setDocSrcLocationPrex("file:///C:/268BA2D4");
richObject.setDocSrcParent("test.files");
richObject.setNextPartId("01D5AADE.67ACB0D0");
richObject.setShapeidPrex("_x56fe__x7247__x0020");
richObject.setTypeid("#_x0000_t75");
richObject.setSpidPrex("_x0000_i");
richObject.setWebAppliction(false);
//-----------------------------------------
RichHtmlHandler richHtmlHandler = WordGeneratorWithFreemarker.createRichHtmlHandler(richObject);
List richHtmlHandlerList = new ArrayList();
richHtmlHandlerList.add(richHtmlHandler);
data.put("imagesXmlHrefString", WordGeneratorWithFreemarker.getXmlImgHref(richHtmlHandlerList));
logger.debug("------imagesXmlHrefString-------" + WordGeneratorWithFreemarker.getXmlImgHref(richHtmlHandlerList));
data.put("imagesBase64String", WordGeneratorWithFreemarker.getImagesBase64String(richHtmlHandlerList));
logger.debug("------imagesBase64String-------" + WordGeneratorWithFreemarker.getImagesBase64String(richHtmlHandlerList));
data.put("projectCode", "1234");
data.put("title", "演示demo");
data.put("list", richHtmlHandler.getHandledDocBodyBlock());
String docFilePath = "D:\\test.doc";
String templatePath = Class.class.getResource("/ftl").getPath();
templatePath = java.net.URLDecoder.decode(templatePath, "utf-8");//这里我的路径有空格添加此处理
logger.debug("------templatePath-------" + templatePath);
WordGeneratorWithFreemarker.createDoc(templatePath, "test.ftl", data, docFilePath);
}
}
运行效果
springboot导出
@Override
public void export(HttpServletRequest request, HttpServletResponse response, String tmplId, String prjId) throws Exception {
//用map存放数据
HashMap data = getData(prjId);
//
TemplateConfig templateConfig = templateConfigService.selectByPrimaryKey(tmplId);
String templateName = templateConfig.getTemplateName();
// getRichContent(templateConfig,"");
String templatePath = Class.class.getResource("/ftl").getPath();
templatePath = java.net.URLDecoder.decode(templatePath, "utf-8");
logger.debug("------templatePath-------" + templatePath);
WordGeneratorWithFreemarker.createDoc(templatePath, templateName + ".ftl", data, response);
}
private String getRichContent(TemplateConfig templateConfig, String content) throws Exception {
RichObject richObject = getRichObject(templateConfig);
richObject.setHtml(content);
RichHtmlHandler richHtmlHandler = WordGeneratorWithFreemarker.createRichHtmlHandler(richObject);
List richHtmlHandlerList = new ArrayList();
richHtmlHandlerList.add(richHtmlHandler);
return richHtmlHandler.getHandledDocBodyBlock();
}
private HashMap getData(String projectId) {
Map map = planTenderMapper.getProjectInfo(projectId);
HashMap data = new HashMap();
data.put("projectCode", "200000000002168");
data.put("dateYear", "2019");
data.put("evaluationMethod", "xx");
data.put("bidDivision", "xx");
data.put("evaluationWeight", "xx");
data.put("suppliersNumber", "xx");
data.put("winningNumber", "xx");
data.put("biddingAgency", "xx");
data.put("serviceUnit", "xx");
data.put("completionTime", "2019年12月");
return data;
}
private RichObject getRichObject(TemplateConfig templateConfig) {
RichObject richObject = new RichObject();
//--------------------此处可以spring配置文件配置,也可以直接读取属性文件获取------------------
//从mht文件中找
richObject.setDocSrcLocationPrex("file:///C:/" + templateConfig.getLocationPrex());
richObject.setDocSrcParent(templateConfig.getTemplateName() + ".files");
richObject.setNextPartId(templateConfig.getNextPartId());
richObject.setShapeidPrex("_x56fe__x7247__x0020");
richObject.setTypeid("#_x0000_t75");
richObject.setSpidPrex("_x0000_i");
richObject.setWebAppliction(false);
//-----------------------------------------
return richObject;
}