情景假设:我们有一个学生信息数据,需要从SFTP解析入库,但是因为隔离装置的问题无法直接读取,需要转移到OSS平台(OSS与SFTP可以互相访问)再解析入库。
目录
一、思路
1、首先明确思路。如下图所示:
学生类:
@Data
public class Students {
private String name;
private String age;
private String score;
}
二、获取SFTP文件
1、SFTP配置
我们要明确sftp服务器主机IP地址、端口、账号、密码等信息,通过读取配置文件获取SFTP的配置信息并创建SFTP通道:
@Value("${ftp.hosts}")
private String hosts; //sftp地址
@Value("${ftp.port}")
private String port; //sftp端口
@Value("${ftp.username}")
private String username; //sftp用户名
@Value("${ftp.password}")
private String password; //sftp密码
@Value("${ftp.filePath}")
private String filePath; //stfp文件保存位置
定义全局静态变量,并通过以上信息创建sftp通道,实现文件的上传、下载
private static Session session = null; //用于保存登录时的session信息
private static ChannelSftp channel = null; //保存ChannelSftp 的通道
/**
* 创建一个sftp通道
*/
public static ChannelSftp getSftp(String hosts, String port, String username, String password){
JSch jSch = new JSch();
//根据主机IP、端口、用户名创建一个session对象
try {
session = jSch.getSession(username, hosts, Integer.parseInt(port));
log.info("获取Session成功");
if (StringUtils.isNoneBlank(password)) {
session.setPassword(password);
}
Properties properties = new Properties();
properties.put("StrictHostKeyChecking", "no");
session.setConfig(properties); //为session对象设置properties
session.setTimeout(2000); //设置session过期时间
session.connect();
log.info("开始成功");
channel = (ChannelSftp) session.openChannel("sftp"); //打开sftp通道
channel.connect();
log.info("成功连接sftp服务器!!!");
} catch (JSchException e) {
e.printStackTrace();
log.error(("获取Session失败,请检查用户名、主机IP、端口号"));
}
return channel;
}
当不需要sftp通道时需要关闭channel和session,避免资源浪费
/**
* 关闭channel和session
*/
public static void shutDownChannel(){
if (channel != null){
channel.disconnect();
}
if (session != null){
session.disconnect();
}
}
2、SFTP文件上传
/**
* SFTP文件上传
*
* @param uploadFile 需要上传的文件
*/
public boolean UploadToSftp(File uploadFile) {
//定义返回值
boolean flag = true;
//获取channelSftp对象
ChannelSftp channelSftp = SftpChannel.getSftp(hosts, port, username, password);
//判断文件路径是否存在
try {
Vector dir = channelSftp.ls(filePath);
//文件夹不存在则创建这个文件夹
if (dir.isEmpty()) {
channelSftp.mkdir(filePath);
}
String destFilePath = filePath + uploadFile.getName();
//文件上传
try {
channelSftp.put(new FileInputStream(uploadFile), destFilePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
flag = false;
log.error("文件上传异常");
}
} catch (SftpException e) {
e.printStackTrace();
flag= false;
log.error("文件路径异常");
} finally {
if (channelSftp != null) {
channelSftp.quit();
}
try {
SftpChannel.shutDownChannel();
} catch (Exception e) {
e.printStackTrace();
log.error("channel或session关闭失败");
}
}
return flag;
}
3、获取下载文件输入流
public Map<String,Object> downSftpFile(ChannelSftp sftp){
Map<String,Object> resultMap = new HashMap<>();
InputStream inputStream = null;
try {
if (StringUtils.isNoneBlank(filePath)) {
sftp.cd(filePath);//进入所在路径
}
Vector vector = sftp.ls("./");
for (Object o : vector) {
ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) o;
//文件名称
String fileName = file.getFilename();
if (StringUtils.isNoneBlank(fileName) && !fileName.startsWith(".")) {
inputStream = sftp.get(fileName);
}
resultMap.put("filename",fileName);
resultMap.put("inputStream",inputStream);
}
} catch (SftpException e) {
e.printStackTrace();
resultMap.put("error","error");
log.error("下载失败:" +e);
}finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
log.error("下载输入流关闭失败:" + e);
}
}
}
return resultMap;
}
三、OSS上传
1、OSS配置
我们要明确OSS的配置信息信息,通过读取配置文件获取OSS的配置信息:
@Value("${oss.endpoint}")
private String endpoint; //oss域名
@Value("${oss.accessKey}")
private String accessKey; //oss 资源管理器账号
@Value("${oss.accessSecret}")
private String accessSecret; //oss 资源管理密码
@Value("${oss.bucketName}")
private String bucketName; //oss bucketName
@Value("${oss.filePath}")
private String filePath; //oss文件保存位置
2、OSS文件上传
/**
* 文件上传
* @param filename 上传文件名
* @param inputStream 上传文件输入流
* @return
*/
public Map<String, String> uploadfile(String filename, InputStream inputStream) {
Map<String, String> mapresult = new HashMap<>();
Date date = new Date();
String path = bucketName + "自定义文件路径";
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// 私有云要关闭CNAME
conf.setSupportCname(false);
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, accessSecret, conf);
if (ossClient != null && ossClient.doesBucketExist(bucketName)) {
log.info("****************cunzai****************");
} else {
log.info("****************bu cunzai****************");
}
try {
if (ossClient != null) {
ossClient.putObject(bucketName, path + "/" + filename, inputStream);
log.info("上传成功");
ossClient.shutdown();
}
} catch (Exception e) {
log.info("上传失败");
mapresult.put("msg", "操作失败");
log.error(String.valueOf(e));
} finally {
if (null != ossClient) {
ossClient.shutdown();
}
}
return mapresult;
}
3、SFTP文件上传到OSS
此时我们可以实现SFTP文件上传到OSS。
InputStream inputStream = null;
SftpChannel sftpChannel = new SftpChannel();
OssUtils ossUtils = new OssUtils();
ChannelSftp sftp = SftpChannel.getSftp(hosts, port, username, password);
Map<String, Object> map = sftpChannel.downSftpFile(sftp);
String error = (String) map.get("error");
if (StringUtils.isNotEmpty(error) && error.equals("error")) {
return;
}
try {
String filename = (String) map.get("filename");
inputStream = (InputStream) map.get("inputStream");
if (StringUtils.isNotEmpty(filename) && ObjectUtil.isNotEmpty(inputStream)){
try {
ossUtils.uploadfile(filename,inputStream);
} catch (Exception e) {
log.error("OSS文件上传失败");
}
}
} catch (Exception e) {
log.error("SFTP文件读取失败");
}finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、OSS文件下载读取
public List<String> downloadFilestream(String filename) {
List<String> list = new ArrayList<>();
String path = "文件夹路径";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = path + "/" + filename;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, accessSecret);
try {
// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
while (true) {
String line = reader.readLine();
if (line == null) break;
else list.add(line);
}
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
reader.close();
// ossObject对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
ossObject.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return list;
}
5、文件解析入库
这样我们就可以补齐“SFTP文件上传到OSS”代码,实现文件解析入库
InputStream inputStream = null;
SftpChannel sftpChannel = new SftpChannel();
Students students = new Students();
OssUtils ossUtils = new OssUtils();
ChannelSftp sftp = SftpChannel.getSftp(hosts, port, username, password);
Map<String, Object> map = sftpChannel.downSftpFile(sftp);
String error = (String) map.get("error");
if (StringUtils.isNotEmpty(error) && error.equals("error")) {
return;
}
try {
String filename = (String) map.get("filename");
inputStream = (InputStream) map.get("inputStream");
if (StringUtils.isNotEmpty(filename) && ObjectUtil.isNotEmpty(inputStream)){
try {
ossUtils.uploadfile(filename,inputStream);
List<String> list = ossUtils.downloadFilestream(filename);
for (String str : list) {
String[] split = str.split("\\t");
students.setName(split[0]);
students.setAge(split[1]);
students.setScore(split[2]);
}
} catch (Exception e) {
log.error("OSS文件上传失败");
}
}
} catch (Exception e) {
log.error("SFTP文件读取失败");
}finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、总结
这样我们就实现了我们的目的,成功的把SFTP中的学生文件转移到OSS并解析到我们的数据库。