From 9fbd156fa0eb3091dd033c3eebf5fbc53c6ab6de Mon Sep 17 00:00:00 2001 From: xin <1099200748@qq.com> Date: Tue, 03 Jun 2025 02:08:22 +0800 Subject: [PATCH] 桶 --- oying-system/src/main/resources/config/application-dev.yml | 6 oying-tools/src/main/java/com/oying/service/impl/BucketStorageServiceImpl.java | 133 ++++++++++++++ oying-tools/src/main/java/com/oying/mapper/BucketStorageMapper.java | 22 ++ oying-tools/src/main/java/com/oying/utils/ObsProperties.java | 21 ++ oying-tools/src/main/java/com/oying/domain/BucketStorage.java | 49 +++++ oying-tools/src/main/java/com/oying/domain/dto/BucketStorageQueryCriteria.java | 25 ++ oying-tools/src/main/java/com/oying/service/BucketStorageService.java | 57 ++++++ oying-tools/src/main/java/com/oying/utils/ObsUtils.java | 127 ++++++++++++++ oying-system/src/main/resources/config/application-prod.yml | 6 oying-tools/src/main/java/com/oying/rest/BucketStorageController.java | 78 ++++++++ pom.xml | 6 11 files changed, 530 insertions(+), 0 deletions(-) diff --git a/oying-system/src/main/resources/config/application-dev.yml b/oying-system/src/main/resources/config/application-dev.yml index 3ea16c0..eea81b5 100644 --- a/oying-system/src/main/resources/config/application-dev.yml +++ b/oying-system/src/main/resources/config/application-dev.yml @@ -170,3 +170,9 @@ notify-url: https://localhost/oying/api/swiftPass/alipayCallback # 退款通知地址 refund-url: https://localhost/oying/api/swiftPass/returnNotify + +obs: + access_key_id: RZ1UIOZDZ58DD4NWPD6Q + access_key_secret: QpE58YEFtgoIwUoGNlN5JlNY7t6qVu7vMkix8gAI + bucket: oying + endpoint: https://obs.cn-southwest-2.myhuaweicloud.com diff --git a/oying-system/src/main/resources/config/application-prod.yml b/oying-system/src/main/resources/config/application-prod.yml index cefa2d9..67e895d 100644 --- a/oying-system/src/main/resources/config/application-prod.yml +++ b/oying-system/src/main/resources/config/application-prod.yml @@ -180,3 +180,9 @@ notify-url: https://localhost/oying/api/swiftPass/alipayCallback # 退款通知地址 refund-url: https://localhost/oying/api/swiftPass/returnNotify + +obs: + access_key_id: RZ1UIOZDZ58DD4NWPD6Q + access_key_secret: QpE58YEFtgoIwUoGNlN5JlNY7t6qVu7vMkix8gAI + bucket: oying + endpoint: https://obs.cn-southwest-2.myhuaweicloud.com diff --git a/oying-tools/src/main/java/com/oying/domain/BucketStorage.java b/oying-tools/src/main/java/com/oying/domain/BucketStorage.java new file mode 100644 index 0000000..9baedd1 --- /dev/null +++ b/oying-tools/src/main/java/com/oying/domain/BucketStorage.java @@ -0,0 +1,49 @@ +package com.oying.domain; + +import com.oying.base.BaseEntity; +import cn.hutool.core.bean.BeanUtil; +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.copier.CopyOptions; +import java.io.Serializable; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Getter; +import lombok.Setter; + +/** +* @description / +* @author lixin +* @date 2025-06-03 +**/ +@Getter +@Setter +@TableName("tool_bucket_storage") +public class BucketStorage extends BaseEntity implements Serializable { + + @TableId(value = "bucket_id", type = IdType.AUTO) + @ApiModelProperty(value = "主键") + private Long bucketId; + + @ApiModelProperty(value = "文件真实的名称") + private String realName; + + @ApiModelProperty(value = "文件名") + private String name; + + @ApiModelProperty(value = "后缀") + private String suffix; + + @ApiModelProperty(value = "路径") + private String path; + + @ApiModelProperty(value = "类型") + private String type; + + @ApiModelProperty(value = "大小") + private String size; + + public void copy(BucketStorage source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/oying-tools/src/main/java/com/oying/domain/dto/BucketStorageQueryCriteria.java b/oying-tools/src/main/java/com/oying/domain/dto/BucketStorageQueryCriteria.java new file mode 100644 index 0000000..32811d9 --- /dev/null +++ b/oying-tools/src/main/java/com/oying/domain/dto/BucketStorageQueryCriteria.java @@ -0,0 +1,25 @@ +package com.oying.domain.dto; + +import lombok.Data; +import java.sql.Timestamp; +import java.util.List; +import io.swagger.annotations.ApiModelProperty; + +/** +* @author lixin +* @date 2025-06-03 +**/ +@Data +public class BucketStorageQueryCriteria{ + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; + + @ApiModelProperty(value = "模糊查询") + private String blurry; + + private List<Timestamp> createTime; +} diff --git a/oying-tools/src/main/java/com/oying/mapper/BucketStorageMapper.java b/oying-tools/src/main/java/com/oying/mapper/BucketStorageMapper.java new file mode 100644 index 0000000..395a18c --- /dev/null +++ b/oying-tools/src/main/java/com/oying/mapper/BucketStorageMapper.java @@ -0,0 +1,22 @@ +package com.oying.mapper; + +import com.oying.domain.BucketStorage; +import com.oying.domain.dto.BucketStorageQueryCriteria; +import java.util.List; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +/** +* @author lixin +* @date 2025-06-03 +**/ +@Mapper +public interface BucketStorageMapper extends BaseMapper<BucketStorage> { + + IPage<BucketStorage> findAll(@Param("criteria") BucketStorageQueryCriteria criteria, Page<Object> page); + + List<BucketStorage> findAll(@Param("criteria") BucketStorageQueryCriteria criteria); +} diff --git a/oying-tools/src/main/java/com/oying/rest/BucketStorageController.java b/oying-tools/src/main/java/com/oying/rest/BucketStorageController.java new file mode 100644 index 0000000..c0873e0 --- /dev/null +++ b/oying-tools/src/main/java/com/oying/rest/BucketStorageController.java @@ -0,0 +1,78 @@ +package com.oying.rest; + +import com.oying.annotation.Log; +import com.oying.domain.BucketStorage; +import com.oying.exception.BadRequestException; +import com.oying.service.BucketStorageService; +import com.oying.domain.dto.BucketStorageQueryCriteria; +import com.oying.utils.FileUtil; +import lombok.RequiredArgsConstructor; +import java.util.List; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import io.swagger.annotations.*; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.oying.utils.PageResult; +import org.springframework.web.multipart.MultipartFile; + +/** +* @author lixin +* @date 2025-06-03 +**/ +@RestController +@RequiredArgsConstructor +@Api(tags = "存储桶") +@RequestMapping("/api/bucketStorage") +public class BucketStorageController { + + private final BucketStorageService bucketStorageService; + + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('bucketStorage:list')") + public void exportBucketStorage(HttpServletResponse response, BucketStorageQueryCriteria criteria) throws IOException { + bucketStorageService.download(bucketStorageService.queryAll(criteria), response); + } + + @GetMapping + @ApiOperation("查询存储桶") + @PreAuthorize("@el.check('bucketStorage:list')") + public ResponseEntity<PageResult<BucketStorage>> queryBucketStorage(BucketStorageQueryCriteria criteria){ + Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize()); + return new ResponseEntity<>(bucketStorageService.queryAll(criteria,page),HttpStatus.OK); + } + + @PostMapping + @Log("上传存储桶文件") + @ApiOperation("上传存储桶文件") + @PreAuthorize("@el.check('bucketStorage:add')") + public ResponseEntity<Object> create(@RequestParam String name, @RequestParam("file") MultipartFile file) { + return new ResponseEntity<>(bucketStorageService.create(name, file), HttpStatus.CREATED); + } + + @PostMapping("/pictures") + @ApiOperation("上传图片") + public ResponseEntity<Object> upload(@RequestParam MultipartFile file) { + // 判断文件是否为图片 + String suffix = FileUtil.getExtensionName(file.getOriginalFilename()); + FileUtil.checkSize(5, file.getSize()); + if (!FileUtil.IMAGE.equals(FileUtil.getFileType(suffix))) { + throw new BadRequestException("只能上传图片"); + } + BucketStorage bucketStorage = bucketStorageService.create(null, file); + return new ResponseEntity<>(bucketStorage, HttpStatus.OK); + } + + @DeleteMapping + @Log("删除存储桶") + @ApiOperation("删除存储桶") + @PreAuthorize("@el.check('bucketStorage:del')") + public ResponseEntity<Object> deleteBucketStorage(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) { + bucketStorageService.deleteAll(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/oying-tools/src/main/java/com/oying/service/BucketStorageService.java b/oying-tools/src/main/java/com/oying/service/BucketStorageService.java new file mode 100644 index 0000000..3b6dd6b --- /dev/null +++ b/oying-tools/src/main/java/com/oying/service/BucketStorageService.java @@ -0,0 +1,57 @@ +package com.oying.service; + +import com.oying.domain.BucketStorage; +import com.oying.domain.dto.BucketStorageQueryCriteria; + +import java.io.File; +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.oying.utils.PageResult; +import org.springframework.web.multipart.MultipartFile; + +/** +* @description 服务接口 +* @author lixin +* @date 2025-06-03 +**/ +public interface BucketStorageService extends IService<BucketStorage> { + + /** + * 查询数据分页 + * @param criteria 条件 + * @param page 分页参数 + * @return PageResult + */ + PageResult<BucketStorage> queryAll(BucketStorageQueryCriteria criteria, Page<Object> page); + + /** + * 查询所有数据不分页 + * @param criteria 条件参数 + * @return List<BucketStorageDto> + */ + List<BucketStorage> queryAll(BucketStorageQueryCriteria criteria); + + /** + * 创建 + */ + BucketStorage create(String name, MultipartFile file); + + BucketStorage createFile(String name, File file); + + /** + * 多选删除 + * @param ids / + */ + void deleteAll(List<Long> ids); + + /** + * 导出数据 + * @param all 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<BucketStorage> all, HttpServletResponse response) throws IOException; +} diff --git a/oying-tools/src/main/java/com/oying/service/impl/BucketStorageServiceImpl.java b/oying-tools/src/main/java/com/oying/service/impl/BucketStorageServiceImpl.java new file mode 100644 index 0000000..6d60979 --- /dev/null +++ b/oying-tools/src/main/java/com/oying/service/impl/BucketStorageServiceImpl.java @@ -0,0 +1,133 @@ +package com.oying.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.obs.services.internal.ObsProperties; +import com.obs.services.model.AccessControlList; +import com.obs.services.model.PutObjectResult; +import com.oying.domain.BucketStorage; +import com.oying.utils.FileUtil; +import lombok.RequiredArgsConstructor; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.oying.service.BucketStorageService; +import com.oying.domain.dto.BucketStorageQueryCriteria; +import com.oying.mapper.BucketStorageMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.oying.utils.PageUtil; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import com.oying.utils.PageResult; +import org.springframework.web.multipart.MultipartFile; + +/** +* @description 服务实现 +* @author lixin +* @date 2025-06-03 +**/ +@Service +@RequiredArgsConstructor +public class BucketStorageServiceImpl extends ServiceImpl<BucketStorageMapper, BucketStorage> implements BucketStorageService { + + private final BucketStorageMapper bucketStorageMapper; + private final ObsProperties + + @Override + public PageResult<BucketStorage> queryAll(BucketStorageQueryCriteria criteria, Page<Object> page){ + return PageUtil.toPage(bucketStorageMapper.findAll(criteria, page)); + } + + @Override + public List<BucketStorage> queryAll(BucketStorageQueryCriteria criteria){ + return bucketStorageMapper.findAll(criteria); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public BucketStorage createFile(String name, File file) { + ObsConfig config = obsConfigService.findById(1L); + FileUtil.checkSize(properties.getMaxSize(), file.length()); + String suffix = FileUtil.getExtensionName(file.getName()); + String type = FileUtil.getFileType(suffix); + String reaName = System.currentTimeMillis() + "." + suffix; + String objectKey = type + "/" + reaName; + PutObjectResult result = ObsUtils.putObject(config, file, objectKey, AccessControlList.REST_CANNED_PUBLIC_READ); + if (ObjectUtil.isNull(result)) { + throw new BadRequestException("上传失败"); + } + name = StringUtils.isBlank(name) ? FileUtil.getFileNameNoEx(reaName) : name; + BucketStorage bucketStorage = new BucketStorage( + reaName, + name, + suffix, + objectKey, + type, + FileUtil.getSize(file.length()) + ); + return bucketStorageRepository.save(bucketStorage); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public BucketStorage create(String name, MultipartFile file) { + FileUtil.checkSize(properties.getMaxSize(), file.getSize()); + String suffix = FileUtil.getExtensionName(file.getOriginalFilename()); + String type = FileUtil.getFileType(suffix); + String reaName = System.currentTimeMillis() + "." + suffix; + String objectKey = type + "/" + reaName; + PutObjectResult result = ObsUtils.putObject(config, FileUtil.toFile(file), objectKey,AccessControlList.REST_CANNED_PUBLIC_READ); + if (ObjectUtil.isNull(result)) { + throw new BadRequestException("上传失败"); + } + name = StringUtils.isBlank(name) ? FileUtil.getFileNameNoEx(reaName) : name; + BucketStorage bucketStorage = new BucketStorage( + reaName, + name, + suffix, + objectKey, + type, + FileUtil.getSize(file.getSize()) + ); + return bucketStorageRepository.save(bucketStorage); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(BucketStorage resources) { + BucketStorage bucketStorage = getById(resources.getBucketId()); + bucketStorage.copy(resources); + bucketStorageMapper.updateById(bucketStorage); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteAll(List<Long> ids) { + bucketStorageMapper.deleteBatchIds(ids); + } + + @Override + public void download(List<BucketStorage> all, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (BucketStorage bucketStorage : all) { + Map<String, Object> map = new LinkedHashMap<>(); + map.put("文件真实的名称", bucketStorage.getRealName()); + map.put("文件名", bucketStorage.getName()); + map.put("后缀", bucketStorage.getSuffix()); + map.put("路径", bucketStorage.getPath()); + map.put("类型", bucketStorage.getType()); + map.put("大小", bucketStorage.getSize()); + map.put("创建人", bucketStorage.getCreateBy()); + map.put("创建时间", bucketStorage.getCreateTime()); + map.put("修改者", bucketStorage.getUpdateBy()); + map.put("修改时间", bucketStorage.getUpdateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/oying-tools/src/main/java/com/oying/utils/ObsProperties.java b/oying-tools/src/main/java/com/oying/utils/ObsProperties.java new file mode 100644 index 0000000..c6e0724 --- /dev/null +++ b/oying-tools/src/main/java/com/oying/utils/ObsProperties.java @@ -0,0 +1,21 @@ +package com.oying.utils; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author xin + * @description + * @date 2025/6/3 01:54 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "obs") +public class ObsProperties { + + private String accessKeyId; + private String accessKeySecret; + private String bucket; + private String endpoint; +} diff --git a/oying-tools/src/main/java/com/oying/utils/ObsUtils.java b/oying-tools/src/main/java/com/oying/utils/ObsUtils.java new file mode 100644 index 0000000..23c45fe --- /dev/null +++ b/oying-tools/src/main/java/com/oying/utils/ObsUtils.java @@ -0,0 +1,127 @@ +package com.oying.utils; + +import com.obs.services.ObsClient; +import com.obs.services.model.AccessControlList; +import com.obs.services.model.ObsObject; +import com.obs.services.model.PutObjectRequest; +import com.obs.services.model.PutObjectResult; +import com.oying.exception.BadRequestException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; + +public class ObsUtils { + + + + /** + * 创建ObsClient实例 + * + * @param properties obs配置 + * @return ObsClient实例 + */ + public static ObsClient getObsClient(ObsProperties properties) { + // 创建ObsClient实例 + return new ObsClient(properties.getAccessKeyId(), properties.getAccessKeySecret(), properties.getEndpoint()); + } + + /** + * 上传对象权限 + * + * @param properties obs配置 + * @param file 文件 + * @param objectKey 对象名 + * @param acl 对象权限 + * @return PutObjectResult + */ + public static PutObjectResult putObject(ObsProperties properties, File file, String objectKey, AccessControlList acl) { + try { + // 创建ObsClient实例 + ObsClient obsClient = getObsClient(properties); + PutObjectRequest request = new PutObjectRequest(); + request.setBucketName(properties.getBucket()); + request.setObjectKey(objectKey); + request.setFile(file); + // 对象权限 + request.setAcl(acl); + // 为待上传的本地文件路径,需要指定到具体的文件名 + return obsClient.putObject(request); + } catch (Exception e) { + throw new BadRequestException("上传对象失败" + e.getMessage()); + } finally { + FileUtil.del(file); + } + } + + /** + * 上传对象 + * + * @param properties obs配置 + * @param file 文件 + * @param objectKey 对象名 + * @return PutObjectResult + */ + public static PutObjectResult putObject(ObsProperties properties, File file, String objectKey) { + try { + // 创建ObsClient实例 + ObsClient obsClient = getObsClient(properties); + // 为待上传的本地文件路径,需要指定到具体的文件名 + return obsClient.putObject(properties.getBucket(), objectKey, file); + } catch (Exception e) { + throw new BadRequestException("上传对象失败" + e.getMessage()); + } finally { + FileUtil.del(file); + } + } + + /** + * 下载对象 + * + * @param properties obs配置 + * @param objectKey 对象名 + * @param path 保存路径 + */ + public static String getObject(ObsProperties properties, String objectKey, String path) { + // 创建ObsClient实例 + ObsClient obsClient = getObsClient(properties); + ObsObject obsObject = obsClient.getObject(properties.getBucket(), objectKey); + InputStream in = obsObject.getObjectContent(); + if (in != null) { + FileOutputStream out = null; + try { + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + out = new FileOutputStream(path); + byte[] b = new byte[1024]; + int length; + while ((length = in.read(b)) > 0) { + out.write(b, 0, length); + } + } catch (Exception e) { + throw new BadRequestException("流输出异常"); + } finally { + CloseUtil.close(in); + CloseUtil.close(out); + } + } + return path; + } + + /** + * 删除对象 + * + * @param properties obs配置 + * @param objectKey 对象名 + */ + public static void deleteObject(ObsProperties properties, String objectKey) { + // 创建ObsClient实例 + ObsClient obsClient = getObsClient(properties); + // 删除指定的对象 + obsClient.deleteObject(properties.getBucket(), objectKey); + } +} diff --git a/pom.xml b/pom.xml index 489ecc4..1264ba2 100644 --- a/pom.xml +++ b/pom.xml @@ -236,6 +236,12 @@ <artifactId>commons-text</artifactId> <version>1.13.0</version> </dependency> + <!-- 华为云对象存储服务 OBS--> + <dependency> + <groupId>com.huaweicloud</groupId> + <artifactId>esdk-obs-java-bundle</artifactId> + <version>3.22.12</version> + </dependency> </dependencies> <build> -- Gitblit v1.9.3