diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/core/OssClient.java index 390b770b..2f9c451c 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/core/OssClient.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/core/OssClient.java @@ -2,6 +2,7 @@ package com.ruoyi.common.oss.core; 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; @@ -16,13 +17,15 @@ import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.oss.constant.OssConstant; import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.AccessPolicyType; import com.ruoyi.common.oss.enumd.PolicyType; import com.ruoyi.common.oss.exception.OssException; import com.ruoyi.common.oss.properties.OssProperties; - import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.net.URL; +import java.util.Date; /** * S3 存储协议 所有兼容S3协议的云厂商均支持 @@ -80,9 +83,10 @@ public class OssClient { return; } CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); - createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead); + AccessPolicyType accessPolicy = getAccessPolicy(); + createBucketRequest.setCannedAcl(accessPolicy.getAcl()); client.createBucket(createBucketRequest); - client.setBucketPolicy(bucketName, getPolicy(bucketName, PolicyType.READ)); + client.setBucketPolicy(bucketName, getPolicy(bucketName, accessPolicy.getPolicyType())); } catch (Exception e) { throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]"); } @@ -99,7 +103,7 @@ public class OssClient { metadata.setContentLength(inputStream.available()); PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata); // 设置上传对象的 Acl 为公共读 - putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead); + putObjectRequest.setCannedAcl(getAccessPolicy().getAcl()); client.putObject(putObjectRequest); } catch (Exception e) { throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]"); @@ -112,7 +116,7 @@ public class OssClient { try { client.deleteObject(properties.getBucketName(), path); } catch (Exception e) { - throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]"); + throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]"); } } @@ -168,6 +172,25 @@ public class OssClient { return configKey; } + 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(); + } + + /** + * 获取当前桶权限类型 + * + * @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"); diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/AccessPolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/AccessPolicyType.java new file mode 100644 index 00000000..140f67a9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/AccessPolicyType.java @@ -0,0 +1,55 @@ +package com.ruoyi.common.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); + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java index 78b62ab4..16cd27be 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java @@ -50,4 +50,10 @@ public class OssProperties { */ private String isHttps; + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + + } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/controller/SysOssController.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/controller/SysOssController.java index 4c443021..9896dc4f 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/controller/SysOssController.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/controller/SysOssController.java @@ -2,20 +2,15 @@ package com.ruoyi.resource.controller; 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.core.domain.R; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.common.core.validate.QueryGroup; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.resource.domain.SysOss; import com.ruoyi.resource.domain.bo.SysOssBo; import com.ruoyi.resource.domain.vo.SysOssVo; import com.ruoyi.resource.service.ISysOssService; @@ -79,7 +74,7 @@ public class SysOssController extends BaseController { if (ObjectUtil.isNull(file)) { throw new ServiceException("上传文件不能为空"); } - SysOss oss = iSysOssService.upload(file); + SysOssVo oss = iSysOssService.upload(file); Map map = new HashMap<>(2); map.put("url", oss.getUrl()); map.put("fileName", oss.getOriginalName()); @@ -95,23 +90,7 @@ public class SysOssController extends BaseController { @SaCheckPermission("system:oss:download") @GetMapping("/download/{ossId}") public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { - SysOssVo sysOss = iSysOssService.getById(ossId); - if (ObjectUtil.isNull(sysOss)) { - throw new ServiceException("文件数据不存在!"); - } - FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); - long data; - try { - data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false); - } catch (HttpException e) { - if (e.getMessage().contains("403")) { - throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!"); - } else { - throw new ServiceException(e.getMessage()); - } - } - response.setContentLength(Convert.toInt(data)); + iSysOssService.download(ossId,response); } /** @@ -123,7 +102,7 @@ public class SysOssController extends BaseController { @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) @DeleteMapping("/{ossIds}") public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ossIds) { - return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true)); + return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0); } } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/SysOssConfig.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/SysOssConfig.java index 869648c2..28a4ca23 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/SysOssConfig.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/SysOssConfig.java @@ -83,4 +83,8 @@ public class SysOssConfig extends BaseEntity { */ private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/bo/SysOssConfigBo.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/bo/SysOssConfigBo.java index 39f491cf..744b55bb 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/bo/SysOssConfigBo.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/bo/SysOssConfigBo.java @@ -98,4 +98,11 @@ public class SysOssConfigBo extends BaseEntity { */ private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + @NotBlank(message = "桶权限类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessPolicy; + + } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/vo/SysOssConfigVo.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/vo/SysOssConfigVo.java index de5297b9..16501c15 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/vo/SysOssConfigVo.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/domain/vo/SysOssConfigVo.java @@ -80,4 +80,10 @@ public class SysOssConfigVo { */ private String remark; + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + + } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/ISysOssService.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/ISysOssService.java index cbac3e15..4e613379 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/ISysOssService.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/ISysOssService.java @@ -2,11 +2,12 @@ package com.ruoyi.resource.service; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.resource.domain.SysOss; import com.ruoyi.resource.domain.bo.SysOssBo; import com.ruoyi.resource.domain.vo.SysOssVo; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.Collection; import java.util.List; @@ -23,7 +24,9 @@ public interface ISysOssService { SysOssVo getById(Long ossId); - SysOss upload(MultipartFile file); + SysOssVo upload(MultipartFile file); + + void download(Long ossId, HttpServletResponse response) throws IOException; Boolean deleteWithValidByIds(Collection ids, Boolean isValid); diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java index b655ae7a..60080421 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java @@ -1,17 +1,23 @@ package com.ruoyi.resource.service.impl; +import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpException; +import cn.hutool.http.HttpUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.core.constant.CacheNames; import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.BeanCopyUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.oss.core.OssClient; import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.AccessPolicyType; import com.ruoyi.common.oss.factory.OssFactory; import com.ruoyi.resource.domain.SysOss; import com.ruoyi.resource.domain.bo.SysOssBo; @@ -20,14 +26,17 @@ import com.ruoyi.resource.mapper.SysOssMapper; import com.ruoyi.resource.service.ISysOssService; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * 文件上传 服务层实现 @@ -44,6 +53,8 @@ public class SysOssServiceImpl implements ISysOssService { public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + List filterResult = result.getRecords().stream().map(this::matchingUrl).collect(Collectors.toList()); + result.setRecords(filterResult); return TableDataInfo.build(result); } @@ -51,9 +62,9 @@ public class SysOssServiceImpl implements ISysOssService { public List listByIds(Collection ossIds) { List list = new ArrayList<>(); for (Long id : ossIds) { - SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); + SysOssVo vo = getById(id); if (ObjectUtil.isNotNull(vo)) { - list.add(vo); + list.add(this.matchingUrl(vo)); } } return list; @@ -80,7 +91,28 @@ public class SysOssServiceImpl implements ISysOssService { } @Override - public SysOss upload(MultipartFile file) { + public void download(Long ossId, HttpServletResponse response) throws IOException { + SysOssVo sysOss = this.matchingUrl(SpringUtils.getAopProxy(this).getById(ossId)); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); + } + FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + long data; + try { + data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false); + } catch (HttpException e) { + if (e.getMessage().contains("403")) { + throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!"); + } else { + throw new ServiceException(e.getMessage()); + } + } + response.setContentLength(Convert.toInt(data)); + } + + @Override + public SysOssVo upload(MultipartFile file) { String originalfileName = file.getOriginalFilename(); String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); OssClient storage = OssFactory.instance(); @@ -98,7 +130,9 @@ public class SysOssServiceImpl implements ISysOssService { oss.setOriginalName(originalfileName); oss.setService(storage.getConfigKey()); baseMapper.insert(oss); - return oss; + SysOssVo sysOssVo = new SysOssVo(); + BeanCopyUtils.copy(oss, sysOssVo); + return this.matchingUrl(sysOssVo); } @Override @@ -114,4 +148,21 @@ public class SysOssServiceImpl implements ISysOssService { return baseMapper.deleteBatchIds(ids) > 0; } + /** + * 匹配Url + * + * @param oss OSS对象 + * @return oss 匹配Url的OSS对象 + */ + private SysOssVo matchingUrl(SysOssVo oss) { + OssClient storage = OssFactory.instance(oss.getService()); + /** + * 仅修改桶类型为 private 的URL,临时URL时长为100s + */ + if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { + oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 100)); + } + return oss; + } + } diff --git a/ruoyi-ui/src/views/system/oss/config.vue b/ruoyi-ui/src/views/system/oss/config.vue index 54ad98cb..0120641d 100644 --- a/ruoyi-ui/src/views/system/oss/config.vue +++ b/ruoyi-ui/src/views/system/oss/config.vue @@ -80,6 +80,13 @@ + + +