2024.1.17 晚 小雨
前言:我们可以慢慢向前走,但绝对不能后退
最近有这样一个需求,在某台服务器上有个文件,文件路径为:/ftppub/xx/年月日/xxx.txt
,这个文件每天都会更新,文件路径的日期目录也会随之更改。文件内容为:xx|xx|xx
??有 n 行这样的数据,每一列代表某个字段的值。我需要校验当前某个字段(文件的每一行的第三个字段)的值在该文件中是否存在。
1、引入依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
2、上代码
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
/**
* sftp工具类
*
* @author mltang
* @since JDK8
*/
@Slf4j
public class SftpUtil {
private static ChannelSftp sftp = null;
private static Session session = null;
/**
* 连接sftp服务器
*
* @param privateKey
* @return
*/
public static ChannelSftp sftpConnect(String host, int port, String username, String password, String privateKey) throws SftpException {
try {
JSch jsch = new JSch();
if (!StringUtils.isEmpty(privateKey)) {
jsch.addIdentity(privateKey);// 设置私钥
}
//用户名,主机,端口号
session = jsch.getSession(username, host, port);
//密码
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
// 设置timeout时间
session.setTimeout(30000);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
} catch (Exception e) {
log.error("连接sftp失败", e);
log.error("ip{},port{}", host, port);
throw new SftpException(500, "连接sftp失败", e);
}
return sftp;
}
/**
* ftp读取文件内容并做业务逻辑处理
* @param ftpPath 文件路径
* @param fileName 文件名
* @param taskDate 文件日期
* @param targetUserId 字段用户编号
* @return
* @throws SftpException
* @throws IOException
*/
public static boolean getFtpData(String ftpPath, String fileName, String taskDate, String targetUserId) throws SftpException, IOException {
BufferedReader br = null;
//连接ftp
if (null == sftp) {
return false;
}
String dateStr = StringUtils.isEmpty(taskDate) ? taskDate.replaceAll("-", "") : getYesterday();
String directory = "/" + dateStr + "/";
try {
//下载文件
sftp.cd(ftpPath + directory);
br = new BufferedReader(new InputStreamReader(sftp.get(fileName), StandardCharsets.UTF_8));
String line;
while ((line = br.readLine()) != null) {
String[] cells = line.split("\\|");
if(!StringUtils.isEmpty(cells)){
return cells[2].equals(targetUserId);
}
}
} catch (Exception e) {
log.error(fileName + "文件读取异常{}", Arrays.toString(e.getStackTrace()));
} finally {
assert br != null;
br.close();
closeChannel();
}
return false;
}
/**
* 关闭ftp连接
*/
public static void closeChannel() {
if (sftp != null) {
sftp.disconnect();
}
if (session != null) {
if (session.isConnected()) {
session.disconnect();
}
}
}
/**
* 获取当前日期的前一天日期
* @return
*/
public static String getYesterday() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, -24);
String yesterdayDate = dateFormat.format(calendar.getTime());
System.out.println(yesterdayDate);
return yesterdayDate;
}
}
3、了解一下 privateKey
密钥登录无需用户设置密码,通过rsa密钥对加解密验证,在客户端和服务器端建立安全的连接,简单地说,public key
放在服务器端,private key
放在客户端。
客户端发起请求连接
服务器根据请求用户名识别对应客户端公钥,sshd 服务产生一个随机数,用?public key
进行加密后,发回到客户端
客户端用?private key
解密得到该随机数,客户端将解密后的随机数发回服务器端,
服务端进行匹配,匹配成功认证通过,允许登录。
这种方式避免了密码暴力破解尝试的危险,当然密钥认证因为有加解密和随机数传输验证的过程,连接耗时自然比密码方式长些。