依赖 hutool
FTP配置
inspection.data.ftp.host=172.26.1.41
inspection.data.ftp.port=21
inspection.data.ftp.user=6c
inspection.data.ftp.password=6cqq123
inspection.data.ftp.charsetName=GBK
FTP配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "inspection.data.ftp")
public class FtpParamProperties {
// ftp ip
private String host;
// ftp 端口
private int port;
// ftp 用户
private String user;
// ftp 密码
private String password;
// ftp 编码
private String charsetName;
}
FTP工具类
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.http.ContentType;
import com.cdtye.itps.cms.config.FtpParamProperties;
import com.cdtye.itps.cms.model.dto.DownloadDto;
import com.cdtye.itps.cms.model.dto.FtpPathTree;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Objects;
@Component
public class FtpUtil {
static FtpParamProperties ftpParamProperties;
public static Ftp getConnect() {
return new Ftp(ftpParamProperties.getHost(), ftpParamProperties.getPort()
, ftpParamProperties.getUser(), ftpParamProperties.getPassword()
, Charset.forName(ftpParamProperties.getCharsetName()));
}
public static void downLoad(DownloadDto downloadDto, HttpServletResponse response) {
if (Objects.isNull(downloadDto)) {
throw new RuntimeException("下载参数不能为空");
}
if (StringUtils.isBlank(downloadDto.getFileName())) {
throw new RuntimeException("下载参数中文件名不能为空");
}
if (StringUtils.isBlank(downloadDto.getUrl())) {
throw new RuntimeException("下载参数中url不能为空");
}
response.reset();
response.setContentType(ContentType.OCTET_STREAM.getValue());
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + downloadDto.getFileName());
if (StringUtils.isNotBlank(downloadDto.getUrl())) {
downFormUrl(downloadDto, response);
}
}
private static void downFormUrl(DownloadDto downloadDto, HttpServletResponse response) {
try (InputStream stream = URLUtil.getStream(URLUtil.toUrlForHttp(URLUtil.encodeFragment(downloadDto.getUrl())))) {
byte[] buff = new byte[1024];
OutputStream os = response.getOutputStream();
int i = 0;
while ((i = stream.read(buff)) != -1) {
os.write(buff, 0, i);
os.flush();
}
} catch (IOException e) {
throw new RuntimeException("下载文件异常", e);
}
}
public static FtpPathTree recursionLs(String rootPath, Filter filter) throws Exception {
if (StringUtils.isBlank(rootPath)) {
throw new RuntimeException("目录路径不能为空");
}
FtpPathTree ftpPathTree = new FtpPathTree();
try (Ftp ftp = FtpUtil.getConnect()) {
if (!ftp.exist(rootPath)) {
throw new RuntimeException("目录不存在");
}
ftpPathTree.setFileName(rootPath);
ftpPathTree.setFileFullPath(rootPath);
List ftpFiles = ftp.lsFiles(rootPath, filter);
if (CollectionUtils.isNotEmpty(ftpFiles)) {
recursionChild(ftpFiles, ftp, ftpPathTree, filter);
}
} catch (Exception e) {
throw e;
}
return ftpPathTree;
}
private static FtpPathTree recursionChild(List ftpFiles, Ftp ftp, FtpPathTree ftpPathTree, Filter filter) {
if (CollectionUtils.isNotEmpty(ftpFiles)) {
for (FTPFile ftpFile : ftpFiles) {
String currentPath = ftpPathTree.getFileFullPath() + "/" + ftpFile.getName();
if (ftpFile.isDirectory()) {
// Filter filterDirectory = (f) -> Objects.nonNull(f);
List ftpFiles1 = ftp.lsFiles(currentPath, filter);
if (CollectionUtils.isNotEmpty(ftpFiles1)) {
FtpPathTree ftpPathTree2 = new FtpPathTree();
ftpPathTree2.setFileName(ftpFile.getName());
ftpPathTree2.setFileFullPath(currentPath);
ftpPathTree.getChilds().add(recursionChild(ftpFiles1, ftp, ftpPathTree2, filter));
} else {
FtpPathTree ftpPathTree1 = new FtpPathTree();
ftpPathTree1.setFileName(ftpFile.getName());
ftpPathTree1.setFileFullPath(currentPath);
ftpPathTree.getChilds().add(ftpPathTree1);
}
} else {
FtpPathTree ftpPathTree1 = new FtpPathTree();
ftpPathTree1.setFileName(ftpFile.getName());
ftpPathTree1.setFileFullPath(currentPath);
ftpPathTree1.setFileFlag(Boolean.TRUE);
ftpPathTree.getChilds().add(ftpPathTree1);
}
}
}
return ftpPathTree;
}
public static void recursionFile(List ftpPathTrees, FtpPathTree ftpPathTree) {
if (Objects.nonNull(ftpPathTree)) {
if (ftpPathTree.getFileFlag()) {
ftpPathTrees.add(ftpPathTree);
} else {
if (CollectionUtils.isNotEmpty(ftpPathTree.getChilds())) {
for (FtpPathTree child : ftpPathTree.getChilds()) {
recursionFile(ftpPathTrees, child);
}
}
}
}
}
public static void downloadFile(String fileFullPath, HttpServletResponse response) throws Exception {
if (StringUtils.isBlank(fileFullPath)) {
throw new RuntimeException("文件路径不能为空!");
}
try (ServletOutputStream outputStream = response.getOutputStream(); Ftp ftp = FtpUtil.getConnect()) {
if (!ftp.exist(fileFullPath)) {
throw new RuntimeException("文件不存在!");
}
if (ftp.isDir(fileFullPath)) {
throw new RuntimeException("只能下载文件!");
}
response.reset();
String fullFileName = FileNameUtil.getName(fileFullPath);
String filePath = StringUtils.substringBefore(fileFullPath, fullFileName);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'"
+ URLEncoder.encode(fullFileName, "UTF-8").replace("+", "%20"));
ftp.download(filePath, fullFileName, outputStream);
outputStream.flush();
}
}
@Autowired
public void setFtpParamProperties(FtpParamProperties ftpParamProperties) {
FtpUtil.ftpParamProperties = ftpParamProperties;
}
}
测试类
import cn.hutool.extra.ftp.Ftp;
import com.cdtye.itps.cms.util.FtpUtil;
import org.apache.commons.net.ftp.FTPClient;
import java.io.InputStream;
import java.util.Objects;
public class FTPTest {
public static void main(String[] args) {
try (Ftp ftp = FtpUtil.getConnect()) {
FTPClient client = ftp.getClient();
InputStream inputStream = null;
try {
// 开始主动模式
client.enterLocalPassiveMode();
inputStream = client.retrieveFileStream("FTP路径");
if (Objects.nonNull(inputStream)) {
// 拿到流做事情
}
} catch (Exception e) {
} finally {
if (Objects.nonNull(inputStream)) {
inputStream.close();
}
//重点是这两行,解决假死问题
client.sendNoOp();
client.completePendingCommand();
}
} catch (Exception e) {
}
}
}