update 删除源ruoyi-oss模块,使用x-file-storage重新新模块ruoyi-file,支持大文件分片上传,并开发前端文件和图片上传组件
parent
6ed2c7c601
commit
78b7bac43b
File diff suppressed because one or more lines are too long
@ -1,56 +1,67 @@
|
|||||||
package com.ruoyi.web.controller;
|
package com.ruoyi.web.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.ruoyi.common.annotation.Dev;
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
import com.ruoyi.common.core.domain.R;
|
import com.ruoyi.common.core.domain.R;
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.system.service.ISysOssService;
|
import com.ruoyi.file.FileService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public class UploadController {
|
public class UploadController {
|
||||||
private final ISysOssService iSysOssService;
|
|
||||||
|
|
||||||
|
private final FileService fileService;
|
||||||
|
|
||||||
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
|
|
||||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
||||||
public R upload(@RequestPart("file") MultipartFile file, String pre) {
|
|
||||||
if (ObjectUtil.isNull(file)) {
|
|
||||||
throw new ServiceException("文件为空");
|
|
||||||
}
|
|
||||||
return R.ok(iSysOssService.upload(file, pre));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
|
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
|
||||||
@PostMapping(value = "/uploadImg", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
public R uploadImg(@RequestPart("file") MultipartFile file, String pre) {
|
public R upload(@RequestPart("file") MultipartFile file, String pre) {
|
||||||
if (ObjectUtil.isNull(file)) {
|
if (ObjectUtil.isNull(file)) {
|
||||||
throw new ServiceException("文件为空");
|
throw new ServiceException("文件为空");
|
||||||
}
|
|
||||||
if(!file.getContentType().startsWith("image/")){
|
|
||||||
throw new ServiceException("不是图片");
|
|
||||||
}
|
|
||||||
return R.ok(iSysOssService.uploadImgs(file, pre));
|
|
||||||
}
|
}
|
||||||
|
// return R.ok(iSysOssService.upload(file, pre));
|
||||||
|
return R.ok(fileService.setPrefix(pre).save(file));//TODO: fileService
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
|
||||||
* 下载OSS对象
|
@PostMapping(value = "/uploadImg", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
*
|
public R uploadImg(@RequestPart("file") MultipartFile file, String pre) {
|
||||||
* @param ossId OSS对象ID
|
if (ObjectUtil.isNull(file)) {
|
||||||
*/
|
throw new ServiceException("文件为空");
|
||||||
@PostMapping("/download/{ossId}")
|
}
|
||||||
public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
|
if (!file.getContentType().startsWith("image/")) {
|
||||||
iSysOssService.download(ossId, response);
|
throw new ServiceException("不是图片");
|
||||||
}
|
}
|
||||||
|
// return R.ok(iSysOssService.uploadImgs(file, pre));
|
||||||
|
|
||||||
|
return R.ok(fileService.setPrefix(pre).setThumbnail().saveImage(file));//TODO: fileService
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@PostMapping("/download")
|
||||||
|
public ModelAndView download(String url, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
// iSysOssService.download(ossId, response);
|
||||||
|
fileService.download(url, Duration.ofMinutes(30), request, response);//TODO: fileService
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,105 +0,0 @@
|
|||||||
package com.ruoyi.web.controller.system;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
|
||||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
|
||||||
import com.ruoyi.common.core.domain.PageQuery;
|
|
||||||
import com.ruoyi.common.core.domain.R;
|
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
|
||||||
import com.ruoyi.common.core.validate.AddGroup;
|
|
||||||
import com.ruoyi.common.core.validate.EditGroup;
|
|
||||||
import com.ruoyi.common.core.validate.QueryGroup;
|
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
|
||||||
import com.ruoyi.system.domain.bo.SysOssConfigBo;
|
|
||||||
import com.ruoyi.system.domain.vo.SysOssConfigVo;
|
|
||||||
import com.ruoyi.system.service.ISysOssConfigService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储配置
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
* @author 孤舟烟雨
|
|
||||||
* @date 2021-08-13
|
|
||||||
*/
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/system/oss/config")
|
|
||||||
public class SysOssConfigController extends BaseController {
|
|
||||||
|
|
||||||
private final ISysOssConfigService iSysOssConfigService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询对象存储配置列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:list")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) {
|
|
||||||
return iSysOssConfigService.queryPageList(bo, pageQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对象存储配置详细信息
|
|
||||||
*
|
|
||||||
* @param ossConfigId OSS配置ID
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:query")
|
|
||||||
@GetMapping("/{ossConfigId}")
|
|
||||||
public R<SysOssConfigVo> getInfo(@NotNull(message = "主键不能为空")
|
|
||||||
@PathVariable Long ossConfigId) {
|
|
||||||
return R.ok(iSysOssConfigService.queryById(ossConfigId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增对象存储配置
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:add")
|
|
||||||
@Log(title = "对象存储配置", businessType = BusinessType.INSERT)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PostMapping()
|
|
||||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
|
|
||||||
return toAjax(iSysOssConfigService.insertByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改对象存储配置
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:edit")
|
|
||||||
@Log(title = "对象存储配置", businessType = BusinessType.UPDATE)
|
|
||||||
@RepeatSubmit()
|
|
||||||
@PutMapping()
|
|
||||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
|
|
||||||
return toAjax(iSysOssConfigService.updateByBo(bo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除对象存储配置
|
|
||||||
*
|
|
||||||
* @param ossConfigIds OSS配置ID串
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:remove")
|
|
||||||
@Log(title = "对象存储配置", businessType = BusinessType.DELETE)
|
|
||||||
@DeleteMapping("/{ossConfigIds}")
|
|
||||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
|
||||||
@PathVariable Long[] ossConfigIds) {
|
|
||||||
return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 状态修改
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:edit")
|
|
||||||
@Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE)
|
|
||||||
@PutMapping("/changeStatus")
|
|
||||||
public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {
|
|
||||||
return toAjax(iSysOssConfigService.updateOssConfigStatus(bo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
package com.ruoyi.web.controller.system;
|
|
||||||
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.http.HttpException;
|
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
|
||||||
import com.ruoyi.common.core.domain.PageQuery;
|
|
||||||
import com.ruoyi.common.core.domain.R;
|
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
|
||||||
import com.ruoyi.common.core.validate.QueryGroup;
|
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
|
||||||
import com.ruoyi.common.utils.file.FileUtils;
|
|
||||||
import com.ruoyi.oss.core.OssClient;
|
|
||||||
import com.ruoyi.oss.factory.OssFactory;
|
|
||||||
import com.ruoyi.system.domain.SysOss;
|
|
||||||
import com.ruoyi.system.domain.bo.SysOssBo;
|
|
||||||
import com.ruoyi.system.domain.vo.SysOssVo;
|
|
||||||
import com.ruoyi.system.service.ISysOssService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传 控制层
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Validated
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/system/oss")
|
|
||||||
public class SysOssController extends BaseController {
|
|
||||||
|
|
||||||
private final ISysOssService iSysOssService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询OSS对象存储列表
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:list")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) {
|
|
||||||
return iSysOssService.queryPageList(bo, pageQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询OSS对象基于id串
|
|
||||||
*
|
|
||||||
* @param ossIds OSS对象ID串
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:list")
|
|
||||||
@GetMapping("/listByIds/{ossIds}")
|
|
||||||
public R<List<SysOssVo>> listByIds(@NotEmpty(message = "主键不能为空")
|
|
||||||
@PathVariable Long[] ossIds) {
|
|
||||||
List<SysOssVo> list = iSysOssService.listByIds(Arrays.asList(ossIds));
|
|
||||||
return R.ok(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传OSS对象存储
|
|
||||||
*
|
|
||||||
* @param file 文件
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:upload")
|
|
||||||
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
|
|
||||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
||||||
public R<Map<String, String>> upload(@RequestPart("file") MultipartFile file) {
|
|
||||||
if (ObjectUtil.isNull(file)) {
|
|
||||||
throw new ServiceException("上传文件不能为空");
|
|
||||||
}
|
|
||||||
SysOssVo oss = iSysOssService.upload(file);
|
|
||||||
Map<String, String> map = new HashMap<>(2);
|
|
||||||
map.put("url", oss.getUrl());
|
|
||||||
map.put("fileName", oss.getOriginalName());
|
|
||||||
map.put("ossId", oss.getOssId().toString());
|
|
||||||
return R.ok(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载OSS对象
|
|
||||||
*
|
|
||||||
* @param ossId OSS对象ID
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:download")
|
|
||||||
@GetMapping("/download/{ossId}")
|
|
||||||
public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
|
|
||||||
iSysOssService.download(ossId,response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除OSS对象存储
|
|
||||||
*
|
|
||||||
* @param ossIds OSS对象ID串
|
|
||||||
*/
|
|
||||||
@SaCheckPermission("system:oss:remove")
|
|
||||||
@Log(title = "OSS对象存储", businessType = BusinessType.DELETE)
|
|
||||||
@DeleteMapping("/{ossIds}")
|
|
||||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
|
||||||
@PathVariable Long[] ossIds) {
|
|
||||||
return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,201 @@
|
|||||||
|
package com.ruoyi.test;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.HexUtil;
|
||||||
|
import com.ruoyi.TestSuper;
|
||||||
|
import com.ruoyi.file.FileService;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.dromara.x.file.storage.core.FileInfo;
|
||||||
|
import org.dromara.x.file.storage.core.FileStorageService;
|
||||||
|
import org.dromara.x.file.storage.core.tika.TikaFactory;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class XFileStorageTest extends TestSuper {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FileStorageService fileStorageService;//注入实列
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FileService fileService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TikaFactory tikaFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public InputStream getInstream() {
|
||||||
|
return this.getClass().getResourceAsStream("/test.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("分片上传")
|
||||||
|
@Disabled
|
||||||
|
@SneakyThrows
|
||||||
|
public void testMultipartUpload() {
|
||||||
|
File file = new File("D:\\test.mp4");
|
||||||
|
String uploadId = fileService.setPlatform("aliyun").setUri("/test.mp4").multipartUploadInit();
|
||||||
|
try (
|
||||||
|
InputStream in = new FileInputStream(file);
|
||||||
|
) {
|
||||||
|
byte[] bs = new byte[5 * 1024 * 1024];//每一片5MB
|
||||||
|
int len = 0;
|
||||||
|
int partNumber = 0;
|
||||||
|
try {
|
||||||
|
while ((len = in.read(bs)) > 0) {
|
||||||
|
partNumber++;
|
||||||
|
ByteArrayInputStream bin = new ByteArrayInputStream(bs, 0, len);
|
||||||
|
fileService.multipartUpload(uploadId, partNumber, bin);
|
||||||
|
out("上传分片成功:" + partNumber + " len:" + len);
|
||||||
|
|
||||||
|
}
|
||||||
|
out("分片上传成功:" + fileService.multipartUploadComplete(uploadId));
|
||||||
|
} catch (Exception e) {
|
||||||
|
out("分片上传失败", e);
|
||||||
|
fileService.multipartUploadAbort(uploadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("分片上传")
|
||||||
|
@Disabled
|
||||||
|
@SneakyThrows
|
||||||
|
public void testMultipartUpload1() {
|
||||||
|
File file = new File("D:\\test.mp4");//文件大概6M
|
||||||
|
// File file = new File("D:\\VMware-images\\CentOS-7-x86_64-Minimal-2009.iso");;//900M+
|
||||||
|
FileInfo fileInfo = fileStorageService.initiateMultipartUpload().setPlatform("aliyun").setPath("default/").setSaveFilename(file.getName()).init();
|
||||||
|
try (
|
||||||
|
InputStream in = new FileInputStream(file);
|
||||||
|
) {
|
||||||
|
byte[] bs = new byte[5 * 1024 * 1024];//每一片5MB
|
||||||
|
int len = 0;
|
||||||
|
int partNumber = 1;
|
||||||
|
try {
|
||||||
|
while ((len = in.read(bs)) > 0) {
|
||||||
|
partNumber++;
|
||||||
|
ByteArrayInputStream bin = new ByteArrayInputStream(bs, 0, len);
|
||||||
|
fileStorageService.uploadPart(fileInfo, partNumber, bin).upload();
|
||||||
|
out("上传分片成功:" + partNumber + " len:" + len);
|
||||||
|
|
||||||
|
}
|
||||||
|
out("分片上传成功:" + fileStorageService.completeMultipartUpload(fileInfo).complete().getUrl());
|
||||||
|
} catch (Exception e) {
|
||||||
|
out("分片上传失败", e);
|
||||||
|
fileStorageService.abortMultipartUpload(fileInfo).abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("读取配置信息")
|
||||||
|
public void testConfig() throws Exception {
|
||||||
|
out(fileStorageService.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("保存文件")
|
||||||
|
@SneakyThrows
|
||||||
|
public void saveTest() {
|
||||||
|
// out("保存随机文件名:" + fileService.setFilename("test.png").save(getInstream()));
|
||||||
|
// out("保存文件名:" + fileService.setKeepFilename().setFilename("test.png").save(getInstream()));
|
||||||
|
// out("指定保存规则:" + fileService.setFilename("test.png").setRule("/{yyyy}/{MM}/{dd}/{id}.{ext}").save(getInstream()));
|
||||||
|
out("指定保存路径:" + fileService.setUri("/aa/bb/cc/a.png").save(getInstream()));
|
||||||
|
out("aliyun指定保存路径:" + fileService.setPlatform("aliyun").setUri("/aa/bb/cc/a.png").save(getInstream()));
|
||||||
|
out("local指定保存路径:" + fileService.setPlatform("local").setUri("/aa/bb/cc/a.png").save(getInstream()));
|
||||||
|
// out("指定路径前缀保存随机文件名:" + fileService.setPrefix("test").setFilename("test.png").save(getInstream()));
|
||||||
|
// out("指定平台保存随机文件名:" + fileService.setPlatform("local").setFilename("test.png").save(getInstream()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("保存图片")
|
||||||
|
@SneakyThrows
|
||||||
|
public void saveImage() {
|
||||||
|
// out("保存图片:" + fileService.saveImage(getInstream()));
|
||||||
|
// out("保存图片+缩略图:" + fileService.setThumbnail().saveImage(getInstream()));
|
||||||
|
// out("保存图片+调整大小+缩略图:" + fileService.setSize(500,500).setThumbnail().saveImage(getInstream()));
|
||||||
|
// out("保存图片+水印+调整大小+缩略图:" + fileService.setPlatform("aliyun").setWatermark().setSize(700, 700).setThumbnail().saveImage(getInstream()));
|
||||||
|
out("保存图片+水印+调整大小+缩略图+源文件:" + fileService.setPlatform("local").setFilename("test.png").setSaveSrc().setWatermark().setSize(700, 700).setThumbnail().saveImage(getInstream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String uri = "/files/default/aa/bb/cc/a.png";
|
||||||
|
|
||||||
|
private String aliyun = "https://base-2024.oss-cn-shenzhen.aliyuncs.com/default/aa/bb/cc/a.png";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("删除文件")
|
||||||
|
@SneakyThrows
|
||||||
|
public void deleteTest() {
|
||||||
|
// fileService.delete(uri);
|
||||||
|
// fileService.setPlatform("local").delete("/upload/default/aa/bb/cc/a.png");
|
||||||
|
fileService.setPlatform("aliyun").delete(aliyun);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("下载文件")
|
||||||
|
@SneakyThrows
|
||||||
|
public void downloadTest() {
|
||||||
|
// FileInfo fileInfo = new FileInfo();
|
||||||
|
// fileInfo.setPath("default/aa/bb/cc/");
|
||||||
|
// fileInfo.setFilename("a.png");
|
||||||
|
// fileInfo.setPlatform(fileStorageService.getFileStorage("aliyun").getPlatform());
|
||||||
|
// out(HexUtil.encodeHex(fileStorageService.download(fileInfo).bytes()));
|
||||||
|
// out(HexUtil.encodeHex(fileService.download(uri).bytes()));
|
||||||
|
out(HexUtil.encodeHex(fileService.setPlatform("aliyun").download(aliyun).bytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("生成预签名URL")
|
||||||
|
@SneakyThrows
|
||||||
|
public void generatePresignedUrlTest() {
|
||||||
|
out(fileService.generatePresignedUrl(uri, Duration.ofMinutes(30)));
|
||||||
|
out(fileService.setPlatform("aliyun").generatePresignedUrl(aliyun, Duration.ofMinutes(30)));
|
||||||
|
try {
|
||||||
|
out(fileService.setPlatform("local").generatePresignedUrl(uri, Duration.ofMinutes(30)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
out("不支持预签名", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("类型检测")
|
||||||
|
@SneakyThrows
|
||||||
|
public void contentTypeTest() {
|
||||||
|
System.out.println(tikaFactory.getTika().detect(getInstream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
@DisplayName("转换格式")
|
||||||
|
@SneakyThrows
|
||||||
|
public void testWebp() {
|
||||||
|
BufferedImage image = ImageIO.read(getInstream());
|
||||||
|
ImageIO.write(image, "webp", new File("/test.webp"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
@ -1,25 +0,0 @@
|
|||||||
package com.ruoyi.common.translation.impl;
|
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.TranslationType;
|
|
||||||
import com.ruoyi.common.constant.TransConstant;
|
|
||||||
import com.ruoyi.common.core.service.OssService;
|
|
||||||
import com.ruoyi.common.translation.TranslationInterface;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS翻译实现
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@AllArgsConstructor
|
|
||||||
@TranslationType(type = TransConstant.OSS_ID_TO_URL)
|
|
||||||
public class OssUrlTranslationImpl implements TranslationInterface<String> {
|
|
||||||
|
|
||||||
private final OssService ossService;
|
|
||||||
|
|
||||||
public String translation(Object key, String other) {
|
|
||||||
return ossService.selectUrlByIds(key.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +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">
|
|
||||||
<parent>
|
|
||||||
<artifactId>ruoyi-vue-plus</artifactId>
|
|
||||||
<groupId>com.ruoyi</groupId>
|
|
||||||
<version>4.6.0</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>ruoyi-oss</artifactId>
|
|
||||||
|
|
||||||
<description>
|
|
||||||
OSS对象存储模块
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<!-- 通用工具-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.ruoyi</groupId>
|
|
||||||
<artifactId>ruoyi-common</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.amazonaws</groupId>
|
|
||||||
<artifactId>aws-java-sdk-s3</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package com.ruoyi.oss.constant;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储常量
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public interface OssConstant {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认配置KEY
|
|
||||||
*/
|
|
||||||
String DEFAULT_CONFIG_KEY = "sys_oss:default_config";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 预览列表资源开关Key
|
|
||||||
*/
|
|
||||||
String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统数据ids
|
|
||||||
*/
|
|
||||||
List<Long> SYSTEM_DATA_IDS = Arrays.asList(1L, 2L, 3L, 4L);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 云服务商
|
|
||||||
*/
|
|
||||||
String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https 状态
|
|
||||||
*/
|
|
||||||
String IS_HTTPS = "Y";
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,268 +0,0 @@
|
|||||||
package com.ruoyi.oss.core;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import com.amazonaws.ClientConfiguration;
|
|
||||||
import com.amazonaws.HttpMethod;
|
|
||||||
import com.amazonaws.Protocol;
|
|
||||||
import com.amazonaws.auth.AWSCredentials;
|
|
||||||
import com.amazonaws.auth.AWSCredentialsProvider;
|
|
||||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
|
||||||
import com.amazonaws.auth.BasicAWSCredentials;
|
|
||||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
|
||||||
import com.amazonaws.services.s3.AmazonS3;
|
|
||||||
import com.amazonaws.services.s3.AmazonS3Client;
|
|
||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
|
||||||
import com.amazonaws.services.s3.model.*;
|
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.oss.constant.OssConstant;
|
|
||||||
import com.ruoyi.oss.entity.UploadResult;
|
|
||||||
import com.ruoyi.oss.enumd.AccessPolicyType;
|
|
||||||
import com.ruoyi.oss.enumd.PolicyType;
|
|
||||||
import com.ruoyi.oss.exception.OssException;
|
|
||||||
import com.ruoyi.oss.properties.OssProperties;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* S3 存储协议 所有兼容S3协议的云厂商均支持
|
|
||||||
* 阿里云 腾讯云 七牛云 minio
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public class OssClient {
|
|
||||||
|
|
||||||
private final String configKey;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final OssProperties properties;
|
|
||||||
|
|
||||||
private final AmazonS3 client;
|
|
||||||
|
|
||||||
public OssClient(String configKey, OssProperties ossProperties) {
|
|
||||||
this.configKey = configKey;
|
|
||||||
this.properties = ossProperties;
|
|
||||||
try {
|
|
||||||
AwsClientBuilder.EndpointConfiguration endpointConfig =
|
|
||||||
new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion());
|
|
||||||
|
|
||||||
AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
|
|
||||||
AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
|
|
||||||
ClientConfiguration clientConfig = new ClientConfiguration();
|
|
||||||
if (OssConstant.IS_HTTPS.equals(properties.getIsHttps())) {
|
|
||||||
clientConfig.setProtocol(Protocol.HTTPS);
|
|
||||||
} else {
|
|
||||||
clientConfig.setProtocol(Protocol.HTTP);
|
|
||||||
}
|
|
||||||
AmazonS3ClientBuilder build = AmazonS3Client.builder()
|
|
||||||
.withEndpointConfiguration(endpointConfig)
|
|
||||||
.withClientConfiguration(clientConfig)
|
|
||||||
.withCredentials(credentialsProvider)
|
|
||||||
.disableChunkedEncoding();
|
|
||||||
if (!StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)) {
|
|
||||||
// minio 使用https限制使用域名访问 需要此配置 站点填域名
|
|
||||||
build.enablePathStyleAccess();
|
|
||||||
}
|
|
||||||
this.client = build.build();
|
|
||||||
|
|
||||||
createBucket();
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e instanceof OssException) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
throw new OssException("配置错误! 请检查系统配置:[" + e.getMessage() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createBucket() {
|
|
||||||
try {
|
|
||||||
String bucketName = properties.getBucketName();
|
|
||||||
if (client.doesBucketExistV2(bucketName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
|
|
||||||
AccessPolicyType accessPolicy = getAccessPolicy();
|
|
||||||
createBucketRequest.setCannedAcl(accessPolicy.getAcl());
|
|
||||||
client.createBucket(createBucketRequest);
|
|
||||||
client.setBucketPolicy(bucketName, getPolicy(bucketName, accessPolicy.getPolicyType()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UploadResult upload(byte[] data, String path, String contentType) {
|
|
||||||
return upload(new ByteArrayInputStream(data), path, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UploadResult upload(InputStream inputStream, String path, String contentType) {
|
|
||||||
if (!(inputStream instanceof ByteArrayInputStream)) {
|
|
||||||
inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ObjectMetadata metadata = new ObjectMetadata();
|
|
||||||
metadata.setContentType(contentType);
|
|
||||||
metadata.setContentLength(inputStream.available());
|
|
||||||
PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata);
|
|
||||||
// 设置上传对象的 Acl 为公共读
|
|
||||||
putObjectRequest.setCannedAcl(getAccessPolicy().getAcl());
|
|
||||||
client.putObject(putObjectRequest);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");
|
|
||||||
}
|
|
||||||
return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(String path) {
|
|
||||||
path = path.replace(getUrl() + "/", "");
|
|
||||||
try {
|
|
||||||
client.deleteObject(properties.getBucketName(), path);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
|
|
||||||
return upload(data, getPath(properties.getPrefix(), suffix), contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) {
|
|
||||||
return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件元数据
|
|
||||||
*
|
|
||||||
* @param path 完整文件路径
|
|
||||||
*/
|
|
||||||
public ObjectMetadata getObjectMetadata(String path) {
|
|
||||||
path = path.replace(getUrl() + "/", "");
|
|
||||||
S3Object object = client.getObject(properties.getBucketName(), path);
|
|
||||||
return object.getObjectMetadata();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getObjectContent(String path) {
|
|
||||||
path = path.replace(getUrl() + "/", "");
|
|
||||||
S3Object object = client.getObject(properties.getBucketName(), path);
|
|
||||||
return object.getObjectContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
String domain = properties.getDomain();
|
|
||||||
String endpoint = properties.getEndpoint();
|
|
||||||
String header = OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? "https://" : "http://";
|
|
||||||
// 云服务商直接返回
|
|
||||||
if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) {
|
|
||||||
if (StringUtils.isNotBlank(domain)) {
|
|
||||||
if(domain.contains("{root}")){
|
|
||||||
return domain.replace("{root}", "");
|
|
||||||
}else if(domain.contains("//")){
|
|
||||||
return domain;
|
|
||||||
}else{
|
|
||||||
return header + domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return header + properties.getBucketName() + "." + endpoint;
|
|
||||||
}
|
|
||||||
// minio 单独处理
|
|
||||||
if (StringUtils.isNotBlank(domain)) {
|
|
||||||
if(domain.equalsIgnoreCase("{root}")){
|
|
||||||
return domain.replace("{root}", "")+ "/" + properties.getBucketName();
|
|
||||||
}else if(domain.contains("//")){
|
|
||||||
return domain + "/" + properties.getBucketName();
|
|
||||||
}else{
|
|
||||||
return header + domain + "/" + properties.getBucketName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return header + endpoint + "/" + properties.getBucketName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPath(String prefix, String suffix) {
|
|
||||||
// 生成uuid
|
|
||||||
String uuid = IdUtil.fastSimpleUUID();
|
|
||||||
// 文件路径
|
|
||||||
String path = DateUtils.datePath() + "/" + uuid;
|
|
||||||
if (StringUtils.isNotBlank(prefix)) {
|
|
||||||
path = prefix + "/" + path;
|
|
||||||
}
|
|
||||||
return path + suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getConfigKey() {
|
|
||||||
return configKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取私有URL链接
|
|
||||||
*
|
|
||||||
* @param objectKey 对象KEY
|
|
||||||
* @param second 授权时间
|
|
||||||
*/
|
|
||||||
public String getPrivateUrl(String objectKey, Integer second) {
|
|
||||||
GeneratePresignedUrlRequest generatePresignedUrlRequest =
|
|
||||||
new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey)
|
|
||||||
.withMethod(HttpMethod.GET)
|
|
||||||
.withExpiration(new Date(System.currentTimeMillis() + 1000L * second));
|
|
||||||
URL url = client.generatePresignedUrl(generatePresignedUrlRequest);
|
|
||||||
return url.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查配置是否相同
|
|
||||||
*/
|
|
||||||
public boolean checkPropertiesSame(OssProperties properties) {
|
|
||||||
return this.properties.equals(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前桶权限类型
|
|
||||||
*
|
|
||||||
* @return 当前桶权限类型code
|
|
||||||
*/
|
|
||||||
public AccessPolicyType getAccessPolicy() {
|
|
||||||
return AccessPolicyType.getByType(properties.getAccessPolicy());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPolicy(String bucketName, PolicyType policyType) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n");
|
|
||||||
if (policyType == PolicyType.WRITE) {
|
|
||||||
builder.append("\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n");
|
|
||||||
} else if (policyType == PolicyType.READ_WRITE) {
|
|
||||||
builder.append("\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n");
|
|
||||||
} else {
|
|
||||||
builder.append("\"s3:GetBucketLocation\"\n");
|
|
||||||
}
|
|
||||||
builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");
|
|
||||||
builder.append(bucketName);
|
|
||||||
builder.append("\"\n},\n");
|
|
||||||
if (policyType == PolicyType.READ) {
|
|
||||||
builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");
|
|
||||||
builder.append(bucketName);
|
|
||||||
builder.append("\"\n},\n");
|
|
||||||
}
|
|
||||||
builder.append("{\n\"Action\": ");
|
|
||||||
switch (policyType) {
|
|
||||||
case WRITE:
|
|
||||||
builder.append("[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n");
|
|
||||||
break;
|
|
||||||
case READ_WRITE:
|
|
||||||
builder.append("[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
builder.append("\"s3:GetObject\",\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::");
|
|
||||||
builder.append(bucketName);
|
|
||||||
builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package com.ruoyi.oss.entity;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传返回体
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class UploadResult {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件路径
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名
|
|
||||||
*/
|
|
||||||
private String filename;
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package com.ruoyi.oss.enumd;
|
|
||||||
|
|
||||||
import com.amazonaws.services.s3.model.CannedAccessControlList;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 桶访问策略配置
|
|
||||||
*
|
|
||||||
* @author 陈賝
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AccessPolicyType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* private
|
|
||||||
*/
|
|
||||||
PRIVATE("0", CannedAccessControlList.Private, PolicyType.WRITE),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* public
|
|
||||||
*/
|
|
||||||
PUBLIC("1", CannedAccessControlList.PublicRead, PolicyType.READ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* custom
|
|
||||||
*/
|
|
||||||
CUSTOM("2",CannedAccessControlList.PublicRead, PolicyType.READ);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 桶 权限类型
|
|
||||||
*/
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件对象 权限类型
|
|
||||||
*/
|
|
||||||
private final CannedAccessControlList acl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 桶策略类型
|
|
||||||
*/
|
|
||||||
private final PolicyType policyType;
|
|
||||||
|
|
||||||
public static AccessPolicyType getByType(String type) {
|
|
||||||
for (AccessPolicyType value : values()) {
|
|
||||||
if (value.getType().equals(type)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new RuntimeException("'type' not found By " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package com.ruoyi.oss.enumd;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* minio策略配置
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum PolicyType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只读
|
|
||||||
*/
|
|
||||||
READ("read-only"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只写
|
|
||||||
*/
|
|
||||||
WRITE("write-only"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读写
|
|
||||||
*/
|
|
||||||
READ_WRITE("read-write");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
package com.ruoyi.oss.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS异常类
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public class OssException extends RuntimeException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public OssException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
package com.ruoyi.oss.factory;
|
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheNames;
|
|
||||||
import com.ruoyi.common.utils.JsonUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.redis.CacheUtils;
|
|
||||||
import com.ruoyi.common.utils.redis.RedisUtils;
|
|
||||||
import com.ruoyi.oss.constant.OssConstant;
|
|
||||||
import com.ruoyi.oss.core.OssClient;
|
|
||||||
import com.ruoyi.oss.exception.OssException;
|
|
||||||
import com.ruoyi.oss.properties.OssProperties;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传Factory
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class OssFactory {
|
|
||||||
|
|
||||||
private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取默认实例
|
|
||||||
*/
|
|
||||||
public static OssClient instance() {
|
|
||||||
// 获取redis 默认类型
|
|
||||||
String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY);
|
|
||||||
if (StringUtils.isEmpty(configKey)) {
|
|
||||||
throw new OssException("文件存储服务类型无法找到!");
|
|
||||||
}
|
|
||||||
return instance(configKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据类型获取实例
|
|
||||||
*/
|
|
||||||
public static OssClient instance(String configKey) {
|
|
||||||
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
|
|
||||||
if (json == null) {
|
|
||||||
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
|
|
||||||
}
|
|
||||||
OssProperties properties = JsonUtils.parseObject(json, OssProperties.class);
|
|
||||||
OssClient client = CLIENT_CACHE.get(configKey);
|
|
||||||
if (client == null) {
|
|
||||||
CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));
|
|
||||||
log.info("创建OSS实例 key => {}", configKey);
|
|
||||||
return CLIENT_CACHE.get(configKey);
|
|
||||||
}
|
|
||||||
// 配置不相同则重新构建
|
|
||||||
if (!client.checkPropertiesSame(properties)) {
|
|
||||||
CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));
|
|
||||||
log.info("重载OSS实例 key => {}", configKey);
|
|
||||||
return CLIENT_CACHE.get(configKey);
|
|
||||||
}
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
# 系统文件模块
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
<?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.ruoyi</groupId>
|
||||||
|
<artifactId>ruoyi-vue-plus</artifactId>
|
||||||
|
<version>4.6.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>ruoyi-system-file</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
系统文件模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ruoyi</groupId>
|
||||||
|
<artifactId>ruoyi-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.gotson</groupId>
|
||||||
|
<artifactId>webp-imageio</artifactId>
|
||||||
|
<version>0.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara.x-file-storage</groupId>
|
||||||
|
<artifactId>x-file-storage-spring</artifactId>
|
||||||
|
<version>2.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 华为云OBS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.huaweicloud</groupId>
|
||||||
|
<artifactId>esdk-obs-java</artifactId>
|
||||||
|
<version>3.22.12</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 华为云OSS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun.oss</groupId>
|
||||||
|
<artifactId>aliyun-sdk-oss</artifactId>
|
||||||
|
<version>3.17.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 七牛云Kodo -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiniu</groupId>
|
||||||
|
<artifactId>qiniu-java-sdk</artifactId>
|
||||||
|
<version>7.12.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 腾讯云COS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qcloud</groupId>
|
||||||
|
<artifactId>cos_api</artifactId>
|
||||||
|
<version>5.6.137</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- minio -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.minio</groupId>
|
||||||
|
<artifactId>minio</artifactId>
|
||||||
|
<version>8.5.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Amazon S3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.amazonaws</groupId>
|
||||||
|
<artifactId>aws-java-sdk-s3</artifactId>
|
||||||
|
<version>1.12.429</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 如果出现 okhttp 版本问题,可以尝试引入以下版本,没问题则无需引入-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>4.12.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- FTP SFTP -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jsch</artifactId>
|
||||||
|
<version>0.1.55</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-net</groupId>
|
||||||
|
<artifactId>commons-net</artifactId>
|
||||||
|
<version>3.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--糊涂工具类扩展-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-extra</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Apache 的对象池 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
<version>2.11.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- WebDAV -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.lookfirst</groupId>
|
||||||
|
<artifactId>sardine</artifactId>
|
||||||
|
<version>5.10</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.ruoyi.file;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import com.ruoyi.common.annotation.Dev;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/file/test/")
|
||||||
|
public class FileDownloadTestController {
|
||||||
|
|
||||||
|
private final FileService fileService;
|
||||||
|
|
||||||
|
@GetMapping("/download")
|
||||||
|
@SaIgnore
|
||||||
|
@Dev
|
||||||
|
public ModelAndView downloadFile(String url,String p, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
fileService.setPlatform(p).download(url, Duration.ofHours(1), request, response);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.ruoyi.file.config;
|
||||||
|
|
||||||
|
|
||||||
|
import org.dromara.x.file.storage.spring.EnableFileStorage;
|
||||||
|
import org.dromara.x.file.storage.spring.FileStorageAutoConfiguration;
|
||||||
|
import org.dromara.x.file.storage.spring.SpringFileStorageProperties;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
//@EnableFileStorage
|
||||||
|
@Import({FileStorageAutoConfiguration.class})
|
||||||
|
public class FileConfig {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.ruoyi.file.config;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.img.ImgUtil;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "ruoyi.file")
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
public class SpringFileStorageProperties extends org.dromara.x.file.storage.spring.SpringFileStorageProperties {
|
||||||
|
|
||||||
|
private Integer maxWidth;
|
||||||
|
private Integer maxHeight;
|
||||||
|
private File watermark;
|
||||||
|
private Integer thWidth;
|
||||||
|
private Integer thHeight;
|
||||||
|
@Getter
|
||||||
|
@Setter(AccessLevel.PRIVATE)
|
||||||
|
private BufferedImage watermarkImage;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
try {
|
||||||
|
if (watermark != null && watermark.isFile()) {
|
||||||
|
watermarkImage = ImgUtil.read(watermark);
|
||||||
|
log.warn("水印图片加载成功:" + watermark.toString());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("初始化水印失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.ruoyi.file.impl;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.x.file.storage.core.FileInfo;
|
||||||
|
import org.dromara.x.file.storage.core.FileStorageService;
|
||||||
|
import org.dromara.x.file.storage.core.aspect.CompleteMultipartUploadAspectChain;
|
||||||
|
import org.dromara.x.file.storage.core.aspect.FileStorageAspect;
|
||||||
|
import org.dromara.x.file.storage.core.aspect.ListPartsAspectChain;
|
||||||
|
import org.dromara.x.file.storage.core.platform.AliyunOssFileStorage;
|
||||||
|
import org.dromara.x.file.storage.core.platform.FileStorage;
|
||||||
|
import org.dromara.x.file.storage.core.recorder.FileRecorder;
|
||||||
|
import org.dromara.x.file.storage.core.tika.ContentTypeDetect;
|
||||||
|
import org.dromara.x.file.storage.core.upload.CompleteMultipartUploadPretreatment;
|
||||||
|
import org.dromara.x.file.storage.core.upload.FilePartInfoList;
|
||||||
|
import org.dromara.x.file.storage.core.upload.ListPartsPretreatment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class FixFileStorageAspect implements FileStorageAspect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FilePartInfoList listParts(ListPartsAspectChain chain, ListPartsPretreatment pre, FileStorage fileStorage) {
|
||||||
|
if(fileStorage instanceof AliyunOssFileStorage) {
|
||||||
|
pre.setPartNumberMarker(null);
|
||||||
|
}
|
||||||
|
return chain.next(pre,fileStorage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 文件模块
|
||||||
|
*/
|
||||||
|
package com.ruoyi.file;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@ -1,75 +0,0 @@
|
|||||||
package com.ruoyi.system.config;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.file.FileNameUtil;
|
|
||||||
import cn.hutool.core.util.URLUtil;
|
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
|
||||||
import com.ruoyi.common.utils.HttpDownloadUtil;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本地文件公开下载配置
|
|
||||||
* 方式一:SpringBoot静态资源配置
|
|
||||||
* 方式二:Servlet
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Slf4j
|
|
||||||
public class DownloadFileConfig {
|
|
||||||
|
|
||||||
private final RuoYiConfig config;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebMvcConfigurer DownloadFileWebMvcConfigurer() {
|
|
||||||
return new WebMvcConfigurer(){
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
||||||
//加入外部静态资源html文件夹
|
|
||||||
String path = new File(new File(config.upload.savePath).getAbsolutePath()).toURI().toString();
|
|
||||||
registry.addResourceHandler(config.upload.pre+"/**").addResourceLocations(path);
|
|
||||||
log.info("添加静态资源目: {}/** ={}",config.upload.pre,path);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ServletRegistrationBean DownloadFileServletRegistrationBean() {
|
|
||||||
ServletRegistrationBean bean = new ServletRegistrationBean();
|
|
||||||
bean.setServlet(new HttpServlet() {
|
|
||||||
@Override
|
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
||||||
String uri = req.getRequestURI().substring(config.upload.pre.length());
|
|
||||||
uri = URLUtil.decode(uri);
|
|
||||||
File down = new File(config.upload.savePath, uri);
|
|
||||||
if(down.isFile()) {
|
|
||||||
try {
|
|
||||||
HttpDownloadUtil.download(req, resp,down,
|
|
||||||
FileNameUtil.getName(uri));
|
|
||||||
resp.getOutputStream().close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
resp.reset();
|
|
||||||
resp.sendError(404);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
resp.sendError(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
bean.addUrlMappings(config.upload.pre+"/*");
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
package com.ruoyi.system.domain;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import com.ruoyi.common.core.domain.BaseEntity;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS对象存储对象
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@TableName("sys_oss")
|
|
||||||
public class SysOss extends BaseEntity {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储主键
|
|
||||||
*/
|
|
||||||
@TableId(value = "oss_id")
|
|
||||||
private Long ossId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名
|
|
||||||
*/
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 原名
|
|
||||||
*/
|
|
||||||
private String originalName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件后缀名
|
|
||||||
*/
|
|
||||||
private String fileSuffix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL地址
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务商
|
|
||||||
*/
|
|
||||||
private String service;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
package com.ruoyi.system.domain.bo;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.BaseEntity;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS对象存储分页查询对象 sys_oss
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class SysOssBo extends BaseEntity {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ossId
|
|
||||||
*/
|
|
||||||
private Long ossId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名
|
|
||||||
*/
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 原名
|
|
||||||
*/
|
|
||||||
private String originalName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件后缀名
|
|
||||||
*/
|
|
||||||
private String fileSuffix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL地址
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务商
|
|
||||||
*/
|
|
||||||
private String service;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
package com.ruoyi.system.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS对象存储视图对象 sys_oss
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class SysOssVo {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储主键
|
|
||||||
*/
|
|
||||||
private Long ossId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名
|
|
||||||
*/
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 原名
|
|
||||||
*/
|
|
||||||
private String originalName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件后缀名
|
|
||||||
*/
|
|
||||||
private String fileSuffix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL地址
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建时间
|
|
||||||
*/
|
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传人
|
|
||||||
*/
|
|
||||||
private String createBy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务商
|
|
||||||
*/
|
|
||||||
private String service;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
package com.ruoyi.system.mapper;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.mapper.BaseMapperPlus;
|
|
||||||
import com.ruoyi.system.domain.SysOssConfig;
|
|
||||||
import com.ruoyi.system.domain.vo.SysOssConfigVo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储配置Mapper接口
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
* @author 孤舟烟雨
|
|
||||||
* @date 2021-08-13
|
|
||||||
*/
|
|
||||||
public interface SysOssConfigMapper extends BaseMapperPlus<SysOssConfigMapper, SysOssConfig, SysOssConfigVo> {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
package com.ruoyi.system.mapper;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.mapper.BaseMapperPlus;
|
|
||||||
import com.ruoyi.system.domain.SysOss;
|
|
||||||
import com.ruoyi.system.domain.vo.SysOssVo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传 数据层
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public interface SysOssMapper extends BaseMapperPlus<SysOssMapper, SysOss, SysOssVo> {
|
|
||||||
}
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
package com.ruoyi.system.service;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.img.Img;
|
|
||||||
import cn.hutool.core.lang.UUID;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
|
|
||||||
import java.awt.Image;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
|
||||||
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
|
||||||
import cn.hutool.crypto.symmetric.SymmetricCrypto;
|
|
||||||
import com.ruoyi.common.utils.IdUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* - 本地文件保存服务
|
|
||||||
* Author : J.L.Zhou
|
|
||||||
* E-Mail : 2233875735@qq.com
|
|
||||||
* Tel : 151 1104 7708
|
|
||||||
* Date : 2021-6-1 11:48:16
|
|
||||||
* Version : 1.0
|
|
||||||
* Copyright 2021 jlzhou.top Inc. All rights reserved.
|
|
||||||
* Warning: this content is only for internal circulation of the company.
|
|
||||||
* It is forbidden to divulge it or use it for other commercial purposes.
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public interface FileService {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* - 保存文件,文件名随机
|
|
||||||
*
|
|
||||||
* @param in
|
|
||||||
* @param filename - 原文件名
|
|
||||||
* @param pre - 存放路径前缀
|
|
||||||
* @return - 保存的文件URL
|
|
||||||
* @throws 400-499
|
|
||||||
*/
|
|
||||||
default String save(InputStream in, String filename, String pre) {
|
|
||||||
return save(in, filename, pre, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param in
|
|
||||||
* @param filename - 原文件名
|
|
||||||
* @param pre - 存放路径前缀
|
|
||||||
* @param randomName - 是否随机文件名
|
|
||||||
* @return
|
|
||||||
* @throws 400-499
|
|
||||||
*/
|
|
||||||
default String save(InputStream in, String filename, String pre, boolean randomName) {
|
|
||||||
if (StrUtil.isNotBlank(pre) && !pre.matches("^[\\w\\/]+$")) {
|
|
||||||
throw new RuntimeException("存放路径前缀只能有单词字符组成");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (in == null || in.available() == 0) {
|
|
||||||
throw new RuntimeException("读取上传文件长度错误");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("读取上传文件长度错误", e);
|
|
||||||
}
|
|
||||||
if (StrUtil.isEmpty(filename)) {
|
|
||||||
throw new RuntimeException("文件名为空");
|
|
||||||
}
|
|
||||||
filename = filename.replace(" ", "");
|
|
||||||
String name = (StrUtil.isNotBlank(pre)?(pre+"/"):"")
|
|
||||||
+ generateURI("{yyyy}/{MM}/{dd}/{id36}" + (randomName ? ".{ext}" : "/{filename}.{ext}"), filename);
|
|
||||||
|
|
||||||
return save(in, name);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
String save(InputStream in, String filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* - 删除文件
|
|
||||||
*
|
|
||||||
* @param file 文件的URL
|
|
||||||
*/
|
|
||||||
void delete(String file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取保存的文件对象
|
|
||||||
* @param file
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
File getFile(String file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* - 根据存放规则和文件名生成存放的URI
|
|
||||||
* - 支持
|
|
||||||
* - {yyyy}/{MM}/{dd}/{HH}/{mm}/{ss} 年月日时分秒
|
|
||||||
* - {UUID} 32位的唯一标志
|
|
||||||
* - {id} int类型的唯一id,防止重复建议+年月日路径
|
|
||||||
* - {id16} int类型的唯一id16进制表示,防止重复建议+年月日路径
|
|
||||||
* - {id36} int类型的唯一id36进制表示,防止重复建议+年月日路径
|
|
||||||
* - {filename} 文件基础名称
|
|
||||||
* - {ext} 扩展名
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param rule
|
|
||||||
* @param filename
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default String generateURI(String rule, String filename) {
|
|
||||||
return SpringUtils.getBean(ISysOssService.class).generateURI(rule, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
package com.ruoyi.system.service;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.PageQuery;
|
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
|
||||||
import com.ruoyi.system.domain.bo.SysOssConfigBo;
|
|
||||||
import com.ruoyi.system.domain.vo.SysOssConfigVo;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象存储配置Service接口
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
* @author 孤舟烟雨
|
|
||||||
* @date 2021-08-13
|
|
||||||
*/
|
|
||||||
public interface ISysOssConfigService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化OSS配置
|
|
||||||
*/
|
|
||||||
void init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询单个
|
|
||||||
*/
|
|
||||||
SysOssConfigVo queryById(Long ossConfigId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询列表
|
|
||||||
*/
|
|
||||||
TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据新增业务对象插入对象存储配置
|
|
||||||
*
|
|
||||||
* @param bo 对象存储配置新增业务对象
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Boolean insertByBo(SysOssConfigBo bo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据编辑业务对象修改对象存储配置
|
|
||||||
*
|
|
||||||
* @param bo 对象存储配置编辑业务对象
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Boolean updateByBo(SysOssConfigBo bo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验并删除数据
|
|
||||||
*
|
|
||||||
* @param ids 主键集合
|
|
||||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用停用状态
|
|
||||||
*/
|
|
||||||
int updateOssConfigStatus(SysOssConfigBo bo);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
package com.ruoyi.system.service.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
|
||||||
import com.ruoyi.system.service.FileService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* - 文件存储的本地存储实现
|
|
||||||
* Author : J.L.Zhou
|
|
||||||
* E-Mail : 2233875735@qq.com
|
|
||||||
* Tel : 151 1104 7708
|
|
||||||
* Date : 2021-09-16 14:17
|
|
||||||
* Version : 1.0
|
|
||||||
* Copyright 2021 jlzhou.top Inc. All rights reserved.
|
|
||||||
* Warning: this content is only for internal circulation of the company.
|
|
||||||
* It is forbidden to divulge it or use it for other commercial purposes.
|
|
||||||
* </pre>
|
|
||||||
**/
|
|
||||||
@Service("upload")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Slf4j
|
|
||||||
public class FileServiceImpl implements FileService {
|
|
||||||
|
|
||||||
public final RuoYiConfig config;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String filename) {
|
|
||||||
if (StrUtil.isEmpty(filename)) {
|
|
||||||
throw new RuntimeException("文件名不能为空");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (filename.startsWith(config.upload.pre)) {
|
|
||||||
filename = filename.substring(config.upload.pre.length());
|
|
||||||
}
|
|
||||||
if (filename.indexOf("?") > -1) {
|
|
||||||
filename = filename.substring(0, filename.indexOf("?"));
|
|
||||||
}
|
|
||||||
File file = new File(config.upload.savePath, filename);
|
|
||||||
log.debug("file:"+file.exists());
|
|
||||||
file.delete();
|
|
||||||
log.info("删除:{}",file.getAbsolutePath());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("删除错误", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getFile(String filename) {
|
|
||||||
if (StrUtil.isEmpty(filename)) {
|
|
||||||
throw new RuntimeException("文件名不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filename.startsWith(config.upload.pre)) {
|
|
||||||
filename = filename.substring(config.upload.pre.length());
|
|
||||||
}
|
|
||||||
if (filename.indexOf("?") > -1) {
|
|
||||||
filename = filename.substring(0, filename.indexOf("?"));
|
|
||||||
}
|
|
||||||
return new File(config.upload.savePath, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String save(InputStream in, String filename) {
|
|
||||||
File file = new File(config.upload.savePath, filename);
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
try(
|
|
||||||
FileOutputStream out = new FileOutputStream(file);
|
|
||||||
) {
|
|
||||||
IoUtil.copy(in, out);
|
|
||||||
return config.upload.pre + "/" + filename;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE mapper
|
|
||||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="com.ruoyi.system.mapper.SysOssConfigMapper">
|
|
||||||
|
|
||||||
<resultMap type="com.ruoyi.system.domain.SysOssConfig" id="SysOssConfigResult">
|
|
||||||
<result property="ossConfigId" column="oss_config_id"/>
|
|
||||||
<result property="configKey" column="config_key"/>
|
|
||||||
<result property="accessKey" column="access_key"/>
|
|
||||||
<result property="secretKey" column="secret_key"/>
|
|
||||||
<result property="bucketName" column="bucket_name"/>
|
|
||||||
<result property="prefix" column="prefix"/>
|
|
||||||
<result property="endpoint" column="endpoint"/>
|
|
||||||
<result property="isHttps" column="is_https"/>
|
|
||||||
<result property="region" column="region"/>
|
|
||||||
<result property="status" column="status"/>
|
|
||||||
<result property="ext1" column="ext1"/>
|
|
||||||
<result property="createBy" column="create_by"/>
|
|
||||||
<result property="createTime" column="create_time"/>
|
|
||||||
<result property="updateBy" column="update_by"/>
|
|
||||||
<result property="updateTime" column="update_time"/>
|
|
||||||
<result property="remark" column="remark"/>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="com.ruoyi.system.mapper.SysOssMapper">
|
|
||||||
|
|
||||||
<resultMap type="com.ruoyi.system.domain.SysOss" id="SysOssResult">
|
|
||||||
<result property="ossId" column="oss_id"/>
|
|
||||||
<result property="fileName" column="file_name"/>
|
|
||||||
<result property="fileSuffix" column="file_suffix"/>
|
|
||||||
<result property="url" column="url"/>
|
|
||||||
<result property="createTime" column="create_time"/>
|
|
||||||
<result property="createBy" column="create_by"/>
|
|
||||||
<result property="updateTime" column="update_time"/>
|
|
||||||
<result property="updateBy" column="update_by"/>
|
|
||||||
<result property="service" column="service"/>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
|
||||||
Loading…
Reference in New Issue