昨天来的个需求,我们的客户需要下载对账文件的话,需要自己去登录ftp 服务器去进行下载
本身是有商户后台,所以想吧这个功能直接添加到商户后台页面上,web进行下载。这是背景。
之前没有了解过这个,所以还是在网上查找了一番 ,找到了这篇博客
参考: https://blog.csdn.net/rodge_rom/article/details/78888541
我看了一下这个里面的方法,有个返回流的,我就看到希望了,所以,进行了一番修改
在这导入工具类之前,我们需要导入个jar包
commons-net-3.6.jar
我会附上链接,不需要兄弟们找了 http://mvnrepository.com/artifact/commons-net/commons-net/3.6
看自己用的什么框架,引入方法我就不说了,需要下载的话,点击红框的jar就可以了
下面是修改完后的工具类
工具类里只需要修改 两 处地方
ftp_address=“你自己ftp服务器地址”
ftp_port=“ftp服务器的端口”
其他都不用动
介绍在下面(工具类很长)所以使劲往下拉
package com.ecard.products.utils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* FTP服务工具类
*
* @author: DangYangFei
* @time: 2018年6月12日 14:36:37
* @version: V1.0.0
*/
public class FTPUtil {
/** 日志对象 **/
private static final Logger LOGGER = LoggerFactory.getLogger(FTPUtil.class);
/** FTP地址 **/
private String FTP_ADDRESS = "";
/** FTP端口 **/
private int FTP_PORT = 0;
/** FTP用户名 **/
private String FTP_USERNAME = "";
/** FTP密码 **/
private String FTP_PASSWORD = "";
/** FTP基础目录 **/
private String BASE_PATH = "";
/** 初始化登录ftp 默认false 登录成功返回true **/
private Boolean b=false;
public Boolean getB() {
return b;
}
/**
* 2018-6-13 12:39:55
* 新添,初始化登录ftp,连接失败 返回b 为:false ,成功 为 :true
* @param FTP_USERNAME
* @param FTP_PASSWORD
* @param BASE_PATH
*/
public FTPUtil(String FTP_ADDRESS, int FTP_PORT, String FTP_USERNAME, String FTP_PASSWORD, String BASE_PATH) {
this.FTP_ADDRESS = FTP_ADDRESS;
this.FTP_PORT = FTP_PORT;
this.FTP_USERNAME = FTP_USERNAME;
this.FTP_PASSWORD = FTP_PASSWORD;
this.BASE_PATH = BASE_PATH;
b = login(FTP_ADDRESS, FTP_PORT, this.FTP_USERNAME, this.FTP_PASSWORD);
}
/** 本地字符编码 **/
private static String localCharset = "GBK";
/** FTP协议里面,规定文件名编码为iso-8859-1 **/
private static String serverCharset = "ISO-8859-1";
/** UTF-8字符编码 **/
private static final String CHARSET_UTF8 = "UTF-8";
/** OPTS UTF8字符串常量 **/
private static final String OPTS_UTF8 = "OPTS UTF8";
/** 设置缓冲区大小4M **/
private static final int BUFFER_SIZE = 1024 * 1024 * 4;
/** FTPClient对象 **/
private static FTPClient ftpClient = null;
/**
* 下载指定文件到本地
*
* @param ftpPath FTP服务器文件相对路径,例如:test/123
* @param fileName 要下载的文件名,例如:test.txt
* @param savePath 保存文件到本地的路径,例如:D:/test
* @return 成功返回true,否则返回false
*/
public boolean downloadFile(String ftpPath, String fileName, String savePath) {
// 登录
boolean flag = false;
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return flag;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return flag;
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
File file = new File(savePath + '/' + ftpName);
try {
OutputStream os = new FileOutputStream(file);
flag = ftpClient.retrieveFile(ff, os);
} catch (Exception e) {
System.out.println(e.getMessage());
LOGGER.error(e.getMessage(), e);
}
break;
}
}
} catch (IOException e) {
System.out.println("下载文件失败"+e);
LOGGER.error("下载文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return flag;
}
/**
* 下载该目录下所有文件到本地
*
* @param ftpPath FTP服务器上的相对路径,例如:test/123
* @param savePath 保存文件到本地的路径,例如:D:/test
* @return 成功返回true,否则返回false
*/
public boolean downloadFiles(String ftpPath, String savePath) {
// 登录
boolean flag = false;
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return flag;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return flag;
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
File file = new File(savePath + '/' + ftpName);
try {
OutputStream os = new FileOutputStream(file);
ftpClient.retrieveFile(ff, os);
} catch (Exception e) {
System.out.println(e.getMessage()+e);
LOGGER.error(e.getMessage(), e);
}
}
flag = true;
} catch (IOException e) {
System.out.println("下载文件失败"+e);
LOGGER.error("下载文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return flag;
}
/**
* 获取该目录下所有文件,以字节数组返回
*
* @param ftpPath FTP服务器上文件所在相对路径,例如:test/123
* @return Map<String, Object> 其中key为文件名,value为字节数组对象
*/
public Map<String, byte[]> getFileBytes(String ftpPath) {
// 登录
Map<String, byte[]> map = new HashMap<String, byte[]>();
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return map;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return map;
}
for (String ff : fs) {
try {
InputStream is = ftpClient.retrieveFileStream(ff);
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int readLength = 0;
while ((readLength = is.read(buffer, 0, BUFFER_SIZE)) > 0) {
byteStream.write(buffer, 0, readLength);
}
map.put(ftpName, byteStream.toByteArray());
ftpClient.completePendingCommand(); // 处理多个文件
} catch (Exception e) {
System.out.println(e.getMessage());
LOGGER.error(e.getMessage(), e);
}
}
} catch (IOException e) {
System.out.println("获取文件失败"+e);
LOGGER.error("获取文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return map;
}
/**
* 根据名称获取文件,以字节数组返回
*
* @param ftpPath FTP服务器文件相对路径,例如:test/123
* @param fileName 文件名,例如:test.xls
* @return byte[] 字节数组对象
*/
public byte[] getFileBytesByName(String ftpPath, String fileName) {
// 登录
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return byteStream.toByteArray();
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return byteStream.toByteArray();
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
try {
InputStream is = ftpClient.retrieveFileStream(ff);
byte[] buffer = new byte[BUFFER_SIZE];
int len = -1;
while ((len = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
byteStream.write(buffer, 0, len);
}
} catch (Exception e) {
System.out.println(e.getMessage()+e);
LOGGER.error(e.getMessage(), e);
}
break;
}
}
} catch (IOException e) {
System.out.println("获取文件失败"+e);
LOGGER.error("获取文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return byteStream.toByteArray();
}
/**
* 获取该目录下所有文件,以输入流返回
*
* @param ftpPath FTP服务器上文件相对路径,例如:test/123
* @return Map<String, InputStream> 其中key为文件名,value为输入流对象
*/
public Map<String, InputStream> getFileInputStream(String ftpPath) {
// 登录
Map<String, InputStream> map = new HashMap<String, InputStream>();
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return map;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return map;
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
InputStream is = ftpClient.retrieveFileStream(ff);
map.put(ftpName, is);
ftpClient.completePendingCommand(); // 处理多个文件
}
} catch (IOException e) {
System.out.println("获取文件失败"+e);
LOGGER.error("获取文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return map;
}
/**
* 根据名称获取文件,以输入流返回
*
* @param ftpPath FTP服务器上文件相对路径,例如:test/123
* @param fileName 文件名,例如:test.txt
* @return InputStream 输入流对象
*/
public InputStream getInputStreamByName(String ftpPath, String fileName) {
// 登录
InputStream input = null;
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
LOGGER.error(BASE_PATH + ftpPath + "该目录不存在");
return input;
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + ftpPath + "该目录下没有文件");
return input;
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
input = ftpClient.retrieveFileStream(ff);
break;
}
}
} catch (IOException e) {
System.out.println("获取文件失败"+e);
LOGGER.error("获取文件失败", e);
}finally {
Boolean connect = closeConnect();
System.out.println("连接关闭状态:" + connect);
}
}
return input;
}
/**
* 根据文件夹,文件 名称,判断是否存在
*
* @param ftpPath FTP服务器上文件相对路径,例如:test/123
* @param fileName 文件名,例如:test.txt
* @return map
*/
public Map checkoutFtpPathAndFileName(String ftpPath, String fileName) {
// 登录
Map<String,Boolean> map = new HashMap<String, Boolean>();
map.put("filePath",false);
map.put("fileName",false);
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + ftpPath);
// 判断是否存在该目录
if (!ftpClient.changeWorkingDirectory(path)) {
System.out.println(BASE_PATH + ftpPath + "该目录不存在");
map.put("filePath",false);
}else {
map.put("filePath",true);
}
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String[] fs = ftpClient.listNames();
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + ftpPath + "该目录下没有文件");
map.put("fileName",false);
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
map.put("fileName",true);
}
}
} catch (IOException e) {
System.out.println("获取文件失败"+e);
LOGGER.error("获取文件失败", e);
}
}
return map;
}
/**
* 删除指定文件
*
* @param filePath 文件相对路径,例如:test/123/test.txt
* @return 成功返回true,否则返回false
*/
public boolean deleteFile(String filePath) {
// 登录
boolean flag = false;
if (ftpClient != null) {
try {
String path = changeEncoding(BASE_PATH + filePath);
flag = ftpClient.deleteFile(path);
} catch (IOException e) {
System.out.println("删除文件失败"+e);
LOGGER.error("删除文件失败", e);
} finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return flag;
}
/**
* 删除目录下所有文件
*
* @param dirPath 文件相对路径,例如:test/123
* @return 成功返回true,否则返回false
*/
public boolean deleteFiles(String dirPath) {
// 登录
boolean flag = false;
if (ftpClient != null) {
try {
ftpClient.enterLocalPassiveMode(); // 设置被动模式,开通一个端口来传输数据
String path = changeEncoding(BASE_PATH + dirPath);
String[] fs = ftpClient.listNames(path);
// 判断该目录下是否有文件
if (fs == null || fs.length == 0) {
System.out.println(BASE_PATH + dirPath + "该目录下没有文件");
LOGGER.error(BASE_PATH + dirPath + "该目录下没有文件");
return flag;
}
for (String ftpFile : fs) {
ftpClient.deleteFile(ftpFile);
}
flag = true;
} catch (IOException e) {
System.out.println("删除文件失败"+e);
LOGGER.error("删除文件失败", e);
}finally {
Boolean close = closeConnect();
System.out.println("连接是否关闭:"+close);
}
}
return flag;
}
/**
* 连接FTP服务器
*
* @param address 地址,如:127.0.0.1
* @param port 端口,如:21
* @param username 用户名,如:root
* @param password 密码,如:root
*/
private Boolean login(String address, int port, String username, String password) {
ftpClient = new FTPClient();
try {
ftpClient.connect(address, port);
ftpClient.login(username, password);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
closeConnect();
System.out.println("FTP服务器连接失败:"+"地址:"+address+" 端口:"+port+" 用户名:"+username+" 密码:"+password);
LOGGER.error("FTP服务器连接失败");
}else {
b=true;
}
} catch (Exception e) {
System.out.println("FTP登录失败"+e);
LOGGER.error("FTP登录失败", e);
}
return b;
}
/**
* 关闭FTP连接
*
*/
public Boolean closeConnect() {
Boolean b=false;
if (ftpClient != null && ftpClient.isConnected()) {
try {
ftpClient.logout();
b=true;
} catch (IOException e) {
System.out.println("关闭FTP连接失败"+e);
LOGGER.error("关闭FTP连接失败", e);
}
}
return b;
}
/**
* FTP服务器路径编码转换
*
* @param ftpPath FTP服务器路径
* @return String
*/
private static String changeEncoding(String ftpPath) {
String directory = null;
try {
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
localCharset = CHARSET_UTF8;
}
directory = new String(ftpPath.getBytes(localCharset), serverCharset);
} catch (Exception e) {
System.out.println("路径编码转换失败"+e);
LOGGER.error("路径编码转换失败", e);
}
return directory;
}
/**
* 在服务器上递归创建目录
*
* @param dirPath 上传目录路径
* @return
*/
private void createDirectorys(String dirPath) {
try {
if (!dirPath.endsWith("/")) {
dirPath += "/";
}
String directory = dirPath.substring(0, dirPath.lastIndexOf("/") + 1);
ftpClient.makeDirectory("/");
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
}else{
start = 0;
}
end = directory.indexOf("/", start);
while(true) {
String subDirectory = new String(dirPath.substring(start, end));
if (!ftpClient.changeWorkingDirectory(subDirectory)) {
if (ftpClient.makeDirectory(subDirectory)) {
ftpClient.changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录失败");
LOGGER.info("创建目录失败");
return;
}
}
start = end + 1;
end = directory.indexOf("/", start);
//检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
} catch (Exception e) {
System.out.println("上传目录创建失败"+e);
LOGGER.error("上传目录创建失败", e);
}
}
}
这里有很多方法,但是现在我的这个需要返回流的形式,所以只用的这个
开始介绍用法
利用有参构造 进行初始化登录ftp 如果登录成功了会返回true 否则返回false
有参构造最后面的ftp_base_path 这个参数说一下
这个参数传的是你当前账号登录以后所能看到的当前路径,也就是说直接给他个空串就可以了
链接成功以后呢,b 返回的就是true ,我们就可以继续往下进行操作了
String ftpUserName = "";
String ftpPassword = "";
String ftpPath = "/"+"文件夹名"+"/";
String fileName = "文件名";
FTPUtil ftpUtil = new FTPUtil(ftpUserName, ftpPassword, "");
Boolean b = ftpUtil.getB();
校验一下文件夹和文件是否存在, 这个是我自己改了一下,你们可以自己去工具类里进行修改成自己想要的字段
这里的返回也是,两个参数 ,false 代表不存在,true代表存在
添加这个方法是因为实际业务需要进行判断返回前端进行提示,所以故此添加
Map map = ftpUtil.checkoutFtpPathAndFileName(ftpPath, fileName)
Boolean filePahtBoolean = map.get("filePath")
Boolean fileNameBoolean = map.get("fileName")
这个方法需要手动自己关闭连接,所以 ftpUtil.closeConnect(),成功返回true, 失败返回false
上面的都齐全了,下面我们开始页面进行下载了
这个方法只需要把文件所在的 路径 和 文件名 传进去就可以了,返回的是一个InputStream
InputStream inputStream = ftpUtil.getInputStreamByName(ftpPath, fileName)
页面进行下载弹出框
这个就不多介绍了, 弹出框文件的名称 修改成功自己的命名规则就可以了
/**
*
* @param fileName 文件名称
* @param inputStream 读取文件返回流
* @param response
*/
public static void downloadFtpFile(String fileName,InputStream inputStream ,HttpServletResponse response) {
try {
BufferedInputStream br = new BufferedInputStream(inputStream);
byte[] buf = new byte[1024];
int len = 0;
response.reset();
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
OutputStream out = response.getOutputStream();
while ((len = br.read(buf)) > 0) out.write(buf, 0, len);
br.close();
out.close();
} catch (IOException e) {
System.out.println("文件读取错误。");
}
}