需求
之前发过一篇博客记录使用POI将Word文档转为HTML文件的方法.
最近在将那个方法整合为项目中能用的接口,但在实际操作中发现了一些问题.
由于我的需求是将试卷上传,将其内容转为HTML后按照题号进行分割再存入数据库,所以对于试题中的图片部分,要像之前项目中一样上传到我们的云服务器上,图片的src里也是一个url.
这样一来,必须要实现对img中的src替换,将网上其他例子中的通过File对象获取的路径替换为一个url.
实现
上一篇博客写了处理文档的过程,
地址:https://blog.csdn.net/u010827544/article/details/88909310
对于doc和docx的处理是不同的类和方法,所以对于图片的处理也是分开的
doc文档
先把全部代码贴上来
public File docToHtml(File docFile) {
String htmlPath=docFile.getAbsolutePath().replaceAll(docFile.getName(),"")+docFile.getName().replaceAll(".doc",".html");
OutputStreamWriter outputStreamWriter = null;
if(!docFile.exists()){
System.out.println("文件不存在");
}else try {
//加载word文档生成XWPF对象
InputStream in = new FileInputStream(docFile);
HWPFDocument doc=new HWPFDocument(in);
org.w3c.dom.Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter=new WordToHtmlConverter(document);
//保存图片,并返回图片的相对路径
//将图片上传,调用上传的方法
wordToHtmlConverter.setPicturesManager((content, pictureType, name, width, height) -> {
Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
String bucketName = gatewayConfig.get("bucketName");
String imgName=System.currentTimeMillis() + "_"+name;
try {
String hash = qiniuFileManager.uploadali(content,imgName, bucketName);//bucketName参数无用
} catch (IOException e) {
e.printStackTrace();
}
return gatewayConfig.get("alilink") + "/" + imgName;
});
wordToHtmlConverter.processDocument(doc);
org.w3c.dom.Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(new File(htmlPath));
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
return new File(htmlPath);
}
对图片src的处理是wordToHtmlConverter
的setPicturesManager
方法,该方法的参数是
public void setPicturesManager(PicturesManager fileManager) {
this.picturesManager = fileManager;
}
一个PicturesManager
接口,于是对该接口中的
String savePicture(byte[] var1, PictureType var2, String var3, float var4, float var5);
这个方法进行重写即可实现对src的修改,该接口中的方法的参数分别是:
byte[] var1, PictureType var2, String var3, float var4, float var5
图片byte,图片type,图片名,图片宽度,图片高度
所以在实现过程中,我将图片上传到云服务器和获取图片url的方法写在了这里
wordToHtmlConverter.setPicturesManager((content, pictureType, name, width, height) -> {
//获取上传配置
Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
String bucketName = gatewayConfig.get("bucketName");
String imgName=System.currentTimeMillis() + "_"+name;//设置图片文件名
try {
//上传图片
String hash = qiniuFileManager.uploadali(content,imgName, bucketName);//bucketName参数无用
} catch (IOException e) {
e.printStackTrace();
}
return gatewayConfig.get("alilink") + "/" + imgName;//获取图片url
});
这样重写完成之后,调用该方法,生成的html文件中图片的src就是上传之后的url了
效果:
docx文档
对于docx文档的处理废了一些功夫,因为不像doc一样对于图片的处理的类是直接在converter里面的,而是在XHTMLOptions
中的,对于图片的处理则是封装在options.setExtractor
中的,所以找到可以重写的接口废了一段时间,最后还是论坛的朋友提供了方法.
这里贴一下帖子地址:https://bbs.csdn.net/topics/392566824
之前我考虑去写一个类继承ImageManager
,但是论坛的朋友提出重写IURIResolver
接口,实测可以.
源代码:
@Override
public File docxToHtml(File docxFile) {
String htmlPath=docxFile.getAbsolutePath().replaceAll(docxFile.getName(),"")+docxFile.getName().replaceAll(".docx",".html");
String imagePath=docxFile.getAbsolutePath().replaceAll(docxFile.getName(),"")+"docxImage\\";
File imageFile=new File(imagePath);
if(!docxFile.exists()){
System.out.println("文件不存在!");
}
Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
String bucketName = gatewayConfig.get("bucketName");
try {
InputStream in=new FileInputStream(docxFile);
XWPFDocument document=new XWPFDocument(in);
//存储图片
XHTMLOptions options=XHTMLOptions.create().URIResolver(new FileURIResolver(imageFile));
options.setExtractor(new FileImageExtractor(imageFile));
options.URIResolver((uri)->{
File imgFile=new File(imagePath+uri);//获取图片
String imgName=System.currentTimeMillis() + "_"+imgFile.getName();//设置图片文件名
InputStream is= null;
try {
is = new FileInputStream(imgFile);
byte[] isbyte=new byte[is.available()];
is.read(isbyte);
//上传图片
String hash = qiniuFileManager.uploadali(isbyte,imgName, bucketName);//bucketName参数无用
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return gatewayConfig.get("alilink") + "/" + imgName;//返回图片url
});
OutputStream out=new FileOutputStream(htmlPath);
XHTMLConverter converter=new XHTMLConverter();
converter.convert(document,out,options);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return new File(htmlPath);
}
大体上传过程与doc的类似
docx的方法是在options.URIResolver
这个方法中,这个方法的参数是
public XHTMLOptions URIResolver(IURIResolver resolver) {
this.resolver = resolver;
return this;
}
IURIResolver
接口的resolve方法即根据参数uri返回uri,所以重写这个方法即可.
public interface IURIResolver {
String resolve(String var1);
}
所以我按照上方贴的源代码重写了这个方法,
options.URIResolver((uri)->{
File imgFile=new File(imagePath+uri);
String imgName=System.currentTimeMillis() + "_"+imgFile.getName();
InputStream is= null;
try {
is = new FileInputStream(imgFile);
byte[] isbyte=new byte[is.available()];
is.read(isbyte);
String hash = qiniuFileManager.uploadali(isbyte,imgName, bucketName);//bucketName参数无用
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return gatewayConfig.get("alilink") + "/" + imgName;
});
参数uri是图片在本地缓存的相对路径,根据路径得到图片文件,然后将File转为byte[],调用上传接口,最后返回上传之后的url.就能达到和doc同样的效果,这里就不再贴图了
再次感谢论坛回复我的那位朋友!