0


SpringBoot-集成FTP(上传、下载、删除)

由于服务在内网部署,需要使用ftp服务器管理文件,总结如下

一、引入依赖

<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.9.0</version>
</dependency>

<!-- hutool -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>

Tip:使用commons-net 3.9.0版本,之前的版本有漏洞

二、配置文件

ftp:
  basePath: /
  host: 192.168.1.100
  httpPath: ftp://192.168.1.100
  password: demo
  port: 21
  username: demo

配置文件类:

package com.example.demo.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * @Author: meng
 * @Description: ftp配置
 * @Date: 2023/6/30 13:44
 * @Version: 1.0
 */
@Data
@Component
@ConfigurationProperties(prefix = "ftp")
public class FtpProperties {
    /**
     * ftp服务器的地址
     */
    private String host;
    /**
     * ftp服务器的端口号(连接端口号)
     */
    private String port;
    /**
     * ftp的用户名
     */
    private String username;
    /**
     * ftp的密码
     */
    private String password;
    /**
     * ftp上传的根目录
     */
    private String basePath;
    /**
     * 回显地址
     */
    private String httpPath;
}

三、Controller层

Tip:Response为通用返回类,不熟悉的可以看这篇文章:Springboot - 通用返回类BaseResults_W_Meng_H的博客-CSDN博客BaseResults类public class BaseResults { private Integer code; private String message; private T data; public BaseResults() { super(); } public BaseResu...https://blog.csdn.net/W_Meng_H/article/details/104995823

package com.example.demo.controller;

import com.example.demo.service.FtpService;
import com.template.common.core.data.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: meng
 * @Description: 文件服务
 * @Date: 2023/6/30 14:33
 * @Version: 1.0
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    private FtpService ftpService;

    // 单上传文件
    @PostMapping(value = "upload", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    public Response uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        return ftpService.uploadMultipartFile(file, request);
    }

    // 导出文件
    @GetMapping(value = "download")
    public void downloadFile(@RequestParam String fileName, @RequestParam String ftpFilePath, HttpServletResponse response) {
        ftpService.downloadFileToFtp(fileName, ftpFilePath, response);
    }

    // 删除文件
    @GetMapping(value = "delete")
    public Response deleteFile(@RequestParam String ftpFilePath) {
        return ftpService.deleteFileToFtp(ftpFilePath);
    }

}

四、Service层

package com.example.demo.service;

import com.template.common.core.data.Response;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: meng
 * @Description: ftp服务类
 * @Date: 2023/6/30 13:46
 * @Version: 1.0
 */
public interface FtpService {
    /**
     * 上传文件到ftp
     * @param multipartFile
     * @param request
     * @return
     */
    public Response uploadMultipartFile(MultipartFile multipartFile, HttpServletRequest request);

    /**
     * 下载ftp文件,直接转到输出流
     * @param fileName
     * @param ftpFilePath
     * @param response
     */
    public void downloadFileToFtp(String fileName, String ftpFilePath, HttpServletResponse response);

    /**
     * 删除ftp文件
     * @param ftpFilePath ftp下文件路径,根目录开始
     * @return
     */
    Response deleteFileToFtp(String ftpFilePath);
}

实现类:

package com.example.demo.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.demo.config.FtpProperties;
import com.example.demo.service.FtpService;
import com.example.demo.tools.FileUtils;
import com.template.common.core.data.Response;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;

/**
 * @Author: meng
 * @Description: ftp服务类
 * @Date: 2023/6/30 13:47
 * @Version: 1.0
 */
@Service
public class FtpServiceImpl implements FtpService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FtpProperties ftpProperties;

    // 方式一
    @Override
    public Response uploadMultipartFile(MultipartFile multipartFile, HttpServletRequest request) {
        if (multipartFile == null || multipartFile.isEmpty()) {
            return Response.error("没有上传文件");
        }
        //1、获取原文件后缀名
        String originalFileName = multipartFile.getOriginalFilename();
        String suffix = originalFileName.substring(originalFileName.lastIndexOf('.'));
        //2、使用UUID生成新文件名
        String newFileName = IdUtil.fastSimpleUUID();
        //3、将MultipartFile转化为File
        File file = null;
        try {
            // file = FileUtils.multipartFileToFile(multipartFile);
            flag = uploadFileToFtp(multipartFile.getInputStream(), newFileName + suffix, today, ftpClient);
        } catch (Exception e) {
            logger.error("文件上传失败:", e);
            return Response.error("文件上传失败");
        }
        if (ObjectUtil.isNull(file)) {
            return Response.error("文件上传失败");
        }
        //当前日期字符串
        String today = File.separator + DateUtil.format(new Date(), "yyyyMMdd");
        Boolean flag = uploadFileToFtp(file, newFileName + suffix, today);
        if (!flag) {
            return Response.error("文件上传失败");
        }
        System.out.println(file.toURI());
        File f = new File(file.toURI());
        f.delete();
        String filePath = ftpProperties.getHttpPath() + today + File.separator + newFileName + suffix;
        return Response.success(filePath);
    }
    
    // 方式二
    public Response uploadMultipartFile2(MultipartFile multipartFile, HttpServletRequest request) {
        FTPClient ftpClient = connectFtpServer();
        if (multipartFile == null || multipartFile.isEmpty()) {
            return R.error(Constants.FILE_EMPTY);
        }
        //获取原文件后缀名
        String originalFileName = multipartFile.getOriginalFilename();
        String suffix = originalFileName.substring(originalFileName.lastIndexOf('.'));
        //使用UUID生成新文件名
        String newFileName = IdUtil.fastSimpleUUID();
        //当前日期字符串
        String today = separator + DateUtil.date().toString(DATE_FORMAT);
        Boolean flag = false;
        try {
            flag = uploadFileToFtp(multipartFile.getInputStream(), newFileName + suffix, today, ftpClient);
        } catch (Exception e) {
            logger.error("文件上传失败:", e);
        }
        if (!flag) {
            logger.info("文件上传失败");
            return R.error("文件上传失败");
        }
        String filePath = ftpProperties.getHttpPath() + today + File.separator + newFileName + suffix;
        return Response.success(filePath);
    }

    public Boolean uploadFileToFtp(File file, String fileName, String filePath) {
        logger.info("调用文件上传接口");
        // 定义保存结果
        boolean iaOk = false;
        // 初始化连接
        FTPClient ftp = connectFtpServer();
        if (ftp != null) {
            try {
                // 设置文件传输模式为二进制,可以保证传输的内容不会被改变
                ftp.setFileType(FTP.BINARY_FILE_TYPE);
                ftp.enterLocalPassiveMode();    //注:上传文件都为0字节,设置为被动模式即可
                // 跳转到指定路径,逐级跳转,不存在的话就创建再进入
                toPathOrCreateDir(ftp, filePath);
                InputStream inputStream = new FileInputStream(file);
                // 上传文件 参数:上传后的文件名,输入流,,返回Boolean类型,上传成功返回true
                iaOk = ftp.storeFile(fileName, inputStream);
                // 关闭输入流
                inputStream.close();
                // 退出ftp
                ftp.logout();
            } catch (IOException e) {
                logger.error(e.toString());
            } finally {
                if (ftp.isConnected()) {
                    try {
                        // 断开ftp的连接
                        ftp.disconnect();
                    } catch (IOException ioe) {
                        logger.error(ioe.toString());
                    }
                }
            }
        }
        return iaOk;
    }

    @Override
    public void downloadFileToFtp(String fileName, String ftpFilePath, HttpServletResponse response) {
        FTPClient ftpClient = connectFtpServer();
        try {
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            // 设置文件ContentType类型,这样设置,会自动判断下载文件类型
            response.setContentType("application/x-msdownload");
            // 设置文件头:最后一个参数是设置下载的文件名并编码为UTF-8
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            InputStream is = ftpClient.retrieveFileStream(ftpFilePath);
            BufferedInputStream bis = new BufferedInputStream(is);
            OutputStream out = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = bis.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.flush();
            out.close();

            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            ftpClient.logout();
        } catch (Exception e) {
            logger.error("FTP文件下载失败:", e);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                    logger.error(ioe.toString());
                }
            }
        }
    }

    @Override
    public Response deleteFileToFtp(String ftpFilePath) {
        FTPClient ftp = connectFtpServer();
        boolean resu = false;
        try {
            resu = ftp.deleteFile(ftpFilePath);
            ftp.logout();
        } catch (Exception e) {
            logger.error("FTP文件删除失败:{}", e);
            return Response.error("文件删除失败");
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                    logger.error(ioe.toString());
                }
            }
        }
        return Response.SUCCESS;
    }

    private FTPClient connectFtpServer() {
        // 创建FTPClient对象(对于连接ftp服务器,以及上传和上传都必须要用到一个对象)
        logger.info("创建FTP连接");
        FTPClient ftpClient = new FTPClient();
        // 设置连接超时时间
        ftpClient.setConnectTimeout(1000 * 60);
        // 设置ftp字符集
        ftpClient.setControlEncoding("utf-8");
        // 设置被动模式,文件传输端口设置,否则文件上传不成功,也不报错
        ftpClient.enterLocalPassiveMode();
        try {
            // 定义返回的状态码
            int replyCode;
            // 连接ftp(当前项目所部署的服务器和ftp服务器之间可以相互通讯,表示连接成功)
            ftpClient.connect(ftpProperties.getHost());
            // 输入账号和密码进行登录
            ftpClient.login(ftpProperties.getUsername(), ftpProperties.getPassword());
            // 接受状态码(如果成功,返回230,如果失败返回503)
            replyCode = ftpClient.getReplyCode();
            // 根据状态码检测ftp的连接,调用isPositiveCompletion(reply)-->如果连接成功返回true,否则返回false
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                logger.info("connect ftp {} failed", ftpProperties.getHost());
                // 连接失败,断开连接
                ftpClient.disconnect();
                return null;
            }
            logger.info("replyCode:" + replyCode);
        } catch (IOException e) {
            logger.error("connect fail:" + e.toString());
            return null;
        }
        return ftpClient;
    }

    private void toPathOrCreateDir(FTPClient ftp, String filePath) throws IOException {
        String[] dirs = filePath.split("/");
        for (String dir : dirs) {
            if (StrUtil.isBlank(dir)) {
                continue;
            }

            if (!ftp.changeWorkingDirectory(dir)) {
                ftp.makeDirectory(dir);
                ftp.changeWorkingDirectory(dir);
            }
        }
    }

}

五、相关工具类

package com.example.demo.tools;

import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @Author: meng
 * @Description: 文件转换工具类
 * @Date: 2023/6/30 14:13
 * @Version: 1.0
 */
public class FileUtils {

    /**
     * MultipartFile 转 File
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {
        File toFile = null;
        if(file.equals("")||file.getSize()<=0){
            file = null;
        }else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            toFile = inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    private static File inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
标签: spring boot FTP

本文转载自: https://blog.csdn.net/W_Meng_H/article/details/131483210
版权归原作者 W_Meng_H 所有, 如有侵权,请联系我们删除。

“SpringBoot-集成FTP(上传、下载、删除)”的评论:

还没有评论