com.jcraft
jsch
将sftp上传的类注入进spring里
@Bean
public SftpUtil getSftpUtil() {
return SftpUtil.getSftpUtil();
}
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class SftpUpload {
//注入上面的工具
@Autowired
SftpUtil sftpUtil;
private static final Logger log = LoggerFactory.getLogger(SftpUpload.class.getName());
/**
* @Title: uploadToSftp
* @Description: 上傳文件到Sftp工具類
* @param file 前台上傳的文件
* @param model 文件夾名
* @return 返回上傳後訪問路徑
* @author: 月夜流心
*/
public String uploadToSftp(MultipartFile file,String model) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date =sdf.format(new Date()) + "/";
try {
boolean upload = sftpUtil.upload(file.getInputStream(), file.getOriginalFilename() ,"/root/fileUpload");
if(!upload) {
return null;
}
} catch (IOException e) {
log.error(e.getMessage());
return null;
}
return "/root/fileUpload" + file.getOriginalFilename();
}
}
sftp工具类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
/**
* sftp上传下载工具类
*/
public class SftpUtil {
//ip port username password
private static final String SFTP_IP = "127.0.0.1";
private static final Integer SFTP_PORT = 22;
private static final String SFTP_USERNAME = "root";
private static final String SFTP_PASSNM = "test123.";
private static final Logger log = LoggerFactory.getLogger(SftpUtil.class.getName());
/**
* session
*/
private Session session;
/**
* 通道
*/
private ChannelSftp channel;
/**
* 规避多线程并发不断开问题
*/
private static ThreadLocal<SftpUtil> sftpLocal = new ThreadLocal<>();
/**
* 私有构造方法
*/
private SftpUtil() {
}
/**
* 构造函数 非线程安全,故权限为私有
*/
private SftpUtil(String host, Integer port, String username, String password) {
super();
init(host, port, username, password);
}
/**
* 获取本地线程存储的sftp客户端
* @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_PASSNM));
}
return sftpLocal.get();
}
/**
* 获取本地线程存储的sftp客户端
* @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");
session.setConfig(config);
// 设置超时
//session.setTimeout(3*1000);
// 设置密码
session.setPassword(password);
session.connect();
// 打开SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
// 建立SFTP通道的连接
channel.connect();
} catch (JSchException e) {
log.error(e.getMessage());
}
}
/**
* 是否已连接
* @return boolean
*/
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);
}
}
}
/**
* 释放本地线程存储的sftp客户端
*/
public static void release() {
if (null != sftpLocal.get()) {
sftpLocal.get().closeChannel();
sftpLocal.set(null);
}
}
/*
*//**
* 列出目录下文件,只列出文件名字,没有类型
* @param dir 目录
* @return List
*/ /*
@SuppressWarnings("unchecked")
public List list(String dir) {
if (channel == null) {
log.error("获取sftp连接失败,请检查" + SFTP_IP + SFTP_PORT + "@" + SFTP_USERNAME + "" + SFTP_PASSNM + "是否可以访问");
return null;
}
Vector files = null;
try {
files = channel.ls(dir);
} catch (SftpException e) {
log.error(e.getMessage());
}
if (null != files) {
List fileNames = new ArrayList<>();
for (ChannelSftp.LsEntry file : files) {
String fileName = file.getFilename();
if (StringUtils.equals(".", fileName) || StringUtils.equals("..", fileName)) {
continue;
}
fileNames.add(fileName);
}
return fileNames;
}
return null;
}
*/ /**
* 列出文件详情
* @param dir
* @return List
*//*
@SuppressWarnings({ "rawtypes", "unchecked" })
public List listDetail(String dir) {
if (channel == null) {
log.error("获取sftp连接失败,请检查" + SFTP_IP + SFTP_PORT + "@" + SFTP_USERNAME + "" + SFTP_PASSNM + "是否可以访问");
return null;
}
Vector files = null;
try {
files = channel.ls(dir);
} catch (SftpException e) {
log.error(e.getMessage());
}
if (null != files) {
List
// public static String timestampToDate(long time) {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// return sdf.format(time);
// }
/**
* @param file 上传文件
* @param remotePath 服务器存放路径,支持多级目录
*/
public void upload(File file, String remotePath) {
if (channel == null) {
log.error("获取sftp连接失败,请检查" + SFTP_IP + SFTP_PORT + "@" + SFTP_USERNAME + "" + SFTP_PASSNM + "是否可以访问");
}
try (FileInputStream fileInputStream = new FileInputStream(file)){
if (file.isFile()) {
//服务器要创建的目录
try {
createDir(remotePath);
} catch (Exception e) {
log.error("創建路徑失敗:" + remotePath);
}
channel.cd(remotePath);
channel.put(fileInputStream, file.getName());
}
} catch (FileNotFoundException e) {
log.error("上传文件没有找到");
} catch (SftpException e1) {
log.error("上传ftp服务器错误");
} catch (IOException e2) {
log.error(e2.getMessage());
}
}
/**
* @param file 上传文件
* @param remoteName 上传文件名字
* @param remotePath 服务器存放路径,支持多级目录
*/
public boolean upload(File file, String remoteName, String remotePath) {
if (channel == null) {
log.error("获取sftp连接失败,请检查" + SFTP_IP + SFTP_PORT + "@" + SFTP_USERNAME + "" + SFTP_PASSNM + "是否可以访问");
} else {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
if (file.isFile()) {
//服务器要创建的目录
createDir(remotePath);
channel.cd(remotePath);
log.error(remotePath + " " + remoteName);
channel.put(fileInputStream, remoteName);
return true;
}
} catch (FileNotFoundException e) {
log.error(e.getMessage(), "上传文件没有找到");
return false;
} catch (SftpException e) {
log.error(e.getMessage());
return false;
} catch (IOException e2) {
log.error(e2.getMessage());
}
}
return false;
}
/**
* @param inputStream 上传文件
* @param remoteName 上传文件名字
* @param remotePath 服务器存放路径,支持多级目录
*/
public boolean upload(InputStream inputStream, String remoteName, String remotePath) {
if (channel == null) {
log.error("获取sftp连接失败,请检查" + SFTP_IP + SFTP_PORT + "@" + SFTP_USERNAME + "" + SFTP_PASSNM + "是否可以访问");
} else {
try (InputStream input = inputStream) {
//服务器要创建的目录
String rPath = remotePath;
createDir(rPath);
channel.cd(remotePath);
log.info(remotePath + " " + remoteName);
channel.put(input, remoteName);
return true;
} catch (SftpException | IOException e) {
log.error(e.getMessage());
return false;
}
}
return false;
}
/**
* 下载文件
* @param downDir 下载目录
* @param src 源文件
* @param dst 保存后的文件名称或目录
*/
public void downFile(String downDir, String src, String dst) {
try {
channel.cd(downDir);
channel.get(src, dst);
} catch (SftpException e) {
log.error(e.getMessage());
}
}
public void downFiles(String rootDir, String src, String dst) throws Exception {
channel.cd(rootDir);
channel.get(src, dst);
}
/**
* 下载文件
* @param rootDir 服务器路径
* @param targetPath 目标路径
* @return File
*/
public File downFile(String rootDir, String targetPath) {
OutputStream outputStream = null;
File file = null;
try {
channel.cd(rootDir);
file = new File(targetPath.substring(targetPath.lastIndexOf("/") + 1));
outputStream = new FileOutputStream(file);
channel.get(targetPath, outputStream);
} catch (SftpException e) {
log.error(e.getMessage());
return null;
} catch (FileNotFoundException e) {
log.error("找不到需要下载或查看的文件,请检查文件路徑或是ftp服务器");
return null;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
return file;
}
@SuppressWarnings("rawtypes")
public Vector listFile(String rootDir, String remotePath) throws SftpException {
channel.cd(rootDir);
return channel.ls(remotePath);
}
/**
* 列出目录下的文件
* @param directory:要列出的目录
*/
@SuppressWarnings("rawtypes")
public Vector listFile(String directory) throws SftpException {
return channel.ls(directory);
}
/**
* 删除文件
* @param filePath 文件全路径
* @throws SftpException SftpException
*/
public void deleteFile(String filePath) throws SftpException {
channel.rm(filePath);
}
/**
* 创建一个文件目录
*/
public void createDir(String createpath) {
try {
if (isDirExist(createpath)) {
this.channel.cd(createpath);
return;
}
String[] pathArry = createpath.split("/");
StringBuffer filePath = new StringBuffer("/");
for (String path : pathArry) {
if ("".equals(path)) {
continue;
}
filePath.append(path).append("/");
if (isDirExist(filePath.toString())) {
channel.cd(filePath.toString());
} else {
// 建立目录
channel.mkdir(filePath.toString());
// 进入并设置为当前目录
channel.cd(filePath.toString());
}
}
this.channel.cd(createpath);
} catch (SftpException e) {
log.error(e.getMessage());
}
}
/**
* 判断目录是否存在
*/
public boolean isDirExist(String directory) {
boolean isDirExistFlag = false;
try {
SftpATTRS sftpATTRS = channel.lstat(directory);
isDirExistFlag = true;
return sftpATTRS.isDir();
} catch (Exception e) {
if ("no such file".equals(e.getMessage().toLowerCase())) {
isDirExistFlag = false;
}
}
return isDirExistFlag;
}
static String PS = "/";
/**
* This method is called recursively to download the folder content from SFTP
* server
*
* @param sourcePath
* @param destinationPath
* @throws SftpException
*/
@SuppressWarnings("unchecked")
public void recursiveFolderDownload(String sourcePath, String destinationPath) throws SftpException {
// Let list of folder content
Vector<ChannelSftp.LsEntry> fileAndFolderList = channel.ls(sourcePath);
// Iterate through list of folder content
for (ChannelSftp.LsEntry item : fileAndFolderList) {
// Check if it is a file (not a directory).
if (!item.getAttrs().isDir()) {
if (
!(new File(destinationPath + PS + item.getFilename())).exists() || (item.getAttrs()
.getMTime() > new File(destinationPath + PS + item.getFilename()).lastModified() / 1000)
) { // Download only if changed later.
new File(destinationPath + PS + item.getFilename());
// Download file from source (source filename, destination filename).
channel.get(sourcePath + PS + item.getFilename(), destinationPath + PS + item.getFilename());
}
} else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) {
// Empty folder copy.
new File(destinationPath + PS + item.getFilename()).mkdirs();
// Enter found folder on server to read its contents and create locally.
recursiveFolderDownload(sourcePath + PS + item.getFilename(),destinationPath + PS + item.getFilename());
}
}
}
/**
* 文件夹不存在,创建
* @param folder 待创建的文件节夹
*/
public void createFolder(String folder) {
SftpATTRS stat = null;
try {
stat = channel.stat(folder);
} catch (SftpException e) {
log.debug("复制目的地文件夹" + folder + "不存在,创建");
}
if (stat == null) {
try {
channel.mkdir(folder);
} catch (SftpException e) {
log.error("创建失败", e.getCause());
}
}
}
public InputStream get(String filePath) {
InputStream inputStream = null;
try {
inputStream = channel.get(filePath);
} catch (SftpException e) {
log.error(e.getMessage());
}
return inputStream;
}
public void put(InputStream inputStream, String filePath) {
try {
channel.put(inputStream, filePath);
} catch (SftpException e) {
log.error(e.getMessage());
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public Vector<ChannelSftp.LsEntry> ls(String filePath) {
Vector ls = null;
try {
ls = channel.ls(filePath);
} catch (SftpException e) {
log.error(e.getMessage());
}
return ls;
}
/**
* 复制文件夹
* @param src 源文件夹
* @param desc 目的文件夹
*/
public void copy(String src, String desc) {
// 检查目的文件存在与否,不存在则创建
this.createDir(desc);
// 查看源文件列表
Vector<ChannelSftp.LsEntry> fileAndFolderList = this.ls(src);
for (ChannelSftp.LsEntry item : fileAndFolderList) {
if (!item.getAttrs().isDir()) {
try (
InputStream tInputStream = this.get(src + PS + item.getFilename());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream nInputStream = new ByteArrayInputStream(baos.toByteArray())
) {
byte[] buffer = new byte[1024];
int len;
while ((len = tInputStream.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
this.put(nInputStream, desc + PS + item.getFilename());
} catch (IOException e) {
log.error(e.getMessage());
}
// 排除. 和 ..
} else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) {
// 创建文件,可能不需要
this.createFolder(desc + PS + item.getFilename());
//递归复制文件
copy(src + PS + item.getFilename(), desc + PS + item.getFilename());
}
}
}
}