最近做關於對賬文件的項目,就是約定第三方將對賬文件放至SFTP服務器上,然后我將加密后的SFTP文件拿到、解密、然后發送郵件給需要的人。
關於發送郵件在上一篇已經說過了不多贅述https://www.cnblogs.com/yangchengdebokeyuan/p/14812179.html
關於SFTP操作我自己總結的其實就是長時間對一個文件服務器進行操作,其中大致分為三個步驟 登錄服務器(建立連接)、操作文件及邏輯處理、登出(關閉連接)
其實我除了操作文件的邏輯以及服務器不同之外用的全是同事之前寫的SFTP工具類,所以此篇邏輯部分只能作為參考並不能直接引用。
一、建立鏈接&斷開鏈接
其實就是調用util類的方法就行了,因為項(zi)目(ji)急(lan)就沒做過多了解,有興趣的小伙伴可以了解下_(:з」∠)_

import com.jcraft.jsch.*; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import java.io.*; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class SftpUtils { @Value("${FTP-HOST}") private String sftpHost; @Value("${FTP-PORT}") private Integer sftpPort; @Value("${FTP-USERNAME}") private String username; @Value("${FTP-PASSWORD}") private String password; private ChannelSftp sftp; private Session session; private static Logger logger = LoggerFactory.getLogger(SftpUtils.class); protected final static int CLIENT_TIMEOUT = 1000 * 180; public SftpUtils(String username, String password, String sftpHost, int sftpPort) { this.username = username; this.password = password; this.sftpHost = sftpHost; this.sftpPort = sftpPort; } public SftpUtils() { } public void login() { try { JSch jsch = new JSch(); session = jsch.getSession(username, sftpHost, sftpPort); session.setTimeout(CLIENT_TIMEOUT); if (password != null) { session.setPassword(password); } Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; if (sftp != null) { logger.debug("SftpUtils-sftpHost:{},sftpPort:{},username:{},password:{},success", sftpHost, sftpPort, username, password); } else { logger.debug("SftpUtils-sftpHost:{},sftpPort:{},username:{},password:{},faild", sftpHost, sftpPort, username, password); } } catch (Exception e) { logout(); e.printStackTrace(); logger.debug("login" + e); } } /** * 關閉連接 server */ public void logout() { if (sftp != null) { if (sftp.isConnected()) { sftp.disconnect(); } } if (session != null) { if (session.isConnected()) { session.disconnect(); } } } /** * 將輸入流的數據上傳到sftp作為文件。文件完整路徑=basePath+directory * * @param directory 上傳到該目錄 * @param sftpFileName sftp端文件名 */ public boolean upload(String directory, String sftpFileName, InputStream input) { try { if (directory != null && !"".equals(directory)) { sftp.cd(directory); } sftp.put(input, sftpFileName); //上傳文件 return true; } catch (SftpException e) { e.printStackTrace(); return false; } } public InputStream readFile(String ftpPath) { InputStream inputStream = null; try { inputStream = sftp.get(ftpPath); } catch (Exception e) { e.printStackTrace(); logger.info("readFile error."); } return inputStream; } public static int compress(List<String> filePaths, String zipFilePath, Boolean keepDirStructure) throws IOException { byte[] buf = new byte[1024]; File zipFile = new File(zipFilePath); //zip文件不存在,則創建文件,用於壓縮 if (!zipFile.exists()) zipFile.createNewFile(); int fileCount = 0;//記錄壓縮了幾個文件? try { ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile)); for (int i = 0; i < filePaths.size(); i++) { String relativePath = filePaths.get(i); if (StringUtils.isEmpty(relativePath)) { continue; } File sourceFile = new File(relativePath);//絕對路徑找到file if (sourceFile == null || !sourceFile.exists()) { continue; } FileInputStream fis = new FileInputStream(sourceFile); if (keepDirStructure != null && keepDirStructure) { //保持目錄結構 zos.putNextEntry(new ZipEntry(relativePath)); } else { //直接放到壓縮包的根目錄 zos.putNextEntry(new ZipEntry(sourceFile.getName())); } //System.out.println("壓縮當前文件:"+sourceFile.getName()); int len; while ((len = fis.read(buf)) > 0) { zos.write(buf, 0, len); } zos.closeEntry(); fis.close(); fileCount++; } zos.close(); logger.debug("壓縮完成"); } catch (Exception e) { e.printStackTrace(); } return fileCount; } /** * 更換文件名 * [oldFileName, newfileName] * * @return boolean * * @date 2020/10/20 16:10 */ public boolean renameFile(String oldFileName, String newfileName) { boolean flag = false; if (sftp != null) { try { sftp.rename(oldFileName, newfileName); flag = true; } catch (Exception e) { logger.error("更換文件名--ERROR:" + e); flag = false; } } return flag; } /** * 讀取ftp目錄下全部文件夾 * [directory] * * @return java.util.Vector * * @date 2020/10/21 9:28 */ public Vector listFiles(String directory) throws SftpException { return sftp.ls(directory); } /** * 文件夾是否存在 * [directory] * * @return boolean * * @date 2020/10/21 16:47 */ public boolean isDirExist(String directory) { boolean isDirExistFlag = false; try { SftpATTRS sftpATTRS = sftp.lstat(directory); isDirExistFlag = true; return sftpATTRS.isDir(); } catch (Exception e) { if (e.getMessage().toLowerCase().equals("no such file")) { isDirExistFlag = false; } logger.debug("isDirExist:" + e); } return isDirExistFlag; } /** * 刪除文件 * [oldFileName, newfileName] * * @return boolean * * @date 2020/10/22 9:54 */ public boolean delete(String directory, String deleteFile) throws Exception { boolean flag = false; if (sftp != null) { try { sftp.cd(directory); sftp.rm(deleteFile); flag = true; } catch (Exception e) { logger.error("刪除文件夾--ERROR:" + e); flag = false; } } return flag; } /** * 創建該文件夾 * [createpath] * * @return void * * @date 2020/10/21 16:53 */ public void createDir(String createpath) { try { if (isDirExist(createpath)) { this.sftp.cd(createpath); return; } String pathArry[] = createpath.split("/"); StringBuffer filePath = new StringBuffer("/"); for (String path : pathArry) { if (path.equals("")) { continue; } filePath.append(path + "/"); if (isDirExist(filePath.toString())) { sftp.cd(filePath.toString()); } else { // 建立目錄 sftp.mkdir(filePath.toString()); // 進入並設置為當前目錄 sftp.cd(filePath.toString()); } } this.sftp.cd(createpath); } catch (SftpException e) { logger.error("創建路徑錯誤:" + createpath); } } public static void main(String[] args) { // SftpUtils sftp1 = new SftpUtils("sftptest", "xxxxx", "172.30.xx.xxx", 443); // sftp1.login(); // ChannelSftp sftp = new ChannelSftp(); // if (sftp != null) { // try { // sftp.rename("/home/sftptest/TEST/xxx094300.csv", "/home/sftptest/TEST/xxxx094300.csv"); // } catch (Exception e) { // logger.error("更換文件名--ERROR:" + e); // } // } } }
二、文件處理
1.文件操作及邏輯處理都會放出來但是解密部分就不放出來了,見諒~

package com.allianz.quartzjob.util; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /*** * * @author y.c * @date 2021-05-25 10:40:59 * */ public class TxtUtils { private static Logger logger = LoggerFactory.getLogger(TxtUtils.class); public static PsbcMerchantMain psbcUtils = new PsbcMerchantMain(); public static List showTxt(String path, String filename) { String filePath = path+"/"+filename; FileInputStream fileInputStream = null; InputStreamReader fie = null; BufferedReader by =null; List list = null; try { fileInputStream = new FileInputStream(filePath); fie = new InputStreamReader(fileInputStream,"UTF-8"); by = new BufferedReader(fie); String line = ""; list = new ArrayList(); while((line=by.readLine())!= null){ list.add(line); } fileInputStream.close(); fie.close(); by.close(); } catch (IOException e) { e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); }finally { if (null!=fileInputStream){ try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (null!=fie){ try { fie.close(); } catch (IOException e) { e.printStackTrace(); } } if (null!=by){ try { by.close(); } catch (IOException e) { e.printStackTrace(); } } } return list; } public static List showPSBCTxt(InputStream inputStream) { InputStreamReader fie = null; BufferedReader by =null; List list = null; try { fie = new InputStreamReader(inputStream,"UTF-8"); by = new BufferedReader(fie); String line = ""; list = new ArrayList(); int i = 0; while((line=by.readLine())!= null){ logger.error(line.toString()); //第一行為總條數不參與解密 if (i>0){ try { line = psbcUtils.PSBCdecrypt(line); } catch (Exception e) { logger.error("PSBC 解密失敗》》》 "+line); line = null; } } i++; list.add(line); } logger.error(">>>>>>>>解密結果:"+list.toString()); inputStream.close(); fie.close(); by.close(); } catch (IOException e) { e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); }finally { if (null != inputStream) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != fie) { try { fie.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != by) { try { by.close(); } catch (IOException e) { e.printStackTrace(); } } } return list; } public static void main(String[] args) { String path="D:\\Desktop\\"; String name="99360000007_EL_CHECK_ACCOUNT_0000000004_0000_20210522_A_0001_0001.txt"; List list = showTxt(path,name); List listNew = new ArrayList(); PsbcMerchantMain psbcUtils = new PsbcMerchantMain(); logger.error(">>>>>>>List:"+list); list.size(); int countList=0; String decStr =null; if (null!=list&&list.size()>0){ countList = Integer.valueOf(list.get(0).toString()); for (int i = 0; i <list.size() ; i++) { if (i==0){ listNew.add(String.valueOf(countList)); continue;//第一行不用解密 } String str = list.get(i).toString(); System.out.println(i+">>>>>>>> 解密 i:"+str); //解密 try { decStr = psbcUtils.PSBCdecrypt(str); } catch (Exception e) { logger.error("PSBC 解密失敗》》》 "+i); decStr = null; } System.out.println(">>>>>>>>解密結果:"+decStr); listNew.add(decStr); } } // System.out.println(showTxt(path,name)); logger.error(">>>>>>>listNew:"+listNew.toString()); boolean a =listNew.size()>0?writeDataHubData(listNew,"","對賬文件"):false; logger.error("生成結果:"+a); } public static boolean writeDataHubData(List<String> result,String path, String fileName) { long start = System.currentTimeMillis(); String filePath = null; filePath = "D:\\Desktop\\txt\\"; StringBuffer content = new StringBuffer(); boolean flag = false; BufferedWriter out = null; try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = sdf.format(new Date()); if (result != null && !result.isEmpty() && StringUtils.isNotEmpty(fileName)) { File pathFile = new File(filePath); if(!pathFile.exists()){ pathFile.mkdirs(); } String relFilePath = filePath + fileName; File file = new File(relFilePath); if (!file.exists()) { file.createNewFile(); } out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); for (String info : result) { out.write(info); out.newLine(); } flag = true; logger.info("寫入文件耗時:*********************************" + (System.currentTimeMillis() - start) + "毫秒"); } } catch (IOException e) { e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } return flag; } } /*** * 將list存入服務器 * @author y.c * @date 2021-05-25 18:31:04 * */ public static boolean saveTXT(List<String> result ,String path, String fileName) { long start = System.currentTimeMillis(); String filePath = path; StringBuffer content = new StringBuffer(); boolean flag = false; BufferedWriter out = null; try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = sdf.format(new Date()); if (result != null && !result.isEmpty() && StringUtils.isNotEmpty(fileName)) { fileName += "_" + dateStr + ".txt"; File pathFile = new File(filePath); if(!pathFile.exists()){ pathFile.mkdirs(); } String relFilePath = filePath + fileName; File file = new File(relFilePath); if (!file.exists()) { file.createNewFile(); } out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); for (String info : result) { out.write(info); out.newLine(); } flag = true; logger.info("寫入文件耗時:*********************************" + (System.currentTimeMillis() - start) + "毫秒"); } } catch (IOException e) { e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } return flag; } } public static String getDateFloderName() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = sdf.format(new Date()); Date date = sdf.parse(dateStr); if (date != null) { Calendar c = Calendar.getInstance(); c.setTime(date); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int dateNow = c.get(Calendar.DATE); String folderName = year + "/" + month + "/" + dateNow + "/"; return folderName; } else { return ""; } } public static String getPCDateFloderName() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = sdf.format(new Date()); Date date = sdf.parse(dateStr); if (date != null) { Calendar c = Calendar.getInstance(); c.setTime(date); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int dateNow = c.get(Calendar.DATE); String folderName = year + "\\" + month + "\\" + dateNow + "\\"; return folderName; } else { return ""; } } public static String getNowDate(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = sdf.format(new Date()); return dateStr; } }
2.業務邏輯

import com.allianz.quartzjob.entity.psbc.FtpEntity; import com.allianz.quartzjob.service.PSBCService; import com.allianz.quartzjob.util.MailUtil; import com.allianz.quartzjob.util.SftpUtils; import com.allianz.quartzjob.util.TxtUtils; import com.jcraft.jsch.ChannelSftp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.text.ParseException; import java.util.Iterator; import java.util.List; import java.util.Vector; public class ReadPsbcThread implements Runnable { private static Logger logger = LoggerFactory.getLogger(ReadPsbcThread.class); public static TxtUtils txtUtils = new TxtUtils(); private FtpEntity psbcFtp; private PSBCService psbcService; public ReadPsbcThread(FtpEntity psbcFtp,PSBCService psbcService) { this.psbcFtp=psbcFtp; this.psbcService=psbcService; } @Override public void run() { logger.info("ReadPsbcThread>>>>>>--start!"); String logMsg = "SFTP初始化失敗..."; String tmpPathName="/tmp"; SftpUtils sftp = null; try { //連接SFTP sftp = new SftpUtils( psbcFtp.getPSBC_FTP_USERNAME(), psbcFtp.getPSBC_FTP_PASSWORD(), psbcFtp.getPSBC_FTP_HOST(), psbcFtp.getPSBC_FTP_PORT()); logMsg = "SFTP登錄失敗..."; sftp.login(); //在文件服務器上檢索文件 String ftpUnReadPath =psbcFtp.getPSBC_FILE_UNREADFILE(); //讀取目錄路徑下全部文件 Vector vector = sftp.listFiles(ftpUnReadPath); if (vector.size() > 0) { Iterator iterator = vector.iterator(); while (iterator.hasNext()) { ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) iterator.next(); String UnReadFileNamePsbc = entry.getFilename(); logMsg = "SFTP未找到TXT文件..."+psbcFtp.getPSBC_FILE_UNREADFILE(); //判斷是否有txt文件 if (UnReadFileNamePsbc.contains(".txt")) { logger.info("Read---PSBC文件名:" + UnReadFileNamePsbc); logger.info("Read---PSBC文件名:" + ftpUnReadPath + UnReadFileNamePsbc); logMsg = "SFTP 讀取TXT文件失敗..."+ftpUnReadPath + UnReadFileNamePsbc; InputStream inputStream = sftp.readFile(ftpUnReadPath + UnReadFileNamePsbc); if (null != inputStream) { //獲取明文list//讀取內容並解密 List list = txtUtils.showPSBCTxt(inputStream); logger.error("SFTP 讀取TXT文件list..."+list.toString()); // 先將保存到本地 String localPath =psbcFtp.getPSBC_FILE_TMP(); //boolean saveStatus = txtUtils.saveTXT(list,localPath,readFileNamePsbc); boolean saveStatus = txtUtils.writeDataHubData(list,localPath,UnReadFileNamePsbc); logger.error("先將解密后文件保存到本地:"+saveStatus); if (!saveStatus){ logMsg = "SFTP 將解密后文件保存到本地失敗..."+saveStatus; continue; } logMsg= "SFTP 文件保存到本地成功保存!解密后的文件到SFTP服務器失敗..."+saveStatus; // 保存解密后的文件到SFTP服務器 String readFilePath=psbcFtp.getPSBC_FILE_READFILE(); try { readFilePath = readFilePath+txtUtils.getDateFloderName(); sftp.createDir(readFilePath); } catch (ParseException e) { logger.error("獲取路徑失敗..."+readFilePath); } FileInputStream fos = new FileInputStream(new File(localPath+UnReadFileNamePsbc)); saveStatus = sftp.upload(readFilePath, UnReadFileNamePsbc, fos); if (!saveStatus){ logMsg= "SFTP 文件保存到本地成功!保存解密后的文件到SFTP服務器失敗..."+saveStatus; continue; } logMsg= "SFTP 解密文件操作成功源文件移動失敗..."+saveStatus; // 再將源文件移動至已處理文件夾 String uploadFileUrl = ftpUnReadPath + txtUtils.getDateFloderName()+UnReadFileNamePsbc; sftp.createDir(ftpUnReadPath + txtUtils.getDateFloderName()); //移除讀取文件 saveStatus = sftp.renameFile(ftpUnReadPath + UnReadFileNamePsbc, uploadFileUrl); if (!saveStatus){ logMsg= "SFTP 解密文件操作成功源文件移動失敗..."+saveStatus; continue; } logMsg= "SFTP 文件操作成功發送郵件失敗..."+saveStatus; //文件操作成功發送郵件 String mailHost=psbcFtp.getPSBC_MAIL_HOST(); String senderUsername=psbcFtp.getPSBC_MAIL_SENDER(); MailUtil se = new MailUtil(false,mailHost,senderUsername); File affix = new File(localPath+UnReadFileNamePsbc); String subject="PSBC對賬文件-"+txtUtils.getNowDate(); String sendHtml="今日份對賬文件如附件,請查收~~~"; String receiveUser=psbcFtp.getPSBC_MAIL_RECIPIENT(); boolean status = se.doSendEmail(subject, sendHtml, receiveUser, affix);// logMsg= "SFTP 文件操作成功發送郵件成功..."+status; } } } } sftp.logout(); } catch (Exception e) { logger.error(logMsg); e.printStackTrace(); }finally { if (sftp != null){ sftp.logout(); } } logger.info("ReadPsbcThread>>>>>>" + tmpPathName + "--End!"+logMsg); } }
3.實體

import lombok.Data; @Data public class FtpEntity { private String PSBC_FTP_USERNAME;//ftp用戶名 private String PSBC_FTP_PASSWORD;//ftp密碼 private String PSBC_FTP_HOST;//ftp IP private int PSBC_FTP_PORT;//ftp 端口 private String PSBC_MAIL_HOST;//郵箱smtp服務器 private String PSBC_MAIL_AUTH; private String PSBC_MAIL_SENDER;//郵件發件人 private String PSBC_MAIL_RECIPIENT;//郵件收件人(多個用;隔開) private String PSBC_FILE_UNREADFILE;//解密前文件地址 private String PSBC_FILE_READFILE;//解密后文件地址 private String PSBC_FILE_TMP;//解密后文件臨時存放地址 }
僅供參考哈~~~