- 最近在工作功能使用了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 ThreadLocal sftpLocal = 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();
List list = 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 ? "删除成功" : "文件不存在或删除失败");
}
}