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 mons.pool2.BasePooledObjectFactory;import mons.pool2.PooledObject;import mons.pool2.impl.DefaultPooledObject;@Slf4jpublic 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;// hostprivate 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";@Overridepublic ChannelSftp create() throws Exception {return null;}@Overridepublic 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);}@Overridepublic PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {return new DefaultPooledObject<>(channelSftp);}@Overridepublic 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连接失败");}}@Overridepublic 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 mons.pool2.impl.AbandonedConfig;import mons.pool2.impl.GenericObjectPool;import mons.pool2.impl.GenericObjectPoolConfig;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Configuration;import org.ponent;@Configuration@Component@Datapublic 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 mon.api.result.annotation.ResultResponse;import mon.api.result.data.CollectionData;import mon.api.result.result.ResultEnum;import com.ztc.mon.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("*")@ResultResponsepublic class SftpController {@AutowiredFileSystemService 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@Slf4jpublic class FileSystemService {@Autowiredprivate 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!!