oss 文件操作

This commit is contained in:
Github_lizhw 2026-01-08 23:05:39 +08:00
parent 3d47accfeb
commit 552d9b4ca3
2 changed files with 312 additions and 0 deletions

View File

@ -0,0 +1,200 @@
package com.luban.api.s3.ctrl;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
import org.liuxp.minioplus.api.StorageService;
import org.liuxp.minioplus.api.model.vo.CompleteResultVo;
import org.liuxp.minioplus.api.model.vo.FileCheckResultVo;
import org.liuxp.minioplus.api.model.vo.FilePreShardingVo;
import org.liuxp.minioplus.common.enums.MinioPlusErrorCode;
import org.liuxp.minioplus.common.enums.StorageBucketEnums;
import org.liuxp.minioplus.common.exception.MinioPlusException;
import org.liuxp.minioplus.extension.context.Response;
import org.liuxp.minioplus.extension.context.UserHolder;
import org.liuxp.minioplus.extension.dto.FileCheckDTO;
import org.liuxp.minioplus.extension.dto.FileCompleteDTO;
import org.liuxp.minioplus.extension.dto.PreShardingDTO;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.ByteArrayInputStream;
import java.net.URI;
/**
* 对象存储标准接口定义
* 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me
* @since 2024/6/18
*/
@Slf4j
@Controller
@RequestMapping("storage2")
public class Storage2Controller implements StorageWebAPI {
/**
* 存储引擎Service接口定义
*/
private final StorageService storageService;
/**
* 构造方法
*
* @param storageService 注入存储引擎Service接口定义实现类
*/
public Storage2Controller(StorageService storageService) {
this.storageService = storageService;
}
/**
* 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果
*/
@Override
public Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO) {
FilePreShardingVo resultVo = storageService.sharding(preShardingDTO.getFileSize());
return Response.success(resultVo);
}
/**
* 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参
* @return 检查结果
*/
@Override
public Response<FileCheckResultVo> init(FileCheckDTO fileCheckDTO) {
// 取得当前登录用户信息
String userId = UserHolder.get();
FileCheckResultVo resultVo = storageService.init(fileCheckDTO.getFileMd5(), fileCheckDTO.getFullFileName(), fileCheckDTO.getFileSize(), fileCheckDTO.getIsPrivate(), userId);
return Response.success(resultVo);
}
/**
* 文件上传完成
*
* @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功
*/
@Override
public Response<Object> complete(String fileKey, FileCompleteDTO fileCompleteDTO) {
// 取得当前登录用户信息
String userId = UserHolder.get();
// 打印调试日志
log.debug("合并文件开始fileKey=" + fileKey + ",partMd5List=" + fileCompleteDTO.getPartMd5List());
CompleteResultVo completeResultVo = storageService.complete(fileKey, fileCompleteDTO.getPartMd5List(), userId);
return Response.success(completeResultVo);
}
/**
* 文件下载
*
* @param fileKey 文件KEY
* @return 文件下载地址
*/
@Override
public ResponseEntity<Void> download(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(storageService.download(fileKey, userId)));
return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER);
}
/**
* 获取图像
*
* @param fileKey 文件KEY
* @return 原图地址
*/
@Override
public ResponseEntity<Void> previewOriginal(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
// 取得文件读取路径
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(storageService.download(fileKey, userId)));
return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER);
}
/**
* 文件预览
* 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY
* @return 缩略图地址
*/
@Override
public ResponseEntity<Void> previewMedium(String fileKey) {
// 取得当前登录用户信息
String userId = UserHolder.get();
String url = storageService.preview(fileKey, userId);
if (url.length() < 10) {
// 当返回值为文件类型时取得图标
url = ICON_PATH + url;
}
// 取得文件读取路径
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(url));
return new ResponseEntity<>(headers, HttpStatus.SEE_OTHER);
}
/**
* 根据文件类型取得图标
*
* @param fileType 文件扩展名
*/
@Override
public void icon(String fileType) {
try {
// 根据文件后缀取得桶
String storageBucket = StorageBucketEnums.getBucketByFileSuffix(fileType, "");
ClassPathResource cpr = new ClassPathResource(storageBucket + ".png");
byte[] bytes = FileCopyUtils.copyToByteArray(cpr.getInputStream());
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
attr.getResponse().setHeader("content-disposition", "inline");
attr.getResponse().setHeader("Content-Length", String.valueOf(bytes.length));
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
IoUtil.copy(inputStream, attr.getResponse().getOutputStream());
}
} catch (Exception e) {
log.error(MinioPlusErrorCode.FILE_ICON_FAILED.getMessage(), e);
// 图标获取失败
throw new MinioPlusException(MinioPlusErrorCode.FILE_ICON_FAILED);
}
}
}

View File

@ -0,0 +1,112 @@
package com.luban.api.s3.ctrl;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.liuxp.minioplus.api.model.vo.FileCheckResultVo;
import org.liuxp.minioplus.api.model.vo.FilePreShardingVo;
import org.liuxp.minioplus.extension.context.Response;
import org.liuxp.minioplus.extension.dto.FileCheckDTO;
import org.liuxp.minioplus.extension.dto.FileCompleteDTO;
import org.liuxp.minioplus.extension.dto.PreShardingDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 对象存储标准接口定义
* 本类的方法是给前端使用的方法
*
* @author contact@liuxp.me
* @since 2024/6/18
*/
@Tag(name = "MinIO Plus 接口")
public interface StorageWebAPI {
/**
* 请求地址前缀
*/
String ROOT_PATH = "/storage";
/**
* 图标请求地址
*/
String ICON_PATH = "/storage/icon/";
/**
* 文件预分片方法
* 在大文件上传时为了防止前端重复计算文件MD5值提供该方法
*
* @param preShardingDTO 文件预分片入参DTO
* @return 预分片结果
*/
@Operation(summary = "文件预分片")
@PostMapping("/upload/sharding")
@ResponseBody
Response<FilePreShardingVo> sharding(@RequestBody @Validated PreShardingDTO preShardingDTO);
/**
* 上传任务初始化
* 上传前的预检查秒传分块上传和断点续传等特性均基于该方法实现
*
* @param fileCheckDTO 文件预检查入参
* @return 检查结果
*/
@Operation(summary = "上传任务初始化")
@PostMapping("/upload/init")
@ResponseBody
Response<FileCheckResultVo> init(@RequestBody @Validated FileCheckDTO fileCheckDTO);
/**
* 文件上传完成
*
* @param fileKey 文件KEY
* @param fileCompleteDTO 文件完成入参DTO
* @return 是否成功
*/
@Operation(summary = "上传完成")
@PostMapping("/upload/complete/{fileKey}")
@ResponseBody
Response<Object> complete(@PathVariable("fileKey") String fileKey, @RequestBody FileCompleteDTO fileCompleteDTO);
/**
* 文件下载
*
* @param fileKey 文件KEY
* @return 文件下载地址
*/
@Operation(summary = "文件下载")
@GetMapping("/download/{fileKey}")
ResponseEntity<Void> download(@PathVariable("fileKey") String fileKey);
/**
* 获取图像
*
* @param fileKey 文件KEY
* @return 原图地址
*/
@Operation(summary = "图片预览 - 原图")
@GetMapping("/image/{fileKey}")
ResponseEntity<Void> previewOriginal(@PathVariable("fileKey") String fileKey);
/**
* 文件预览
* 当文件为图片时返回图片的缩略图
* 当文件不是图片时返回文件类型图标
*
* @param fileKey 文件KEY
* @return 缩略图地址
*/
@Operation(summary = "图片预览 - 缩略图")
@GetMapping("/preview/{fileKey}")
ResponseEntity<Void> previewMedium(@PathVariable("fileKey") String fileKey);
/**
* 根据文件类型取得图标
*
* @param fileType 文件扩展名
*/
@Operation(summary = "获取图标")
@GetMapping("/icon/{fileType}")
void icon(@PathVariable("fileType") String fileType);
}