springboot整合sftp文件服务器实现文件上传下载功能

您所在的位置:网站首页 springboot整合ftp springboot整合sftp文件服务器实现文件上传下载功能

springboot整合sftp文件服务器实现文件上传下载功能

2024-07-05 02:46| 来源: 网络整理| 查看: 265

目录

1、项目结构

2、添加sftp核心配置依赖

3、定义sftpConfig对象

4、定义sftp客户端:里面包含连接校验,文件夹创建,文件判断,文件上传下载等多种方法,根据实际需要使用;

5、定义sftp工厂类

6、启动类中添加SftpFactory;

7、创建测试方法

8、swagger接口调用测试,看是否生成文件

直接上模块代码:

完整项目源码地址(参考ideal-sftp-1018模块):https://github.com/yangshilei/springCloud

1、项目结构

下面红圈中是主要的几个关于sftp客户端操作的对象方法。

2、添加sftp核心配置依赖 com.jcraft jsch 0.1.54 org.apache.commons commons-lang3 commons-io commons-io 2.4 3、定义sftpConfig对象 package com.demo.sftp.sftp; import com.alibaba.fastjson.JSON; import lombok.Data; @Data public class SftpConfig { /** * ftp连接名 */ private String ftpName; /** * SFTP IP地址 */ private String ip; /** * SFTP 端口 */ private Integer port; /** * SFTP 用户名 */ private String userName; /** * SFTP 密码 */ private String password; /** * 连接失败次数 */ private int clientFailNum; @Override public String toString() { return JSON.toJSONString(this); } } 4、定义sftp客户端:里面包含连接校验,文件夹创建,文件判断,文件上传下载等多种方法,根据实际需要使用; package com.demo.sftp.sftp; import com.demo.sftp.utils.Base64Util; import com.jcraft.jsch.*; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import javax.validation.constraints.NotNull; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; @Slf4j @Data public class SftpClient implements AutoCloseable { /** * 配置信息 */ private SftpConfig conf; /** * Sftp客户端对象 */ private ChannelSftp sftp = null; /** * 会话 */ private Session sshSession = null; /** * 通道 */ private Channel channel = null; /** * 最后一次使用的时间 * 为便于计算, 使用long型时间戳记录 */ private long lastUseDate; public SftpClient(SftpConfig conf) { this(conf.getFtpName(), conf.getIp(), conf.getPort(), conf.getUserName(), conf.getPassword()); } public SftpClient(String ip, int port, String username, String password) { this(null, ip, port, username, password); } public SftpClient(String sftpName,String ip, int port, String username, String password) { conf = new SftpConfig(); if(StringUtils.isEmpty(sftpName)){ conf.setFtpName(username + "@" + ip + ":" + port); } conf.setIp(ip); conf.setPort(port); conf.setUserName(username); conf.setPassword(password); this.connect(); } public synchronized ChannelSftp connect(){ if(!this.checkConf()){ log.error("sftp连接失败,连接信息不全"); int clientFailNum = conf.getClientFailNum() + 1; conf.setClientFailNum(clientFailNum); throw new RuntimeException("sftp连接失败,连接信息不全"); } return connect(conf.getIp(), conf.getPort(), conf.getUserName(), conf.getPassword()); } /** * 连接sftp服务器,连接失败就报异常; * @param ip * @param port * @param username * @param password * @return */ private synchronized ChannelSftp connect(String ip, int port, String username, String password){ JSch jsch = new JSch(); Properties sshConfig = new Properties(); try { sshSession = jsch.getSession(username, ip, port); sshSession.setPassword(password); sshConfig.put("StrictHostKeyChecking", "no"); sshSession.setConfig(sshConfig); sshSession.connect(); channel = sshSession.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; log.info("sftp服务器连接成功!"); }catch (Exception e){ log.error("sftp 连接错误: {}@{}:{}; pwd:{}", username, ip, port, password); int num = conf.getClientFailNum() + 1; conf.setClientFailNum(num); throw new RuntimeException("sftp连接错误"); } return sftp; } /** * 校验连接sftp的4个基本信息是否为空 * 齐全:true;否则:false; */ private boolean checkConf() { if (null != conf) { return (conf.getIp() != null && conf.getPort() != 0 && conf.getUserName() != null && conf.getPassword() != null); } return false; } @Override public synchronized void close() { if(null != channel){ channel.disconnect(); } if(null != sftp){ sftp.disconnect(); } if(null != sshSession){ sshSession.disconnect(); } } // *********************************下面是文件操作的方法****************************************************** /** * 功能说明:打开指定目录 */ public synchronized boolean openDir(String directory) { checkClient(); log.info("打开指定目录 sftp cd {}", directory); if (StringUtils.isEmpty(directory)) { log.error("sftp 打开目录失败: 目录名不能为空!"); return false; } try { if (!isDirExist(directory)) { sftp.mkdir(directory); } sftp.cd(directory); return true; } catch (SftpException e) { log.error("sftp 打开目录错误: {}", e.getMessage()); return false; } } /** * 检查连接状态, 连接断开则自动重连,重连失败抛出异常 */ public synchronized void checkClient() { if (!this.isConnected()) { this.connect(); } } /** * 检查连接状态 true: 连接正常 false: 连接断开 */ public synchronized boolean isConnected() { if (sftp != null && sftp.isConnected()) { return true; } log.info("SFTP {}@{} 连接被断开", conf.getUserName(), conf.getIp()); return false; } /** * 判断目录是否存在 */ public synchronized boolean isDirExist(String directory) { boolean isDirExistFlag = false; try { SftpATTRS sftpATTRS = sftp.lstat(directory); isDirExistFlag = true; return sftpATTRS.isDir(); } catch (Exception e) { if ("no such file".equals(e.getMessage().toLowerCase())) { isDirExistFlag = false; } else { this.close(); } } return isDirExistFlag; } /** * 通过发送pwd命令模拟心跳, 用于维持长连接 * 先检查连接状态, 连接断开时进行一次重连 * * @return 连接正常或重连成功返回true * 连接错误且重连失败返回false */ public synchronized boolean heartbeat() { checkClient(); return (null != pwd()); } /** * 查看当前所处目录 */ public synchronized String pwd() { String path = null; try { path = sftp.pwd(); } catch (SftpException e) { log.error("sftp {} 密码错误:{}", conf.getFtpName(), e.getMessage()); } return path; } /** * 重命名文件或者目录 ,移动文件或者目录 * * @param oldpath 旧文件或目录 * @param newpath 新文件或目录 */ public synchronized boolean rename(String oldpath, String newpath) { log.info("sftp 移动文件从旧目录 {}到新目录 {}", oldpath, newpath); try { sftp.rename(oldpath, newpath); return true; } catch (Exception e) { log.error("SFTP移动文件错误: {}", e.getMessage()); return false; } } /** * 上传文件 * 上传本地文件 * * @param directory 上传的目录 * @param fileName 要上传的文件名 */ public synchronized boolean upload(String directory, String fileName, InputStream in) throws IOException { log.info("sftp upload file {} to {}", fileName, directory); if (null == in || null == fileName) { log.error("上传文件失败, 缺少重要参数!"); return false; } boolean status = false; try { if (this.openDir(directory)) { sftp.put(in, fileName); status = true; } } catch (Exception e) { log.error("上传文件错误! {}", e.getMessage()); this.close(); } finally { in.close(); } return status; } /** * 上传图片 * 上传base64Str 格式的图片 * * @param base64Str base64编码必填(去掉"data:image/jpeg;base64,"头) * @param directory 目录,必填(device=设备图片目录,inspection=巡检图片目录) * @param fileName 文件名可以为空(扩展名建议jpg) */ public synchronized String uploadFile(@NotNull String base64Str, String directory, String fileName) { if (StringUtils.isBlank(base64Str)) { throw new RuntimeException("base64Str不能为空"); } try (InputStream inputStream = Base64Util.baseToInputStream(base64Str)) { if (this.openDir(directory)) { if (StringUtils.isEmpty(fileName)) { fileName = this.getUUID() + ".jpg"; } // 图片服务器目录:device=设备图片目录,inspection=巡检图片目录,文件名=UUID // 目标文件名 String dst = FileUtil.unite(directory, fileName); sftp.put(inputStream, dst, ChannelSftp.OVERWRITE); } } catch (Exception e) { log.error("上传图片错误: {}", e); this.close(); } return fileName; } /** * 获取宇宙唯一码. * * @version Revision 1.0.0 * @see: * @功能说明: * * @return */ private String getUUID() { UUID uuid = UUID.randomUUID(); String uuidStr = uuid.toString().toUpperCase(Locale.ENGLISH); if (StringUtils.isEmpty(uuidStr)) { return ""; } return uuidStr; } /** * 下载文件 * * @param directory 下载文件所在路径目录 * @param downFileName 下载的文件名称 * @param savePath 保存到本地的路径目录 */ public synchronized boolean download(String directory, String downFileName, String savePath) { log.info("sftp 下载 {} to {}", FileUtil.unite(directory, downFileName), savePath); boolean status = false; File file = null; FileOutputStream fileOutputStream = null; try { if (openDir(directory)) { if (FileUtil.isExistDir(savePath)) { String saveFile = FileUtil.unite(savePath, downFileName); file = new File(saveFile); fileOutputStream = new FileOutputStream(file); sftp.get(downFileName, fileOutputStream); status = true; } } } catch (Exception e) { log.error("sftp 下载 {} 失败: {}", downFileName, e); this.close(); } finally { try { if (null != fileOutputStream) { fileOutputStream.close(); } } catch (Exception e) { log.error("sftp 下载文件, 关闭输出流失败"); status = false; } } return status; } /** * 下载文件 * * @param directory 下载目录 * @param downloadFile 下载的文件名称 * @param localFile 本地文件名称 * @param saveDir 存在本地的目录 */ public synchronized boolean download(String directory, String downloadFile, String localFile, String saveDir) throws IOException { boolean status = false; File file = null; FileOutputStream fileOutputStream = null; try { if (openDir(directory)) { File fileDir = new File(saveDir); if (isExistsDir(fileDir)) { file = new File(saveDir + localFile); fileOutputStream = new FileOutputStream(file); sftp.get(downloadFile, fileOutputStream); status = true; } } } catch (Exception e) { log.error(e.getMessage()); this.close(); } finally { if (null != fileOutputStream) { fileOutputStream.close(); } } return status; } /** * 下载文件,下载过程中采用重命名防止被其他程序误处理 * * @param downloadPath 下载目录 * @param fileName 文件名 * @param savePath 保存目录 * @param suffixPattren 下载中文件后缀名 * @return boolean */ public synchronized boolean downloadAsnFile(String downloadPath, String fileName, String savePath, String suffixPattren) { boolean status = true; FileOutputStream fileOutputStream = null; try { File fileDir = new File(savePath); if (!fileDir.exists()) { fileDir.mkdirs(); } File tempFile = new File(FileUtil.unite(savePath, fileName + suffixPattren)); fileOutputStream = new FileOutputStream(tempFile); sftp.get(fileName, fileOutputStream); File file = new File(FileUtil.unite(savePath, fileName)); tempFile.renameTo(file); } catch (Exception e) { status = false; log.error("下载文件异常,原因:{}", e.getMessage()); } finally { try { if (null != fileOutputStream) { fileOutputStream.close(); } } catch (IOException e) { log.error("关闭文件{}出错", fileName); } } return status; } /** * 判断指定文件夹是否存在, 不存在则创建 * * @param file 指定文件夹 * @author RenZhengGuo 2016年8月13日 下午5:29:37 */ private synchronized boolean isExistsDir(File file) { boolean mkdir = false; // 如果文件夹不存在则创建 if (!file.exists() && !file.isDirectory()) { log.info("目录不存在,创建目录"); mkdir = file.mkdirs(); } return mkdir; } /** * @param file * @author RenZhengGuo 2016年8月13日 下午5:29:37 */ public synchronized void cd(String file) { // 如果文件夹不存在则创建 try { sftp.cd(file); } catch (SftpException e) { createDir(file); // chmod(Integer.parseInt("777", 8), file); } } /** * 创建目录 * * @param file * @return */ public synchronized boolean mkdir(String file) { if (isDirExist(file)) { return true; } try { sftp.mkdir(file); return true; } catch (SftpException e) { log.error("创建文件夹出错!{}", e); return false; } } /** * 给目录授权 * * @param permsion * @param file */ public synchronized void chmod(int permsion, String file) { try { sftp.chmod(permsion, file); } catch (SftpException e) { log.info("为文件:{}授权失败!", file); } } /** * 创建一个文件目录 */ public synchronized void createDir(String createpath) { try { if (isDirExist(createpath)) { this.sftp.cd(createpath); return; } // mkdir 命令不能创建多级目录, 所以要先根据文件分隔符分割成单个目录组 String[] pathArry = createpath.trim().split(FileUtil.DEF_LINE_SEPARATOR); StringBuilder filePath = null; // 如果是绝对路径会以"/"开头, 此时分割出的数组首位是空串应替换成"/" if (pathArry[0].isEmpty()) { filePath = new StringBuilder(FileUtil.DEF_LINE_SEPARATOR); } else { filePath = new StringBuilder(); } for (String pathNode : pathArry) { if (StringUtils.isEmpty(pathNode)) { continue; } filePath.append(pathNode); String path = filePath.toString(); if (!isDirExist(path)) { sftp.mkdir(path); } filePath.append(FileUtil.DEF_LINE_SEPARATOR); } this.sftp.cd(createpath); } catch (SftpException e) { log.info("创建路径错误:" + createpath); } } /** * 判断文件是否存在 */ public synchronized boolean fileExist(String directory, String fileName) { boolean isDirExistFlag = false; try { Vector vector = sftp.ls(directory); if (vector != null && !vector.isEmpty()) { Iterator iterator = vector.iterator(); while (iterator.hasNext()) { ChannelSftp.LsEntry f = iterator.next(); if (f.getAttrs().isDir()) { continue; } if (fileName.equals(f.getFilename())) { return true; } } } return false; } catch (Exception e) { if ("no such file".equals(e.getMessage().toLowerCase())) { isDirExistFlag = false; } else { this.close(); } } return isDirExistFlag; } /** * 删除文件 * 不能使用全路径删除, 先CD到文件所在目录, 删除完毕后在CD回原目录 * * @param directory 要删除文件所在目录 * @param deleteFile 要删除的文件 */ public synchronized boolean delete(String directory, String deleteFile) { checkClient(); log.info("sftp del {}/{}", directory, deleteFile); String pwd = pwd(); boolean status = false; try { sftp.cd(directory); sftp.rm(deleteFile); status = true; sftp.cd(pwd); } catch (Exception e) { log.error("sftp 删除文件错误: {}", e); this.close(); } return status; } /** * 删除文件 * 删除当前目录下的文件 * * @param deleteFile 要删除的文件 */ public synchronized boolean delete(String deleteFile) { checkClient(); log.info("sftp del {}", deleteFile); boolean status = false; try { sftp.rm(deleteFile); status = true; } catch (Exception e) { log.error("sftp 删除文件错误: {}", e); this.close(); } return status; } /** * 列出指定目录下的文件 * 失败时返回空list * * @param directory 要列出的目录 * @return 文件名列表 */ public synchronized List listFiles(String directory) { checkClient(); log.info("sftp ls {}", directory); List ftpFileNameList = new ArrayList(); if (!StringUtils.isEmpty(directory)) { try { Vector sftpFile = sftp.ls(directory); for (ChannelSftp.LsEntry item : sftpFile) { ftpFileNameList.add(item.getFilename()); } } catch (SftpException e) { log.error("sftp 获取文件列表错误! {}", e.getMessage()); this.close(); } } return ftpFileNameList; } /** * 改变目录用户组 * * @param gid * @param path * @return boolean */ public synchronized boolean chgrp(Integer gid, String path) { try { sftp.chgrp(gid, path); return true; } catch (SftpException e) { log.info("改变用户组失败:{}", e.getMessage()); return false; } } /** * 打开指定文件名的文件, 返回InputStream * 失败返回 null * * @param filePath 要打开的文件名 * @return io流 */ public synchronized InputStream openFile(String filePath) { log.info("sftp open file {}", filePath); InputStream inputStream = null; try { inputStream = sftp.get(filePath); return inputStream; } catch (SftpException e) { log.error("打开文件错误: {}", e); this.close(); return null; } } } 5、定义sftp工厂类 package com.demo.sftp.sftp; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * Sftp连接创建工厂 */ @Slf4j public class SftpFactory { private Map factory; private final int DEF_MAP_NUM = 16; /** * 默认连接数 * 初始化连接池的时候默认创建的连接数 */ private int defClientNum = 1; /** * 连接池自动增长的维护时间间隔 */ private int growDistanceTime = 10; /** * 连接池自动清理空闲连接的维护时间间隔 */ private int strictionDistanceTime = 2; public SftpFactory() { factory = new HashMap(DEF_MAP_NUM); } public SftpFactory(int defClientNum) { if (defClientNum > 0){ this.defClientNum = defClientNum; } factory = new HashMap(DEF_MAP_NUM); } /** * 通过工厂创建SFTP连接 * 如果连接池里已经有同样的连接则直接从连接池里获取 * 如果连接池里没有, 则创建新的 * * @param config SFTP连接配置 * @return SFTP连接对象 */ public SftpClient createSftp(SftpConfig config){ return createSftp(config.getIp(),config.getPort(),config.getUserName(),config.getPassword()); } public SftpClient createSftp(String ip, int port, String username, String password){ String key = username + "@" + ip + ":" + port; SftpConfig conf = new SftpConfig(); conf.setIp(ip); conf.setPort(port); conf.setUserName(username); conf.setPassword(password); conf.setFtpName(key); SftpList sftpList = factory.get(key); if (null == sftpList){ sftpList = new SftpList(conf, defClientNum); factory.put(key, sftpList); } else if (sftpList.isEmpty()){ sftpList.add(conf); } return sftpList.next(); } private class SftpList{ private List sftpClients; private SftpClient tempClient; private SftpConfig conf; /** * 最大连接数 */ private final int MAX_CLIENT_NUM = 10; /** * 最小连接数 */ private final int MIN_CLIENT_NUM = 1; /** * 最大错误次数, */ private final int MAX_ERROR_NUM = 3; private int index = 0; private SftpList(SftpConfig config) { this(config, defClientNum); } /** * 创建一个新的连接池 * @param config sftp 连接配置 * @param clientNum 指定连接数 */ private SftpList(SftpConfig config, int clientNum){ if (clientNum < MIN_CLIENT_NUM){ clientNum = MIN_CLIENT_NUM; }else if (clientNum > MAX_CLIENT_NUM){ clientNum = MIN_CLIENT_NUM; } this.sftpClients = new ArrayList(clientNum); this.conf = config; init(); } /** * 在已有连接池增加一个 sftp 连接, * 增加后的总连接数不能大于最大连接数 * * @param config 连接配置 */ public void add(SftpConfig config){ if (conf == null || conf.getFtpName() == null){ conf = config; } add(); } private void add(){ if (size() < MAX_CLIENT_NUM){ SftpClient sftp = new SftpClient(conf); sftpClients.add(sftp); } } /** * 初始化连接池 * 如果连接池是空的则自动按默认连接数增加连接 */ public void init(){ int size = sftpClients.size(); if (size = size()){ index = 0; } SftpClient sftp = sftpClients.get(index); if (sftp == null || !sftp.isConnected()){ log.warn("SFTP---{}({}) 空连接尝试重连: {}", index, size(), conf.getFtpName()); sftp = new SftpClient(conf); sftpClients.set(index, sftp); } sftp.setLastUseDate(System.currentTimeMillis()); log.info("获取 SFTP-{}({}): {}", index, size(), conf.getFtpName()); return sftp; } /** * 获取一条早期使用的 sftp 连接 * @return sftp 连接 */ private SftpClient early(){ int i = index + 2; if (i == sftpClients.size()){ i = 0; } return sftpClients.get(i); } private void updateConf(SftpConfig config){ if (null != config){ conf.setIp(config.getIp()); conf.setPort(config.getPort()); conf.setUserName(config.getUserName()); conf.setPassword(config.getPassword()); } for (SftpClient ftp : sftpClients){ ftp.setConf(conf); } log.info("更新 SFTP 连接: {}", conf.getFtpName()); } /** * 删除最后一个连接 * 为避免关闭使用中的连接, 先将最后一个连接放到缓存中, 等下一次检查连接时再删除 */ private void removeLast(){ int lastIndex = sftpClients.size() - 1; if (this.tempClient != null){ this.tempClient.close(); } tempClient = sftpClients.get(lastIndex); sftpClients.remove(lastIndex); log.info("删除最后一条 SFTP 连接: {}", conf.getFtpName()); } /** * 删除一个指定的连接, 删除的连接会直接关闭 * @param index 需要删除的连接下标 */ private void removeSftp(int index){ if (sftpClients.size() > index){ SftpClient ftp = sftpClients.get(index); if (ftp != null){ ftp.close(); } sftpClients.remove(index); log.info("删除 SFTP-{}({}) 连接: {}", index, size(), conf.getFtpName()); } } private void removeAll(){ for (SftpClient ftp : sftpClients){ ftp.close(); } sftpClients.clear(); log.info("清除 SFTP 连接池: {}", conf.getFtpName()); } private final long DELAY = 10L; private final long LONG_DISTANCE = TimeUnit.MINUTES.toMillis(growDistanceTime); private final long SHORT_DISTANCE = TimeUnit.MINUTES.toMillis(strictionDistanceTime); /** * 定时器, 定时检查连接状态; * 超过15分钟没有调用SFTP连接, 则关闭最后一个连接; * 总连接数等于最小连接数(MIN_CLIENT_NUM)时不再关闭连接; * * 所有SFTP连接的最后一次调用时间间隔小于2分钟时, 说明使用比较频繁; * SFTP连接调用频繁时, 自动增加一个新连接; * 总连接数等于最大连接数(MAX_CLIENT_NUM)时, 不再增加连接; */ public void heartbeat(){ ThreadFactory threadFactory = new BasicThreadFactory.Builder() .namingPattern("sftp-heartbeat-%d").daemon(false).build(); ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, threadFactory); executorService.scheduleWithFixedDelay(()->{ // 关闭临时连接 if (tempClient != null){ tempClient.close(); tempClient = null; } // sftp 连接心跳 for (SftpClient f : sftpClients){ try{ f.heartbeat(); }catch(Exception e){ log.error("sftp心跳错误"); removeAll(); } } // 总连接数大于最小连接数时, 判断最后一次使用的连接距当前的使用间隔 // 大于10分钟未使用的移到临时连接, 等待下一次自动关闭 if (sftpClients.size() > MIN_CLIENT_NUM){ long nowDate = System.currentTimeMillis(); long da = nowDate - early().getLastUseDate(); if (da > LONG_DISTANCE){ removeLast(); log.info("清理空闲连接: {}", conf.getFtpName()); } } // 总连接数小于最大连接数时, 轮询所有连接 // 如果使用间隔小于2分钟, 自动增加一个连接 if (sftpClients.size() < MAX_CLIENT_NUM && checkClient()){ add(); } }, DELAY, DELAY, TimeUnit.MINUTES); } private boolean checkClient(){ long nowDate = System.currentTimeMillis(); for (SftpClient ftp: sftpClients){ long da = nowDate - ftp.getLastUseDate(); if (da > SHORT_DISTANCE){ return false; } } log.info("增加连接: {}", conf.getFtpName()); return true; } public boolean isEmpty(){ return sftpClients.isEmpty(); } public int size(){ return sftpClients.size(); } } } 6、启动类中添加SftpFactory; package com.demo.sftp; import com.demo.sftp.sftp.SftpFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableAsync; import springfox.documentation.swagger2.annotations.EnableSwagger2; @SpringBootApplication @EnableSwagger2 @EnableAsync // 开启spring异步注解 public class SftpApplication { public static void main(String[] args) { SpringApplication.run(SftpApplication.class,args); } @Bean public SftpFactory sftpFactory(){ return new SftpFactory(); } } 7、创建测试方法

因为太懒,本方法中关于sftp的连接信息是直接写死的,实际项目中建议将sftp连接信息配置到配置文件中或者数据库中进行动态获取,这样当sftp的连接信息有所变动时候,可以避免修改对应连接sftp客户端的代码。

package com.demo.sftp.controller; import com.demo.sftp.dto.Result; import com.demo.sftp.sftp.FileUtil; import com.demo.sftp.sftp.SftpClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @Slf4j @Api("sftp学习接口") @RestController @RequestMapping(value = "/sftp") public class TestController { @ApiOperation(value = "测试接口",notes = "测试接口") @PostMapping("/test") Result test(){ log.info("请求正常"); this.uploadFile(); return Result.ok("success"); } /** * 模拟上传文件到sftp服务器: * 代码生成数据,写入文件并上传到sftp服务器; */ private void uploadFile(){ // 因为该模块代码对外公开,所以此处使用代码的符合表示实际的连接信息。 String ip = "ip"; String port = "port"; String userName = "username"; String passWord = "passWord"; SftpClient sftp = new SftpClient(null, ip, Integer.parseInt(port), userName, passWord); log.info("sftp客户端创建成功"); String content = this.getContent(); ByteArrayInputStream bakInputStream = new ByteArrayInputStream(content.getBytes()); ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes()); log.info("开始上传文件"); String bakPath = "/upload/bakPath"; String storePath = "/upload/storePath"; String fileName = "YSL_" + 8888 + "_test" + System.currentTimeMillis(); String tempFileName = "~" + fileName; boolean b = this.uploadFile(sftp, bakPath, storePath, fileName, tempFileName, bakInputStream, inputStream); log.info("文件上传结束"); if(!b){ log.info("文件上传失败了"); return; } sftp.close(); } /** * 文件内容封装 */ private String getContent(){ StringBuilder outStr = new StringBuilder("STA|1"+"\r\n"); outStr.append("数据编号,企业ID,企业名称,操作类型,账单类型,产品类型,产品唯一识别编码," + "账目项1,账目项1产品单价,账目项1产品个数,账目项2,账目项2产品单价,账目项2产品个数"+"\r\n"); outStr.append(1+",") .append(1112233+",")// 数据编号 .append(31803+",") // 企业ID .append(3+",") // 操作类型 .append(2 + ",") // 账单类型 .append(40+",") // 产品类型编号 .append("SV3333333"+",") // 产品唯一识别编码 .append("zmx111222"+",") // 账目项1 .append(233+",") // 账目项1产品单价 .append(1+",") // 账目项1产品个数 .append("zmx111222"+",") // 账目项2 .append(33+",") // 账目项2产品单价 .append(1+",") // 账目项2产品个数 .append("\r\n") .append("end"); return outStr.toString(); } /** * 上传文件 */ public static boolean uploadFile(SftpClient sftp, String bakPath, String storePath, String fileName, String tempFileName, InputStream bakInput, InputStream input) { try { //上传至备份目录 log.info("开始上传文件fileName==={}",fileName); sftp.upload(bakPath, fileName, bakInput); // 文件上传到备份文件夹 //上传临时文件至下发目录 boolean b = sftp.upload(storePath, tempFileName, input); // 临时文件上传成功,修改临时文件名为正式名 if (b) { sftp.rename(FileUtil.unite(storePath, tempFileName), FileUtil.unite(storePath, fileName)); } return true; } catch (IOException e) { log.error("上传文件{}出错", fileName); log.error(e.getLocalizedMessage()); return false; } } }   8、swagger接口调用测试,看是否生成文件

查看对应sftp目录下是否确实创建目录成功:如果使用的账号在当前目录没有创建目录的权限,则需要手动将对应的文件目录创建好之后才能使用程序上传文件。

文件夹下文件也上传成功

至此sftp上传文件的演示结束,实际生产中,可能有很多的文件服务器,对应不同的账号,建议这些信息写入系统信息数据库表中,以动态读取的形式获取配置信息,毕竟将很多的sftp服务器信息都配置在配置文件中还是显得很冗余。

 

 

 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3