springboot SFTP 文件上传下载功能

Posted 小污龟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot SFTP 文件上传下载功能相关的知识,希望对你有一定的参考价值。

 

新增sftp.properies

文件保存 sftp服务器信息

# 协议
sftp.client.protocol=sftp
# ip地址
sftp.client.host=改成自己的文件服务器地址
# 端口
sftp.client.port=22
# 用户名
sftp.client.username=root
# 密码
sftp.client.password=改成自己的密码
# 文件上传根路径
sftp.client.root=/home/sftp/
# 密钥文件路径
sftp.client.privateKey=
# 密钥的密码
sftp.client.passphrase=
#
sftp.client.sessionStrictHostKeyChecking=no
# session连接超时时间
sftp.client.sessionConnectTimeout=15000
# channel连接超时时间
sftp.client.channelConnectedTimeout=15000

SftpProperties.java 文件

package cn.rc.properties;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
public class SftpProperties {
    @Value("${sftp.client.host}")
    private String host;

    @Value("${sftp.client.port}")
    private Integer port;

    @Value("${sftp.client.protocol}")
    private String protocol;

    @Value("${sftp.client.username}")
    private String username;

    @Value("${sftp.client.password}")
    private String password;

    @Value("${sftp.client.root}")
    private String root;

    @Value("${sftp.client.privateKey}")
    private String privateKey;

    @Value("${sftp.client.passphrase}")
    private String passphrase;

    @Value("${sftp.client.sessionStrictHostKeyChecking}")
    private String sessionStrictHostKeyChecking;

    @Value("${sftp.client.sessionConnectTimeout}")
    private Integer sessionConnectTimeout;

    @Value("${sftp.client.channelConnectedTimeout}")
    private Integer channelConnectedTimeout;

}

Application.java   文件启动类

引入属性加上文件上传大小的设置

/**
 * Eureka服务端
 *
 * @author wanjun
 */
@SpringBootApplication
@EnableDiscoveryClient
@Slf4j
@MapperScan(basePackages = {"cn.rc.mapper"})
@PropertySource({"sftp.properties"})
public class Application {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

    /**
     * 文件上传配置
     * @return
     */
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        //文件最大
        //factory.setMaxFileSize("1024KB"); //KB,MB
        /// 设置总上传数据总大小
        factory.setMaxRequestSize("20480KB"); //最大上传为4M
        return factory.createMultipartConfig();
    }
}

 


文件上传下载的接口

FileSystemController.java

package cn.rc.controller;

import cn.rc.properties.SftpProperties;
import cn.rc.service.FileSystemService;
import com.oracle.tools.packager.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

@Controller
public class FileSystemController {
    @Autowired
    private FileSystemService fileSystemService;

    /**
     * 实现多文件上传
     */
    @RequestMapping(value = "upload", method = RequestMethod.POST)
    @ResponseBody
    public Boolean upload(@RequestParam("files") List<MultipartFile> files, HttpServletRequest request) {
        if (files.isEmpty()) {
            return false;
        }
        for (MultipartFile file : files) {
            String fileName = file.getOriginalFilename();
            int size = (int) file.getSize();
            System.out.println(fileName + "-->" + size);
            if (file.isEmpty()) {
                return false;
            } else {
                try {
                    File dest = multipartFileToFile(file);
                    fileSystemService.uploadFile("/513_education/" + fileName, dest);
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
        }
        return true;
    }


    @RequestMapping("/download")
    public String downLoad(HttpServletResponse response) throws Exception {
        String downUrl = "/home/sftp/513_education/" + "20200225223754.csv";
        File file = fileSystemService.downloadFile(downUrl);
        String filename = file.getName();
        if (file.exists()) { //判断文件父目录是否存在
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            // response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment;fileName=" + java.net.URLEncoder.encode(filename, "UTF-8"));
            byte[] buffer = new byte[1024];
            FileInputStream fis = null; //文件输入流
            BufferedInputStream bis = null;

            OutputStream os = null; //输出流
            try {
                os = response.getOutputStream();
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer);
                    i = bis.read(buffer);
                }

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("----------file download---" + filename);
            try {
                bis.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    public static File multipartFileToFile(MultipartFile multiFile) {
        // 获取文件名
        String fileName = multiFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = fileName.substring(fileName.lastIndexOf("."));
        // 若需要防止生成的临时文件重复,可以在文件名后添加随机码

        try {
            File file = File.createTempFile(fileName, prefix);
            multiFile.transferTo(file);
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

FileSystemService
package cn.rc.service;

import java.io.File;
import java.io.InputStream;

public interface FileSystemService {

    boolean uploadFile(String targetPath, InputStream inputStream) throws Exception;

    boolean uploadFile(String targetPath, File file) throws Exception;

    File downloadFile(String targetPath) throws Exception;

    boolean deleteFile(String targetPath) throws Exception;
}


FileSystemServiceImpl.java
package cn.rc.service.impl;

import cn.rc.properties.SftpProperties;
import cn.rc.service.FileSystemService;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Arrays;

@Slf4j
@Service("fileSystemService")
public class FileSystemServiceImpl implements FileSystemService {

    @Autowired
    private SftpProperties config;

    // 设置第一次登陆的时候提示,可选值:(ask | yes | no)
    private static final String SESSION_CONFIG_STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";

    /**
     * 创建SFTP连接
     *
     * @return
     * @throws Exception
     */
    private ChannelSftp createSftp() throws Exception {
        JSch jsch = new JSch();
        log.info("Try to connect sftp[" + config.getUsername() + "@" + config.getHost() + "], use password[" + config.getPassword() + "]");

        Session session = createSession(jsch, config.getHost(), config.getUsername(), config.getPort());
        session.setPassword(config.getPassword());
        session.connect(config.getSessionConnectTimeout());

        log.info("Session connected to {}.", config.getHost());

        Channel channel = session.openChannel(config.getProtocol());
        channel.connect(config.getChannelConnectedTimeout());

        log.info("Channel created to {}.", config.getHost());

        return (ChannelSftp) channel;
    }

    /**
     * 加密秘钥方式登陆
     *
     * @return
     */
    private ChannelSftp connectByKey() throws Exception {
        JSch jsch = new JSch();

        // 设置密钥和密码 ,支持密钥的方式登陆
        if (StringUtils.isNotBlank(config.getPrivateKey())) {
            if (StringUtils.isNotBlank(config.getPassphrase())) {
                // 设置带口令的密钥
                jsch.addIdentity(config.getPrivateKey(), config.getPassphrase());
            } else {
                // 设置不带口令的密钥
                jsch.addIdentity(config.getPrivateKey());
            }
        }
        log.info("Try to connect sftp[" + config.getUsername() + "@" + config.getHost() + "], use private key[" + config.getPrivateKey()
                + "] with passphrase[" + config.getPassphrase() + "]");

        Session session = createSession(jsch, config.getHost(), config.getUsername(), config.getPort());
        // 设置登陆超时时间
        session.connect(config.getSessionConnectTimeout());
        log.info("Session connected to " + config.getHost() + ".");

        // 创建sftp通信通道
        Channel channel = session.openChannel(config.getProtocol());
        channel.connect(config.getChannelConnectedTimeout());
        log.info("Channel created to " + config.getHost() + ".");
        return (ChannelSftp) channel;
    }

    /**
     * 创建session
     *
     * @param jsch
     * @param host
     * @param username
     * @param port
     * @return
     * @throws Exception
     */
    private Session createSession(JSch jsch, String host, String username, Integer port) throws Exception {
        Session session = null;

        if (port <= 0) {
            session = jsch.getSession(username, host);
        } else {
            session = jsch.getSession(username, host, port);
        }

        if (session == null) {
            throw new Exception(host + " session is null");
        }

        session.setConfig(SESSION_CONFIG_STRICT_HOST_KEY_CHECKING, config.getSessionStrictHostKeyChecking());
        return session;
    }

    /**
     * 关闭连接
     *
     * @param sftp
     */
    private void disconnect(ChannelSftp sftp) {
        try {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                } else if (sftp.isClosed()) {
                    log.info("sftp is closed already");
                }
                if (null != sftp.getSession()) {
                    sftp.getSession().disconnect();
                }
            }
        } catch (JSchException e) {
            e.printStackTrace();
        }
    }


    /**
     * 将inputStream上传到指定路径下(单级或多级目录)
     *
     * @param targetPath  路径+文件名  比如/ home/513_education/test.xlsl
     * @param inputStream
     * @return
     * @throws Exception
     */
    @Override
    public boolean uploadFile(String targetPath, InputStream inputStream) throws Exception {
        ChannelSftp sftp = this.createSftp();
        try {
            sftp.cd(config.getRoot());
            log.info("Change path to {}", config.getRoot());

            int index = targetPath.lastIndexOf("/");
            String fileDir = targetPath.substring(0, index);
            String fileName = targetPath.substring(index + 1);
            boolean dirs = this.createDirs(fileDir, sftp);
            if (!dirs) {
                log.error("Remote path error. path:{}", targetPath);
                throw new Exception("Upload File failure");
            }
            sftp.put(inputStream, fileName);
            return true;
        } catch (Exception e) {
            log.error("Upload file failure. TargetPath: {}", targetPath, e);
            throw new Exception("Upload File failure");
        } finally {
            this.disconnect(sftp);
        }
    }


    /**
     * 创建多级目录
     *
     * @param dirPath
     * @param sftp
     * @return
     */
    private boolean createDirs(String dirPath, ChannelSftp sftp) {
        if (dirPath != null && !dirPath.isEmpty()
                && sftp != null) {
            String[] dirs = Arrays.stream(dirPath.split("/"))
                    .filter(StringUtils::isNotBlank)
                    .toArray(String[]::new);

            for (String dir : dirs) {
                try {
                    sftp.cd(dir);
                    log.info("Change directory {}", dir);
                } catch (Exception e) {
                    try {
                        sftp.mkdir(dir);
                        log.info("Create directory {}", dir);
                    } catch (SftpException e1) {
                        log.error("Create directory failure, directory:{}", dir, e1);
                        e1.printStackTrace();
                    }
                    try {
                        sftp.cd(dir);
                        log.info("Change directory {}", dir);
                    } catch (SftpException e1) {
                        log.error("Change directory failure, directory:{}", dir, e1);
                        e1.printStackTrace();
                    }
                }
            }
            return true;
        }
        return false;
    }


    /**
     * 将文件上传到指定目录
     *
     * @param targetPath
     * @param file
     * @return
     * @throws Exception
     */
    @Override
    public boolean uploadFile(String targetPath, File file) throws Exception {
        return this.uploadFile(targetPath, new FileInputStream(file));
    }

    /**
     * 下载文件
     *
     * @param targetPath
     * @return
     * @throws Exception
     */
    @Override
    public File downloadFile(String targetPath) throws Exception {
        ChannelSftp sftp = this.createSftp();
        OutputStream outputStream = null;
        try {
            sftp.cd(config.getRoot());
            log.info("Change path to {}", config.getRoot());

            File file = new File(targetPath.substring(targetPath.lastIndexOf("/") + 1));

            outputStream = new FileOutputStream(file);
            sftp.get(targetPath, outputStream);
            log.info("Download file success. TargetPath: {}", targetPath);
            return file;
        } catch (Exception e) {
            log.error("Download file failure. TargetPath: {}", targetPath, e);
            throw new Exception("Download File failure");
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            this.disconnect(sftp);
        }
    }

    /**
     * 删除文件
     *
     * @param targetPath
     * @return
     * @throws Exception
     */
    @Override
    public boolean deleteFile(String targetPath) throws Exception {
        ChannelSftp sftp = null;
        try {
            sftp = this.createSftp();
            sftp.cd(config.getRoot());
            sftp.rm(targetPath);
            return true;
        } catch (Exception e) {
            log.error("Delete file failure. TargetPath: {}", targetPath, e);
            throw new Exception("Delete File failure");
        } finally {
            this.disconnect(sftp);
        }
    }
}

 

启动项目并用postman测试

 

 

选择文件后请求,响应true

 

查看控制台打印输出:

 

 

 

登陆文件服务器 查看相应目录下:

文件已经被上传

 

以上是关于springboot SFTP 文件上传下载功能的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# java通过sftp模式实现FTP的文件上传下载删除功能

SpringBoot + SFTP 实现文件上传与下载实战

基于 SpringBoot 的 FileService

Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)八(文件的上传FastDFS和校验)(Nginx的请求前缀配置,在发布项目的时候要注意)(代

JSch - Java实现的SFTP(文件下载详解篇)

Xshell5下利用sftp上传下载传输文件