一、环境
jdk1.8
+ springboot2.3.2.RELEASE
+ commons-net-3.6.jar
+ commons-lang3-3.8.jar
+ commons-io-2.6.jar
二、添加pom.xml文件依赖
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
<!-- 引入 Apache commons-io 包,方便操作文件-->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
三、FTP 工具类
package org.lhj.pro.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.*;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FtpUtil {
private final static Log logger = LogFactory.getLog(FtpUtil.class);
private static String LOCAL_CHARSET = "UTF-8";
// FTP协议里面,规定文件名编码为iso-8859-1
private static String SERVER_CHARSET = "ISO-8859-1";
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static Date TODAY_TIME = new Date();
/**
*
* @Description: 创建ftp客户端
* @return FTPClient
* @Date: 2020年11月7日 上午9:31:02
* @Author: army
*/
public static FTPClient getFTPClient(String ftpHost, String ftpUserName, String ftpPassword, int ftpPort) {
FTPClient ftpClient = new FTPClient();
try {
ftpClient = new FTPClient();
ftpClient.connect(ftpHost, ftpPort); // 连接FTP服务器
ftpClient.login(ftpUserName, ftpPassword); // 登陆FTP服务器
ftpClient.setControlEncoding("UTF-8"); // 中文支持
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
logger.info("未连接到FTP,用户名或密码错误。");
ftpClient.disconnect();
} else {
logger.info("FTP连接成功。");
}
} catch (SocketException e) {
e.printStackTrace();
logger.info("FTP的IP地址可能错误,请正确配置。");
} catch (IOException e) {
e.printStackTrace();
logger.info("FTP的端口错误,请正确配置。");
}
return ftpClient;
}
// 判断ftp的目标文件下是否有此文件
public static boolean isExsits(String ftpPath, String fileName, FTPClient ftpx) {
try {
FTPFile[] files = ftpx.listFiles(ftpPath);
if (files != null && files.length > 0) {
System.out.println("files size:" + files[0].getSize());
for (FTPFile file : files) {
String st = new String(file.getName().getBytes(LOCAL_CHARSET), SERVER_CHARSET);
String st1 = new String(st.getBytes(SERVER_CHARSET), LOCAL_CHARSET);
if (st1.equals(fileName)) {
return true;
}
}
return false;
} else {
return false;
}
} catch (Exception e) {
logger.error("获取文件列表失败" + e.getMessage() + e.getClass().getName());
return false;
// e.printStackTrace();
}
}
/**
* 从FTP服务器下载文件
*
* @param ftpHost FTP IP地址
* @param ftpUserName FTP 用户名
* @param ftpPassword FTP用户名密码
* @param ftpPort FTP端口
* @param ftpPath FTP服务器中文件所在路径 格式: ftptest/aa
* @param localPath 下载到本地的位置 格式:H:/download
* @param fileName FTP服务器上要下载的文件名称
* @param targetFileName 本地上要的文件名称
*/
public static String downloadFtpFile(String ftpHost, String ftpUserName, String ftpPassword, int ftpPort,
String ftpPath, String localPath, String fileName, String targetFileName) {
FTPClient ftpClient = null;
try {
ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
LOCAL_CHARSET = "UTF-8";
}
if (!ftpClient.changeWorkingDirectory(ftpPath)) {
logger.error("文件夹路径不对");
return "文件夹路径不对";
}
;
boolean flag = isExsits(ftpPath, fileName, ftpClient);
if (!flag) {
logger.error("文件:" + fileName + " 不存在");
return "文件:" + fileName + " 不存在";
}
String f_ame = new String(fileName.getBytes("GBK"), FTP.DEFAULT_CONTROL_ENCODING); // 编码文件格式,解决中文文件名
File localFile = new File(localPath + File.separatorChar + targetFileName);
OutputStream os = new FileOutputStream(localFile);
ftpClient.retrieveFile(f_ame, os);
os.close();
ftpClient.logout();
File file = new File(System.getProperty("java.io.tmpdir") + targetFileName);
FileInputStream inputFile = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
inputFile.read(buffer);
inputFile.close();
if (file.exists()) {
file.delete();// 删除文件
}
return "下载成功";
} catch (FileNotFoundException e) {
logger.error("没有找到" + ftpPath + "文件");
e.printStackTrace();
} catch (SocketException e) {
logger.error("连接FTP失败.");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
logger.error("文件读取错误。");
e.printStackTrace();
}
return "下载失败";
}
/**
*
* @Description: ftp上传
* @return String
* @Date: 2020年11月7日 上午9:30:20
* @Author: army
*/
public static String uploadFile(String ftpHost, String ftpUserName, String ftpPassword, int ftpPort, InputStream is,
String name) {
String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
String path_wl = today;
System.err.println(name);
FTPClient ftp = new FTPClient();
try {
// 设置编码
// ftp.setControlEncoding("utf-8");
ftp.setControlEncoding("GBK");
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
// 连接ftp服务器
ftp.connect(ftpHost, ftpPort);
// 响应码
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
ftp.disconnect();
}
// 登录ftp
boolean login = ftp.login(ftpUserName, ftpPassword);
if (!login) {
return "ftp服务器登录失败。请重新开始";
}
// 设置为二进制格式
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
// System.out.println("已连接"+ftp.isConnected());//查看ftp是否已连接
logger.debug("ftp连接状态" + ftp.isConnected());
if (!ftp.changeWorkingDirectory(path_wl)) {
boolean b = ftp.makeDirectory(path_wl);
if (b) {
ftp.changeWorkingDirectory(path_wl);
ftp.appendFile(name, is);
}
} else {
ftp.appendFile(name, is);
}
logger.debug("写入成功==========");
} catch (IOException e) {
logger.error("文件保存失败:" + e.getMessage());
e.printStackTrace();
return "文件保存失败";
} finally {
try {
ftp.logout();
ftp.disconnect();
if (ftp.isConnected()) {
ftp.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "文件保存成功";
}
}
四、定义FTP连接参数
package org.lhj.pro.constants;
public class FtpConstants {
public static final String HOST = "127.0.0.1";
public static final int PORT = 21;
public static final String USER_NAME = "army";
public static final String PASSWORD = "army";
}
五、创建Controller测试
package org.lhj.pro.controller;
import org.lhj.pro.constants.FtpConstants;
import org.lhj.pro.util.FtpUtil;
import org.lhj.pro.util.OssFileUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@RestController
@RequestMapping("/ftp)
public class TestController {
@RequestMapping("/upload/localfile")
public String localfile() {
try {
String filePath = "E:\\temp\\8721.jpg";
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(filePath);
String fileName = file.getName();
FtpUtil.getFTPClient(FtpConstants.HOST, FtpConstants.USER_NAME, FtpConstants.PASSWORD, FtpConstants.PORT);
return FtpUtil.uploadFile(FtpConstants.HOST, FtpConstants.USER_NAME, FtpConstants.PASSWORD, FtpConstants.PORT,fileInputStream ,fileName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
六、浏览器查看上传结果
业务实现踩过的坑:
- 记得关闭防火墙
- 创建ftp时一定记得勾选写入权限
- Internet属性>>高级>>将“使用被动FTP(用于防火墙和DSL调制解调器的兼容)”选项去掉