目录
一、配置SFTP服务器
在yml文件或者properties文件中添加sftp服务器配置信息,包含文件服务器的ip地址,用户名和密码等信息。
sftp.oa.hostname =
sftp.oa.port = 22
sftp.oa.username =
sftp.oa.password =
sftp.oa.timeout = 1000
二、SFTP工具类
1. sftp配置类
package com.hand.hcf.app.expense.sftp;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
/**
* @ClassName: SftpConfig
* @Description: sftp配置类
* @Author:
* @CreateDate: 2019/9/18
* @Version: 1.0
*/
@Configuration
@Data
public class SftpConfig {
@Value("${sftp.oa.hostname}")
private String hostname;
@Value("${sftp.oa.port}")
private Integer port;
@Value("${sftp.oa.username}")
private String username;
@Value("${sftp.oa.password}")
private String password;
@Value("${sftp.oa.timeout}")
private Integer timeout;
private Resource privateKey;
private String remoteRootPath;
private String fileSuffix;
}
2.工具类
package com.hand.hcf.app.expense.sftp;
import com.hand.hcf.core.exception.BizException;
import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
public class SFTP {
private long count;
/**
* 已经连接次数
*/
private long count1 = 0;
private long sleepTime;
private static final Logger logger = LoggerFactory.getLogger(SFTP.class);
/**
* 连接sftp服务器
*
* @return
*/
public ChannelSftp connect(SftpConfig sftpConfig) {
ChannelSftp sftp = null;
try {
JSch jsch = new JSch();
jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHostname(), sftpConfig.getPort());
Session sshSession = jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHostname(), sftpConfig.getPort());
logger.info("Session created ... UserName=" + sftpConfig.getUsername() + ";host=" + sftpConfig.getHostname() + ";port=" + sftpConfig.getPort());
sshSession.setPassword(sftpConfig.getPassword());
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.setTimeout(sftpConfig.getTimeout());
sshSession.connect();
logger.info("Session connected ...");
logger.info("Opening Channel ...");
Channel channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
logger.info("登录成功");
} catch (Exception e) {
try {
count1 += 1;
if (count == count1) {
throw new RuntimeException(e);
}
Thread.sleep(sleepTime);
logger.info("重新连接....");
connect(sftpConfig);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
}
return sftp;
}
/**
* 上传文件
*
* @param directory 上传的目录
* @param uploadFile 要上传的文件
* @param sftpConfig
*/
public void upload(String directory, String uploadFile, SftpConfig sftpConfig) {
ChannelSftp sftp = connect(sftpConfig);
try {
sftp.cd(directory);
} catch (SftpException e) {
try {
sftp.mkdir(directory);
sftp.cd(directory);
} catch (SftpException e1) {
throw new RuntimeException("ftp创建文件路径失败" + directory);
}
}
File file = new File(uploadFile);
InputStream inputStream=null;
try {
inputStream = new FileInputStream(file);
sftp.put(inputStream, file.getName());
} catch (Exception e) {
throw new RuntimeException("sftp异常" + e);
} finally {
disConnect(sftp);
closeStream(inputStream,null);
}
}
/**
* 下载文件
*
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
* @param sftpConfig
*/
public void download(String directory, String downloadFile, String saveFile, SftpConfig sftpConfig) {
OutputStream output = null;
try {
File localDirFile = new File(saveFile);
// 判断本地目录是否存在,不存在需要新建各级目录
if (!localDirFile.exists()) {
localDirFile.mkdirs();
}
if (logger.isInfoEnabled()) {
logger.info("开始获取远程文件:[{}]---->[{}]", new Object[]{directory, saveFile});
}
ChannelSftp sftp = connect(sftpConfig);
sftp.cd(directory);
if (logger.isInfoEnabled()) {
logger.info("打开远程文件:[{}]", new Object[]{directory});
}
output = new FileOutputStream(new File(saveFile.concat(File.separator).concat(downloadFile)));
sftp.get(downloadFile, output);
if (logger.isInfoEnabled()) {
logger.info("文件下载成功");
}
disConnect(sftp);
} catch (Exception e) {
if (logger.isInfoEnabled()) {
logger.info("文件下载出现异常,[{}]", e);
}
throw new RuntimeException("文件下载出现异常,[{}]", e);
} finally {
closeStream(null,output);
}
}
public void writeFileToRes(HttpServletResponse response, SftpConfig sftpConfig,String path) {
InputStream inputStream = null;
ServletOutputStream outputStream=null;
try {
ChannelSftp sftp = connect(sftpConfig);
sftp.cd("\\EFT");
sftp.cd("\\BANKSLIPS");
sftp.cd("\\PDF");
inputStream = sftp.get(path);
byte[] buf = new byte[1024 * 10];
outputStream = response.getOutputStream();
// response.setHeader("content-type", "application/octet-stream");
// response.setContentType("application/octet-stream");
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(path, "UTF-8"));
int readLength;
while (((readLength = inputStream.read(buf)) != -1)) {
outputStream.write(buf, 0, readLength);
}
outputStream.flush();
} catch (SftpException e) {
throw new BizException("sftp exception","sftp exception " + e.getMessage());
} catch (IOException e) {
throw new BizException("io exception","io exception " + e.getMessage());
}finally {
closeStream(null,outputStream);
try {
if(inputStream!=null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 下载远程文件夹下的所有文件
*
* @param remoteFilePath
* @param localDirPath
* @throws Exception
*/
public void getFileDir(String remoteFilePath, String localDirPath, SftpConfig sftpConfig) throws Exception {
File localDirFile = new File(localDirPath);
// 判断本地目录是否存在,不存在需要新建各级目录
if (!localDirFile.exists()) {
localDirFile.mkdirs();
}
if (logger.isInfoEnabled()) {
logger.info("sftp文件服务器文件夹[{}],下载到本地目录[{}]", new Object[]{remoteFilePath, localDirFile});
}
ChannelSftp channelSftp = connect(sftpConfig);
Vector<LsEntry> lsEntries = channelSftp.ls(remoteFilePath);
if (logger.isInfoEnabled()) {
logger.info("远程目录下的文件为[{}]", lsEntries);
}
for (LsEntry entry : lsEntries) {
String fileName = entry.getFilename();
if (checkFileName(fileName)) {
continue;
}
String remoteFileName = getRemoteFilePath(remoteFilePath, fileName);
channelSftp.get(remoteFileName, localDirPath);
}
disConnect(channelSftp);
}
/**
* 关闭流
* @param outputStream
*/
private void closeStream(InputStream inputStream,OutputStream outputStream) {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private boolean checkFileName(String fileName) {
if (".".equals(fileName) || "..".equals(fileName)) {
return true;
}
return false;
}
private String getRemoteFilePath(String remoteFilePath, String fileName) {
if (remoteFilePath.endsWith("/")) {
return remoteFilePath.concat(fileName);
} else {
return remoteFilePath.concat("/").concat(fileName);
}
}
/**
* 删除文件
*
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
* @param sftp
*/
public void delete(String directory, String deleteFile, ChannelSftp sftp) {
try {
sftp.cd(directory);
sftp.rm(deleteFile);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 列出目录下的文件
*
* @param directory 要列出的目录
* @param sftpConfig
* @return
* @throws SftpException
*/
public List<String> listFiles(String directory, SftpConfig sftpConfig) throws SftpException {
ChannelSftp sftp = connect(sftpConfig);
List fileNameList = new ArrayList();
try {
sftp.cd(directory);
} catch (SftpException e) {
return fileNameList;
}
Vector vector = sftp.ls(directory);
for (int i = 0; i < vector.size(); i++) {
if (vector.get(i) instanceof LsEntry) {
LsEntry lsEntry = (LsEntry) vector.get(i);
String fileName = lsEntry.getFilename();
if (".".equals(fileName) || "..".equals(fileName)) {
continue;
}
fileNameList.add(fileName);
}
}
disConnect(sftp);
return fileNameList;
}
/**
* 断掉连接
*/
public void disConnect(ChannelSftp sftp) {
try {
sftp.disconnect();
sftp.getSession().disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public SFTP(long count, long sleepTime) {
this.count = count;
this.sleepTime = sleepTime;
}
public SFTP() {
}
}
三、具体实现案例
1.调用打印接口,将文件生成到本地。
2.将文件路径和文件名设置到文件服务器。
3. 结合webservice发送带附件的邮件。
public Boolean sendEmail(ExpenseReportHeader header) {
ApprovalErrorDataCO co=new ApprovalErrorDataCO();
co.setDocumentId(header.getId());
co.setDocumentNumber(header.getRequisitionNumber());
co.setDocumentOid(header.getDocumentOid());
co.setApplicationName("fec-expense");
co.setDocumentOperation("上传附件发送邮件");
/**
* 1.调用打印接口
* 2.将文件路径和文件名上传到文件服务器
* 3.跟随附件一起发送邮件
*/
String content = organizationService.getParameterValue(null, OrgInformationUtil.getCurrentSetOfBookId(), "COLLECT");
if (content != null) {
content = content.replace("AMOUNT", String.valueOf(header.getTotalAmount())).replace("SHEET", header.getRequisitionNumber());
}
//1.调用打印接口,获取pdf文件
StringBuffer strLog=new StringBuffer();
ResponseEntity<byte[]> res=null;
try {
res= printInfoService.getPrintInfo(header.getId(),null);
}catch (Exception e){
// throw new BizException("文件打印失败!"+e.getMessage());
strLog.append("文件打印出错!"+e.getMessage());
}
//pdf文件名
String pdf_name=ExpenseReportPrintInfoService.pdf_name;
SFTP ftp = new SFTP(5, 1000);
//将文件流转为文件
synchronized (this){
if (pdf_name.contains("\\")){
pdf_name= pdf_name.substring(pdf_name.indexOf('\\')+1);
}
File file=null;
try {
file=byteToFile(res.getBody(),"",pdf_name);
}catch (Exception e){
strLog.append("生成文件出错:"+e.getMessage());
}
try {
//2.使用sftp协议将文件上传至服务器的指定路径
ftp.upload("/MAIL",file.getPath(),sftpConfig);
}catch (Exception e){
strLog.append("上传出错:"+e.getMessage());
}
//3.跟随附件一起发送邮件
//发送邮件,收单生成打印文件标志;
String subject="财务收单打印";
try{
if (!strLog.toString().contains("出错")){
WorkFlowDocumentRefCO workFlowDocumentRefCO=workflowClient.getDocumentRefByDoucmentNumber(header.getRequisitionNumber());
String email= contactClient.getByUserOid(workFlowDocumentRefCO.getSubmittedBy().toString()).getEmail();
fecPeripheralInterface.sendMail(subject,content,email,"",pdf_name,header.getRequisitionNumber());
}
} catch (Exception e) {
strLog.append(e.getMessage());
}finally {
if (file!=null){
file.delete();
}
if (strLog.toString().contains("出错")){
co.setErrorMsg(strLog.toString());
workflowInterface.createApprovalErrorData(co);
}
}
}
return true;
}
需要将需要发送邮件的附件路径同时也写到邮件表中,然后使用webservice读取的时候根据路径来读到附件服务器上的附件即可。
四、删除SFTP服务器上的文件
通过调用上面封装好的ftp.delete()方法,删除服务器上的文件。
@Test
public void testConnect(){
SFTP ftp = new SFTP(5, 1000);
ChannelSftp channelSftp=null;
try {
//2.使用sftp协议将文件上传至服务器的指定路径
channelSftp = ftp.connect(sftpConfig);
//然后判断文件是否存在,如果存在先删除,再上传
Vector vector = channelSftp.ls("/MAIL");
for (int i = 0; i < vector.size(); i++) {
if (vector.get(i) instanceof ChannelSftp.LsEntry) {
ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) vector.get(i);
String fileName = lsEntry.getFilename();
if ("test.png".equals(fileName)) {
ftp.delete("/MAIL","test.png",channelSftp);
break;
}
}
}
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}finally {
if (ftp!=null){
ftp.disConnect(channelSftp);
}
if (channelSftp!=null){
channelSftp.disconnect();
}
}
}