springboot读取sftp的文件
1.添加pom依赖(基于springboot项目)
com.jcraft jsch 0.1.54
2.application.yaml配置文件
sftp: ip: 192.168.1.102 port: 22 username: admin password: admin root: /img #文件根目录
3.工具类
import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpException; import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import java.util.concurrent.TimeUnit; /** * */ @Slf4j public class SFTPUtil { /** * 下载重试次数 */ private static final int DOWNLOAD_RETRY = 3; /** * 下载重试间隔时间 单位毫秒 */ private static final long DOWNLOAD_SLEEP = 3 * 1000; private static final SFTPUtil SFTP = new SFTPUtil(); private static ChannelSftp client; private static Session session; /** * @return */ public static SFTPUtil getInstance() { return SFTP; } /** * 获取SFTP连接 * * @param username * @param password * @param ip * @param port * @return */ synchronized public ChannelSftp makeConnection(String username, String password, String ip, int port) { if (client == null || session == null || !client.isConnected() || !session.isConnected()) { try { JSch jsch = new JSch(); session = jsch.getSession(username, ip, port); if (password != null) { session.setPassword(password); } Properties config = new Properties(); // 设置第一次登陆的时候主机公钥确认提示,可选值:(ask | yes | no) config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); //sftp协议 Channel channel = session.openChannel("sftp"); channel.connect(); client = (ChannelSftp) channel; log.info("sftp connected success,connect to [{}:{}], username [{}]", ip, port, username); } catch (JSchException e) { log.error("sftp connected fail,connect to [{}:{}], username [{}], password [{}], error message : [{}]", ip, port, username, password, e.getMessage()); } } return client; } /** * * 关闭连接 server */ public static void close() { if (client != null && client.isConnected()) { client.disconnect(); } if (session != null && session.isConnected()) { session.disconnect(); } } /** * 单次下载文件 * * @param downloadFile 下载文件地址 * @param saveFile 保存文件地址 * @param ip 主机地址 * @param port 主机端口 * @param username 用户名 * @param password 密码 * @param rootPath 根目录 * @return */ public synchronized static File download(String downloadFile, String saveFile, String ip, Integer port, String username, String password, String rootPath) { boolean result = false; File file = null; Integer i = 0; while (!result) { //获取连接 ChannelSftp sftp = getInstance().makeConnection(username, password, ip, port); FileOutputStream fileOutputStream = null; log.info("sftp file download start, target filepath is {}, save filepath is {}", downloadFile, saveFile); try { sftp.cd(rootPath); file = new File(saveFile); if (file.exists()) { file.delete(); } else { file.createNewFile(); } fileOutputStream = new FileOutputStream(file); sftp.get(downloadFile, fileOutputStream); result = true; } catch (FileNotFoundException e) { log.error("sftp file download fail, FileNotFound: [{}]", e.getMessage()); } catch (IOException e) { log.error("sftp file download fail, IOException: [{}]", e.getMessage()); } catch (SftpException e) { i++; log.error("sftp file download fail, sftpException: [{}]", e.getMessage()); if (i > DOWNLOAD_RETRY) { log.error("sftp file download fail, retry three times, SftpException: [{}]", e.getMessage()); return file; } try { TimeUnit.MILLISECONDS.sleep(DOWNLOAD_SLEEP); } catch (InterruptedException ex) { ex.printStackTrace(); } } finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } SFTPUtil.close(); } return file; } /** * 下载文件 * * @param downloadFile 下载文件的路径 * @param saveFile 保存的路径 * @param rootPath 根目录 * @return */ public synchronized static File download(String downloadFile, String saveFile, String rootPath) { boolean result = false; File file = null; Integer i = 0; while (!result) { FileOutputStream fileOutputStream = null; log.info("sftp file download start, target filepath is {}, save filepath is {}", downloadFile, saveFile); try { //获取连接、读取文件(ChannelSftp) session.openChannel("sftp") client.cd(rootPath); file = new File(saveFile); if (file.exists()) { file.delete(); } else { file.createNewFile(); } fileOutputStream = new FileOutputStream(file); client.get(downloadFile, fileOutputStream); result = true; } catch (FileNotFoundException e) { log.error("sftp file download fail, FileNotFound: [{}]", e.getMessage()); } catch (IOException e) { log.error("sftp file download fail, IOException: [{}]", e.getMessage()); } catch (SftpException e) { i++; log.error("sftp file download fail, sftpException: [{}]", e.getMessage()); if (i > DOWNLOAD_RETRY) { log.error("sftp file download fail, retry three times, SftpException: [{}]", e.getMessage()); return file; } try { TimeUnit.MILLISECONDS.sleep(DOWNLOAD_SLEEP); } catch (InterruptedException ex) { ex.printStackTrace(); } } finally { try { if (fileOutputStream != null) { fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } return file; } }
4.实际调用
public class SFTP { @Value("${sftp.ip}") String ip; @Value("${sftp.port}") Integer port; @Value("${sftp.username}") String username; @Value("${sftp.password}") String password; @Value("${sftp.root}") String rootPath; @GetMapping("/test") public void test() throws IOException { SFTPUtil.getInstance().makeConnection(username, password, ip, port); File file= SFTPUtil.download(downloadFilePath, "1.txt", rootPath); SFTPUtil.close(); InputStreamReader read = null; BufferedReader bufferedReader = null; String encoding = "utf-8"; try { read = new InputStreamReader(new FileInputStream(file), encoding); bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { log.info("[{}] downfile is [{}] ", username, lineTxt); } read.close(); bufferedReader.close(); file.delete(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (read != null) { read.close(); } if (bufferedReader != null) { bufferedReader.close(); } if (file != null && file.exists()) { file.delete(); } } catch (IOException e) { e.printStackTrace(); } } } }
springboot使用SFTP文件上传
最近在工作功能使用了sftp做文件上传下载的功能,在这里简单的记录一下
pom文件中引入相关的jar包
com.jcraft jsch 0.1.54
建立springboot项目,在application.properties添加如下配置
sftp.ip=127.0.0.1 sftp.port=22 sftp.username=xuyy sftp.password=paswpord #ftp根目录 sftp.rootpath="D:SFTP/
上面一sftp开头的都是自定义配置,需要写个配置类读取一下,自动注入到springboot中
package com.uinnova.ftpsynweb.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * 特点: 读取配置文件。可以对静态变量直接赋值 * * @author xuyangyang */ @Component @ConfigurationProperties(prefix = "sftp") @Data public class SftpConfig { public static String ip; public static Integer port; public static String username; public static String password; public static String rootpath; //注意这里是 static 修饰,便于sftputil直接取值 public static String getIp() { return ip; } public void setIp(String ip) { SftpConfig.ip = ip; } public static Integer getPort() { return port; } public void setPort(Integer port) { SftpConfig.port = port; } public static String getUsername() { return username; } public void setUsername(String username) { SftpConfig.username = username; } public static String getPassword() { return password; } public void setPassword(String password) { SftpConfig.password = password; } public static String getRootpath() { return rootpath; } public void setRootpath(String rootpath) { SftpConfig.rootpath = rootpath; } }
下面是具体的工具类,代码写的比较简单,可以自己下载优化一下,等我有时间在优化
package com.uinnova.ftpsynweb.util; import com.jcraft.jsch.*; import com.uinnova.ftpsynweb.config.SftpConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thymeleaf.util.StringUtils; import javax.transaction.SystemException; import java.io.*; import java.util.*; /** * SFTP工具类 */ @Slf4j @Component public class SftpUtil { @Autowired SftpConfig sftpConfig; private static String sftp_ip = SftpConfig.getIp(); private static Integer sftp_port = SftpConfig.getPort(); private static String sftp_username = SftpConfig.getUsername(); private static String sftp_password = SftpConfig.getPassword(); /** * sftp存储根目录 */ public static String windows_path = "D:SFTP/"; public static String linux_path = "/home/xuyy/"; private Session session; private ChannelSftp channel; /** * 规避多线程并发不断开问题 */ private volatile static ThreadLocalsftpLocal = new ThreadLocal<>(); private SftpUtil() { } private SftpUtil(String host, Integer port, String username, String password) { super(); init(host, port, username, password); } /** * 获取本地线程存储的sftp客户端,使用玩必须调用 release()释放连接 * * @return * @throws Exception */ public static SftpUtil getSftpUtil() { SftpUtil sftpUtil = sftpLocal.get(); if (null == sftpUtil || !sftpUtil.isConnected()) { sftpLocal.set(new SftpUtil(sftp_ip, sftp_port, sftp_username, sftp_password)); } return sftpLocal.get(); } /** * 获取本地线程存储的sftp客户端,使用玩必须调用 release()释放连接 * * @param host * @param port * @param username * @param password * @return */ public static SftpUtil getSftpUtil(String host, Integer port, String username, String password) { SftpUtil sftpUtil = sftpLocal.get(); if (null == sftpUtil || !sftpUtil.isConnected()) { log.info("建立连接"); sftpLocal.set(new SftpUtil(host, port, username, password)); } else { log.info("连接已经存在"); } return sftpLocal.get(); } /** * 初始化 创建一个新的 SFTP 通道 * * @param host * @param port * @param username * @param password */ private void init(String host, Integer port, String username, String password) { try { //场景JSch对象 JSch jSch = new JSch(); // jsch.addIdentity(); 私钥 session = jSch.getSession(username, host, port); // 第一次登陆时候提示, (ask|yes|no) Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); config.put("compression.s2c", "zlib,none"); config.put("compression.c2s", "zlib,none"); session.setConfig(config); //设置超时 // session.setTimeout(10*1000); //设置密码 session.setPassword(password); session.connect(); //打开SFTP通道 channel = (ChannelSftp) session.openChannel("sftp"); //建立SFTP通道的连接 channel.connect(); // 失败重试2次 失败不管了,只发送一次 失败回复 并行调用所有节点 } catch (JSchException e) { log.error("init话sftp异常,可能是获得连接错误,请检查用户名密码或者重启sftp服务" + e); } } /** * 是否已连接 * * @return */ private boolean isConnected() { return null != channel && channel.isConnected(); } /** * 关闭通道 */ public void closeChannel() { if (null != channel) { try { channel.disconnect(); } catch (Exception e) { log.error("关闭SFTP通道发生异常:", e); } } if (null != session) { try { session.disconnect(); } catch (Exception e) { log.error("SFTP关闭 session异常:", e); } } } /** * 每次连接必须释放资源,类似OSS服务 * 释放本地线程存储的sftp客户端 */ public static void release() { if (null != sftpLocal.get()) { sftpLocal.get().closeChannel(); sftpLocal.set(null); } } /** * 列出目录下文件,只列出文件名字,没有类型 * * @param dir 目录 * @return */ public List list(String dir) { if (channel == null) { log.error("获取sftp连接失败,请检查" + sftp_ip + +sftp_port + "@" + sftp_username + " " + sftp_password + "是否可以访问"); return null; } Vector files = null; try { files = channel.ls(dir); } catch (SftpException e) { log.error(e.getMessage()); } if (null != files) { List fileNames = new ArrayList (); Iterator iter = files.iterator(); while (iter.hasNext()) { String fileName = iter.next().getFilename(); if (StringUtils.equals(".", fileName) || StringUtils.equals("..", fileName)) { continue; } fileNames.add(fileName); } return fileNames; } return null; } /** * 列出文件详情 * * @param dir * @return */ public List listDetail(String dir) { if (channel == null) { log.error("获取sftp连接失败,请检查" + sftp_ip + +sftp_port + "@" + sftp_username + " " + sftp_password + "是否可以访问"); return null; } Vector files = null; try { files = channel.ls(dir); } catch (SftpException e) { log.error("listDetail 获取目录列表 channel.ls " + dir + "失败 " + e); } if (null != files) { List
下面是具体的几个接口,这里也贴出来了,方便大家使用
@Slf4j @RestController public class FileController { /** * @param file 上传文件 * @param targetPath 保存文件路径 * @param fileName 上传文件名字 * @return * @throws IOException */ @RequestMapping(value = "/file/upload") @ResponseBody public Return upload(@RequestParam("file") MultipartFile file, String targetPath, String fileName) throws IOException { log.debug("上传文件原始名字:" + file.getOriginalFilename() + "上传路径:" + targetPath + "上传文件名: " + fileName); InputStream uploadFile = file.getInputStream(); SftpUtil sftpUtil = SftpUtil.getSftpUtil(); boolean upload = false; if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { upload = sftpUtil.upload(uploadFile, fileName, targetPath); } else { upload = sftpUtil.upload(uploadFile, fileName, SftpConfig.getRootpath() + targetPath); } SftpUtil.release(); return Return.Ok(upload); } /** * 需要下载的文件具体路径 * * @param targetPath * @param response * @return * @throws UnsupportedEncodingException */ @RequestMapping(value = "/file/download") @ResponseBody public void download(String targetPath, HttpServletResponse response) throws UnsupportedEncodingException { log.debug("下载文件名字" + targetPath); // targetPath = new String(targetPath.getBytes("ISO8859-1"), "UTF-8"); if (StringUtils.isEmpty(targetPath) || !targetPath.contains("/")) { log.error("下载路径不正确" + targetPath); // return Return.Fail("下载路径不正确"); } String fileName = targetPath.substring(targetPath.lastIndexOf("/") + 1); log.debug(fileName); File file = null; SftpUtil sftpUtil = SftpUtil.getSftpUtil(); if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { file = sftpUtil.downFile("/", targetPath); } else { file = sftpUtil.downFile("/", SftpConfig.getRootpath() + targetPath); } SftpUtil.release(); if (!Objects.isNull(file)) { // 配置文件下载 response.setHeader("content-type", "application/octet-stream"); response.setContentType("application/octet-stream"); // 下载文件能正常显示中文 // response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1")); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); byte[] buffer = new byte[1024]; FileInputStream fis = null; BufferedInputStream bis = null; try { fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buffer); while (i != -1) { os.write(buffer, 0, i); i = bis.read(buffer); } // return Return.Ok("下载成功"); } catch (Exception e) { log.error("down fail" + e); // return Return.Fail("下載失敗"); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { log.error("down fail" + e); } } if (fis != null) { try { fis.close(); } catch (IOException e) { log.error("down fail" + e); } } } } // return Return.Fail("下載失敗"); } /** * 获取sftp下文件消息列表 * * @param filePath 文件路径 * @return */ @RequestMapping(value = "/file/list") @ResponseBody public Return list(@RequestParam("filePath") String filePath) { log.debug("获取路径下列表 :{}", filePath); SftpUtil sftpUtil = SftpUtil.getSftpUtil(); Listlist = new ArrayList(); if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { list = sftpUtil.listDetail(filePath); } else { list = sftpUtil.listDetail(SftpConfig.getRootpath() + filePath); } SftpUtil.release(); return Return.Ok(list); } /** * 递归获得文件path下所有文件列表 * * @param filePath 文件路径 * @return */ @RequestMapping(value = "/file/listOfRecursion") @ResponseBody public Return listOfRecursion(@RequestParam("filePath") String filePath) { log.debug("获取路径下列表 :{}", filePath); SftpUtil sftpUtil = SftpUtil.getSftpUtil(); ArrayList strings = new ArrayList<>(); Return ret = null; List list; List list1 = new ArrayList<>(); try { if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { list = sftpUtil.listOfRecursion(filePath, strings); ret = Return.Ok(list); } else { list = sftpUtil.listOfRecursion(SftpConfig.getRootpath() + filePath, strings); for (String str : list) { str = StringUtils.substring(str, SftpConfig.getRootpath().length() - 1); list1.add(str); } ret = Return.Ok(list1); } } catch (SftpException e) { log.error("listOfRecursion 获取目录列表 channel.ls " + filePath + "失败 " + e); SftpUtil.release(); ret = Return.Fail(e.getMessage()); }finally { SftpUtil.release(); } return ret; } /** * sftp内复制文件夹 * * @param src 源文件夹 * @param desc 目的文件夹 * @return */ @RequestMapping(value = "file/copy") @ResponseBody public Return copy(String src, String desc) { SftpUtil sftpUtil = SftpUtil.getSftpUtil(); if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { sftpUtil.copy(src, desc); } else { sftpUtil.copy(SftpConfig.getRootpath() + src, SftpConfig.getRootpath() + desc); } SftpUtil.release(); return Return.Ok("复制成功"); } /** * 删除文件 文件存在返回true ,文件不存在或删除失败返回 false * * @param filePath * @return */ @RequestMapping(value = "file/del") @ResponseBody public Return del(String filePath) { log.debug("删除此文件 :{}", filePath); Boolean flag = false; SftpUtil sftpUtil = SftpUtil.getSftpUtil(); if (SftpConfig.WIN.equals(SftpConfig.getEnv())) { flag = sftpUtil.del(filePath); } else { flag = sftpUtil.del(SftpConfig.getRootpath() + filePath); } SftpUtil.release(); return new Return(flag, flag ? "删除成功" : "文件不存在或删除失败"); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。