SpringBoot 整合 Ftp 上传、下载、删除文件

文章目录

      • 1、引入依赖
      • 2、定义配置文件 application.yml
      • 3、定义配置类
      • 4、定义 FTP 工具类
      • 5、测试
      • 6、异常记录

FTP 服务连接工具:FileZilla 安装配置

1、引入依赖

<dependency>
    <groupId>commons-netgroupId>
    <artifactId>commons-netartifactId>
    <version>3.3version>
    <scope>compilescope>
dependency>

2、定义配置文件 application.yml

spring:
  ftp:
    ip: 192.168.40.138
    port: 14147
    username: root
    password: 123456
    path: D:/filezillawork

3、定义配置类

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.net.SocketException;

/**
 * hbcx工区FTP服务器配置
 */

@Data
@Slf4j
@Configuration
public class FtpConfig {

    /**
     * FTP IP地址
     */
    @Value("${spring.ftp.ip}")
    private String ip;

    /**
     * FTP端口号
     */
    @Value("${spring.ftp.port}")
    private Integer port;

    /**
     * FTP登录账号
     */
    @Value("${spring.ftp.username}")
    private String username;

    /**
     * FTP登录密码
     */
    @Value("${spring.ftp.password}")
    private String password;

    /**
     * FTP工作路径
     */
    @Value("${spring.ftp.path}")
    private String path;

    private FTPClient ftpClient;

    /**
     * 连接 FTP 服务
     */
    public FTPClient connect() {
        ftpClient = new FTPClient();
        try {
            // 设置编码
            ftpClient.setControlEncoding("UTF-8");
            // 设置连接超时时间(单位:毫秒)
            ftpClient.setConnectTimeout(10 * 1000);
            // 连接
            ftpClient.connect(ip, port);
            // 登录
            ftpClient.login(username, password);
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                log.error("未连接到FTP,用户名或密码错误");
                // 拒绝连接
                ftpClient.disconnect();
            } else {
                log.info("连接到FTP成功");
                // 设置二进制方式传输文件
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                // 设置被动工作模式
                ftpClient.enterLocalPassiveMode();
            }
            return ftpClient;
        } catch (SocketException e) {
            e.printStackTrace();
            log.error("FTP的IP地址错误");
        } catch (IOException e) {
            e.printStackTrace();
            log.error("FTP的端口错误");
        }
        return ftpClient;
    }

    /**
     * 断开 FTP 服务
     */
    public void closeConnect() {
        log.warn("关闭ftp服务器");
        try {
            if (ftpClient != null) {
                ftpClient.logout();
                ftpClient.disconnect();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

4、定义 FTP 工具类

import com.boyia.ftpdemov2.config.FtpConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 2023/2/5 15:04
 *
 * @author HZ
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FtpUtil {

    private final FtpConfig ftpConfig;

    public static final String DIR_SPLIT = "/";

    /**
     * 获取 FTPClient
     * @return FTPClient
     */
    private FTPClient getFTPClient() {
        FTPClient ftpClient = ftpConfig.connect();
        if (ftpClient == null || !FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            throw new RuntimeException("ftp客户端异常");
        }
        return ftpClient;
    }

    /**
     * 获取FTP某一特定目录下的所有文件名称
     *
     * @param ftpDirPath FTP上的目标文件路径
     */
    public List<String> getFileNameList(String ftpDirPath) {
        FTPClient ftpClient = getFTPClient();
        try {
            // 通过提供的文件路径获取 FTPFile 文件列表
            // FTPFile[] ftpFiles = ftpClient.listFiles(ftpDirPath, FTPFile::isFile); // 只获取文件
            // FTPFile[] ftpFiles = ftpClient.listFiles(ftpDirPath, FTPFile::isDirectory); // 只获取目录
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpDirPath);
            if (ftpFiles != null && ftpFiles.length > 0) {
                return Arrays.stream(ftpFiles).map(FTPFile::getName).collect(Collectors.toList());
            }
            log.error(String.format("路径有误,或目录【%s】为空", ftpDirPath));
        } catch (IOException e) {
            log.error("文件获取异常:", e);
        } finally {
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.logout();
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 上传文件
     *
     * @param uploadPath 上传路径
     * @param fileName   文件名
     * @param input      文件输入流
     * @return 上传结果
     */
    public boolean upload(String uploadPath, String fileName, InputStream input) {
        FTPClient ftpClient = getFTPClient();
        try {
            // 切换到工作目录
            if (!ftpClient.changeWorkingDirectory(uploadPath)) {
                ftpClient.makeDirectory(uploadPath);
                ftpClient.changeWorkingDirectory(uploadPath);
            }
            // 文件写入
            boolean storeFile = ftpClient.storeFile(fileName, input);
            if (storeFile) {
                log.info("文件:{}上传成功", fileName);
            } else {
                throw new RuntimeException("ftp文件写入异常");
            }
            ftpClient.logout();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 下载文件 *
     *
     * @param ftpPath     FTP服务器文件目录 *
     * @param ftpFileName 文件名称 *
     * @param localPath   下载后的文件路径 *
     * @return
     */
    public boolean download(String ftpPath, String ftpFileName, String localPath) {
        FTPClient ftpClient = getFTPClient();
        OutputStream outputStream = null;
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.isFile() && file.getName().equals(ftpFileName));
            if (ftpFiles != null && ftpFiles.length > 0) {
                FTPFile ftpFile = ftpFiles[0];
                File localFile = new File(localPath + DIR_SPLIT + ftpFile.getName());
                // 判断本地路径目录是否存在,不存在则创建
                if (!localFile.getParentFile().exists()) {
                    localFile.getParentFile().mkdirs();
                }
                outputStream = Files.newOutputStream(localFile.toPath());
                ftpClient.retrieveFile(ftpFile.getName(), outputStream);

                log.info("fileName:{},size:{}", ftpFile.getName(), ftpFile.getSize());
                log.info("下载文件成功...");
                return true;
            } else {
                log.info("文件不存在,filePathname:{},", ftpPath + DIR_SPLIT + ftpFileName);
            }
        } catch (Exception e) {
            log.error("下载文件失败...");
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.logout();
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 从FTP服务器删除文件或目录
     * 存在文件的目录无法删除
     * 
     * @param ftpPath  服务器文件存储路径
     * @param fileName 服务器文件存储名称
     * @return 删除结果
     */
    public boolean delete(String ftpPath, String fileName) {
        FTPClient ftpClient = getFTPClient();
        try {
            // 在 ftp 目录下获取文件名与 fileName 匹配的文件信息
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.getName().equals(fileName));
            // 删除文件
            if (ftpFiles != null && ftpFiles.length > 0) {
                boolean del;
                String deleteFilePath = ftpPath + DIR_SPLIT + fileName;
                FTPFile ftpFile = ftpFiles[0];
                if (ftpFile.isDirectory()) {
                    del = ftpClient.removeDirectory(deleteFilePath);
                } else {
                    del = ftpClient.deleteFile(deleteFilePath);
                }
                log.info(del ? "文件:{}删除成功" : "文件:{}删除失败", fileName);
                return del;
            } else {
                log.warn("文件:{}未找到", fileName);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.logout();
                    ftpClient.disconnect();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

}

5、测试

注意:此处的根目录 “./” 等同于 FTP 的共享文件夹目录

@RestController
@RequestMapping("/ftp")
@RequiredArgsConstructor
public class FtpController {

    private final FtpUtil ftpUtil;

    private static final String ROOT_DIR = "./";

    @GetMapping("/getFileNameList")
    public List<String> getFileNameList() {
        return ftpUtil.getFileNameList(ROOT_DIR);
    }

    @PostMapping("/upload")
    public boolean uploadToFtpServer(MultipartFile file) throws IOException {
        // 读取文件信息
        String fileName = file.getOriginalFilename();
        InputStream fileInputStream = file.getInputStream();
        // 上传文件到 Ftp 服务
        return ftpUtil.upload(ROOT_DIR, fileName, fileInputStream);
    }

    @GetMapping("/download")
    public boolean download(){
        String localPath = "C:/Users/A/Desktop/243.jpg", ftpFileName = "330.png";
        return ftpUtil.download(ROOT_DIR, ftpFileName, localPath);
    }

    @GetMapping("/delete")
    public boolean delete(String fileName){
        return ftpUtil.delete(ROOT_DIR, fileName);
    }
}

6、异常记录

  • 异常
    连接 FTP 服务器时,确认连接地址、用户名、密码、共享文件地址都是正确的,但依然无法连接
    SpringBoot 整合 Ftp 上传、下载、删除文件_第1张图片
  • 解决
    首先到 FileZilla 服务端查看错误日志:
    SpringBoot 整合 Ftp 上传、下载、删除文件_第2张图片
    此时,只需要到 FileZilla 服务端,点击 “编辑” -> “设置” -> “SSL/TLS设置”,取消勾选 “为FTP启用SSL/TLS支持”,最后点击确定 就可以正常连接 FTP 服务器了
    SpringBoot 整合 Ftp 上传、下载、删除文件_第3张图片

你可能感兴趣的:(spring,boot,java,spring)