概述:
本文章主要是基于内容发布,通过ChannelSftp将文件复制到另一台机器涉及多线程调用,和怎么上传文件和文件夹,及ChannelSftp 中的语法说明。
POM
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
相关代码
public class sftpsynchronization {
private static Logger logger= LoggerFactory.getLogger(sftpsynchronization.class);
/**
* 生产环境设计多线程大数据量时 ,会出现部分文件丢失,private static ChannelSftp channel = null,
* 去掉static后即可解决,原因:channel 对象加了static后会导致 容器中只存在一个channel 所以多线程执行时,
* 如果存在某一个线程关闭了channel ,会导致其他的线程执行报错;所以去掉static每个线程为单独的
*/
private ChannelSftp channel;
private Session session;
/**
* 规避多线程并发不断开问题
*/
private ThreadLocal<sftpsynchronization> sftpLocal = new ThreadLocal<sftpsynchronization>();
/**
* 创建sftp连接
* @param map
*/
public void connectServer(Map<String, Object> map) {
try {
// 创建JSch对象
JSch jsch = new JSch();
// 根据用户名,主机ip,端口获取一个Session对象
String sftpPassword = CMSUtil.stringFormat(map.get("loginPwd"));
session = jsch.getSession(CMSUtil.stringFormat(map.get("loginUser")), CMSUtil.stringFormat(map.get("targetServer")), CMSUtil.intFormat(CMSUtil.stringFormat(map.get("targetPort"))));
if (sftpPassword != null) {
// 设置密码
session.setPassword(sftpPassword);
}
Properties configTemp = new Properties();
configTemp.put("StrictHostKeyChecking", "no");
// 为Session对象设置properties
session.setConfig(configTemp);
// 设置timeout时间
session.setTimeout(60000);
session.connect();
// 通过Session建立链接
// 打开SFTP通道
channel = (ChannelSftp) session.openChannel("sftp");
// 建立SFTP通道的连接
channel.connect();
} catch (JSchException e) {
// //e.printStackTrace();
logger.info("创建sftp连接失败");
}
}
/**
* 断开SFTP Channel、Session连接
*
* @param channel
* @param session
*/
public void closeChannel(ChannelSftp channel, Session session) {
try {
if (channel != null) {
channel.disconnect();
sftpLocal.set(null);
}
if (session != null) {
session.disconnect();
}
} catch (Exception e) {
logger.info(e.getMessage());
}
}
/**
* 判断sftp是否连接
*
* @return
*/
public boolean isChannel() {
try {
if (channel.isConnected()) {
return true;
}
} catch (Exception e) {
logger.info(e.getMessage());
}
return false;
}
/**
* 获取本地线程存储的sftp客户端
* @param map
* @return
* @throws Exception
*/
public sftpsynchronization getSftpUtil(Map<String,Object> map) throws Exception {
sftpsynchronization sftpUtil = sftpLocal.get();
if (null == sftpUtil || !sftpUtil.isChannel()) {
sftpLocal.set(new sftpsynchronization(map));
}
return sftpLocal.get();
}
private sftpsynchronization(Map<String,Object> map) throws Exception {
super();
connectServer(map);
}
/**
* 释放本地线程存储的sftp客户端
*
* @param sftpUtil
*/
public void release(sftpsynchronization sftpUtil) {
sftpUtil.closeChannel(sftpUtil.channel, sftpUtil.session);
}
/**
* 判断目录是否存在
* @param path
* @return
*/
public boolean isExistDir(String path){
boolean isExist=false;
try {
SftpATTRS sftpATTRS = channel.lstat(path);
isExist = true;
return sftpATTRS.isDir();
} catch (Exception e) {
if (e.getMessage().toLowerCase().equals("no such file")) {
isExist = false;
}
}
return isExist;
}
/**
* 仅发布站点/栏目首页
* 模板样式文件单个文件上传
* 不需要同步附件和附图
* @param map
* @param localFile
* @param datapath
*/
public static void publishdistri(Map<String, Object> map, String localFile, String datapath) {
//站点分发跟目录
String dataPath = CMSUtil.stringFormat(map.get("dataPath"));
sftpsynchronization sftpUtil = null;
try {
String newdatapah = datapath.replaceAll("//", "/");
String localFilens = localFile.replaceAll("//", "/");
sftpsynchronization sftp = new sftpsynchronization();
sftpUtil = sftp.getSftpUtil(map);
sftpUtil.copyFileNew(localFilens, dataPath, newdatapah);
} catch (Exception e) {
logger.error("仅发布站点/栏目首页SFTP站分发错误"+e.getMessage());
//e.printStackTrace();
} finally {
sftpUtil.release(sftpUtil);
}
}
/**
* 上传文件
* 文件内容复制
* @param localFile 指定本地文件
* @param remoteFile 配置服务路径
* @param realpath 服务器具体路径
* @throws SftpException
*/
public void copyFileNew(String localFile, String remoteFile, String realpath) throws SftpException {
File file = new File(localFile);
//上传sftp目录
String pathOut= remoteFile+"/" + realpath;
if(file.exists()){
try {
channel.cd(pathOut);
} catch (Exception e) {
// 目录不存在,则创建文件夹
String[] dirs = pathOut.split("/");
String tempPath = "";
int index = 0;
mkdirDir(dirs, tempPath, dirs.length, index);
}
if (file.isDirectory()) { //对象是否是文件夹
File[] files = file.listFiles();
if (files == null || files.length <= 0) {
logger.info("读取文件错误");
}
String realpathtemp=realpath;
//cd 目录
String realpathcd="";
for (File f : files) {
String fp = f.getAbsolutePath();
if (f.isDirectory()) {
realpathcd = remoteFile+"/" +realpathtemp + "/" + f.getName();
realpath = realpathtemp + "/" + f.getName();
try {
channel.cd(realpathcd);
} catch (Exception e) {
String pathOutTemp= remoteFile+"/" + realpath.replaceAll("//","/");
String[] dirs = pathOutTemp.split("/");
String tempPath = "";
int index = 0;
mkdirDir(dirs, tempPath, dirs.length, index);
}
copyFileNew(fp,remoteFile, realpath);
} else {
//OVERWRITE 覆盖文件
channel.put(fp, remoteFile + "/" + realpath, ChannelSftp.OVERWRITE);
}
}
} else {
String fp = file.getAbsolutePath();
channel.put(fp, remoteFile + "/" + realpath, ChannelSftp.OVERWRITE);
}
}
}
/**
* 递归根据路径创建文件夹
* @param dirs 根据 / 分隔后的数组文件夹名称
* @param tempPath 拼接路径
* @param length 文件夹的格式
* @param index 数组下标
* @return
*/
public void mkdirDir(String[] dirs, String tempPath, int length, int index) {
// 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
index++;
if (index < length) {
// 目录不存在,则创建文件夹
tempPath += "/" + dirs[index];
}
try {
channel.cd(tempPath);
if (index < length) {
mkdirDir(dirs, tempPath, length, index);
}
} catch (SftpException ex) {
try {
channel.mkdir(tempPath);
channel.cd(tempPath);
} catch (SftpException e) {
logger.error("SFTP创建文件失败"+e.getMessage());
}
mkdirDir(dirs, tempPath, length, index);
}
}
}
版权声明:本文为qq_20025777原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。