Commit 39e17a53 by 284718418@qq.com

1.云盘上传文件

2.云盘服务器配置
3.云盘访问地址配置
4.云盘地址配置
parent 7f1532d4
......@@ -47,6 +47,11 @@
<dependencies>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- <exclusions> <exclusion> <groupId>org.springframework.boot</groupId>
......
package cn.timer.api.aspect;
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;
/**
* @author wuqingjun
* @email 284718418@qq.com
* @date 2021/12/28
*/
@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;
}
// host
private String host;
// 端口
private Integer port;
// 协议
private String protocol;
// 用户
private String username;
// 密码
private String password;
private String sessionStrictHostKeyChecking;
// session超时时间
private Integer sessionConnectTimeout;
// channel超时时间
private Integer channelConnectedTimeout;
// 设置第一次登陆的时候提示,可选值:(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;
}
}
......@@ -68,7 +68,7 @@ public class DiskFiles extends Model<DiskFiles> {
* 显示大小
*/
@ApiModelProperty(value = "显示大小:10KB,5M,2G")
private Long showSize;
private String showSize;
/**
* 文件格式类型
*/
......
......@@ -254,7 +254,7 @@ public interface JxglEnumInterface {
*/
@Getter
enum DiskCatalogueType implements JxglEnumInterface {
NEED(0, "0云盘"), NOT_NEED(1, "1文件夹");
NEED(0, "云盘"), NOT_NEED(1, "文件夹");
private Integer type;
......@@ -267,4 +267,22 @@ public interface JxglEnumInterface {
}
/**
* 云盘-文件浏览记录类型: 0查看,1下载,2创建
*/
@Getter
enum DiskFilesLogType implements JxglEnumInterface {
LOOK_LOG(0, "查看"), DOWN_LOAD_LOG(1, "下载"), CREATE_LOG(1, "下载");
private Integer type;
private String name;
DiskFilesLogType(Integer type, String name) {
this.type = type;
this.name = name;
}
}
}
package cn.timer.api.config.sftp;
import cn.timer.api.aspect.ChannelSftpFactory;
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;
/**
* @author wuqingjun
* @email 284718418@qq.com
* @date 2021/12/28
*/
@Configuration
@Component
@Data
public class SftpConfiguration {
//连接池
public GenericObjectPool<ChannelSftp> channelSftpPool;
//host
@Value("${sftp.client.host}")
private String 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.sessionStrictHostKeyChecking}")
private String sessionStrictHostKeyChecking;
//session超时时间
@Value("${sftp.client.sessionConnectTimeout}")
private Integer sessionConnectTimeout;
//channel超时时间
@Value("${sftp.client.channelConnectedTimeout}")
private Integer channelConnectedTimeout;
//图片服务url
@Value("${sftp.client.serverUrl}")
private String serverUrl;
/**
* @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();
//在Maintenance的时候检查是否有泄漏
abandonedConfig.setRemoveAbandonedOnMaintenance(true);
//borrow 的时候检查泄漏
abandonedConfig.setRemoveAbandonedOnBorrow(true);
//如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象
abandonedConfig.setRemoveAbandonedTimeout(10);
this.channelSftpPool.setAbandonedConfig(abandonedConfig);
//30秒运行一次维护任务
this.channelSftpPool.setTimeBetweenEvictionRunsMillis(30000);
}
}
......@@ -41,7 +41,7 @@ public class DiskCatalogueController{
* @return
*/
@PostMapping(value = "/add_catalogue")
@ApiOperation(value = "1.新建文件夹或共享空间", httpMethod = "POST", notes = "接口发布说明")
@ApiOperation(value = "1.新建文件夹或共享空间", httpMethod = "POST", notes = "新建文件夹或共享空间:type=0共享空间,1文件夹")
@ApiOperationSupport(order = 1)
public Result<Object> addygda(@CurrentUser UserBean userBean, @Validated @RequestBody DiskCatalogueDto diskCatalogueDto) {
Integer empNum = userBean.getEmpNum();
......
package cn.timer.api.controller.disk;
import cn.timer.api.config.annotation.CurrentUser;
import cn.timer.api.config.annotation.UserBean;
import cn.timer.api.service.FtpService;
import cn.timer.api.utils.Result;
import cn.timer.api.utils.ResultUtil;
import com.alibaba.druid.Constants;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Param;
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 javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -17,7 +30,7 @@ import javax.transaction.Transactional;
@Api(tags = "云盘")
@Transactional(rollbackOn = Exception.class)
@RestController
@RequestMapping("diskcataloguefiles")
@RequestMapping("/disk")
public class DiskCatalogueFilesController{
}
package cn.timer.api.controller.disk;
import cn.timer.api.bean.disk.DiskCatalogueFiles;
import cn.timer.api.bean.disk.DiskFiles;
import cn.timer.api.bean.disk.DiskFilesLog;
import cn.timer.api.config.annotation.CurrentUser;
import cn.timer.api.config.annotation.UserBean;
import cn.timer.api.config.enuminterface.JxglEnumInterface;
import cn.timer.api.config.sftp.SftpConfiguration;
import cn.timer.api.dto.disk.DiskCatalogueDto;
import cn.timer.api.dto.disk.DiskFilesDto;
import cn.timer.api.dto.disk.FileInfoDto;
import cn.timer.api.service.FtpService;
import cn.timer.api.utils.Result;
import cn.timer.api.utils.ResultUtil;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.transaction.Transactional;
import java.util.List;
/**
......@@ -17,7 +35,75 @@ import javax.transaction.Transactional;
@Api(tags = "云盘")
@Transactional(rollbackOn = Exception.class)
@RestController
@RequestMapping("diskfiles")
public class DiskFilesController{
@RequestMapping("/disk")
public class DiskFilesController {
@Autowired
private FtpService ftpService;
@Value("${sftp.client.root}")
private String root;
@Value("${sftp.client.targetPath}")
private String targetPath;
@Value("${sftp.client.reservedName}")
private boolean reservedName;
@Value("${sftp.client.serverUrl}")
private String serverUrl;
@ApiOperation(value = "上传普通文件", httpMethod = "POST", notes = "接口发布说明")
@ResponseBody
@PostMapping("/upload")
public Result<Object> upload(@CurrentUser UserBean userBean, @RequestParam(required = true) MultipartFile[] file,@RequestParam(required = true) Integer catalogueId) {
if (file == null || file.length == 0) {
return ResultUtil.error("上传失败,请选择上传文件");
}
Integer empNum = userBean.getEmpNum();
Integer orgCode = userBean.getOrgCode();
DiskFiles diskFiles = new DiskFiles();
DiskCatalogueFiles diskCatalogueFiles = new DiskCatalogueFiles();
DiskFilesLog diskFilesLog = new DiskFilesLog();
List<FileInfoDto> imageUrls;
try {
//上传文件到服务器
imageUrls = ftpService.uploadFile(targetPath, file, reservedName);
for (FileInfoDto dto : imageUrls) {
//新增资源上传文件
diskFiles.setCreateUserId(empNum);
diskFiles.setFileType(dto.getFileSuffix());
//"/home/disk/123456.jpg"
diskFiles.setDiskPath(root + targetPath + "/" + dto.getFileName());
diskFiles.setUrlPath(dto.getUrlPath());
diskFiles.setTitle(dto.getResourceFileName());
diskFiles.setFileSize(dto.getFileSize());
// 显示大小:10KB,5M,2G 后续优化
diskFiles.setShowSize(dto.getFileSize() + "B");
diskFiles.insert();
//新增中间关系
diskCatalogueFiles.setCatalogueId(catalogueId);
diskCatalogueFiles.setFilesId(diskFiles.getId());
diskCatalogueFiles.insert();
//新增 文件浏览记录
diskFilesLog.setFilePath(dto.getUrlPath());
diskFilesLog.setFilesId(diskFiles.getId());
diskFilesLog.setFileSize(dto.getFileSize());
diskFilesLog.setTitle(dto.getResourceFileName());
diskFilesLog.setType(JxglEnumInterface.DiskFilesLogType.CREATE_LOG.getType());
diskFilesLog.setUserId(empNum);
diskFilesLog.setUserName(userBean.getUserInfo().getName());
diskFilesLog.insert();
}
return ResultUtil.data(imageUrls);
} catch (Exception e) {
e.printStackTrace();
}
return ResultUtil.error("上传文件失败");
}
}
package cn.timer.api.dto.disk;
import cn.timer.api.config.exception.Regular;
import cn.timer.api.config.exception.ValidationMsg;
import cn.timer.api.utils.Page;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
......@@ -12,13 +9,9 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.util.Date;
/**
* 云盘-资源目录表
*
* @author wuqingjun
* @email 284718418@qq.com
* @date 2021-12-27 10:05:49
......
package cn.timer.api.dto.disk;
import cn.timer.api.config.exception.ValidationMsg;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @author wuqingjun
* @email 284718418@qq.com
* @date 2021-12-27 10:05:49
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DiskFilesDto implements Serializable{
private static final long serialVersionUID = -1230023773946170921L;
/**
* 资源目录ID
*/
@NotNull(message = ValidationMsg.NOTNULL)
@ApiModelProperty(value = "资源目录ID")
private Integer catalogueId;
/**
* 0云盘,1文件夹
*/
@NotNull(message = ValidationMsg.NOTNULL)
@ApiModelProperty(value = "0云盘,1文件夹")
private Integer type;
}
package cn.timer.api.dto.disk;
import cn.timer.api.config.exception.ValidationMsg;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @author wuqingjun
* @email 284718418@qq.com
* @date 2021-12-27 10:05:49
*/
@Data
public class FileInfoDto implements Serializable{
private static final long serialVersionUID = -1230023773946170931L;
/**
* 文件路径
*/
private String urlPath;
/**
* 原来文件名称
*/
private String resourceFileName;
/**
* 文件大小,单位KB
*/
private Long fileSize;
/**
* 文件后缀
*/
private String fileSuffix;
/**
* 文件文件全称
*/
private String fileName;
}
package cn.timer.api.service;
import cn.timer.api.dto.disk.FileInfoDto;
import com.jcraft.jsch.ChannelSftp;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 上传文件的实现层
*/
public interface FtpService {
boolean createDirs(String dirPath, ChannelSftp sftp);
/**
* 上传文件到服务器
* @param targetPath
* @param files
* @param reservedName
* @return
*/
List<FileInfoDto> uploadFile(String targetPath, MultipartFile[] files, boolean reservedName);
/**
* 删除服务器文件
* @param targetPath
* @return
*/
boolean deleteFile(List<String> targetPath);
}
package cn.timer.api.service.impl;
import cn.timer.api.config.sftp.SftpConfiguration;
import cn.timer.api.dto.disk.FileInfoDto;
import cn.timer.api.service.FtpService;
import cn.timer.api.utils.Md5;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
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.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@Service
@Slf4j
public class FtpServiceImpl implements FtpService {
@Autowired
private SftpConfiguration config;
@Override
public 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;
}
@Override
public List<FileInfoDto> uploadFile(String targetPath, MultipartFile[] files, boolean reservedName) {
ChannelSftp sftp = config.getSftpSocket();
List<FileInfoDto> resultStrs = new ArrayList<FileInfoDto>();
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("上传文件失败");
}
FileInfoDto dto = null;
for (MultipartFile file : files) {
dto = new FileInfoDto();
String fileName = "";
String name = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (reservedName) {
fileName = Md5.md5(name+UUID.randomUUID().toString()) + suffix;
} else {
fileName = UUID.randomUUID().toString()+suffix;
}
sftp.put(file.getInputStream(), fileName);
dto.setUrlPath(config.getServerUrl() + "/" +fileName);
dto.setResourceFileName(name);
dto.setFileName(fileName);
/*Float size = Float.parseFloat(String.valueOf(file.getSize())) / 1024;
BigDecimal b = new BigDecimal(size);
// 2表示2位 ROUND_HALF_UP表明四舍五入,
size = b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();*/
dto.setFileSize(file.getSize());
dto.setFileSuffix(suffix);
resultStrs.add(dto);
}
return resultStrs;
} catch (Exception e) {
log.error("上传文件失败", targetPath, e);
e.printStackTrace();
throw new RuntimeException("上传文件失败");
} finally {
config.returnSftpSocket(sftp);
}
}
@Override
public boolean deleteFile(List<String> targetPath){
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);
}
}
}
......@@ -210,3 +210,19 @@ config-8timer:
#导出zip临时地址
zip:
path: '/data/crm-zip/'
#sftp 配置
sftp:
client:
protocol: 'sftp'
host: '120.78.162.177'
port: '22'
username: 'root'
password: 'fksdlfjs(*&&%HGgjfkdjsfhksh9781283KFHFFGHghhndbv##2@'
root: '/home'
sessionStrictHostKeyChecking: 'no'
sessionConnectTimeout: '1500'
channelConnectedTimeout: '1500'
serverUrl: 'https://img.8timer.cn'
targetPath: '/disk'
reservedName: false
\ No newline at end of file
......@@ -154,7 +154,7 @@ pagehelper:
logging:
level:
root: info
cn.timer.api.dao: debug
cn.timer.api.dao: info
pattern:
console: '--%p--%m%n'
......@@ -210,4 +210,19 @@ config-8timer:
#导出zip临时地址
zip:
path: '/data/crm-zip/'
#sftp 配置
sftp:
client:
protocol: 'sftp'
host: '120.78.162.177'
port: '22'
username: 'root'
password: 'fksdlfjs(*&&%HGgjfkdjsfhksh9781283KFHFFGHghhndbv##2@'
root: '/home'
sessionStrictHostKeyChecking: 'no'
sessionConnectTimeout: '1500'
channelConnectedTimeout: '1500'
serverUrl: 'https://test-img.8timer.cn'
targetPath: '/disk'
reservedName: false
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment