1.前言
之前使用的是apache.commons.net.ftp.FTP的链接方式.今天在linux上面重新部署FTP之后.上传文件时
org.apache.commons.net.MalformedServerReplyException: Could not parse response code.
Server Reply: SSH-2.0-OpenSSH_8.0
2.解决
1. 办法:使用com.jcraft.jsch.JSch提供的SSH
2.步骤
<dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.54</version> </dependency>
3.链接相关代码块
- 配置基本信息,我这边使用的yml文件引入的方式
@Value("${ftp.ftpIp}")
private String ftpIp;//IP
@Value("${ftp.ftpBasepath}")
private String ftpBasepath;//文件路径
@Value("${ftp.imageBaseUrl}")
private String imageBaseUrl;//下载地址
@Value("${ftp.ftpPort}")
private Integer ftpPort;//端口
@Value("${ftp.ftpUsername}")
private String ftpUsername; //FTP帐号
@Value("${ftp.ftpPassword}")
private String ftpPassword;//FTP密码
- 链接服务器代码
/**
* 连接服务器
*/
public Map<String, Object> getConnect() throws Exception {
Session session = null;
Channel channel = null;
ChannelSftp sftp = null;// sftp操作类
JSch jsch = new JSch();//创建客户端
session = jsch.getSession(ftpUsername, ftpPort + "", ftpPort);//连接属性
session.setPassword(ftpPassword);//输入密码
//设置
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no"); // 不验证 HostKey
//激活设置
session.setConfig(config);
//登录
try {
session.connect();
} catch (Exception e) {
if (session.isConnected())
session.disconnect();
logger.error("连接服务器失败,请检查主机[" + ftpIp + "],端口[" + ftpPort
+ "],用户名[" + ftpUsername + "],端口[" + ftpPort
+ "]是否正确,以上信息正确的情况下请检查网络连接是否正常或者请求被防火墙拒绝.");
}
channel = session.openChannel("sftp");
//打开通道
try {
channel.connect();
} catch (Exception e) {
if (channel.isConnected())
channel.disconnect();
logger.error("连接服务器失败,请检查主机[" + ftpIp + "],端口[" + ftpPort
+ "],用户名[" + ftpUsername + "],密码是否正确,以上信息正确的情况下请检查网络连接是否正常或者请求被防火墙拒绝.");
}
//保存属性
sftp = (ChannelSftp) channel;
HashMap<String, Object> map = new HashMap<>();
map.put("channel", channel);
map.put("session", session);
map.put("sftp", sftp);
return map;
}
- 断开连接
/**
* 断开连接
*/
public static void disConn(HashMap<String, Object> map) throws Exception {
Session session = (Session) map.get("session");
Channel channel = (Channel) map.get("channel ");
ChannelSftp sftp = (ChannelSftp) map.get("sftp");
if (null != sftp) {
sftp.disconnect();
sftp.exit();
}
if (null != channel) {
channel.disconnect();
}
if (null != session) {
session.disconnect();
}
}
4.文件操作相关代码
- 上传文件
/**
* 上传文件
*
* @param directory 上传的目录-相对于SFPT设置的用户访问目录,
* 为空则在SFTP设置的根目录进行创建文件(除设置了服务器全磁盘访问)
* @param uploadFile 要上传的文件全路径
*/
public void upload(String directory, String uploadFile) throws Exception {
JschUtils jschUtils = new JschUtils();
//建立连接
Map<String, Object> map = jschUtils.getConnect();
Session session = (Session) map.get("session");
Channel channel = (Channel) map.get("channel ");
ChannelSftp sftp = (ChannelSftp) map.get("sftp");
try {
try {
sftp.cd(directory); //进入目录
} catch (SftpException sException) {
if (sftp.SSH_FX_NO_SUCH_FILE == sException.id) { //指定上传路径不存在
sftp.mkdir(directory);//创建目录
sftp.cd(directory); //进入目录
}
}
File file = new File(uploadFile);
InputStream in = new FileInputStream(file);
sftp.put(in, file.getName());
in.close(); } catch (Exception e) {
throw new Exception(e.getMessage(),e);
} finally {
disConn(map);
}
}
- 下载文件
/**
* 下载文件
* @param directory 下载目录 根据SFTP设置的根目录来进行传入
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
*/
public static void download(String directory, String downloadFile,String saveFile) throws Exception {
JschUtils jschUtils = new JschUtils();
//建立连接
Map<String, Object> map = jschUtils.getConnect();
ChannelSftp sftp = (ChannelSftp) map.get("sftp");
try {
sftp.cd(directory); //进入目录
File file = new File(saveFile);
boolean bFile;
bFile = false;
bFile = file.exists();
if (!bFile) {
bFile = file.mkdirs();//创建目录
}
OutputStream out=new FileOutputStream(new File(saveFile,downloadFile));
sftp.get(downloadFile, out);
out.flush();
out.close();
} catch (Exception e) {
throw new Exception(e.getMessage(),e);
} finally {
disConn(map);
}
}
6.其他
这种方式是不支持创建多层目录的,需要一层一层去判断
if (sftp.SSH_FX_NO_SUCH_FILE == sException.id) { //指定上传路径不存在
//创建多层目录及判断
String filedirurl = ftpBasepath + filePath;
String[] dirs = filedirurl.split("/");
String tempPath = "";//虚拟层
for (String dir : dirs) {
if (null == dir || "".equals(dir)) {
continue;
} else {
tempPath += "/" + dir;
try {
logger.info("检测目录[" + tempPath + "]");
sftp.cd(tempPath);
} catch (SftpException ex) {
try {
logger.error("创建目录[" + tempPath + "]");
sftp.mkdir(tempPath);
sftp.cd(tempPath);
logger.error("进入目录[" + tempPath + "]");
} catch (SftpException e1) {
logger.error("创建目录[" + tempPath
+ "]失败1,异常信息[" + e1.getMessage() + "]");
} catch (Exception e1) {
logger.error("创建目录[" + tempPath
+ "]失败2,异常信息[" + e1.getMessage() + "]");
}
} catch (Exception e1) {
logger.error("创建目录[" + tempPath + "]失败3,异常信息["
+ e1.getMessage() + "]");
}
}
}
sftp.cd(ftpBasepath + filePath); //进入目录
}