因为在做毕设,发现之前的搭建ftp文件服务器,通过ftp协议无法操作虚拟机临时文件,又因为ftp文件服务器搭建的比较麻烦;而
hadoop的HDFS虽然可以实现,但我这里用不到那么复杂的;所以我封装了一个文件上传下载的工具类,采用sftp协议.
简单方便可用性高!!!
目录
1、依赖
2、配置(yml)
3、SFTPUtils
4、Controller
5、总结:通过封装成工具类,提高了代码的可复用性,和简洁性
1、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
2、配置(yml)
sftp:
ip: 192.168.23.142
port: 22
username: root
password: 123456
downloadSleep: 100 #文件下载失败下次超时重试时间
downloadRetry: 10 #文件下载失败重试次数
uploadSleep: 100 #文件上传失败下次超时重试时间
uploadRettry: 10 #文件上传失败重试次数
3、SFTPUtils
package com.zj.docker.utils;
import com.jcraft.jsch.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Properties;
/**
* @Auther: zj
* @Date: 2018/12/18 16:58
* @Description:
*/
public class SFTPUtils {
/**
* 默认端口
*/
private final static int DEFAULT_PORT = 22;
private final static String HOST = "host";
private final static String PORT = "port";
private final static String USER_NAME = "userName";
private final static String PASSWORD = "password";
/**
* 服务端保存的文件名
*/
private String remote;
/**
* 服务端保存的路径
*/
private String remotePath;
/**
* 本地文件
*/
private File local;
/**
* 主机地址
*/
private String host;
/**
* 端口
*/
private int port = DEFAULT_PORT;
/**
* 登录名
*/
private String userName;
/**
* 登录密码
*/
private String password;
private ChannelSftp sftp;
public SFTPUtils(String host, int port, String userName, String password) {
this.init(host, port, userName, password);
}
/**
* 初始化
*
* @param host
* @param port
* @param userName
* @param password
* @date 2018/12/18
*/
private void init(String host, int port, String userName, String password) {
this.host = host;
this.port = port;
this.userName = userName;
this.password = password;
}
/**
* 连接sftp
*
* @throws JSchException
* @date 2018/12/18
*/
private void connect() throws JSchException, NoSuchFieldException, IllegalAccessException, SftpException {
JSch jsch = new JSch();
// 取得一个SFTP服务器的会话
Session session = jsch.getSession(userName, host, port);
// 设置连接服务器密码
session.setPassword(password);
Properties sessionConfig = new Properties();
// StrictHostKeyChecking
// "如果设为"yes",ssh将不会自动把计算机的密匙加入"$HOME/.ssh/known_hosts"文件,
// 且一旦计算机的密匙发生了变化,就拒绝连接。
sessionConfig.setProperty("StrictHostKeyChecking", "no");
// 设置会话参数
session.setConfig(sessionConfig);
// 连接
session.connect();
// 打开一个sftp渠道
Channel channel = session.openChannel("sftp");
sftp = (ChannelSftp) channel;
channel.connect();
Class cl = ChannelSftp.class;
Field f =cl.getDeclaredField("server_version");
f.setAccessible(true);
f.set(sftp, 2);
sftp.setFilenameEncoding("GBK");
}
/**
* 上传文件
* @date 2018/12/18
*/
public void uploadFile() throws Exception {
FileInputStream inputStream = null;
try {
connect();
if (isEmpty(remote)) {
remote = local.getName();
}
if (!isEmpty(remotePath)) {
sftp.cd(remotePath);
}
inputStream = new FileInputStream(local);
sftp.put(inputStream, remote);
} catch (Exception e) {
throw e;
} finally {
sftp.disconnect();
close(inputStream);
}
}
public void uploadFile(InputStream inputStream) throws Exception {
try {
connect();
if (isEmpty(remote)) {
remote = local.getName();
}
if (!isEmpty(remotePath)) {
createDir(remotePath);
}
sftp.put(inputStream, remote);
} catch (Exception e) {
throw e;
} finally {
sftp.disconnect();
close(inputStream);
}
}
@Async("taskExecutor")//异步
public void uploadFile(String filename, String filePath, MultipartFile file) throws Exception {
try {
connect();
if (!isEmpty( filePath )) {
createDir( filePath );
}
sftp.put( file.getInputStream(), filename );
}catch (Exception e) {
throw e;
} finally {
sftp.disconnect();
close(file.getInputStream());
}
}
public boolean isDirExist(String directory) throws Exception {
boolean isDirExistFlag = false;
try {
SftpATTRS sftpATTRS = sftp.lstat(directory);
isDirExistFlag = true;
return sftpATTRS.isDir();
} catch (Exception e) {
if (e.getMessage().toLowerCase().equals("no such file")) {
isDirExistFlag = false;
}
}
return isDirExistFlag;
}
public void createDir(String createpath) throws Exception {
try {
if (isDirExist(createpath)) {
this.sftp.cd(createpath);
} else {
String pathArry[] = createpath.split("/");
for (String path : pathArry) {
if (path.equals("")) {
continue;
}
if (isDirExist(path.toString())) {
sftp.cd(path.toString());
} else {
// 建立目录
sftp.mkdir(path.toString());
// 进入并设置为当前目录
sftp.cd(path.toString());
}
}
}
} catch (SftpException e) {
throw new Exception("创建路径错误:" + createpath);
}
}
/**
* 下载
* @date 2018/12/18
*/
public void download() throws Exception {
FileOutputStream output = null;
try {
this.connect();
if (null != remotePath || !("".equals(remotePath))) {
sftp.cd(remotePath);
}
output = new FileOutputStream(local);
sftp.get(remote, output);
} catch (Exception e) {
throw e;
} finally {
sftp.disconnect();
close(output);
}
}
public void download(OutputStream outputStream) throws Exception {
try {
this.connect();
if (null != remotePath || !("".equals(remotePath))) {
sftp.cd(remotePath);
}
sftp.get(remote, outputStream);
} catch (Exception e) {
throw e;
} finally {
sftp.disconnect();
}
}
public static boolean isEmpty(String str) {
if (null == str || "".equals(str)) {
return true;
}
return false;
}
public static void close(OutputStream... outputStreams) {
for (OutputStream outputStream : outputStreams) {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void close(InputStream... inputStreams) {
for (InputStream inputStream : inputStreams) {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void setRemote(String remote) {
this.remote = remote;
}
public void setRemotePath(String remotePath) {
this.remotePath = remotePath;
}
public void setLocal(File local) {
this.local = local;
}
}
4、Controller
测试,这边就简单举了一个例子
@Value("${sftp.ip}")
private String SFTP_ADDRESS; //ip
@Value("${sftp.port}")
private Integer SFTP_PORT; //port
@Value("${sftp.username}")
private String SFTP_USERNAME; //sftp username
@Value("${sftp.password}")
private String SFTP_PASSWORD; //sftp password
--------------------------------------------------
/**
* 上传文件到数据卷,普通用户权限
* @param request
* @param name 数据卷的名称
* @param file 上传的文件
* @return
* @throws Exception
*/
@PostMapping("/customer/uploadDocToVolume")
public ResultVo customerUploadDocToVolume(HttpServletRequest request,
@RequestParam("name") String name,
@RequestParam("file") MultipartFile file
) throws Exception {
//鉴权
String username = userRoleAuthentication.getUsernameAndAutenticateUserRoleFromRequest( request, RoleEnum.User.getMessage() );
if (Objects.equals( username, CommonEnum.FALSE.getMessage())) {
return ResultVoUtil.error();
}
//校验参数
if (StringUtils.isBlank( name )||file==null ) {
return ResultVoUtil.error(CommonEnum.PARAM_ERROR.getMessage());
}
String bashPath ="/var/lib/docker/volumes/";
String picSavePath = "/"+name+"/_data";
SFTPUtils sftpUtils = new SFTPUtils( SFTP_ADDRESS,SFTP_PORT,SFTP_USERNAME,SFTP_PASSWORD);
//上传文件,同步
sftpUtils.uploadFile( file.getOriginalFilename(),bashPath+picSavePath,file );
return ResultVoUtil.success("上传文件成功");
}
5、总结
通过封装成工具类,提高了代码的可复用性,和简洁性