1、首先引入pom文件依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>2、创建sftp工厂
package com.ztc.lrh.web.config;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
@Slf4j
public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp> {
public ChannelSftpFactory(String host, Integer port, String protocol, String username, String password,
String sessionStrictHostKeyChecking, Integer sessionConnectTimeout, Integer channelConnectedTimeout) {
super();
this.host = host;
this.port = port;
this.protocol = protocol;
this.username = username;
this.password = password;
this.sessionStrictHostKeyChecking = sessionStrictHostKeyChecking;
this.sessionConnectTimeout = sessionConnectTimeout;
this.channelConnectedTimeout = channelConnectedTimeout;
}
private String host;// host
private Integer port;// 端口
private String protocol;// 协议
private String username;// 用户
private String password;// 密码
private String sessionStrictHostKeyChecking;
private Integer sessionConnectTimeout;// session超时时间
private Integer channelConnectedTimeout;// channel超时时间
// 设置第一次登陆的时候提示,可选值:(ask | yes | no)
private static final String SESSION_CONFIG_STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";
@Override
public ChannelSftp create() throws Exception {
return null;
}
@Override
public PooledObject<ChannelSftp> makeObject() throws Exception {
JSch jsch = new JSch();
//log.info("sftp尝试连接[" + username + "@" + host + "], use password[" + password + "]");
Session session = createSession(jsch, host, username, port);
session.setPassword(password);
session.connect(sessionConnectTimeout);
//log.info("sftp已连接到:{}", host);
Channel channel = session.openChannel(protocol);
channel.connect(channelConnectedTimeout);
//log.info("sftp创建channel:{}", host);
return new DefaultPooledObject<ChannelSftp>((ChannelSftp) channel);
}
@Override
public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
return new DefaultPooledObject<>(channelSftp);
}
@Override
public void destroyObject(PooledObject<ChannelSftp> sftpPooled) throws Exception {
ChannelSftp sftp = sftpPooled.getObject();
try {
if (sftp != null) {
if (sftp.isConnected()) {
sftp.disconnect();
} else if (sftp.isClosed()) {
log.info("sftp连接已关闭");
}
if (null != sftp.getSession()) {
sftp.getSession().disconnect();
}
}
} catch (JSchException e) {
log.error("关闭sftp连接失败: {}", e);
e.printStackTrace();
throw new Exception("关闭sftp连接失败");
}
}
@Override
public boolean validateObject(PooledObject<ChannelSftp> sftpPooled) {
try {
ChannelSftp sftp = sftpPooled.getObject();
if (sftp != null) {
return (sftp.isConnected() && sftp.getSession().isConnected());
}
} catch (JSchException e) {
log.error("sftp连接校验失败: {}", e);
e.printStackTrace();
throw new RuntimeException("sftp连接校验失败");
}
return false;
}
/**
* 创建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 = null;
if (port <= 0) {
session = jsch.getSession(username, host);
} else {
session = jsch.getSession(username, host, port);
}
if (session == null) {
throw new RuntimeException(host + " sftp建立连接session is null");
}
session.setConfig(SESSION_CONFIG_STRICT_HOST_KEY_CHECKING, sessionStrictHostKeyChecking);
return session;
}
}
3、添加配置
sftp:
client:
protocol: ${sftpProtocolValue}
host: ${sftpHost}
port: ${sftpPort}
username: ${sftpUser}
password: ${sftpPwd}
root: ${sftpRoot}
privateKey: ${sftpPrivateKey}
passphrase: ${sftpPass}
sessionStrictHostKeyChecking: ${sftpSession}
sessionConnectTimeout: ${sftpSessionTime}
channelConnectedTimeout: ${sftpChannel}
serverUrl: ${sftpUrl}
targetPath: ${sftpTarget}
reservedName: ${sftpReserved}实际值根据自己情况补充
4、创建sftp配置类
package com.ztc.lrh.web.config;
import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
@Component
@Data
public class SftpConfiguration {
public GenericObjectPool<ChannelSftp> channelSftpPool;//连接池
@Value("${sftp.client.host}")
private String host;//host
@Value("${sftp.client.port}")
private Integer port;//端口
@Value("${sftp.client.protocol}")
private String protocol;//协议
@Value("${sftp.client.username}")
private String username;//用户
@Value("${sftp.client.password}")
private String password;//密码
@Value("${sftp.client.root}")
private String root;//根路径
@Value("${sftp.client.privateKey}")
private String privateKey;//密匙路径
@Value("${sftp.client.passphrase}")
private String passphrase;//密匙密码
@Value("${sftp.client.sessionStrictHostKeyChecking}")
private String sessionStrictHostKeyChecking;
@Value("${sftp.client.sessionConnectTimeout}")
private Integer sessionConnectTimeout;//session超时时间
@Value("${sftp.client.channelConnectedTimeout}")
private Integer channelConnectedTimeout;//channel超时时间
@Value("${sftp.client.serverUrl}")
private String serverUrl;//图片服务url
/**
* @Title: getSftpSocket
* @Description: 获取连接
* @param: @return
* @return: ChannelSftp
* @throws
*/
public ChannelSftp getSftpSocket(){
try {
if(null == this.channelSftpPool){
initPool();
}
return this.channelSftpPool.borrowObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @Title: returnSftpSocket
* @Description: 归还连接
* @param: @param sftp
* @return: void
* @throws
*/
public void returnSftpSocket(ChannelSftp sftp){
this.channelSftpPool.returnObject(sftp);
}
/**
* @Title: initPool
* @Description: 初始化连接池
* @param:
* @return: void
* @throws
*/
private void initPool(){
GenericObjectPoolConfig config=new GenericObjectPoolConfig();
config.setMinIdle(10);
config.setMaxTotal(10);
config.setMaxWaitMillis(30000);
this.channelSftpPool = new GenericObjectPool<>(new ChannelSftpFactory(host, port, protocol, username, password,
sessionStrictHostKeyChecking, sessionConnectTimeout, channelConnectedTimeout),config);
AbandonedConfig abandonedConfig = new AbandonedConfig();
abandonedConfig.setRemoveAbandonedOnMaintenance(true); //在Maintenance的时候检查是否有泄漏
abandonedConfig.setRemoveAbandonedOnBorrow(true); //borrow 的时候检查泄漏
abandonedConfig.setRemoveAbandonedTimeout(10); //如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象
this.channelSftpPool.setAbandonedConfig(abandonedConfig);
this.channelSftpPool.setTimeBetweenEvictionRunsMillis(30000); //30秒运行一次维护任务
}
}
5、创建文件上传controller
package com.ztc.lrh.web.controller;
import com.ztc.common.api.result.annotation.ResultResponse;
import com.ztc.common.api.result.data.CollectionData;
import com.ztc.common.api.result.result.ResultEnum;
import com.ztc.lrh.web.common.Constants;
import com.ztc.lrh.web.service.impl.FileSystemService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@Slf4j
@Api(tags = "sftp")
@CrossOrigin("*")
@ResultResponse
public class SftpController {
@Autowired
FileSystemService service;
@Value("${sftp.client.targetPath}")
private String targetPath;
@Value("${sftp.client.reservedName}")
private boolean reservedName;
@PostMapping("/sftp")
public CollectionData<String> upload(@RequestParam(required = true) MultipartFile[] files){
CollectionData<String> collectionData =new CollectionData<String>();
if(files==null || files.length == 0){
Map<String,Object> map = new HashMap<>();
map.put("error","上传失败,请选择上传文件");
collectionData.setMeta(map);
return collectionData;
}
List<String> imageUrls;
try {
imageUrls = service.uploadFile(targetPath, files, reservedName);
collectionData.setList(imageUrls);
return collectionData;
} catch (Exception e) {
e.printStackTrace();
}
Map<String,Object> map = new HashMap<>();
map.put("error","上传文件失败");
collectionData.setMeta(map);
return collectionData;
}
@DeleteMapping("/sftp")
public ResultEnum delete(String[] fileNames){
try {
if(fileNames==null || fileNames.length == 0){
return ResultEnum.STRING.setData("请选择删除文件");
}
List<String> urlList = new ArrayList<String>();
urlList = Arrays.asList(fileNames).stream().map(e ->{ return targetPath+ Constants.SPLIT_DIR+e;}).collect(Collectors.toList());
if(service.deleteFile(urlList)){
return ResultEnum.STRING.setData("success");
}else {
return ResultEnum.STRING.setData("error");
}
} catch (Exception e) {
e.printStackTrace();
return ResultEnum.STRING.setData("删除文件失败");
}
}
}
6、创建文件上传service
package com.ztc.lrh.web.service.impl;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import com.ztc.lrh.web.config.SftpConfiguration;
import com.ztc.lrh.web.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class FileSystemService {
@Autowired
private SftpConfiguration config;
/**
* @Title: createDirs @Description: 创建层级目录 @param: @param
* dirPath @param: @param sftp @param: @return @return: boolean @throws
*/
private boolean createDirs(String dirPath, ChannelSftp sftp) {
if (dirPath != null && !dirPath.isEmpty() && sftp != null) {
String[] dirs = Arrays.stream(dirPath.split("/")).filter(StringUtils::hasLength).toArray(String[]::new);
for (String dir : dirs) {
try {
sftp.cd(dir);
//log.info("stfp切换到目录:{}", dir);
} catch (Exception e) {
try {
sftp.mkdir(dir);
//log.info("sftp创建目录:{}", dir);
} catch (SftpException e1) {
log.error("[sftp创建目录失败]:{}", dir, e1);
e1.printStackTrace();
throw new RuntimeException("sftp创建目录失败");
}
try {
sftp.cd(dir);
//log.info("stfp切换到目录:{}", dir);
} catch (SftpException e1) {
log.error("[sftp切换目录失败]:{}", dir, e1);
e1.printStackTrace();
throw new RuntimeException("sftp切换目录失败");
}
}
}
return true;
}
return false;
}
public List<String> uploadFile(String targetPath, MultipartFile[] files, boolean reservedName) throws Exception {
ChannelSftp sftp = config.getSftpSocket();
List<String> resultStrs = new ArrayList<String>();
try {
sftp.cd(config.getRoot());
//log.info("sftp连接host", config.getRoot());
boolean dirs = this.createDirs(targetPath, sftp);
if (!dirs) {
log.error("sftp创建目录失败", targetPath);
throw new RuntimeException("上传文件失败");
}
for (MultipartFile file : files) {
String fileName = "";
if (reservedName) {
fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."))
/*+ "-" + DateUtil.getCurrentDateTimeSecond()*/
+file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
} else {
fileName = DateUtil.getCurrentDateTimeMilliSecond()
+ file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
}
sftp.put(file.getInputStream(), fileName);
resultStrs.add(config.getServerUrl() + targetPath + "/" + fileName);
}
return resultStrs;
} catch (Exception e) {
log.error("上传文件失败", targetPath, e);
e.printStackTrace();
throw new RuntimeException("上传文件失败");
} finally {
config.returnSftpSocket(sftp);
}
}
public boolean deleteFile(List<String> targetPath) throws Exception {
ChannelSftp sftp = null;
try {
sftp = config.getSftpSocket();
sftp.cd(config.getRoot());
for (String path : targetPath) {
sftp.rm(path);
}
return true;
} catch (Exception e) {
log.error("删除文件失败", targetPath, e);
e.printStackTrace();
throw new RuntimeException("删除文件失败");
} finally {
config.returnSftpSocket(sftp);
}
}
}
前台直接访问controller接口,就可以实现上传、删除文件 ,价值1万的教程免费倾授,wish u all better,world peace。
OVER!!
版权声明:本文为lovestmost原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。