前几天遇到一个需求,需要从FTP里获取PDF并在前端渲染出去,同事采用了直接在iframe嵌入ftp url的方式,个人觉得这种方式并不合理,有很多弊端,比如安全性、跨域、ftp中文路径等问题。所以我建议其采用服务端直接获取ftp文件流,然后转发给前端呈现的方式来解决。以下是主要思路。

从FTP获取文件流

这里用到了2个第三方库:Apache的FTPClient,IOUtils。前者的retrieveFileStream方法实现了将文件转成InputStream,后者的toByteArray方法实现了将InputStream转换成Byte[]。

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import java.io.IOException;
import java.io.InputStream;

/**
* 从ftp获取文件流
*
* @author lefer
* @version 1.0
* @since 2017/08/31 09:38
*/
public class PDFTool {
public byte[] getPDF(){
byte[] result = null;
InputStream is = null;
try{
FTPClient ftpClient= new FTPClient();
ftpClient.connect("ftp IP");
ftpClient.login("username","password");
ftpClient.enterLocalPassiveMode();
is=ftpClient.retrieveFileStream("1.pdf");
result= IOUtils.toByteArray(is);
ftpClient.disconnect();
return result;
}catch (IOException e){
e.printStackTrace();
}
return result;
}
}

为了引入这2个三方库,需要在pom.xml添加依赖.

<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>

将文件流推送到前台(以PDF文件为例)

@RequestMapping(value="/pdfview")
protected String pdfView(
HttpServletRequest request,
HttpSession httpSession,
HttpServletResponse response) {
try {
byte[] documentInBytes = new PDFTool().getPDF();
response.setHeader("Content-Disposition", "inline; filename=\"report.pdf\"");
response.setDateHeader("Expires", -1);
response.setContentType("application/pdf");
response.setContentLength(documentInBytes.length);
response.getOutputStream().write(documentInBytes);
} catch (Exception ioe) {
} finally {
}
return null;
}

后续建议

考虑到我们是行业软件应用环境,有很多老式机器的浏览器不能渲染pdf,为每一台机器去安装pdf阅读器也会带来很大的实施工作量,建议后续直接将pdf转成png展现(比如采用pdfbox),这样会提高兼容性。唯一需要考虑的是pdf转png的性能问题(如果不缓存的话)。

END