<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
核心代码
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import org.jsoup.nodes.Document;
import sun.misc.BASE64Encoder;
@RestController
public class WordController {
@GetMapping("/")
public String html2doc(HttpServletResponse response) throws IOException {
byte b[] = getHtml().getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(b);
POIFSFileSystem poifs = new POIFSFileSystem();
DirectoryEntry directory = poifs.getRoot();
DocumentEntry documentEntry = directory.createDocument("WordDocument", bais);
//输出文件
String name = "test";
name = java.net.URLEncoder.encode(name, "UTF-8");
response.reset();
response.setHeader("Content-Disposition",
"attachment;filename=" +
new String((name + ".doc").getBytes(),
"utf-8"));
response.setContentType("application/msword;charset=utf-8");
OutputStream ostream = response.getOutputStream();
//输出到本地文件的话,new一个文件流
poifs.writeFilesystem(ostream);
bais.close();
ostream.close();
return null;
}
public String getHtml() {
String content = "";
Document doc = Jsoup.parse(content);
Elements img = doc.select("img");
img.forEach(p -> {
p.attr("src", "data:image/jpeg;base64," + ImageToBase64ByOnline(p.attr("src")));
});
doc.head().append("");
// jsoup标准化标签,生成闭合标签
doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
return doc.html();
}
/**
* 在线图片转换成base64字符串
*
* @param imgURL 图片线上路径
* @return
*/
public static String ImageToBase64ByOnline(String imgURL) {
ByteArrayOutputStream data = new ByteArrayOutputStream();
try {
// 创建URL
URL url = new URL(imgURL);
byte[] by = new byte[1024];
// 创建链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
InputStream is = conn.getInputStream();
// 将内容读取内存中
int len = -1;
while ((len = is.read(by)) != -1) {
data.write(by, 0, len);
}
// 关闭流
is.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data.toByteArray());
}
}
maven依赖
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>core-renderer</artifactId>
<version>R8</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
核心代码
import com.lowagie.text.DocumentException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.jsoup.nodes.Document;
import sun.misc.BASE64Encoder;
@RestController
public class PdfController {
@GetMapping("/")
public String html2pdf(HttpServletResponse response) throws DocumentException, IOException {
ITextRenderer renderer = new ITextRenderer();
//图片base64支持,把图片转换为itext自己的图片对象
renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());
renderer.getSharedContext().getTextRenderer().setSmoothingThreshold(0);
renderer.setDocumentFromString(getHtml());
ITextFontResolver fontResolver = renderer.getFontResolver();
renderer.layout();
String fileName = "test.pdf";
fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/pdf");
//打开浏览器窗口预览文件
response.setHeader("Content-Disposition", "filename=" + new String(fileName.getBytes(), "iso8859-1"));
OutputStream ostream = response.getOutputStream();
renderer.createPDF(ostream);
ostream.close();
return null;
}
public String getHtml() {
String content = "";
Document doc = Jsoup.parse(content);
Elements img = doc.select("img");
img.forEach(p -> {
p.attr("src", "data:image/jpeg;base64," + ImageToBase64ByOnline(p.attr("src")));
});
doc.head().append("");
// jsoup标准化标签,生成闭合标签
doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
return doc.html();
}
/**
* 在线图片转换成base64字符串
*
* @param imgURL 图片线上路径
* @return
*/
public static String ImageToBase64ByOnline(String imgURL) {
ByteArrayOutputStream data = new ByteArrayOutputStream();
try {
// 创建URL
URL url = new URL(imgURL);
byte[] by = new byte[1024];
// 创建链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
InputStream is = conn.getInputStream();
// 将内容读取内存中
int len = -1;
while ((len = is.read(by)) != -1) {
data.write(by, 0, len);
}
// 关闭流
is.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data.toByteArray());
}
}
Base64ImgReplacedElementFactory类
import java.io.IOException;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;
import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.codec.Base64;
/**
* 图片base64支持,把图片转换为itext自己的图片对象
*
*/
public class Base64ImgReplacedElementFactory implements ReplacedElementFactory {
/**
* 实现createReplacedElement 替换html中的Img标签
*
* @param c 上下文
* @param box 盒子
* @param uac 回调
* @param cssWidth css宽
* @param cssHeight css高
* @return ReplacedElement
*/
@Override
public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac,
int cssWidth, int cssHeight) {
Element e = box.getElement();
if (e == null) {
return null;
}
String nodeName = e.getNodeName();
// 找到img标签
if (nodeName.equals("img")) {
String attribute = e.getAttribute("src");
FSImage fsImage;
try {
// 生成itext图像
fsImage = buildImage(attribute, uac);
} catch (BadElementException e1) {
fsImage = null;
} catch (IOException e1) {
fsImage = null;
}
if (fsImage != null) {
// 对图像进行缩放
if (cssWidth != -1 || cssHeight != -1) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
/**
* 编解码base64并生成itext图像
*/
protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException,
BadElementException {
FSImage fiImg=null;
if (srcAttr.toLowerCase().startsWith("data:image/")) {
String base64Code= srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(),
srcAttr.length());
// 解码
byte[] decodedBytes = Base64.decode(base64Code);
fiImg= new ITextFSImage(Image.getInstance(decodedBytes));
} else {
fiImg= uac.getImageResource(srcAttr).getImage();
}
return fiImg;
}
@Override
public void reset() {}
@Override
public void remove(Element arg0) {}
@Override
public void setFormSubmissionListener(FormSubmissionListener arg0) {}
}