最近公司有需求word转html,这里记录一下方便以后使用。
- 添加maven依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-transcoder -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.arnx/wmf2svg -->
<dependency>
<groupId>net.arnx</groupId>
<artifactId>wmf2svg</artifactId>
<version>0.9.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/fr.opensagres.xdocreport/org.apache.poi.xwpf.converter.xhtml -->
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
- doc转html
工具类代码如下:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.model.TextPieceTable;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableIterator;
import org.apache.poi.xwpf.converter.core.BasicURIResolver;
import org.apache.poi.xwpf.converter.core.FileImageExtractor;
import org.apache.poi.xwpf.converter.core.FileURIResolver;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
/**
* doc文档操作
* 依赖
* poi-3.13.jar
* poi-scratchpad-3.13.jar
* commonbean.jar
*
* @author yellowcong
* @date 2016年1月8日
*
* 重要方法
* copyDocToHtml 将文档转化为html
* 这个将doc转化为html的文档,没有分页的功能和图片裁减功能,所以导致的显示结果并非很理想
*
* copyHtmlToDoc 将html转化为文档
*
* 这个copyHtmlToDoc的方法还没有写完,比较的麻烦,所以需要慢慢的弄好
*
*/
@Slf4j
public class DocUtils {
//用于存储我们的文件的前缀名称,有内部类,所以需要加入static才可以访问
static String prefixName = "";
private DocUtils(){}
public static void main(String[] args) throws Exception {
//文件所在目录
File file = new File("C:\\D\\test.doc");
//doc转html
docToHtml(file);
//docx 转html(试验不成功)
docxToHtml();
}
/**
* 将我们的doc转化为html文档
* 这个直接输入我们的doc地址,然后就在那个地址下面生成对应的文件,简单方便
* @param file doc文件
*/
public static void docToHtml(File file){
String name = getFileSimpleName(file.getPath())+".html";
DocUtils.copyDocToHtml(file, new File(name));
}
public static String getFileSimpleName(String path){
log.info("文件路径:{}",path);
return path.substring(0,path.lastIndexOf("."));
}
/**
* 将doc转化为html
* @param file 我们的 doc文档
* @param tagart 生成的文档
*/
private static void copyDocToHtml(File file,File tagart){
try {
//获取文件夹名称
prefixName = FilenameUtils.getBaseName(tagart.getName());
//如果没有,就创建目标文件夹
//simpleName 这种方法会去掉 后缀名称
File imgFile = new File(getFileSimpleName(tagart.getPath()));
if(!imgFile.exists()){
imgFile.mkdirs();
}
HWPFDocument doc = new HWPFDocument(new FileInputStream(file));
//初始化转换器
WordToHtmlConverter converter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
//设定图片管理
converter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] paramArrayOfByte,
PictureType paramPictureType, String paramString,
float paramFloat1, float paramFloat2) {
//这里也可以将图片上传到文件服务器 然后返回图片url地址
// return "https://bkimg.cdn.bcebos.com/formula/b9b2c43b9e825cbc2307b2eb9c729128.svg";
//设定图片路径
return prefixName+File.separator+paramString.replace(".wmf",".svg");
}
});
converter.processDocument(doc);
//设定图片
List<Picture> pics = DocUtils.listDocPics(doc);
//存储图片,根据给定的名称
for(Picture pic:pics){
//将文件直接写出去
pic.writeImageContent(new FileOutputStream(new File(imgFile,pic.suggestFullFileName())));
if (pic.suggestFullFileName().contains(".wmf")){ //如果图片资源是wmf格式 需要转换成svg格式才能正常显示
String picName = pic.suggestFullFileName().replace(".wmf",".svg");
Wmf2Png.wmfToSvg(imgFile + "\\" + pic.suggestFullFileName(),imgFile + "\\" + picName);
}
}
//导入w3c的document包
Document docHtml = converter.getDocument();
DOMSource source = new DOMSource(docHtml);
//数据
//ByteOutputStream out = new ByteOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
StreamResult result = new StreamResult(out);
TransformerFactory tf =TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "html");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.transform(source, result);
//输出文件
DocUtils.copyByte2File(out.toByteArray(),tagart);
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将字符数据转化为我们的文件
* @param data 字节数组
* @param file 输出文件
*/
private static void copyByte2File(byte [] data,File file){
if ((data == null) || (data.length <= 0))
return;
OutputStream out = null;
InputStream in = null;
try {
out = new FileOutputStream(file);
in = new ByteArrayInputStream(data);
//in = new ByteInputStream(data,data.length );
byte [] buff = new byte[1024];
int len = 0;
while((len = in.read(buff))>0){
out.write(buff, 0, len);
}
out.flush();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(in != null){
in.close();
}
} catch (Exception e2) {
// TODO: handle exception
}finally{
try {
if(out != null){
out.close();
}
} catch (Exception e3) {
// TODO: handle exception
}
}
}
}
/**
* 将文档中的图片存到文件夹中
* @param pics 图片集合
* @param path 文件存储路径
*/
public static void copyPic2Disk(List<Picture> pics,File path){
if(pics == null || pics.size() <=0){
return;
}
if(!path.isDirectory()){
throw new RuntimeException("路径填写不正确");
}
//当文件夹路径不存在的情况下,我们自己创建文件夹目录
if(!path.exists() ){
path.mkdirs();
}
try {
for(Picture pic:pics){
//写出数据,我们使用的是Poi类中,Picture自己所带的函数
pic.writeImageContent(new FileOutputStream(new File(path,pic.suggestFullFileName())));
// pic.getContent(); //获取字节流,也可以自己写入数据
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取一个文档中的所有图片资源信息
* @param doc
* @return List<Picture> 图片文件集合
*/
public static List<Picture> listDocPics(HWPFDocument doc){
return doc.getPicturesTable().getAllPictures();
}
/**
* 获取一个文档中的所有 表格资源信息
* @param doc
* @return List<Table> 文件中表格的数目
*/
public static List<Table> listDocTables(HWPFDocument doc){
//
TableIterator it = new TableIterator(doc.getRange());
List<Table> tables = new ArrayList<Table>();
while(it.hasNext()){
tables.add(it.next());
}
return tables;
}
public static String docxToHtml() throws Exception {
File path = new File(ResourceUtils.getURL("classpath:").getPath());
String imagePath = path.getAbsolutePath() + "\\static\\image";
String sourceFileName = path.getAbsolutePath() + "\\static\\test.docx";
String targetFileName = path.getAbsolutePath() + "\\static\\test.html";
OutputStreamWriter outputStreamWriter = null;
try {
XWPFDocument document = new XWPFDocument(new FileInputStream(sourceFileName));
XHTMLOptions options = XHTMLOptions.create();
// 存放图片的文件夹
options.setExtractor(new FileImageExtractor(new File(imagePath)));
// html中图片的路径
options.URIResolver(new BasicURIResolver("image"));
outputStreamWriter = new OutputStreamWriter(new FileOutputStream(targetFileName), "utf-8");
XHTMLConverter xhtmlConverter = (XHTMLConverter) XHTMLConverter.getInstance();
xhtmlConverter.convert(document, outputStreamWriter, options);
} finally {
if (outputStreamWriter != null) {
outputStreamWriter.close();
}
}
return targetFileName;
}
public static void docx2Html(){
String path="C:\\D\\testx.docx";
String imagePath="C:\\D\\testx\\";
String outPath="C:\\D\\testx.html";
File file=new File(path);
File imageFile=new File(imagePath);
if(!file.exists()){
System.out.println("文件不存在!");
}
try {
InputStream in=new FileInputStream(file);
XWPFDocument document=new XWPFDocument(in);
//存储图片
XHTMLOptions options=XHTMLOptions.create().URIResolver(new FileURIResolver(imageFile));
options.setExtractor(new FileImageExtractor(imageFile));
OutputStream out=new FileOutputStream(outPath);
/*Writer writer=new FileWriter(file,true);
IContentHandlerFactory factory = options.getContentHandlerFactory();
if (factory == null) {
factory = DefaultContentHandlerFactory.INSTANCE;
}
ContentHandler contentHandler = factory.create(out, writer, options);
//XHTMLConverter.getInstance().convert(document,out,options);*/
XHTMLConverter converter=new XHTMLConverter();
converter.convert(document,out,options);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
swf转svg图片工具类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.zip.GZIPOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import net.arnx.wmf2svg.gdi.svg.SvgGdi;
import net.arnx.wmf2svg.gdi.wmf.WmfParser;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Wmf2Png {
public static void main(String[] args) throws Exception {
// convert("F:\\SVN\\BobUtil\\web\\25177.wmf");
// System.out.println((20 / (21 * 1.0)));
// svgToPng("F:\\SVN\\BobUtil\\web\\25177.svg", "F:\\SVN\\BobUtil\\web\\25177.png");
}
/**
* @Description: 进行转换
* @param filePath
* 文件路径
* @return 设定文件
*/
public static String convert(String filePath) {
String pngFile = "";
File wmfFile = new File(filePath);
try {
if (!wmfFile.getName().contains(".wmf")) {
throw new Exception("请确认输入的文件类型是wmf");
}
// wmf -> svg
String svgFile = filePath.replace("wmf", "svg");
wmfToSvg(filePath, svgFile);
// 对svg做预出理
PreprocessSvgFile(svgFile);
// svg -> png
pngFile = filePath.replace("wmf", "png");
svgToPng(svgFile, pngFile);
// 删除 svg
File file = new File(svgFile);
if (file.exists()) {
file.delete();
}
// 删除 wmf
if (wmfFile.exists()) {
wmfFile.delete();
}
} catch (Exception e) {
try {
e.printStackTrace();
wmfToJpg(filePath);
} catch (Exception e1) {
e1.printStackTrace();
}
}
return wmfFile.getName().replace("wmf", "png");
}
/**
* 将wmf转换为svg
*
* @param src
* @param dest
*/
public static OutputStream wmfToSvgFile(File wmfFile, String dest) throws Exception {
boolean compatible = false;
try {
InputStream in = new FileInputStream(wmfFile);
WmfParser parser = new WmfParser();
final SvgGdi gdi = new SvgGdi(compatible);
parser.parse(in, gdi);
Document doc = gdi.getDocument();
OutputStream out = new FileOutputStream(dest);
if (dest.endsWith(".svgz")) {
out = new GZIPOutputStream(out);
}
getOutput(doc,out);
return out;
//output(doc, out);
} catch (Exception e) {
throw e;
}
}
/**
* 将wmf转换为svg
*
* @param src
* @param dest
*/
public static void wmfToSvg(String src, String dest) throws Exception {
boolean compatible = false;
try {
InputStream in = new FileInputStream(src);
WmfParser parser = new WmfParser();
final SvgGdi gdi = new SvgGdi(compatible);
parser.parse(in, gdi);
Document doc = gdi.getDocument();
OutputStream out = new FileOutputStream(dest);
if (dest.endsWith(".svgz")) {
out = new GZIPOutputStream(out);
}
output(doc, out);
} catch (Exception e) {
throw e;
}
}
/**
* @Description: 输出svg文件
* @param doc
* @param out
* @throws Exception
* 设定文件
*/
private static void output(Document doc, OutputStream out) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 1.0//EN");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
transformer.transform(new DOMSource(doc), new StreamResult(out));
out.flush();
out.close();
out = null;
}
/**
* @Description: 输出svg文件
* @param doc
* @param out
* @throws Exception
* 设定文件
*/
private static void getOutput(Document doc, OutputStream out) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 1.0//EN");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
transformer.transform(new DOMSource(doc), new StreamResult(out));
// out.flush();
// out.close();
// out = null;
}
/**
* @Description:对svg文件做预处理(这里主要是调整大小,先缩小10倍,如果还大于默认值,则按比例缩小)
* @param svgFile
* @throws Exception
* 设定文件
*/
private static void PreprocessSvgFile(String svgFile) throws Exception {
int defaultWeight = 500;// 默认宽度
FileInputStream inputs = new FileInputStream(svgFile);
Scanner sc = new Scanner(inputs, "UTF-8");
ByteArrayOutputStream os = new ByteArrayOutputStream();
while (sc.hasNextLine()) {
String ln = sc.nextLine();
if (!ln.startsWith("<!DOCTYPE")) {
os.write((ln + "\r\n").getBytes());
}
}
os.flush();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
builder = factory.newDocumentBuilder();
Document doc = null;
try {
doc = builder.parse(new ByteArrayInputStream(os.toByteArray()));
} catch (Exception e) {
inputs = new FileInputStream(svgFile);
os = new ByteArrayOutputStream();
int noOfByteRead = 0;
while ((noOfByteRead = inputs.read()) != -1) {
os.write(noOfByteRead);
}
os.flush();
doc = builder.parse(new ByteArrayInputStream(os.toByteArray()));
} finally {
os.close();
inputs.close();
}
int height = Integer.parseInt(((Element) doc.getElementsByTagName("svg").item(0)).getAttribute("height"));
int width = Integer.parseInt(((Element) doc.getElementsByTagName("svg").item(0)).getAttribute("width"));
int newHeight = 0;// 新高
int newWidth = 0;// 新宽
newHeight = height / 10;// 高缩小10倍
newWidth = width / 10; // 宽缩小10倍
// 如果缩小10倍后宽度还比defaultHeight大,则进行调整
if (newWidth > defaultWeight) {
newWidth = defaultWeight;
newHeight = defaultWeight * height / width;
}
((Element) doc.getElementsByTagName("svg").item(0)).setAttribute("width", String.valueOf(newWidth));
((Element) doc.getElementsByTagName("svg").item(0)).setAttribute("height", String.valueOf(newHeight));
OutputStream out = new FileOutputStream(svgFile);
output(doc, out);
}
/**
* 将svg图片转成png图片
*
* @param filePath
* @throws Exception
*/
public static void svgToPng(String svgPath, String pngFile) throws Exception {
File svg = new File(svgPath);
FileInputStream wmfStream = new FileInputStream(svg);
ByteArrayOutputStream imageOut = new ByteArrayOutputStream();
int noOfByteRead = 0;
while ((noOfByteRead = wmfStream.read()) != -1) {
imageOut.write(noOfByteRead);
}
imageOut.flush();
imageOut.close();
wmfStream.close();
ByteArrayOutputStream jpg = new ByteArrayOutputStream();
FileOutputStream jpgOut = new FileOutputStream(pngFile);
byte[] bytes = imageOut.toByteArray();
PNGTranscoder t = new PNGTranscoder();
TranscoderInput in = new TranscoderInput(new ByteArrayInputStream(bytes));
TranscoderOutput out = new TranscoderOutput(jpg);
t.transcode(in, out);
jpgOut.write(jpg.toByteArray());
jpgOut.flush();
jpgOut.close();
imageOut = null;
jpgOut = null;
}
/**
* 将wmf图片转成png图片(备用方法,即当上面的转换失败时用这个)
*
* @param filePath
* @throws Exception
*/
public static String wmfToJpg(String wmfPath) throws Exception {
//先wmf-->svg
File wmf = new File(wmfPath);
FileInputStream wmfStream = new FileInputStream(wmf);
ByteArrayOutputStream imageOut = new ByteArrayOutputStream();
int noOfByteRead = 0;
while ((noOfByteRead = wmfStream.read()) != -1) {
imageOut.write(noOfByteRead);
}
imageOut.flush();
imageOut.close();
wmfStream.close();
// WMFHeaderProperties prop = new WMFHeaderProperties(wmf);
WMFTranscoder transcoder = new WMFTranscoder();
TranscodingHints hints = new TranscodingHints();
transcoder.setTranscodingHints(hints);
TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(imageOut.toByteArray()));
ByteArrayOutputStream svg = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(svg);
transcoder.transcode(input, output);
//再svg-->png
ByteArrayOutputStream jpg = new ByteArrayOutputStream();
String jpgFile = StringUtils.replace(wmfPath, "wmf", "png");
FileOutputStream jpgOut = new FileOutputStream(jpgFile);
byte[] bytes = svg.toByteArray();
PNGTranscoder t = new PNGTranscoder();
TranscoderInput in = new TranscoderInput(new ByteArrayInputStream(bytes));
TranscoderOutput out = new TranscoderOutput(jpg);
t.transcode(in, out);
jpgOut.write(jpg.toByteArray());
jpgOut.flush();
jpgOut.close();
return jpgFile;
}
}
- 验证
运行main程序结果如下:
excel文档图片存储如下:
在线预览test.html,如下: