来自
需要在浏览器中给用户展示远程FTP服务器中的PDF文件(此处仅针对PDF文件,其余文件实现方式类似).
需要注意的地方
- 一定要登录!一定要登录!一定要登录! 不登录不会提示报错,也不提示成功,就因为这个问题搞了一下午…
- 如果FTP文件路径包含中文,一定要转码!(代码里面会有)
- 编码问题,只能自己多试试了.一不小心就乱码了…
- 我是把FTP服务器搭建在Windows系统上,模拟了一个中文文件夹和PDF文件.使用的Windows当前登录用户的用户名和密码登录的FTP服务器.(关于Windows安装FTP服务器,请自行搜之)安装好之后,可以通过文件资源管理器,访问: ftp://127.0.0.1 或者ftp://localhost 用Windows当前登录用户的用户名和密码登录一下试试.
依赖
依赖以下jar文件,Maven(pom.xml):
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency>
源码
Spring Boot项目,只有以下两个文件有修改(可以使用官网的生成器,生成代码之后,修改下面两部分代码即可).
Maven(pom.xml):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>spring-boot-template-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-template-demo</name> <packaging>jar</packaging> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Java:
package com.example.springboottemplatedemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.apache.commons.net.ftp.FTPReply; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Arrays; @SpringBootApplication @Controller public class SpringBootTemplateDemoApplication { public void loggerdebug(String msg) { System.out.println(msg); } /** * 使用FtpClient访问Ftp服务器上的PDF文件 * * 注意: 用户名和密码不能为空,如果是Windows上搭建的FTP服务器,这里的用户名密码可以是Windows系统用户的用户名和密码. * * * 访问示例: http://localhost:8080/showFTPFile?ftpFileUrl=ftp://127.0.0.1/20190820/%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95/123456/622845.pdf&username=usftp&password=uspwd * * url参数说明: * ftpFileUrl: 文件ftp地址,参考: ftp://127.0.0.1/20190820/中文测试/123456/622845.pdf * decode: 是否需要后台解码,如果传过来的路径是js编码了的,需要解码,参考: decode=1 * username: ftp服务器的用户名,不能为空! * password: ftp服务器的密码,不能为空! * download: 如果包含此参数则下载pdf文件,反之则在浏览器中查看(仅支持现代化浏览器!) * * * @param request * @param response * @throws IOException */ @RequestMapping("/showFTPFile") public void showFTPFile(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String ftpFileUrl = request.getParameter("ftpFileUrl"); String decode = request.getParameter("decode"); String ftpUserName = request.getParameter("username"); String ftpPassword = request.getParameter("password"); if (StringUtils.isEmpty(ftpUserName) || StringUtils.isEmpty(ftpPassword)) { try (ServletOutputStream outputStream = response.getOutputStream()) { outputStream.write("用户名和密码不能为空!".getBytes()); outputStream.flush(); } return; } String download = request.getParameter("download"); if (StringUtils.hasText(ftpFileUrl) && ftpFileUrl.startsWith("ftp://")) { if (StringUtils.hasText(decode)) { ftpFileUrl = URLDecoder.decode(ftpFileUrl, "GB2312"); } ftpFileUrl = ftpFileUrl.replaceAll("ftp://", ""); String server = ftpFileUrl.substring(0, ftpFileUrl.indexOf("/")); String fileName = new String(ftpFileUrl.replaceAll(server, ".").getBytes("GBK"), "iso-8859-1"); FTPClient ftpClient = new FTPClient(); try (ServletOutputStream outputStream = response.getOutputStream()) { ftpClient.connect(server); boolean loginCheck=ftpClient.login(ftpUserName, ftpPassword); if(!loginCheck){ try (ServletOutputStream outputStream = response.getOutputStream()) { outputStream.write("登录失败,请检查用户名或密码是否正确!".getBytes()); outputStream.flush(); } return; } int replyCode = ftpClient.getReplyCode(); ftpClient.setDataTimeout(120000); ftpClient.setControlEncoding("UTF-8"); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); if (!FTPReply.isPositiveCompletion(replyCode)) { ftpClient.disconnect(); loggerdebug("FTP连接失败"); } else { loggerdebug("FTP连接成功"); } String contentType = "application/pdf"; response.setContentType(contentType); response.reset(); if (StringUtils.hasText(download)) { // 下载文件. response.addHeader("Content-Disposition", "attachment;filename=report.pdf"); } else { // 在线显示文件. response.setHeader("Content-Disposition", "inline;fileName=report.pdf"); } ftpClient.retrieveFile(fileName, outputStream); outputStream.flush(); } finally { if (ftpClient.isConnected()) { try { ftpClient.logout(); ftpClient.disconnect(); } catch (IOException ioe) { // do nothing } } } } } public static void main(String[] args) { SpringApplication.run(SpringBootTemplateDemoApplication.class, args); } }