Java上传文件至SFTP服务器
Windows搭建SFTP服务器
https://www.cnblogs.com/wangjunguang/p/9453611.html
注意点:
1.以管理员权限运行FreeSSHd
2.如果无法启动,应该是后台服务已经启动,需要在服务里面关掉
写一个SFTPClient工具类
package com.koukay.Controller.Controllers.util;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class SFTPClient {
private final static Logger log = LoggerFactory.getLogger(SFTPClient.class);
@Value("${sftp.directory}")
private String ftpPath;
private volatile boolean isConfig = false;
private ChannelSftpPool channelSftpPool;
@Value("${sftp.host}")
private String host ;// 服务器ip地址
@Value("${sftp.username}")
private String username ; //账号
@Value("${sftp.password}")
private String password ;//密码
@Value("${sftp.port}")
private int port ;// 端口号
private final Cache
package com.koukay.Controller.Controllers.util; import com.jcraft.jsch.ChannelSftp; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class ChannelSftpPool extends Pool{ public ChannelSftpPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory factory) { super(poolConfig, factory); } }
package com.koukay.Controller.Controllers.util; import com.jcraft.jsch.ChannelSftp; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Slf4j public class ChannelSftpPoolConfig extends GenericObjectPoolConfig{ private final static Logger log = LoggerFactory.getLogger(ChannelSftpPoolConfig.class); public ChannelSftpPoolConfig() { int maxTotal = str2Int(SpringBeanUtils.getProperty("koukay.sftp.maxTotal"), 10); int maxWaitMillis = str2Int(SpringBeanUtils.getProperty("koukay.sftp.maxWaitMillis"), 10000); setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); setMaxWaitMillis(maxWaitMillis); setMaxTotal(maxTotal); } private int str2Int(String property, int defaultValue) { if (StringUtils.isNotBlank(property)) { try { return Integer.parseInt(property); } catch (NumberFormatException e) { log.error("property sftp.maxTotal is error,import_limit = {}", property); } } return defaultValue; } }
package com.koukay.Controller.Controllers.util; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import lombok.extern.slf4j.Slf4j; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Slf4j public class ChannelSftpPooledObjectFactory implements PooledObjectFactory{ private final static Logger log = LoggerFactory.getLogger(ChannelSftpPooledObjectFactory.class); private boolean publicKeyAuthentication; private String idRsaPath; private String ftpServer; private String ftpAccount; private String ftpPassword; private int ftpPort; public ChannelSftpPooledObjectFactory(boolean publicKeyAuthentication, String idRsaPath, String ftpServer, String ftpAccount, String ftpPassword, int ftpPort) { this.publicKeyAuthentication = publicKeyAuthentication; this.idRsaPath = idRsaPath; this.ftpServer = ftpServer; this.ftpAccount = ftpAccount; this.ftpPassword = ftpPassword; this.ftpPort = ftpPort; } @Override public PooledObject makeObject() throws Exception { JSch jsch = new JSch(); if (publicKeyAuthentication) { jsch.addIdentity(idRsaPath); } Session session = createSession(jsch, ftpServer, ftpAccount, ftpPort); session.setPassword(ftpPassword); session.setServerAliveInterval(60000); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); return new DefaultPooledObject ((ChannelSftp) channel); } @Override public void destroyObject(PooledObject p) throws Exception { log.info("destroyObject ChannelSftp!"); disconnect(p.getObject()); } @Override public boolean validateObject(PooledObject p) { return true; } @Override public void activateObject(PooledObject p) throws Exception { p.getObject().getSession().sendKeepAliveMsg(); } @Override public void passivateObject(PooledObject p) throws Exception { } /** * 创建session * * @param jsch * @param host * @param username * @param port * @return * @throws Exception */ private Session createSession(JSch jsch, String host, String username, Integer port) throws Exception { Session session; if (port <= 0) { session = jsch.getSession(username, host); } else { session = jsch.getSession(username, host, port); } if (session == null) { throw new Exception(host + " session is null"); } java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); return session; } /** * 关闭连接 * * @param sftp */ public void disconnect(ChannelSftp sftp) { try { if (sftp != null) { if (sftp.isConnected()) { sftp.disconnect(); } else if (sftp.isClosed()) { log.info("sftp is closed already"); } if (sftp.getSession() != null) { sftp.getSession().disconnect(); } } } catch (Exception e) { log.error("", e); } } }
package com.koukay.Controller.Controllers.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Closeable; import java.util.NoSuchElementException; @Slf4j public abstract class Poolimplements Closeable { private final static Logger log = LoggerFactory.getLogger(Pool.class); protected GenericObjectPool internalPool; /** * Using this constructor means you have to set and initialize the internalPool yourself. */ public Pool() { } public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory factory) { initPool(poolConfig, factory); } @Override public void close() { destroy(); } public boolean isClosed() { return this.internalPool.isClosed(); } public void initPool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory factory) { if (this.internalPool != null) { try { closeInternalPool(); } catch (Exception e) { log.error(e.getMessage(), e); } } this.internalPool = new GenericObjectPool (factory, poolConfig); } public T getResource() { try { return internalPool.borrowObject(); } catch (NoSuchElementException nse) { if (null == nse.getCause()) { // The exception was caused by an exhausted pool throw new IllegalStateException( "Could not get a resource since the pool is exhausted", nse); } // Otherwise, the exception was caused by the implemented activateObject() or ValidateObject() throw new IllegalStateException("Could not get a resource from the pool", nse); } catch (Exception e) { throw new IllegalStateException("Could not get a resource from the pool", e); } } protected void returnResourceObject(final T resource) { if (resource == null) { return; } try { internalPool.returnObject(resource); } catch (Exception e) { throw new IllegalStateException("Could not return the resource to the pool", e); } } protected void returnBrokenResource(final T resource) { if (resource != null) { returnBrokenResourceObject(resource); } } protected void returnResource(final T resource) { if (resource != null) { returnResourceObject(resource); } } public void destroy() { closeInternalPool(); } protected void returnBrokenResourceObject(final T resource) { try { internalPool.invalidateObject(resource); } catch (Exception e) { throw new IllegalStateException("Could not return the broken resource to the pool", e); } } protected void closeInternalPool() { try { internalPool.close(); } catch (Exception e) { throw new IllegalStateException("Could not destroy the pool", e); } } /** * Returns the number of instances currently borrowed from this pool. * * @return The number of instances currently borrowed from this pool, -1 if * the pool is inactive. */ public int getNumActive() { if (poolInactive()) { return -1; } return this.internalPool.getNumActive(); } /** * Returns the number of instances currently idle in this pool. * * @return The number of instances currently idle in this pool, -1 if the * pool is inactive. */ public int getNumIdle() { if (poolInactive()) { return -1; } return this.internalPool.getNumIdle(); } /** * Returns an estimate of the number of threads currently blocked waiting for * a resource from this pool. * * @return The number of threads waiting, -1 if the pool is inactive. */ public int getNumWaiters() { if (poolInactive()) { return -1; } return this.internalPool.getNumWaiters(); } /** * Returns the mean waiting time spent by threads to obtain a resource from * this pool. * * @return The mean waiting time, in milliseconds, -1 if the pool is * inactive. */ public long getMeanBorrowWaitTimeMillis() { if (poolInactive()) { return -1; } return this.internalPool.getMeanBorrowWaitTimeMillis(); } /** * Returns the maximum waiting time spent by threads to obtain a resource * from this pool. * * @return The maximum waiting time, in milliseconds, -1 if the pool is * inactive. */ public long getMaxBorrowWaitTimeMillis() { if (poolInactive()) { return -1; } return this.internalPool.getMaxBorrowWaitTimeMillis(); } private boolean poolInactive() { return this.internalPool == null || this.internalPool.isClosed(); } public void addObjects(int count) { try { for (int i = 0; i < count; i++) { this.internalPool.addObject(); } } catch (Exception e) { throw new IllegalStateException("Error trying to add idle objects", e); } } }
package com.koukay.Controller.Controllers.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringBeanUtils implements ApplicationContextAware { public static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public static String getProperty(String key) { if (applicationContext != null) { return applicationContext.getEnvironment().getProperty(key); } return null; } }
依赖如下
com.jcraft
jsch
0.1.54
org.projectlombok
lombok
1.18.4
com.github.ben-manes.caffeine
caffeine
2.8.5
上面的可以引入项目直接用,以下写个测试代码,
package util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; import java.util.Vector; import com.jcraft.jsch.*; /** * * @author patronli * */ public class FtpService { ChannelSftp sftp = null; Session sshSession =null; String host = "192.168.8.159";// 服务器ip地址 String username = "root"; String password = "123456"; int port = 22;// 端口号 /** * 连接sftp服务器 * * @param host * 主机 * @param port * 端口 * @param username * 用户名 * @param password * 密码 * @return */ public ChannelSftp connect(String host, int port, String username, String password) { System.out.println("开始连接sftp"); try { JSch jsch = new JSch(); jsch.getSession(username, host, port); sshSession = jsch.getSession(username, host, port); System.out.println("Session created."); sshSession.setPassword(password); Properties sshConfig = new Properties(); sshConfig.put("StrictHostKeyChecking", "no"); sshSession.setConfig(sshConfig); sshSession.connect(); System.out.println("Session connected."); System.out.println("Opening Channel."); Channel channel = sshSession.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; System.out.println("Connected to " + host + "."); System.out.println("连接sftp成功.."); } catch (Exception e) { System.out.println("连接失败"); e.printStackTrace(); } return sftp; } /** * 上传文件 * * @param directory * 上传的目录 * @param uploadFile * 要上传的文件 * @param sftp */ public void upload(String directory, String uploadFile, ChannelSftp sftp) { System.out.println("进入方法,开始读取文件"); try { sftp.cd(directory); File file = new File(uploadFile); System.out.println("开始上传报表文件" + file.getName()); sftp.put(new FileInputStream(file), file.getName()); System.out.println("上传报表文件" + file.getName() + "完毕"); System.out.println("上传报表文件成功"); } catch (Exception e) { System.out.println("上传报表文件失败"); e.printStackTrace(); } } /** * 下载文件 * * @param directory * 下载目录 * @param sftp * 下载的文件 * @param path * 存在本地的路径 */ public void download(String directory, String downloadFile, ChannelSftp sftp, String path) {// sftp路径,链接,保存的路径+文件名 try { sftp.cd(directory); File file = new File(path); sftp.get(downloadFile, new FileOutputStream(file)); System.out.println("下载成功:" + path); } catch (Exception e) { System.out.println("下载文件出现异常:::"); e.printStackTrace(); } } /** * 删除文件 * * @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) { e.printStackTrace(); } } /** * 列出目录下的文件 * * @param directory * 要列出的目录 * @param sftp * @return * @throws SftpException */ public Vector listFiles(String directory, ChannelSftp sftp) throws SftpException { return sftp.ls(directory); } public void deal(int judge) { String directory = ""; //改成自己要上传的文件名 String fileName = "msdia80.dll"; String localUrl = "D:\\";// 文件下载到本地的地址,虚拟机上的格式/home/fy_flg/reportFile/ String path = localUrl + fileName;// 路径+文件名 ChannelSftp sftp = connect(host, port, username, password); try { if (judge == 1) {// 表示上传 directory = "/upload/";// sftp操作文件的目录 upload(directory, path, sftp);// 上传--sftp目录,要上传文件的地址 }else if (judge == 2){ //下载 directory = "/upload/";// sftp操作文件的目录 path="C:\\Users\\lx\\Desktop\\"+fileName; fileName=directory+fileName; download(directory,fileName, sftp,path);// 下载文件--sftp目录,要下载的文件名字,下载到的地方, }else if (judge == 3){ directory = "/upload/";// sftp操作文件的目录 delete(directory, fileName, sftp);// 删除--sftp目录,要上传文件的地址 } else if (judge == 4){ directory = "/upload/"; try { Vector vector = listFiles(directory, sftp); for (Object o : vector) { System.out.println(o.toString()); } } catch (SftpException e) { e.printStackTrace(); } } }finally { disconnect(); } } /** * 关闭连接 */ public void disconnect() { if (this.sftp != null) { if (this.sftp.isConnected()) { this.sftp.disconnect(); this.sftp = null; System.out.println("sftp 连接已关闭!"); } } if (this.sshSession != null) { if (this.sshSession.isConnected()) { this.sshSession.disconnect(); this.sshSession = null; System.out.println("sshSession 连接已关闭!"); } } } public static void main(String[] args) { FtpService sf = new FtpService(); sf.deal(4); } }