修复漏洞问题

This commit is contained in:
weiweiw 2024-09-19 16:53:25 +08:00
parent 12bd9c20c3
commit 2bcedea253
60 changed files with 456 additions and 2355 deletions

View File

@ -57,7 +57,7 @@ public interface RemoteConfigService {
* @return 结果
*/
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config,@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
public AjaxResult edit(@Validated @RequestBody SysConfig config, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 删除参数配置

View File

@ -4,13 +4,13 @@ import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.constant.ServiceNameConstants;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.domain.SysDictData;
import com.bonus.system.api.domain.SysDictType;
import com.bonus.system.api.factory.RemoteDictTypeFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author wangvivi
*/

View File

@ -5,7 +5,6 @@ import com.bonus.common.core.constant.ServiceNameConstants;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.domain.SysPost;
import com.bonus.system.api.factory.RemoteDeptFallbackFactory;
import com.bonus.system.api.factory.RemotePostFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;

View File

@ -7,7 +7,6 @@ import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.domain.SysRole;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.domain.SysUserRole;
import com.bonus.system.api.factory.RemoteDeptFallbackFactory;
import com.bonus.system.api.factory.RemoteRoleFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;

View File

@ -1,7 +1,6 @@
package com.bonus.system.api;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.domain.SysDept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;

View File

@ -18,6 +18,10 @@ public class SysConfig extends BaseEntity
{
private static final long serialVersionUID = 1L;
//用于excel导出的序号一列,不需要业务逻辑处理
@Excel(name = "序号", isSequence = true, type = Excel.Type.EXPORT)
int sequence;
/** 参数主键 */
@Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
private Long configId;

View File

@ -1,5 +1,6 @@
package com.bonus.system.api.domain;
import lombok.Builder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@ -8,6 +9,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
*
* @author bonus
*/
@Builder
public class SysFile
{
/**
@ -16,9 +18,13 @@ public class SysFile
private String name;
/**
* 文件地址
* 文件地址除mongodb 存fileid之外其他均存上传文件的网络路径
*/
private String url;
// /**
// * 文件存储类型包括 本地obsmongodb等
// */
// private String storageType;
public String getName()
{
@ -47,4 +53,12 @@ public class SysFile
.append("url", getUrl())
.toString();
}
// public String getStorageType() {
// return storageType;
// }
//
// public void setStorageType(String storageType) {
// this.storageType = storageType;
// }
}

View File

@ -19,6 +19,10 @@ public class SysPost extends BaseEntity
{
private static final long serialVersionUID = 1L;
//用于excel导出的序号一列,不需要业务逻辑处理
@Excel(name = "序号", isSequence = true, type = Excel.Type.EXPORT)
int sequence;
/** 岗位序号 */
@Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
private Long postId;

View File

@ -1,8 +1,6 @@
package com.bonus.system.api.factory;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemoteConfigService;
@ -43,11 +41,11 @@ public class RemoteConfigFallbackFactory implements FallbackFactory<RemoteConfig
}
@Override
public AjaxResult getInfo(Long configId, String source){
public AjaxResult getInfo(Long configId, String source){
return AjaxResult.error("根据参数编号获取参数配置列表失败:" + throwable.getMessage());
}
@Override
public AjaxResult getConfigKey(String configKey, String source){
public AjaxResult getConfigKey(String configKey, String source){
return AjaxResult.error("根据参数键名获取参数配置列表失败:" + throwable.getMessage());
}

View File

@ -1,6 +1,5 @@
package com.bonus.system.api.factory;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.system.api.RemoteDeptService;
import com.bonus.system.api.domain.SysDept;
@ -8,8 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 用户服务降级处理

View File

@ -3,10 +3,7 @@ package com.bonus.system.api.factory;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemoteDeptService;
import com.bonus.system.api.RemoteDictDataService;
import com.bonus.system.api.domain.SysConfig;
import com.bonus.system.api.domain.SysDept;
import com.bonus.system.api.domain.SysDictData;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemoteDictTypeService;
import com.bonus.system.api.domain.SysDictData;
import com.bonus.system.api.domain.SysDictType;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemoteNoticeService;
import com.bonus.system.api.domain.SysDictData;
import com.bonus.system.api.domain.SysNotice;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemotePostService;
import com.bonus.system.api.domain.SysNotice;
import com.bonus.system.api.domain.SysPost;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.RemoteRoleService;
import com.bonus.system.api.domain.SysPost;
import com.bonus.system.api.domain.SysRole;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.domain.SysUserRole;

View File

@ -4,7 +4,6 @@ import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.system.api.domain.SysDept;
import com.bonus.system.api.domain.SysRole;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,7 +14,6 @@ import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.api.model.LoginUser;
import java.util.ArrayList;
import java.util.List;
/**

View File

@ -71,6 +71,59 @@
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
<version>3.23.9</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
<scope>compile</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mongodb</groupId>-->
<!-- <artifactId>mongodb-driver-sync</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.12</version> <!-- 版本号可以根据需要调整 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -1,4 +1,4 @@
package com.bonus.oss.config;
package com.bonus.file.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@ -1,8 +1,6 @@
package com.bonus.obs.config;
package com.bonus.file.config;
import com.obs.services.ObsClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ -14,8 +12,6 @@ public class ObsConfig {
private String sk;
private String bucket;
public String getEndpoint() {
return endpoint;
}

View File

@ -1,28 +1,26 @@
package com.bonus.file.controller;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.utils.Base64Utils;
import com.bonus.common.core.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.file.service.ISysFileService;
import com.bonus.system.api.domain.SysFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 文件请求处理
*
*
* @author bonus
*/
@RestController
@ -31,11 +29,17 @@ public class SysFileController
{
private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
private final ISysFileService sysFileService;
@Autowired
private ISysFileService sysFileService;
public SysFileController(ISysFileService fileService) {
this.sysFileService = fileService;
}
/**
* 文件上传请求
* 单文件上传
* @param file 单个文件
* @return 文件信息包括文件名和文件路径
*/
@PostMapping("upload")
@ApiOperation("上传本地文件到服务器")
@ -44,10 +48,7 @@ public class SysFileController
try
{
// 上传并返回访问地址
String url = sysFileService.uploadFile(file);
SysFile sysFile = new SysFile();
sysFile.setName(FileUtils.getName(url));
sysFile.setUrl(url);
SysFile sysFile = sysFileService.uploadFile(file);
return R.ok(sysFile);
}
catch (Exception e)
@ -57,40 +58,57 @@ public class SysFileController
}
}
@GetMapping("/download")
@ApiOperation("从服务器下载文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "url", value = "文件网络地址", required = true),
@ApiImplicitParam(name = "destination", value = "下载的本地路径", required = true),
})
public R<Boolean> downloadFile(String url, String destination) {
/**
* 多文件上传
* @param files 多个文件流
* @return 文件信息
*/
@PostMapping("/uploadFiles")
public AjaxResult uploadFile(MultipartFile[] files) {
try {
String fileUrl = Base64Utils.decodeUrl(url);
if (fileUrl != null) {
String fileName = Base64Utils.getFileNameFromUrl(fileUrl);
sysFileService.downloadFile(fileUrl, destination + "/" + fileName);
return R.ok();
}
} catch (Exception e) {
log.error("下载文件失败", e);
return R.fail(e.getMessage());
return AjaxResult.success(sysFileService.uploadFiles(files));
} catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
return R.fail("下载文件失败");
}
@GetMapping("/delete")
public R<Boolean> deleteFile(String url) {
/**
* 文件下载
* @param response 请求响应
* @param objectKey除mongodb 存fileid之外其他均存上传文件的网络路径
*/
@GetMapping("/download")
public void downloadFile(HttpServletResponse response, @RequestParam String objectKey) throws IOException {
try {
String fileUrl = Base64Utils.decodeUrl(url);
if (fileUrl != null) {
sysFileService.deleteFile(fileUrl);
return R.ok();
}
} catch (Exception e) {
log.error("delete文件失败", e);
return R.fail(e.getMessage());
String fileUrl = Base64Utils.decodeUrl(objectKey);
sysFileService.downloadFile(response, fileUrl);
} catch (Exception e) {
log.error("downloadFile error:{}", e.getMessage());
response.setStatus(HttpStatus.ERROR);
// 设置响应的 Content-Type 为文本
response.setContentType("application/json;charset=UTF-8");
// 将错误信息写入响应体
PrintWriter writer = response.getWriter();
writer.write("{\"error\": \"File download failed: " + e.getMessage() + "\"}");
writer.flush();
writer.close();
}
return R.fail("传入参数不满足要求");
}
/**
* 文件删除
* 从各个存储平台删除文件
* @param objectKey * @param objectKey除mongodb 存fileid之外其他均存上传文件的网络路径
*/
@DeleteMapping("/deleteFile")
public AjaxResult deleteFile(@RequestParam("objectKey") String objectKey) {
try {
String fileUrl = Base64Utils.decodeUrl(objectKey);
sysFileService.deleteFile(fileUrl);
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
return AjaxResult.success("删除文件成功");
}
}

View File

@ -1,59 +0,0 @@
package com.bonus.file.service;
import java.io.InputStream;
import com.alibaba.nacos.common.utils.IoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.bonus.common.core.utils.file.FileTypeUtils;
/**
* FastDFS 文件存储
*
* @author bonus
*/
@Service
public class FastDfsSysFileServiceImpl implements ISysFileService
{
/**
* 域名或本机访问地址
*/
@Value("${fdfs.domain}")
public String domain;
@Autowired
private FastFileStorageClient storageClient;
/**
* FastDfs文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
InputStream inputStream = file.getInputStream();
StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(),
FileTypeUtils.getExtension(file), null);
IoUtils.closeQuietly(inputStream);
return domain + "/" + storePath.getFullPath();
}
@Override
public boolean downloadFile(String urlStr, String destination) throws Exception
{
return false;
}
@Override
public boolean deleteFile(String urlStr) throws Exception
{
return false;
}
}

View File

@ -1,7 +1,13 @@
package com.bonus.file.service;
import com.bonus.common.core.domain.R;
import com.bonus.system.api.domain.SysFile;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.util.List;
/**
* 文件上传接口
*
@ -16,17 +22,25 @@ public interface ISysFileService
* @return 访问地址
* @throws Exception
*/
public String uploadFile(MultipartFile file) throws Exception;
public SysFile uploadFile(MultipartFile file) throws Exception;
/**
* 文件上传接口
*
* @param files 上传的文件
* @return 访问地址
* @throws Exception
*/
public List<SysFile> uploadFiles(MultipartFile[] files) throws Exception;
/**
* 从给定的URL下载文件并将其保存到指定的目标位置
*
* @param urlStr 要下载文件的URL地址
* @param destination 文件下载后保存的本地文件系统路径
* @return 布尔值指示下载是否成功成功返回true失败返回false
* @param response 请求响应
* @throws Exception 如果在下载过程中遇到任何异常例如网络问题文件写入问题等
*/
public boolean downloadFile(String urlStr, String destination) throws Exception;
public void downloadFile(HttpServletResponse response, String urlStr) throws Exception;
/**
* 删除指定URL所指向的文件
@ -35,6 +49,6 @@ public interface ISysFileService
* @return 布尔值指示文件删除是否成功如果文件被成功删除则返回true否则返回false
* @throws Exception 如果在删除文件的过程中遇到错误例如网络问题文件不存在或没有删除权限等
*/
public boolean deleteFile(String urlStr) throws Exception;
public void deleteFile(String urlStr) throws Exception;
}

View File

@ -1,81 +0,0 @@
package com.bonus.file.service;
import com.bonus.file.utils.FileDownloadUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.bonus.file.utils.FileUploadUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 本地文件存储
*
* @author bonus
*/
@Primary
@Service
public class LocalSysFileServiceImpl implements ISysFileService
{
/**
* 资源映射路径 前缀
*/
@Value("${file.prefix}")
public String localFilePrefix;
/**
* 域名或本机访问地址
*/
@Value("${file.domain}")
public String domain;
/**
* 上传文件存储在本地的根路径
*/
@Value("${file.path}")
private String localFilePath;
/**
* 本地文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
String name = FileUploadUtils.upload(localFilePath, file);
String url = domain + localFilePrefix + name;
return url;
}
@Override
public boolean downloadFile(String urlStr, String destination) throws Exception
{
return FileDownloadUtils.downloadFile(urlStr, destination);
}
@Override
public boolean deleteFile(String urlStr) throws Exception
{
String regex = String.format("^(.*?%s)", localFilePrefix);
String updatePath = urlStr.replaceFirst(regex, localFilePath);
Path path = Paths.get(updatePath);
if (Files.exists(path)){
try {
Files.deleteIfExists(path);
}catch (IOException e){
throw new Exception(e.getMessage(), e);
}
}else {
throw new Exception("删除文件时文件不存在");
}
return true;
}
}

View File

@ -1,62 +0,0 @@
package com.bonus.file.service;
import java.io.InputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.nacos.common.utils.IoUtils;
import com.bonus.file.config.MinioConfig;
import com.bonus.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
/**
* Minio 文件存储
*
* @author bonus
*/
@Service
public class MinioSysFileServiceImpl implements ISysFileService
{
@Autowired
private MinioConfig minioConfig;
@Autowired
private MinioClient client;
/**
* Minio文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
String fileName = FileUploadUtils.extractFilename(file);
InputStream inputStream = file.getInputStream();
PutObjectArgs args = PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(fileName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build();
client.putObject(args);
IoUtils.closeQuietly(inputStream);
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
}
@Override
public boolean downloadFile(String urlStr, String destination) throws Exception
{
return false;
}
@Override
public boolean deleteFile(String urlStr) throws Exception
{
return false;
}
}

View File

@ -0,0 +1,120 @@
package com.bonus.file.service.impl;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.nacos.common.utils.IoUtils;
import com.bonus.file.service.ISysFileService;
import com.bonus.file.utils.FileUploadUtils;
import com.bonus.system.api.domain.SysFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.bonus.common.core.utils.file.FileTypeUtils;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletResponse;
/**
* FastDFS 文件存储
*
* @author bonus
*/
@Service
@ConditionalOnProperty(name = "storage.type", havingValue = "fdfs")
public class FastDfsSysFileServiceImpl implements ISysFileService
{
/**
* 域名或本机访问地址
*/
@Value("${fdfs.domain}")
public String domain;
@Autowired
private FastFileStorageClient storageClient;
/**
* FastDfs文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public SysFile uploadFile(MultipartFile file) throws Exception
{
String fileName = FileUploadUtils.extractFilename(file);
InputStream inputStream = file.getInputStream();
StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(),
FileTypeUtils.getExtension(file), null);
IoUtils.closeQuietly(inputStream);
return SysFile.builder().url(domain + "/" + storePath.getFullPath()).name(fileName).build();
}
@Override
public List<SysFile> uploadFiles(MultipartFile[] files) throws Exception {
List<SysFile> sysFiles = new ArrayList<>();
for (MultipartFile file : files) {
SysFile sysFile = uploadFile(file);
sysFiles.add(sysFile);
}
return sysFiles;
}
/**
* FastDfs文件下载接口待测试
*
* @param response 响应对象
* @param urlStr 文件URL地址
* @return 是否下载成功
*/
@Override
public void downloadFile(HttpServletResponse response, String urlStr) throws Exception
{
try {
String path = urlStr.replace(domain + "/", "");
StorePath storePath = StorePath.parseFromUrl(path);
// 下载文件并返回输入流
byte[] fileData = storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), IOUtils::toByteArray);
// 设置响应头
String encodedFileName = URLEncoder.encode(storePath.getPath(), StandardCharsets.UTF_8.toString());
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + storePath.getPath() + "\"");
// 将文件内容写入响应
IOUtils.write(fileData, response.getOutputStream());
response.flushBuffer();
} catch (Exception e) {
throw new Exception("Error occurred while downloading file from FastDfs" + urlStr, e);
}
}
/**
* FastDfs文件删除接口待测试
*
* @param urlStr 文件URL地址
* @return 是否删除成功
*/
@Override
public void deleteFile(String urlStr) throws Exception
{
try {
// URL 中提取文件路径
String path = urlStr.replace(domain + "/", "");
StorePath storePath = StorePath.parseFromUrl(path);
// 删除文件
storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
} catch (Exception e) {
throw new Exception("Error occurred while deleting file from FastDfs" + urlStr, e);
}
}
}

View File

@ -1,13 +1,21 @@
package com.bonus.file.utils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.file.FileUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;
/**
*
@ -20,37 +28,43 @@ public class FileDownloadUtils {
private final static String HTTPS_START_STR = "https://";
private final static String FTP_START_STR = "ftp:/";
public static boolean downloadFile(String urlStr, String destination) throws IOException {
public static boolean downloadFile(HttpServletResponse response,String urlStr) throws IOException {
if (urlStr.startsWith(HTTP_START_STR) || urlStr.startsWith(HTTPS_START_STR)) {
return downloadHttpFile(urlStr, destination);
return downloadHttpFile(response, urlStr);
} else if (urlStr.startsWith(FTP_START_STR)) {
return downloadFtpFile(urlStr, destination);
return downloadFtpFile(response, urlStr);
} else {
throw new IllegalArgumentException("Unsupported protocol: " + urlStr);
}
}
private static boolean downloadHttpFile(String urlStr, String destination) throws IOException {
private static boolean downloadHttpFile(HttpServletResponse response, String urlStr) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
com.bonus.file.utils.FileUtils.setResponseHeaderByUrl(response, urlStr);
try (InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(destination)) {
ServletOutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
System.out.println("HTTP download completed: " + destination);
} finally {
System.out.println("HTTP download completed: ");
} catch (Exception e) {
throw new IOException("没有找到文件");
}
finally {
connection.disconnect();
}
return true;
}
private static boolean downloadFtpFile(String urlStr, String destination) throws IOException {
private static boolean downloadFtpFile(HttpServletResponse response, String urlStr) throws IOException{
FTPClient ftpClient = new FTPClient();
try {
URL url = new URL(urlStr);
@ -67,8 +81,10 @@ public class FileDownloadUtils {
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
com.bonus.file.utils.FileUtils.setResponseHeaderByUrl(response, urlStr);
try (InputStream inputStream = ftpClient.retrieveFileStream(remoteFilePath);
FileOutputStream outputStream = new FileOutputStream(destination)) {
ServletOutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead = -1;
@ -77,11 +93,13 @@ public class FileDownloadUtils {
}
if (ftpClient.completePendingCommand()) {
System.out.println("FTP download completed: " + destination);
System.out.println("FTP download completed: ");
} else {
System.out.println("Failed to complete FTP download: " + destination);
System.out.println("Failed to complete FTP download: ");
}
}
} catch (Exception e) {
throw new IOException(e);
} finally {
ftpClient.logout();
ftpClient.disconnect();
@ -89,27 +107,62 @@ public class FileDownloadUtils {
return true;
}
// public static String replaceUrlPrefix(String originalUrl, String newPrefix) {
// // 使用正则表达式匹配 URL 中的 "statics" 及其之前的部分
// String regex = "^(.*?/statics)";
// return originalUrl.replaceFirst(regex, newPrefix);
// }
// public static void main(String[] args) {
// try {
// // 示例下载文件
// String httpUrl = "http://example.com/file.txt";
// String ftpUrl = "ftp://username:password@ftp.example.com/file.txt";
// String destination = "downloaded_file.txt";
// private static boolean downloadHttpFile(String urlStr, String destination) throws IOException {
// URL url = new URL(urlStr);
// HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// connection.setRequestMethod("GET");
//
// // 下载HTTP文件
// downloadFile(httpUrl, destination);
// try (InputStream inputStream = connection.getInputStream();
// FileOutputStream outputStream = new FileOutputStream(destination)) {
//
// // 下载FTP文件
// downloadFile(ftpUrl, destination);
//
// } catch (IOException ex) {
// ex.printStackTrace();
// byte[] buffer = new byte[4096];
// int bytesRead = -1;
// while ((bytesRead = inputStream.read(buffer)) != -1) {
// outputStream.write(buffer, 0, bytesRead);
// }
// System.out.println("HTTP download completed: " + destination);
// } finally {
// connection.disconnect();
// }
// return true;
// }
//
// private static boolean downloadFtpFile(String urlStr, String destination) throws IOException {
// FTPClient ftpClient = new FTPClient();
// try {
// URL url = new URL(urlStr);
// String host = url.getHost();
// int port = url.getPort() == -1 ? 21 : url.getPort();
// String userInfo = url.getUserInfo();
// String[] credentials = userInfo != null ? userInfo.split(":") : new String[]{"anonymous", ""};
// String username = credentials[0];
// String password = credentials.length > 1 ? credentials[1] : "";
// String remoteFilePath = url.getPath();
//
// ftpClient.connect(host, port);
// ftpClient.login(username, password);
// ftpClient.enterLocalPassiveMode();
// ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//
// try (InputStream inputStream = ftpClient.retrieveFileStream(remoteFilePath);
// FileOutputStream outputStream = new FileOutputStream(destination)) {
//
// byte[] buffer = new byte[4096];
// int bytesRead = -1;
// while ((bytesRead = inputStream.read(buffer)) != -1) {
// outputStream.write(buffer, 0, bytesRead);
// }
//
// if (ftpClient.completePendingCommand()) {
// System.out.println("FTP download completed: " + destination);
// } else {
// System.out.println("Failed to complete FTP download: " + destination);
// }
// }
// } finally {
// ftpClient.logout();
// ftpClient.disconnect();
// }
// return true;
// }
}

View File

@ -0,0 +1,39 @@
package com.bonus.file.utils;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.utils.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class FileUtils {
/**
* 获取文件名
*/
public static String setResponseHeaderByUrl(HttpServletResponse response, String url) {
String safeFileName = com.bonus.common.core.utils.file.FileUtils.getName(url);
if (!StringUtils.hasText(safeFileName)) {
response.setStatus(HttpStatus.BAD_REQUEST);
return null;
}
try {
String encodedFileName = URLEncoder.encode(safeFileName, StandardCharsets.UTF_8.toString());
if (encodedFileName == null) {
response.setStatus(HttpStatus.BAD_REQUEST);
return null;
}
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
return encodedFileName;
} catch (UnsupportedEncodingException e) {
response.setStatus(HttpStatus.BAD_REQUEST);
return null;
}
}
}

View File

@ -1,25 +1,28 @@
package com.bonus.obs.utils;
package com.bonus.file.utils;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.obs.config.ObsConfig;
import com.bonus.obs.domain.ObsInfo;
import com.bonus.file.config.ObsConfig;
import com.bonus.system.api.domain.SysFile;
import com.obs.services.ObsClient;
import com.obs.services.model.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.*;
import java.net.URLConnection;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* @author bonus
*/
@Service
@ConditionalOnProperty(name = "storage.type", havingValue = "obs")
public class ObsUtils {
@Resource
@ -45,10 +48,10 @@ public class ObsUtils {
* @param file 要上传的文件
* @return 上传结果
*/
public ObsInfo uploadFile(String objectKey, File file) {
public SysFile uploadFile(String objectKey, File file) {
if (file.length() < 100 * 1024 * 1024L) {
obsClient.putObject(obsConfig.getBucket(), objectKey, file);
return ObsInfo.builder().bucketName(obsConfig.getBucket()).name(FileUtils.getName(objectKey)).fileType(FileUtils.getName(objectKey).substring(FileUtils.getName(objectKey).lastIndexOf('.')).toLowerCase()).length(file.length()).path(objectKey).build();
return SysFile.builder().url(objectKey).build();
} else {
return multipartUploadFile(objectKey, file);
}
@ -62,7 +65,7 @@ public class ObsUtils {
* @param file 要上传的文件
* @return 上传结果
*/
public ObsInfo multipartUploadFile(String objectKey, File file) {
public SysFile multipartUploadFile(String objectKey, File file) {
// 创建一个固定大小为10的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
try {
@ -84,7 +87,7 @@ public class ObsUtils {
final int partNumber = i + 1;
final long offset = partSize * i;
final long size = Math.min(partSize, fileLength - offset);
Future<UploadPartResult> future = executorService.submit(() -> {
Future<com.obs.services.model.UploadPartResult> future = executorService.submit(() -> {
UploadPartRequest uploadPartRequest = new UploadPartRequest(
obsConfig.getBucket(),
objectKey,
@ -100,8 +103,8 @@ public class ObsUtils {
futures.add(future);
}
for (Future<UploadPartResult> future : futures) {
UploadPartResult uploadPartResult = future.get();
for (Future<com.obs.services.model.UploadPartResult> future : futures) {
com.obs.services.model.UploadPartResult uploadPartResult = future.get();
partETags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
}
@ -117,13 +120,7 @@ public class ObsUtils {
);
obsClient.completeMultipartUpload(completeRequest);
return ObsInfo.builder()
.bucketName(obsConfig.getBucket())
.name(FileUtils.getName(objectKey))
.fileType(FileUtils.getName(objectKey).substring(FileUtils.getName(objectKey).lastIndexOf('.')).toLowerCase())
.length(file.length())
.path(objectKey)
.build();
return SysFile.builder().url(objectKey).build();
} catch (Exception e) {
e.printStackTrace();
return null;
@ -139,7 +136,7 @@ public class ObsUtils {
* @param objectKey 文件在OBS中的键
*/
public R<ObsObject> downloadFile(String objectKey) {
if (!doesObjectExist(objectKey)) {
if (doesObjectExist(objectKey)) {
return R.fail("文件不存在");
}
return R.ok(obsClient.getObject(new GetObjectRequest(obsConfig.getBucket(), objectKey)));
@ -149,12 +146,14 @@ public class ObsUtils {
* 删除文件从OBS
*
* @param objectKey 文件在OBS中的键
* @return 如果删除成功则返回true否则返回false
*/
public R<DeleteObjectResult> deleteFile(String objectKey) {
if (!doesObjectExist(objectKey)) {
return R.fail("文件不存在");
public boolean deleteFile(String objectKey) throws Exception {
if (doesObjectExist(objectKey)) {
throw new Exception("文件不存在");
}
return R.ok(null, "文件删除成功");
obsClient.deleteObject(obsConfig.getBucket(), objectKey);
return true;
}
/**
@ -165,9 +164,9 @@ public class ObsUtils {
*/
public boolean doesObjectExist(String objectKey) {
try {
return obsClient.doesObjectExist(obsConfig.getBucket(), objectKey);
return !obsClient.doesObjectExist(obsConfig.getBucket(), objectKey);
} catch (Exception e) {
return false;
return true;
}
}

View File

@ -1,4 +1,4 @@
package com.bonus.oss.utils;
package com.bonus.file.utils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
@ -6,11 +6,12 @@ import com.aliyun.oss.model.*;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.text.Convert;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.oss.config.OSSConfig;
import com.bonus.oss.domain.OssInfo;
import com.bonus.file.config.OSSConfig;
import com.bonus.system.api.domain.SysFile;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@ -19,6 +20,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import com.bonus.system.api.domain.SysFile;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -29,6 +32,7 @@ import java.util.concurrent.Future;
* @author jiang
*/
@Service
@ConditionalOnProperty(name = "storage.type", havingValue = "oss")
public class OssUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(OssUtils.class);
@ -56,7 +60,7 @@ public class OssUtils {
* @param file 要上传的文件
* @return 包含上传文件信息的结果对象
*/
public R<OssInfo> upload(String objectKey, File file) {
public SysFile upload(String objectKey, File file) throws Exception {
try {
if (file.length() < 10 * 1024 * 1024L) {
ossClient.putObject(ossConfig.getBucket(), objectKey, file);
@ -64,10 +68,10 @@ public class OssUtils {
ossMultipartParallelUpload(objectKey, file);
}
return R.ok(getInfo(objectKey), "文件上传成功");
return getInfo(objectKey);
} catch (Exception e) {
LOGGER.error("文件上传失败", e);
return R.fail("文件上传失败");
return null;
} finally {
if (!file.delete()) {
LOGGER.warn("临时文件删除失败");
@ -151,18 +155,15 @@ public class OssUtils {
* @param objectKey 文件路径
* @return 文件信息对象
*/
public OssInfo getInfo(String objectKey) {
public SysFile getInfo(String objectKey) {
try {
ObjectMetadata objectMetadata = ossClient.getObjectMetadata(ossConfig.getBucket(), objectKey);
return OssInfo.builder()
return SysFile.builder()
.name(FileUtils.getName(objectKey))
.bucketName(ossConfig.getBucket())
.fileType(FileUtils.getName(objectKey).substring(FileUtils.getName(objectKey).lastIndexOf('.')).toLowerCase())
.length(Convert.toStr(objectMetadata.getContentLength()))
.path(objectKey).build();
.url(objectKey).build();
} catch (Exception e) {
LOGGER.error("获取文件信息失败", e);
return OssInfo.builder().build();
return SysFile.builder().build();
}
}
@ -172,15 +173,15 @@ public class OssUtils {
* @param objectKey 文件路径
* @return OSSObject对象包含下载的文件
*/
public R<OSSObject> download(String objectKey) {
public R<OSSObject> download(String objectKey) throws Exception {
if (doesObjectExist(ossConfig.getBucket(), objectKey)) {
return R.fail("文件不存在");
throw new Exception("文件不存在");
}
try {
return R.ok(ossClient.getObject(ossConfig.getBucket(), objectKey));
} catch (Exception e) {
LOGGER.error("文件下载失败", e);
return R.fail("文件下载失败");
throw new Exception("文件下载失败");
}
}
@ -190,16 +191,16 @@ public class OssUtils {
* @param objectKey 文件路径
* @return 删除操作的结果
*/
public R<T> delete(String objectKey) {
public boolean delete(String objectKey) throws Exception {
try {
if (doesObjectExist(ossConfig.getBucket(), objectKey)) {
return R.fail("文件不存在");
throw new Exception("删除文件时文件不存在");
}
ossClient.deleteObject(ossConfig.getBucket(), objectKey);
return R.ok(null, "文件删除成功");
return true;
} catch (Exception e) {
LOGGER.error("文件删除失败", e);
return R.fail("文件删除失败");
throw new Exception("删除文件时文件删除失败");
}
}
@ -210,12 +211,11 @@ public class OssUtils {
* @param objectKey 文件路径
* @return 如果文件存在返回true否则返回false
*/
private boolean doesObjectExist(String bucketName, String objectKey) {
private boolean doesObjectExist(String bucketName, String objectKey) throws Exception {
try {
return !ossClient.doesObjectExist(bucketName, objectKey);
} catch (Exception e) {
LOGGER.error("判断文件是否存在失败", e);
return true;
throw new Exception(e.getMessage());
}
}
}

View File

@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bonus</groupId>
<artifactId>bonus-modules</artifactId>
<version>24.8.0</version>
</parent>
<artifactId>bonus-modules-mongodb</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- FastDFS -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
<!-- Minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<!-- bonus Api System -->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-api-system</artifactId>
</dependency>
<!-- bonus Common Swagger -->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-common-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.12</version> <!-- 版本号可以根据需要调整 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,30 +0,0 @@
package com.bonus.mongodb;
import com.bonus.common.swagger.annotation.EnableCustomSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
*
*
* @author jiang
*/
@EnableCustomSwagger2
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class BonusMongodbApplication {
public static void main(String[] args)
{
SpringApplication.run(BonusMongodbApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ MongoDB存储服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -1,74 +0,0 @@
package com.bonus.mongodb.config;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.URLEncoder;
/**
* @author coisini
* @version 1.0
* @Description MongoDB配置类
* @date Apr 17, 2022
*/
@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
@Data
public class MongoConfig {
/**
* 数据库配置信息
*/
private String database;
private String host;
private Integer port;
private String username;
private String password;
/**移除静态修饰符避免单例模式
*
*/
private MongoClient mongoClient;
/** 使用@Bean注解并在方法内部进行异常处理
*
* @return
*/
@Bean
public MongoClient getMongoClient() {
if (mongoClient == null) {
try {
mongoClient = MongoClients.create(String.format("mongodb://%s:%s@%s:%d/%s", URLEncoder.encode(username, "UTF-8"),URLEncoder.encode(password, "UTF-8"), host, port, database));
} catch (Exception e) {
// 在实际应用中应该有更详细的异常处理策略例如记录日志并抛出自定义异常
throw new RuntimeException("Failed to create MongoClient", e);
}
}
return mongoClient;
}
/** 直接返回MongoDatabase实例依赖注入会处理实例的获取
*
* @return
*/
public MongoDatabase getMongoDatabase() {
return getMongoClient().getDatabase(database);
}
/** 创建GridFSBucket的@Bean方法依赖注入MongoDatabase
*
* @return
*/
@Bean
public GridFSBucket getGridFsBucket() {
return GridFSBuckets.create(getMongoDatabase());
}
}

View File

@ -1,80 +0,0 @@
package com.bonus.mongodb.controller;
import com.bonus.common.core.domain.R;
import com.bonus.mongodb.damain.FileExportVo;
import com.bonus.mongodb.service.MongodbService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
/**
*
*
* @author jiang
*/
@RestController
@RequestMapping("/mongodb/")
@Slf4j
public class MongodbController {
@Resource
private MongodbService mongodbService;
@ApiOperation(value = "单文件上传")
@PostMapping("uploadFile")
public R<FileExportVo> uploadFile(MultipartFile file) {
try {
FileExportVo fileExportVo = mongodbService.uploadFile(file);
return R.ok(fileExportVo);
} catch (Exception e) {
log.error("单文件上传", e);
return R.fail();
}
}
@ApiOperation(value = "多文件上传")
@PostMapping("uploadFiles")
public R<List<FileExportVo>> uploadFiles(MultipartFile[] files) {
try {
List<MultipartFile> multipartFiles = Arrays.asList(files);
List<FileExportVo> list = mongodbService.uploadFiles(multipartFiles);
return R.ok(list);
} catch (Exception e) {
log.error("多文件上传", e);
return R.fail();
}
}
@ApiOperation(value = "文件删除")
@PostMapping("delFile")
public R<T> delFile(String fileId) {
try {
mongodbService.removeFile(fileId);
return R.ok();
} catch (Exception e) {
log.error("文件删除", e);
return R.fail();
}
}
@ApiOperation(value = "获取文件base64")
@PostMapping("getFileBase64")
public R<byte[]> getFileBase64(String fileId) {
try {
FileExportVo fileExportVo = mongodbService.downloadFile(fileId);
return R.ok(fileExportVo.getData());
} catch (Exception e) {
log.error("获取文件base64", e);
return R.fail();
}
}
}

View File

@ -1,49 +0,0 @@
package com.bonus.mongodb.damain;
import java.io.Serializable;
import java.util.Objects;
import cn.hutool.core.bean.BeanUtil;
import lombok.Data;
/**
*
*
* @author jiang
*/
@Data
public class FileExportVo implements Serializable {
private String file;
private String fileId;
private String fileName;
private String contentType;
private String suffix;
private long fileSize;
private String sourceId;
private String id;
private String fileType;
/**
* 资源类型
*/
private String sourceType;
private String updaetTime;
private byte[] data;
public FileExportVo(MongoFile mongoFile) {
BeanUtil.copyProperties(mongoFile, this);
if (Objects.nonNull(mongoFile.getContent())) {
this.data = mongoFile.getContent().getData();
}
this.fileId = mongoFile.getId();
}
}

View File

@ -1,68 +0,0 @@
package com.bonus.mongodb.damain;
import lombok.Builder;
import lombok.Data;
import org.bson.types.Binary;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
*
*
* @author jiang
*/
@Builder
@Data
@Document(collection = "files")
public class MongoFile {
/**
* 主键
*/
@Id
public String id;
/**
* 文件名称
*/
public String fileName;
/**
* 文件大小
*/
public long fileSize;
/**
* 上传时间
*/
public String uploadDate;
/**
* MD5值
*/
public String md5;
/**
* 文件内容
*/
private Binary content;
/**
* 文件类型
*/
public String contentType;
/**
* 文件后缀名
*/
public String suffix;
/**
* 文件描述
*/
public String description;
/**
* 大文件管理GridFS的ID
*/
private String gridFsId;
}

View File

@ -1,13 +0,0 @@
package com.bonus.mongodb.repository;
import com.bonus.mongodb.damain.MongoFile;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
*
*
* @author jiang
*/
public interface MongoFileRepository extends MongoRepository<MongoFile, String> {
}

View File

@ -1,48 +0,0 @@
package com.bonus.mongodb.service;
import com.bonus.mongodb.damain.FileExportVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
*
*
* @author jiang
*/
public interface MongodbService {
/**
* 文件上传
*
* @param file
* @return FileExportVo
* @throws Exception
* @description
* @date 2024/3/11 15:44
*/
FileExportVo uploadFile(MultipartFile file) throws Exception;
/**
* 多文件上传
*
* @param files
* @return
*/
List<FileExportVo> uploadFiles(List<MultipartFile> files);
/**
* 文件下载
*
* @param fileId
* @return
*/
FileExportVo downloadFile(String fileId);
/**
* 文件删除
*
* @param fileId
*/
void removeFile(String fileId);
}

View File

@ -1,284 +0,0 @@
package com.bonus.mongodb.service.impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.mongodb.damain.FileExportVo;
import com.bonus.mongodb.damain.MongoFile;
import com.bonus.mongodb.repository.MongoFileRepository;
import com.bonus.mongodb.service.MongodbService;
import com.bonus.mongodb.utils.Md5Util;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.RequiredArgsConstructor;
import org.bson.types.Binary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
*
*
* @author jiang
*/
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MongodbServiceImpl implements MongodbService {
private static final Logger log = LoggerFactory.getLogger(MongodbServiceImpl.class);
private final MongoFileRepository mongoFileRepository;
private final MongoTemplate mongoTemplate;
private final GridFsTemplate gridFsTemplate;
private final GridFSBucket gridFSBucket;
private static final int MAX_SIZE = 16777216;
private static final String SUFFIX = ".";
/**
* 多文件上传
*
* @param files
* @return
*/
@Override
public List<FileExportVo> uploadFiles(List<MultipartFile> files) {
return files.stream().map(file -> {
try {
return this.uploadFile(file);
} catch (Exception e) {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
}
/**
* 文件上传
*
* @param file
* @return
* @throws Exception
*/
@Override
public FileExportVo uploadFile(MultipartFile file) throws Exception {
if (file.getSize() > MAX_SIZE) {
return this.saveGridFsFile(file);
} else {
return this.saveBinaryFile(file);
}
}
/**
* 文件下载
*
* @param fileId
* @return
*/
@Override
public FileExportVo downloadFile(String fileId) {
Optional<MongoFile> option = this.getBinaryFileById(fileId);
if (option.isPresent()) {
MongoFile mongoFile = option.get();
if (Objects.isNull(mongoFile.getContent())) {
option = this.getGridFsFileById(fileId);
}
}
return option.map(FileExportVo::new).orElse(null);
}
/**
* 文件删除
*
* @param fileId
*/
@Override
public void removeFile(String fileId) {
Optional<MongoFile> option = this.getBinaryFileById(fileId);
if (option.isPresent()) {
if (Objects.nonNull(option.get().getGridFsId())) {
this.removeGridFsFile(fileId);
} else {
this.removeBinaryFile(fileId);
}
}
}
/**
* 删除Binary文件
*
* @param fileId
*/
public void removeBinaryFile(String fileId) {
mongoFileRepository.deleteById(fileId);
}
/**
* 删除GridFs文件
*
* @param fileId
*/
public void removeGridFsFile(String fileId) {
// TODO 根据id查询文件
MongoFile mongoFile = mongoTemplate.findById(fileId, MongoFile.class);
if (Objects.nonNull(mongoFile)) {
// TODO 根据文件ID删除fs.files和fs.chunks中的记录
Query deleteFileQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId()));
gridFsTemplate.delete(deleteFileQuery);
// TODO 删除集合mongoFile中的数据
Query deleteQuery = new Query(Criteria.where("id").is(fileId));
mongoTemplate.remove(deleteQuery, MongoFile.class);
}
}
/**
* 保存Binary文件小文件
*
* @param file
* @return
* @throws Exception
*/
public FileExportVo saveBinaryFile(MultipartFile file) throws Exception {
String suffix = getFileSuffix(file);
MongoFile mongoFile = mongoFileRepository.save(
MongoFile.builder()
.fileName(file.getOriginalFilename())
.fileSize(file.getSize())
.content(new Binary(file.getBytes()))
.contentType(file.getContentType())
.uploadDate(DateUtils.getTime())
.suffix(suffix)
.md5(Md5Util.getMd5(file.getInputStream()))
.build()
);
return new FileExportVo(mongoFile);
}
/**
* 保存GridFs文件大文件
*
* @param file
* @return
* @throws Exception
*/
public FileExportVo saveGridFsFile(MultipartFile file) throws Exception {
String suffix = getFileSuffix(file);
String gridFsId = this.storeFileToGridFs(file.getInputStream(), file.getContentType());
MongoFile mongoFile = mongoTemplate.save(
MongoFile.builder()
.fileName(file.getOriginalFilename())
.fileSize(file.getSize())
.contentType(file.getContentType())
.uploadDate(DateUtils.getTime())
.suffix(suffix)
.md5(Md5Util.getMd5(file.getInputStream()))
.gridFsId(gridFsId)
.build()
);
return new FileExportVo(mongoFile);
}
/**
* 上传文件到Mongodb的GridFs中
*
* @param in
* @param contentType
* @return
*/
public String storeFileToGridFs(InputStream in, String contentType) throws IOException {
try {
String gridFsId = IdUtil.simpleUUID();
// TODO 将文件存储进GridFS中
gridFsTemplate.store(in, gridFsId, contentType);
return gridFsId;
}catch (Exception e){
log.error("上传文件到Mongodb的GridFs中失败",e);
}
finally {
in.close();
}
return null;
}
/**
* 获取Binary文件
*
* @param id
* @return
*/
public Optional<MongoFile> getBinaryFileById(String id) {
return mongoFileRepository.findById(id);
}
/**
* 获取Grid文件
*
* @param id
* @return
*/
public Optional<MongoFile> getGridFsFileById(String id) {
MongoFile mongoFile = mongoTemplate.findById(id, MongoFile.class);
if (Objects.nonNull(mongoFile)) {
Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId()));
try {
// TODO 根据id查询文件
GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
// TODO 打开流下载对象
GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId());
if (in.getGridFSFile().getLength() > 0) {
// TODO 获取流对象
GridFsResource resource = new GridFsResource(fsFile, in);
// TODO 获取数据
mongoFile.setContent(new Binary(IoUtil.readBytes(resource.getInputStream())));
return Optional.of(mongoFile);
} else {
return Optional.empty();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return Optional.empty();
}
/**
* 获取文件后缀
*
* @param file
* @return
*/
private String getFileSuffix(MultipartFile file) {
String suffix = "";
if (Objects.requireNonNull(file.getOriginalFilename()).contains(SUFFIX)) {
suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
}
return suffix;
}
}

View File

@ -1,37 +0,0 @@
package com.bonus.mongodb.utils;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author 10488
* @version 1.0
* @Description MD5工具类
* @date Apr 8, 2022
*/
public class Md5Util {
/**
* 获取该输入流的MD5值
*/
public static String getMd5(InputStream is) throws NoSuchAlgorithmException, IOException {
StringBuffer md5 = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = is.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
}
;
byte[] mdbytes = md.digest();
// convert the byte to hex format
for (int i = 0; i < mdbytes.length; i++) {
md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
is.close();
return md5.toString();
}
}

View File

@ -1,31 +0,0 @@
# Tomcat
server:
port: 9206
# Spring
spring:
servlet:
multipart:
max-file-size: 5GB
max-request-size: 5GB
application:
# 应用名称
name: bonus-mongodb
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.0.56:8848
namespace: f648524d-0a7b-449e-8f92-64e05236fd51
config:
# 配置中心地址
server-addr: 192.168.0.56:8848
namespace: f648524d-0a7b-449e-8f92-64e05236fd51
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/bonus-file" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.bonus" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

View File

@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bonus</groupId>
<artifactId>bonus-modules</artifactId>
<version>24.8.0</version>
</parent>
<artifactId>bonus-modules-obs</artifactId>
<description>
bonus-modules-obs存储服务
</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- FastDFS -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
<!-- Minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<!-- bonus Api System -->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-api-system</artifactId>
</dependency>
<!-- bonus Common Swagger -->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-common-swagger</artifactId>
</dependency>
<!-- huaweicloud obs -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
<version>3.23.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,30 +0,0 @@
package com.bonus.obs;
import com.bonus.common.swagger.annotation.EnableCustomSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
*
*
* @author jiang
*/
@EnableCustomSwagger2
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class BonusObsApplication {
public static void main(String[] args)
{
SpringApplication.run(BonusObsApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ obs存储服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -1,108 +0,0 @@
package com.bonus.obs.controller;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.obs.domain.ObsInfo;
import com.bonus.obs.service.ObsService;
import com.obs.services.model.DeleteObjectResult;
import com.obs.services.model.ObsObject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
*
*
* @author jiang
*/
@RestController
@RequestMapping("/obs")
public class ObsController {
@Resource
private ObsService service;
/**
* 文件上传
*
* @param file 文件流
* @return 文件信息
*/
@PostMapping("/uploadFile")
public R<ObsInfo> uploadFile(MultipartFile file) {
return service.uploadFile(file);
}
/**
* 删除文件从OBS
*
* @param objectKey 文件在OBS中的键
*/
@PostMapping("/deleteFile")
public R<DeleteObjectResult> deleteFile(String objectKey) {
return service.deleteFile(objectKey);
}
/**
* 文件下载
*
* @param objectKey obs文件存储地址
*/
@GetMapping("/downloadFile")
public void downloadFile(HttpServletResponse response, @RequestParam String objectKey) {
R<ObsObject> obsObjectR = service.downloadFile(objectKey);
try {
if (R.isError(obsObjectR)) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
if (obsObjectR.getData() == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
InputStream inputStream = obsObjectR.getData().getObjectContent();
String safeFileName = FileUtils.getFileNameFromPath(objectKey);
String encodedFileName = URLEncoder.encode(safeFileName, StandardCharsets.UTF_8.toString());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
try (OutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
} catch (IOException e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
} catch (IllegalArgumentException e) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
/**
* 文件上传
*
* @param files 文件流
* @return 文件信息
*/
@PostMapping("/uploadFiles")
public R<List<ObsInfo>> uploadFiles(MultipartFile[] files) {
return service.uploadFiles(files);
}
}

View File

@ -1,43 +0,0 @@
package com.bonus.obs.domain;
import lombok.Builder;
import lombok.Data;
/**
* OBSObject Storage Service信息类
* 用于封装与OBS对象相关的元数据信息
* @author jiang
*/
@Data
@Builder
public class ObsInfo {
/**
* 对象的名称
* 代表OBS对象的唯一标识
*/
private String name;
/**
* 对象在OBS中的存储路径
* 包含桶bucket名称和对象在桶内的相对路径
*/
private String path;
/**
* 对象的大小
* 以字符串形式表示可能包含单位如字节KBMB等
*/
private Long length;
/**
* 对象的文件类型
* 用于标识对象的MIME类型例如text/plainimage/jpeg等
*/
private String fileType;
/**
* 对象所属的桶bucket的名称
* 每个桶在OBS中都是唯一的用于存储对象
*/
private String bucketName;
}

View File

@ -1,50 +0,0 @@
package com.bonus.obs.service;
import com.bonus.common.core.domain.R;
import com.bonus.obs.domain.ObsInfo;
import com.obs.services.model.DeleteObjectResult;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PutObjectResult;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
*
*
* @author jiang
*/
public interface ObsService {
/**
* 文件上传
*
* @param file 文件流
* @return 文件信息
*/
R<ObsInfo> uploadFile(MultipartFile file);
/**
* 删除文件从OBS
*
* @param objectKey 文件在OBS中的键
* @return 返回一个包含删除操作结果的响应对象
*/
public R<DeleteObjectResult> deleteFile(String objectKey);
/**
* 下载文件从OBS
*
* @param objectKey 文件在OBS中的键
* @return 返回下载文件的结果
*/
public R<ObsObject> downloadFile(String objectKey);
/**
* 文件上传
*
* @param files 文件流
* @return 文件信息
*/
R<List<ObsInfo>> uploadFiles(MultipartFile[] files);
}

View File

@ -1,108 +0,0 @@
package com.bonus.obs.service.impl;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.obs.domain.ObsInfo;
import com.bonus.obs.service.ObsService;
import com.bonus.obs.utils.ObsUtils;
import com.obs.services.model.DeleteObjectResult;
import com.obs.services.model.ObsObject;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
*
*
* @author jiang
*/
@Service
public class ObsServiceImpl implements ObsService {
@Resource
private ObsUtils obsUtils;
/**
* 文件上传
*
* @param file 文件流
* @return 文件信息
*/
@Override
public R<ObsInfo> uploadFile(MultipartFile file) {
try {
String originalFilename = Objects.requireNonNull(file.getOriginalFilename(), "文件名不能为空");
String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
String objectKey = UuidUtils.generateUuid() + extension;
objectKey = FileUtils.generateObjectName(objectKey);
ObsInfo obsInfo = obsUtils.uploadFile(objectKey, FileUtils.multipartFileToFile(file));
return R.ok(obsInfo, "文件上传成功");
} catch (Exception e) {
return R.fail(e.getMessage());
}
}
/**
* 删除文件从OBS
*
* @param objectKey 文件在OBS中的键
*/
@Override
public R<DeleteObjectResult> deleteFile(String objectKey) {
return obsUtils.deleteFile(objectKey);
}
/**
* 下载文件从OBS
*
* @param objectKey 文件在OBS中的键
*/
@Override
public R<ObsObject> downloadFile(String objectKey) {
return obsUtils.downloadFile(objectKey);
}
/**
* 文件上传
*
* @param files 文件流
* @return 文件信息
*/
@Override
public R<List<ObsInfo>> uploadFiles(MultipartFile[] files) {
// 调整线程池大小
int threadPoolSize = 10;
ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
try {
List<Future<ObsInfo>> futures = new ArrayList<>();
for (MultipartFile multipartFile : files) {
futures.add(executorService.submit(() -> {
String originalFilename = Objects.requireNonNull(multipartFile.getOriginalFilename(), "文件名不能为空");
String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
String objectKey = UuidUtils.generateUuid() + extension;
objectKey = FileUtils.generateObjectName(objectKey);
return obsUtils.uploadFile(objectKey, FileUtils.multipartFileToFile(multipartFile));
}));
}
List<ObsInfo> obsInfos = futures.stream().map(future -> {
try {
return future.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
return R.ok(obsInfos, "文件上传成功");
} catch (Exception e) {
return R.fail("File upload failed.");
}
}
}

View File

@ -1,31 +0,0 @@
# Tomcat
server:
port: 9205
# Spring
spring:
servlet:
multipart:
max-file-size: 5GB
max-request-size: 5GB
application:
# 应用名称
name: bonus-obs
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.0.56:8848
namespace: 9cde1ce1-98bc-4b9c-9213-f1fbf8a5b3cc
config:
# 配置中心地址
server-addr: 192.168.0.56:8848
namespace: 9cde1ce1-98bc-4b9c-9213-f1fbf8a5b3cc
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/bonus-file" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.bonus" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bonus</groupId>
<artifactId>bonus-modules</artifactId>
<version>24.8.0</version>
</parent>
<artifactId>bonus-oss</artifactId>
<description>
bonus-modules-oss存储服务
</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- FastDFS -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
<!-- bonus Common Swagger -->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-common-swagger</artifactId>
</dependency>
<!--阿里云oss 存储-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,30 +0,0 @@
package com.bonus.oss;
import com.bonus.common.swagger.annotation.EnableCustomSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
*
*
* @author jiang
*/
@EnableCustomSwagger2
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class BonusOssApplication {
public static void main(String[] args)
{
SpringApplication.run(BonusOssApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ oss存储服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -1,112 +0,0 @@
package com.bonus.oss.controller;
import com.aliyun.oss.model.OSSObject;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.oss.domain.OssInfo;
import com.bonus.oss.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/oss")
public class OssController {
@Resource
private OssService ossService;
/**
* 文件上传
*
* @param file 文件流
* @return 文件信息
*/
@PostMapping("/uploadFile")
public R<OssInfo> uploadFile(MultipartFile file) {
return ossService.uploadFile(file);
}
/**
* 文件上传
*
* @param files 文件流
* @return 文件信息
*/
@PostMapping("/uploadFiles")
public R<List<OssInfo>> uploadFiles(MultipartFile[] files) {
return ossService.uploadFiles(files);
}
/**
* 文件下载
*
* @param objectKey oss文件存储地址
*/
@GetMapping("/downloadFile")
public void downloadFile(HttpServletResponse response, @RequestParam String objectKey) throws UnsupportedEncodingException {
R<OSSObject> ossObjectR = ossService.downloadFile(objectKey);
if (ossObjectR.getData() == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
OSSObject ossObject = ossObjectR.getData();
String safeFileName = FileUtils.getName(objectKey); // 假设这个方法进行了恰当的文件名清理和验证
if (!StringUtils.hasText(safeFileName)) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
String encodedFileName = URLEncoder.encode(safeFileName, StandardCharsets.UTF_8.toString());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
try (InputStream inputStream = ossObject.getObjectContent();
OutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
} catch (IOException e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
} catch (IllegalArgumentException e) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
} catch (Exception e) {
// 记录异常信息到日志
log.error("文件下载过程中出现未知异常,原因是:", e);
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
/**
* 文件删除
*
* @param objectKey 文件路径
* @return 删除结果
*/
@PostMapping("/deleteFile")
public R<T> deleteFile(@RequestParam String objectKey) {
return ossService.deleteFile(objectKey);
}
}

View File

@ -1,46 +0,0 @@
package com.bonus.oss.domain;
import lombok.Builder;
import lombok.Data;
/**
* OssInfo类用于封装OSSObject Storage Service对象的相关信息
* 通过此类可以方便地管理和访问OSS对象的元数据如名称路径大小等
*
*
* @author jiang
*/
@Builder
@Data
public class OssInfo {
/**
* 文件或对象的名称
* 用于唯一标识OSS中的一个对象
*/
private String name;
/**
* 文件在OSS中的存储路径
* 该路径不包含Bucket名称仅指对象在Bucket内的相对路径
*/
private String path;
/**
* 文件或对象的大小
* 以字符串形式表示单位可能为字节KBMB等
*/
private String length;
/**
* 文件的类型
* 可以是文件的MIME类型或者根据文件扩展名推测的类型
*/
private String fileType;
/**
* 存储文件的Bucket名称
* Bucket是OSS中用于存储对象的容器每个对象必须属于某个Bucket
*/
private String bucketName;
}

View File

@ -1,46 +0,0 @@
package com.bonus.oss.service;
import com.aliyun.oss.model.OSSObject;
import com.bonus.common.core.domain.R;
import com.bonus.oss.domain.OssInfo;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* @author jiang
*/
public interface OssService {
/**
* 文件上传
*
* @param param 文件流
* @return 文件信息
*/
R<OssInfo> uploadFile(MultipartFile param);
/**
* 文件下载
*
* @param objectKey oss文件存储地址
* @return OSSObject对象
*/
R<OSSObject> downloadFile(String objectKey);
/**
* 文件删除
*
* @param objectKey oss文件存储地址
* @return 操作结果
*/
R<T> deleteFile(String objectKey);
/**
* 多文件上传
*
* @param files 文件流
* @return 文件信息
*/
R<List<OssInfo>> uploadFiles(MultipartFile[] files);
}

View File

@ -1,120 +0,0 @@
package com.bonus.oss.service.impl;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.aliyun.oss.model.OSSObject;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.file.FileUtils;
import com.bonus.oss.domain.OssInfo;
import com.bonus.oss.service.OssService;
import com.bonus.oss.utils.OssUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
* @author jiang
*/
@Service
public class OssServiceImpl implements OssService {
@Resource
private OssUtils ossUtils;
/**
* 文件上传
*
* @param file 文件流
* @return 文件信息
*/
@Override
public R<OssInfo> uploadFile(MultipartFile file) {
if (ObjectUtils.isEmpty(file)) {
return R.fail("File is null.");
}
try {
String originalFilename = Objects.requireNonNull(file.getOriginalFilename(), "文件名不能为空");
String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
String objectKey = UuidUtils.generateUuid() + extension;
objectKey = FileUtils.generateObjectName(objectKey);
return ossUtils.upload(objectKey, FileUtils.multipartFileToFile(file));
} catch (Exception e) {
return R.fail("File upload failed.");
}
}
/**
* 文件下载
*
* @param objectKey oss文件存储地址
*/
@Override
public R<OSSObject> downloadFile(String objectKey) {
if (ObjectUtils.isEmpty(objectKey)) {
return R.fail("objectKey is null.");
}
return ossUtils.download(objectKey);
}
/**
* 文件删除
*
* @param objectKey oss文件存储地址
*/
@Override
public R<T> deleteFile(String objectKey) {
try {
if (ObjectUtils.isNotEmpty(objectKey)) {
return ossUtils.delete(objectKey);
} else {
return R.fail("objectKey is null.");
}
} catch (Exception e) {
return R.fail("File delete failed.");
}
}
/**
* 多文件上传
*
* @param files 文件流
* @return 文件信息
*/
@Override
public R<List<OssInfo>> uploadFiles(MultipartFile[] files) {
// 调整线程池大小
int threadPoolSize = 10;
ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
try {
List<Future<OssInfo>> futures = new ArrayList<>();
for (MultipartFile multipartFile : files) {
futures.add(executorService.submit(() -> {
String originalFilename = Objects.requireNonNull(multipartFile.getOriginalFilename(), "文件名不能为空");
String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
String objectKey = UuidUtils.generateUuid() + extension;
objectKey = FileUtils.generateObjectName(objectKey);
return ossUtils.upload(objectKey, FileUtils.multipartFileToFile(multipartFile)).getData();
}));
}
List<OssInfo> obsInfos = futures.stream().map(future -> {
try {
return future.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
return R.ok(obsInfos, "文件上传成功");
} catch (Exception e) {
return R.fail("File upload failed.");
}
}
}

View File

@ -1,30 +0,0 @@
# Tomcat
server:
port: 9204
# Spring
spring:
servlet:
multipart:
max-file-size: 5GB
max-request-size: 5GB
application:
# 应用名称
name: bonus-oss
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.0.56:8848
namespace: 9cde1ce1-98bc-4b9c-9213-f1fbf8a5b3cc
config:
# 配置中心地址
server-addr: 192.168.0.56:8848
namespace: 9cde1ce1-98bc-4b9c-9213-f1fbf8a5b3cc
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/bonus-file" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.bonus" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

View File

@ -6,7 +6,6 @@ import javax.servlet.http.HttpServletResponse;
import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType;
import com.bonus.system.api.domain.SysDictData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;

View File

@ -5,6 +5,7 @@ import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.system.api.domain.SysLogsVo;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;

View File

@ -13,9 +13,6 @@
<module>bonus-gen</module>
<module>bonus-job</module>
<module>bonus-file</module>
<module>bonus-oss</module>
<module>bonus-obs</module>
<module>bonus-mongodb</module>
</modules>
<artifactId>bonus-modules</artifactId>