springboot 整合 FTP(连接池)上传、下载、FTP图片查看、删除

1.项目结构
在这里插入图片描述
2.依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
         <!-- FTP -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.4.2</version>
        </dependency>

3.Ftp类

package com.test.ftp.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Data 编译时能自动生成get set 方法
//@Component Ftp类交给spring 管理
//@Value("${}") 获取配置文件的属性
@Data
@Component
public class Ftp {
    /**
     * FTP地址
     **/
    @Value("${ftp.host}")
    private String host;
    /**
     * FTP端口
     **/
    @Value("${ftp.port}")
    private int port ;
    /**
     * FTP用户名
     **/
    @Value("${ftp.userName}")
    private String userName;
    /**
     * FTP密码
     **/
    @Value("${ftp.passWord}")
    private String passWord;

    /**
     * 目录
     **/
    @Value("${ftp.workDirectory}")
    private String workDirectory;


    /**
     * FTP根目录
     **/
    @Value("${ftp.root}")
    private String root;

    /**
     * 编码
     **/
    @Value("${ftp.encoding}")
    private String encoding;

    /**
     * 最多连接数
     **/
    @Value("${ftp.maxTotal}")
    private int maxTotal;

    @Value("${ftp.minIdle}")
    private int minIdle;

    @Value("${ftp.maxIdle}")
    private int maxIdle;

    @Value("${ftp.maxWaitMillis}")
    private int maxWaitMillis;
}

4.FtpPool

package com.test.ftp.config;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
public class FtpPool {

    private static final Logger log = LoggerFactory.getLogger(FtpPool.class);

    private final GenericObjectPool<FTPClient> internalPool;


    public FtpPool(FtpClientFactory factory){
        Ftp ftp = factory.getFtpInfo();
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(ftp.getMaxTotal());
        poolConfig.setMinIdle(ftp.getMinIdle());
        poolConfig.setMaxIdle(ftp.getMaxIdle());
        poolConfig.setMaxWaitMillis(ftp.getMaxWaitMillis());
        this.internalPool = new GenericObjectPool<>(factory,poolConfig);
        log.info("初始化FTPClient...");
    }


    //从连接池中取连接
    public  FTPClient getFtpClient() {
        try {
            log.info("连接FTP.....");
            return internalPool.borrowObject();
        } catch (Exception e) {
            log.error("连接FTP失败:"+e.getMessage(),e);
            return null;
        }
    }



    //将链接归还到连接池
    public  void returnFTPClient(FTPClient ftpClient) {
        try {
            internalPool.returnObject(ftpClient);
        } catch (Exception e) {
            log.error("归还到连接失败",e);
        }
    }

}


5.FtpClientFactory

package com.test.ftp.config;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;

@Component
public class FtpClientFactory implements PooledObjectFactory<FTPClient> {
    private static final Logger log = LoggerFactory.getLogger(FtpClientFactory.class);

    FtpClientFactory(){
        log.info("初始化FtpFactory... ");
    }

    @Resource
    private Ftp ftp;


    @Override
    public PooledObject<FTPClient> makeObject() {
        log.info("创建连接到连接池...");
        FTPClient ftpClient = new FTPClient();
        return new DefaultPooledObject<>(ftpClient);
    }



    @Override
    public void destroyObject(PooledObject<FTPClient> pooledObject)  {
        FTPClient ftpClient = pooledObject.getObject();
        try {
            ftpClient.logout();
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
            log.info("断开连接...");
        } catch (IOException e) {
            log.error("断开连接失败!");
            throw new RuntimeException("断开连接失败!", e);
        }
    }



    @Override
    public boolean validateObject(PooledObject<FTPClient> pooledObject) {
        FTPClient ftpClient = pooledObject.getObject();
        try {
            log.info("检查连接状态...");
            return ftpClient.sendNoOp();
        } catch (IOException e) {
            return false;
        }
    }




    @Override
    public void activateObject(PooledObject<FTPClient> pooledObject) throws Exception {
        FTPClient ftpClient = pooledObject.getObject();
        ftpClient.connect(ftp.getHost(),ftp.getPort());
        ftpClient.login(ftp.getUserName(), ftp.getPassWord());
        ftpClient.setControlEncoding(ftp.getEncoding());
        ftpClient.changeWorkingDirectory(ftp.getWorkDirectory());
        //设置上传文件类型为二进制,否则将无法打开文件
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        log.info("初始化连接...");
    }



    @Override
    public void passivateObject(PooledObject<FTPClient> pooledObject){
        FTPClient ftpClient = pooledObject.getObject();
        try {
            ftpClient.changeWorkingDirectory(ftp.getRoot());
            ftpClient.logout();
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
            log.info("钝化连接...");
        } catch (IOException e) {
            throw new RuntimeException("关闭连接失败!"+ e.getMessage());
        }
    }


    public Ftp getFtpInfo() {
        log.info("获取FTPPool属性...");
        return ftp;
    }

}

6.FtpUtil

package com.test.ftp.utils;

import com.test.ftp.config.Ftp;
import com.test.ftp.config.FtpPool;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.UUID;

@Component
public class FtpUtil {

    private static final Logger log = LoggerFactory.getLogger(FtpUtil.class);

    @Resource
    private FtpPool rePool;
    @Resource
    private Ftp reFtp;


    private static FtpPool pool;

    private static Ftp ftp;


    //PostConstruct 用在依赖关系注入完成之后需要执行的方法上,以执行任何初始化
    @PostConstruct
    public void init() {
        pool = rePool;
        ftp = reFtp;
        log.info("初始化FTP完成...");
    }


    /**
     * Description: 向FTP服务器上传文件
     *
     * @param inputStream 上传到FTP服务器上的文件流
     * @param fileName    上传到FTP服务器上的文件名
     * @return 成功返回文件名,否则返回null
     */
    public static String upload(FileInputStream inputStream, String fileName,String path){
        //获取 最后的小数点以及后面的字符串
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        FTPClient ftpClient = pool.getFtpClient();

        String newFileName = null;
        if (ftpClient != null) {
            //开始进行文件上传
            newFileName = UUID.randomUUID() + suffix;
            try {
                //修改文件路径
                ftpClient.makeDirectory(path);
                ftpClient.changeWorkingDirectory(path);
                //执行文件传输
                if (!ftpClient.storeFile(newFileName, inputStream)) {//上传失败
                    throw new RuntimeException("上传失败");
                }
                log.info("上传成功!");
            } catch (Exception e) {
                log.error("上传失败:" + e.getMessage(), e);
                return null;
            } finally {//关闭资源
                log.info("开始归还连接");
                pool.returnFTPClient(ftpClient);
            }
        }
        return newFileName;
    }

    /**
     * Description: 下载文件
     *
     * @param fileName FTP服务器中的文件名
     * @param resp     响应客户的响应体
     */
    public static void downLoad(String fileName,String path, HttpServletResponse resp) {
        FTPClient ftpClient = pool.getFtpClient();
        if (ftpClient != null) {
            resp.setContentType("multipart/form-data");
            resp.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
            //将文件直接读取到响应体中
            OutputStream out = null;
            try {
                out = resp.getOutputStream();
                //路径为空时取配置文件的路径
                String newPath = StringUtils.isBlank(path) ? ftp.getWorkDirectory():path;
                ftpClient.retrieveFile( newPath+ "/" + fileName, out);
            } catch (IOException e) {
                log.error("下载失败:");
            } finally {
                if (out != null) {
                    try {
                        out.flush();
                        out.close();
                    } catch (IOException e) {
                        log.error("关闭FTP流失败:" + e.getMessage());
                    }
                }
            }
            //归还连接
            pool.returnFTPClient(ftpClient);
        }
    }

    /**
     * Description: 获取图片
     */
    public static void getFtpImage(HttpServletResponse response,String filepath) {
        //创建FTP连接
        FTPClient ftp;
        OutputStream outStream;
        InputStream in = null;
        try {
            ftp = pool.getFtpClient();
            //获取文件流
            in = ftp.retrieveFileStream(filepath);
            if(in != null) {
                //获取最后小数点的往后的的字符
                String picType = filepath.substring(filepath.lastIndexOf(".") + 1);
                BufferedImage bufImg = ImageIO.read(in);
                outStream = response.getOutputStream();
                ImageIO.write(bufImg, picType, outStream);
                log.info("获取图片成功");
            }else {
                throw new RuntimeException("文件不存在!");
            }
        } catch (IOException e) {
            log.error("获取图片失败", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("关闭流失败", e);
                }
            }
        }
    }





    /**
     * 删除多个文件
     */
    public static Integer deleteFiles(String path, List<String> files) {
        int count = 0;
        FTPClient ftpClient;
        try {
            ftpClient = pool.getFtpClient();
                ftpClient.changeWorkingDirectory(path);
                for (String file : files) {
                    if (ftpClient.deleteFile(file)) {
                        log.info("文件 {} 删除成功", file);
                        count++;
                    } else {
                        log.info("文件 {} 删除失败", file);
                    }
                }
                log.info("共删除 {} 个文件", count);
        } catch (IOException e) {
            log.error("连接FTP服务器失败");
        }
        return count;
    }







7.配置文件属性

#FTP IP 地址
ftp.host = 10.116.xxx.x
ftp.port = 21
ftp.userName = xxxxx
ftp.passWord = 123456
ftp.encoding = utf-8
ftp.workDirectory = /
ftp.root = /
#最大连接数
ftp.maxTotal = 100
#最小空闲
ftp.minIdle = 3
ftp.maxIdle = 5
#最大等待时间
ftp.maxWaitMillis = 30000000


logger.lever = debug


8.测试

package com.test.business.controller;
import com.test.ftp.utils.FtpUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

@RestController
@RequestMapping("ftp")
public class FtpTestController {


    @RequestMapping("/test")
    public void FtpTest(HttpServletResponse response, MultipartFile file) throws IOException {
        //FileInputStream inputStream = file.getInputStream();
        //String fileName = file.getOriginalFilename();
        FileInputStream inputStream = new FileInputStream(new File("C:/Users/admin/Desktop/1.png"));
        //上传
        String path = "image";
        String fileName = FtpUtil.upload(inputStream, "1.png",path);

        System.out.println(fileName);

        //下载
        FtpUtil.downLoad(fileName,path,response);
    }


    @RequestMapping("/getFtpImage")
    public void getFtpImage(HttpServletResponse response, MultipartFile file) throws IOException {
        //FileInputStream inputStream = file.getInputStream();
        //String fileName = file.getOriginalFilename();
        FileInputStream inputStream = new FileInputStream(new File("C:/Users/admin/Desktop/1.png"));
        //上传
        String path = "image";
        String fileName = FtpUtil.upload(inputStream, "1.png",path);

        System.out.println(fileName);

        //查看图片
        String filePath = path+"/"+fileName;
        FtpUtil.getFtpImage(response,filePath);
    }



    @RequestMapping("/deleteFiles")
    public void deleteFiles() throws FileNotFoundException {
        //FileInputStream inputStream = file.getInputStream();
        //String fileName = file.getOriginalFilename();
        FileInputStream inputStream = new FileInputStream(new File("C:/Users/admin/Desktop/1.png"));
        //上传
        String path = "image";
        String fileName = FtpUtil.upload(inputStream, "1.png",path);

        //删除
        List<String> files = new ArrayList<>();
        files.add(fileName);
        FtpUtil.deleteFiles(path,files);
    }





 //多文件上传
    @RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
    public void fileUploads(HttpServletRequest request) throws IOException {
        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        String path = "image";
        for (MultipartFile multipartFile : files) {
            if (!multipartFile.isEmpty()) {
                FtpUtil.upload((FileInputStream) multipartFile.getInputStream(), Objects.requireNonNull(multipartFile.getOriginalFilename()), path);
            }
        }
    }

    /** HTML
     * <p>多文件上传</p>
     * <form method="POST" enctype="multipart/form-data"
     *         action="/upload">
     *     Name: <input type="text" name="name"/>
     *     <p>文件1:<input type="file" name="file" /></p>
     *     <p>文件2:<input type="file" name="file" /></p>
     *     <p><input type="submit" value="多文件上传" /></p>
     * </form>
     */

}
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值