package xxx.utils import com.jcraft.jsch.* import org.slf4j.Logger import org.slf4j.LoggerFactory import java.text.SimpleDateFormat
//使用的是groovy class SftpUtil { private static final Logger logger = LoggerFactory.getLogger(SftpUtil.getClass()) static SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd") JSch jsch = null Session session = null ChannelSftp channel = null static ThreadLocal<SftpUtil> sftpLocal = new ThreadLocal<SftpUtil>() SftpUtil(String userName, String host, int port, String password) { connect(userName, host, port, password) } SftpUtil(String userName, String host, int port, String password, String keyFilePath, String passphrase) { connect(userName, host, port, password, keyFilePath, passphrase) } boolean isConnected() { return null != channel && channel.isConnected() } static SftpUtil getSftpUtil(String userName, String host, int port, String password) throws Exception { SftpUtil sftpUtils = sftpLocal.get() if (sftpUtils == null || !sftpUtils.isConnected()) { sftpLocal.set(new SftpUtil(userName, host, port, password)) } return sftpLocal.get() } static SftpUtil getSftpUtil(String userName, String host, int port, String password, String keyFilePath, String passphrase) throws Exception { SftpUtil sftpUtils = sftpLocal.get() if (sftpUtils == null || !sftpUtils.isConnected()) { sftpLocal.set(new SftpUtil(userName, host, port, password, keyFilePath, passphrase)) } return sftpLocal.get() } static void release() { if (null != sftpLocal.get()) { sftpLocal.get().close() sftpLocal.set(null) } } /** * 連接到指定的IP * * @throws JSchException */ ChannelSftp connect(String userName, String host, int port, String password) { try { jsch = new JSch()// 創建JSch對象 session = jsch.getSession(userName, host, port)// 根據用戶名、主機ip、端口號獲取一個Session對象 session.setConfig("PreferredAuthentications", "password") session.setPassword(password) session.setConfig("StrictHostKeyChecking", "no") session.setTimeout(60000) session.setServerAliveInterval(2000) session.setServerAliveCountMax(8) session.connect(3000) logger.info("sftp session connected.") channel = (ChannelSftp) session.openChannel("sftp") channel.connect(3000) logger.info("Connected successfully ${host} ${userName}") } catch (JSchException e) { logger.error("sftp connected failed...", e) } } /** * 密鑰連接到指定的IP * * @throws JSchException * @param keyFilePath 密鑰路徑 * @param passphrase 密鑰的密碼 */ public void connect(String userName, String host, int port, String password, String keyFilePath, String passphrase) throws Exception { try { jsch = new JSch(); if (keyFilePath != null) { if (passphrase != null) { jsch.addIdentity(keyFilePath, passphrase);// 設置私鑰 } else { jsch.addIdentity(keyFilePath);// 設置私鑰 } logger.info("連接sftp,私鑰文件路徑:" + keyFilePath); } logger.info("SFTP Host: " + host + "; UserName:" + userName); session = jsch.getSession(userName, host, port); logger.debug("Session 已建立."); if (password != null) { session.setPassword(password); } Properties sshConfig = new Properties(); sshConfig.put("StrictHostKeyChecking", "no"); session.setConfig(sshConfig); session.setConfig("kex", "diffie-hellman-group1-sha1"); session.connect(); logger.debug("Session 已連接."); channel = (ChannelSftp) session.openChannel("sftp") channel.connect(3000) logger.info("連接到SFTP成功.Host: " + host); } catch (Exception e) { logger.error("連接SFTP失敗:", e); } } /** * 關閉連接 */ void close() { if (channel != null) { try { channel.disconnect() } catch (Exception e) { logger.error("sftp close channel failed...", e) } } if (session != null) { try { session.disconnect() } catch (Exception e) { logger.error("sftp close session failed...", e) } } } /** * 執行相關的命令, * 但是部分情況不可用 * * @throws JSchException */ String execCmd(String command) throws JSchException { BufferedReader reader = null String result = "" if (channel == null) { logger.info("SFTP服務器未連接") return result } try { if (command != null) { ((ChannelExec) channel).setCommand(command) channel.connect() InputStream input = channel.getInputStream() reader = new BufferedReader(new InputStreamReader(input)) String buf = null while ((buf = reader.readLine()) != null) { logger.info(buf) result += buf } } } catch (IOException e) { logger.error("遠程服務器端IO流錯誤:" + e.getMessage()) e.printStackTrace() } catch (JSchException e) { logger.error("Jsch傳輸異常:" + e.getMessage()) e.printStackTrace() } finally { try { reader.close() } catch (IOException e) { logger.error("遠程服務器端IO流關閉失敗:" + e.getMessage()) e.printStackTrace() } } result } /** * 上傳文件 * * @param fileName * 上傳的文件,含擴展名 * @param ftpPath * 文件本地目錄 * @param outFilePath * 文件上傳目錄 * @throws JSchException* @throws FileNotFoundException* 上傳本地最新文件,並備份服務器端原文件 */ void upload(String fileName, String localPath, String outFilePath) throws Exception { //連接sftp if (channel == null) { logger.info("SFTP服務器未連接") release() return } String localFilepath = localPath + fileName File localFile = new File(localFilepath) FileInputStream input = null try { if (!localFile.exists()) { logger.warn("本地服務器:上傳文件不存在") return } if (existFile(outFilePath, fileName)) { return } String uploadFile = outFilePath + fileName //上傳的文件 logger.info("上傳文件:" + fileName + "開始") input = new FileInputStream(localFile) channel.put(input, uploadFile, ChannelSftp.OVERWRITE) logger.info("上傳到sftp成功") //上傳完成,備份本地文件 String localBak = bakFileName(fileName) String bakPath = bakPath(localPath, fileName) File newfile = new File(bakPath + localBak) if (localFile.renameTo(newfile)) { logger.info("本地文件備份成功:" + localBak) } else { logger.info("本地文件備份失敗:" + localBak) } } catch (Exception e) { logger.info("上傳文件:" + fileName + "失敗") throw e } finally { if (input) { input.close() } release() } } /** * 上傳文件某文件夾下所有文件 * * @param fileName * 上傳的文件,含擴展名 * @param ftpPath * 文件本地目錄 * @param outFilePath * 文件上傳目錄 * @throws JSchException* @throws FileNotFoundException* */ void uploadAllFile(String fileName, String localPath, String outFilePath, String bakPath) throws Exception { //連接sftp if (channel == null) { logger.info("SFTP服務器未連接") release() return } File[] files = [] File localFile = new File(localPath) FileInputStream input = null List<FileInputStream> ins = [] try { if (!localFile.exists()) { logger.warn("本地服務器:上傳文件不存在") return } if (existFile(outFilePath, fileName)) { return } if (localFile.isDirectory()) { files = localFile.listFiles(); if (files == null || files.length <= 0) { return; } for (File f : files) { String uploadFile = outFilePath + f.getName() //上傳的文件 logger.info("上傳文件:" + f.getName() + "開始") input = new FileInputStream(f) ins.add(input) channel.put(input, uploadFile, ChannelSftp.OVERWRITE) logger.info("上傳到sftp成功") } } logger.info(files.size()+"---------------------------------------") } catch (Exception e) { logger.info("上傳文件:" + fileName + "失敗") throw e } finally { ins?.each {it.close()} if (input) { input.close() } release() //上傳完成,備份本地文件 if (bakPath) { files?.each { it.renameTo(new File(bakPath+bakFileName(it.getName()))) } } else { files?.each {logger.info("刪除文件:" + it.getName() + "--:"+it.delete())} } } } /** * 下載文件 * 備份本地文件,再下載服務器端最新文件 * @param localPath 本地存放路徑 * @param remotePath 服務器端存放路徑 * @throws JSchException */ void download(String fileName, String localPath, String remotePath) throws Exception { // src linux服務器文件地址,dst 本地存放地址 if (channel == null) { logger.info("SFTP服務器未連接") return } String remoteFile = remotePath + fileName String localFile = localPath + fileName FileOutputStream output =null try { if (!existFile(remotePath, fileName)) { logger.warn("SFTP服務器:下載文件不存在" + remotePath + fileName) return } File file = new File(localFile) if (file.size() > 0) { //創建新名字的抽象文件 String bakname = bakFileName(fileName) String bakPath = bakPath(localPath, fileName) File newfile = new File(bakPath + bakname) if (file.renameTo(newfile)) { logger.info("本地文件:" + fileName + "備份成功") } else { logger.info("本地文件:" + fileName + "備份失敗,將覆蓋原文件!") } } output = new FileOutputStream(file) logger.info("下載文件:" + fileName + "開始") channel.get(remoteFile, output) logger.info("下載文件:" + fileName + "成功") //下載完成后備份服務器文件 String bakFile = bakFileName(fileName) String bakRemotePath = bakPath(remotePath, fileName) //channel.rename(remoteFile, bakRemotePath + fileName) //delete(remotePath, fileName) logger.info("服務器端文件備份成功:" + bakFile) } catch (Exception e) { logger.info("下載文件:" + fileName + "失敗") throw e } finally { if(output) { output.close() } release() } } /** * 刪除文件 * * @param directory * 要刪除文件所在目錄 * @param deleteFile * 要刪除的文件 * @throws JSchException */ void delete(String directory, String deleteFile) throws Exception { if (channel == null) { logger.info("SFTP服務器未連接") return } channel.cd(directory) channel.rm(deleteFile) logger.info("刪除成功") } /** * 列出目錄下的文件 * * @param directory * 要列出的目錄 * @param sftp * @return * @throws JSchException */ @SuppressWarnings("rawtypes") Vector listFiles(String directory) throws Exception { if (channel == null) { logger.info("SFTP服務器未連接") return null } Vector vector = channel.ls(directory) return vector } /** * 判斷文件是否存在 * @param sourceName * @return */ Boolean existFile(String remotrPath, String filename) { Vector files = listFiles(remotrPath) Boolean rst = false files.each { ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) it if (entry.getFilename() == filename) { rst = true } } rst } String bakFileName(String sourceName) { return sourceName + "." + df.format(new Date()) + System.currentTimeMillis().toString() } String bakPath(String outFilePath, String fileName) { List<String> names = fileName.split(".csv").toList() if (outFilePath.lastIndexOf("/") != -1) { return outFilePath.substring(0, outFilePath.lastIndexOf("/"))+ "bak/" } else if (outFilePath.lastIndexOf("\\") != -1) { return outFilePath.substring(0, outFilePath.lastIndexOf("\\"))+ "bak\\" } return outFilePath + "bak/" } }
相關jar: com.jcraft:jsch:0.1.55
下載調用方式:
1 Response downloadSftpFile(String fileName, String ftpPath, String outFilePath) { 2 Long startMill = new Date().getTime() 3 //連接sftp 4 try { 5 Map sftpApiMap = sftpApiSetting.sftpApiMap 6 7 //通過密碼 8 //SftpUtil.getSftpUtil(sftpApiMap.ftpUserName as String, sftpApiMap.ftpHost as String, sftpApiMap.ftpPort as int, sftpApiMap.ftpPassword as String).download(fileName, ftpPath, outFilePath) 9 //通過私鑰 10 SftpUtil.getSftpUtil(sftpApiMap.ftpUserName as String, sftpApiMap.ftpHost as String, sftpApiMap.ftpPort as int, sftpApiMap.ftpPassword as String, sftpApiMap.keyFilePath as String, sftpApiMap.passphrase as String).download(fileName, ftpPath, outFilePath) 11 } catch (Exception e) { 12 e.printStackTrace() 13 responseMessage = ResponseMessageFactory.error(null, outFilePath + fileName + "文件下載失敗\n" + e.message) 14 } 15 Long endMill = new Date().getTime() 16 logger.info("SFTP:download 完成時間" + (endMill - startMill) / 1000) 17 }
上傳調用:
Response uploadSftpFile(String fileName, String ftpPath, String outFilePath, String bakPath) { Long startMill = new Date().getTime() //連接sftp try { Map sftpApiMap = sftpApiSetting.sftpApiMap //通過密碼 //SftpUtil.getSftpUtil(sftpApiMap.ftpUserName as String, sftpApiMap.ftpHost as String, sftpApiMap.ftpPort as int, sftpApiMap.ftpPassword as String).uploadAllFile(fileName, ftpPath, outFilePath, bakPath) //通過私鑰 SftpUtil.getSftpUtil(sftpApiMap.ftpUserName as String, sftpApiMap.ftpHost as String, sftpApiMap.ftpPort as int, sftpApiMap.ftpPassword as String, sftpApiMap.keyFilePath as String, sftpApiMap.passphrase as String).uploadAllFile(fileName, ftpPath, outFilePath, bakPath) } catch (Exception e) { e.printStackTrace() responseMessage = ResponseMessageFactory.error(null, fileName + "文件上傳失敗\n" + e.message) } Long endMill = new Date().getTime() logger.info("SFTP:upload 完成時間" + (endMill - startMill) / 1000) }