浏览代码

调整分类接口

reghao 3 年之前
父节点
当前提交
512f2fc55c
共有 26 个文件被更改,包括 621 次插入486 次删除
  1. 3 3
      src/main/java/cn/reghao/dfs/store/oss/controller/BucketBasicController.java
  2. 35 35
      src/main/java/cn/reghao/dfs/store/oss/controller/BucketController.java
  3. 21 12
      src/main/java/cn/reghao/dfs/store/oss/controller/ObjectBasicController.java
  4. 12 4
      src/main/java/cn/reghao/dfs/store/oss/controller/ObjectMultipartUploadController.java
  5. 1 2
      src/main/java/cn/reghao/dfs/store/oss/model/dto/DeleteObjects.java
  6. 39 0
      src/main/java/cn/reghao/dfs/store/oss/model/dto/PostObject.java
  7. 0 24
      src/main/java/cn/reghao/dfs/store/oss/model/po/object/PostObject.java
  8. 2 0
      src/main/java/cn/reghao/dfs/store/oss/model/po/service/ListAllMyBucketsResult.java
  9. 0 10
      src/main/java/cn/reghao/dfs/store/oss/model/po/service/Owner.java
  10. 13 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/CompleteMultipartUpload.java
  11. 15 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Delete.java
  12. 12 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/DeleteResult.java
  13. 9 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Deleted.java
  14. 11 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Error.java
  15. 7 10
      src/main/java/cn/reghao/dfs/store/oss/model/vo/InitiateMultipartUploadResult.java
  16. 16 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Initiator.java
  17. 32 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/ListPartsResult.java
  18. 9 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Object.java
  19. 16 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Owner.java
  20. 24 0
      src/main/java/cn/reghao/dfs/store/oss/model/vo/Part.java
  21. 0 11
      src/main/java/cn/reghao/dfs/store/oss/service/BucketBasicService.java
  22. 328 1
      src/main/java/cn/reghao/dfs/store/oss/service/ObjectBasicService.java
  23. 14 0
      src/main/java/cn/reghao/dfs/store/oss/service/ObjectMultipartUploadService.java
  24. 0 24
      src/main/java/cn/reghao/dfs/store/oss/service/ObjectService.java
  25. 0 348
      src/main/java/cn/reghao/dfs/store/oss/service/ObjectServiceImpl.java
  26. 2 2
      src/main/resources/application.yml

+ 3 - 3
src/main/java/cn/reghao/dfs/store/oss/controller/BucketBasicController.java

@@ -23,13 +23,13 @@ public class BucketBasicController {
     }
 
     @ApiOperation("创建一个存储桶")
-    @PutMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucket() {
         return WebBody.success();
     }
 
     @ApiOperation("检查存储桶是否存在")
-    @RequestMapping(value = "/", method = RequestMethod.HEAD, produces = MediaType.APPLICATION_JSON_VALUE)
+    @RequestMapping(value = "/", method = RequestMethod.HEAD, produces = MediaType.APPLICATION_XML_VALUE)
     public String headBucket() {
         return WebBody.success();
     }
@@ -43,7 +43,7 @@ public class BucketBasicController {
     }
 
     @ApiOperation(value = "删除指定的存储桶")
-    @DeleteMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucket() {
         return WebBody.success();
     }

+ 35 - 35
src/main/java/cn/reghao/dfs/store/oss/controller/BucketController.java

@@ -20,211 +20,211 @@ import java.util.List;
 @RequestMapping("/bucket")
 public class BucketController {
     @ApiOperation(value = "删除指定存储桶的 CORS 配置")
-    @DeleteMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketCors() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的默认加密配置")
-    @DeleteMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketEncryption() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的策略配置")
-    @DeleteMapping(value = "/", params = {"policy"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"policy"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketPolicy() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的复制配置")
-    @DeleteMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketReplication() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的静态网站托管配置")
-    @DeleteMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketWebsite() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的生命周期配置")
-    @DeleteMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketLifecycle() {
         return WebBody.success();
     }
 
     @ApiOperation(value = "删除指定存储桶的某个清单任务")
-    @DeleteMapping(value = "/", params = {"inventory"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @DeleteMapping(value = "/", params = {"inventory"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String deleteBucketInventoryConfiguration(@RequestParam("id") String id) {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的 ACL")
-    @GetMapping(value = "/", params = {"acl"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"acl"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketAcl() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的回调通知配置")
-    @GetMapping(value = "/", params = {"notification"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"notification"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketNotification() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的 cors 配置")
-    @GetMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketCors() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的默认加密配置")
-    @GetMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketEncryption() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的策略配置")
-    @GetMapping(value = "/", params = {"uploadId"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"uploadId"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketPolicy() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的复制配置信息")
-    @GetMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketReplication() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的静态网站托管配置")
-    @GetMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketWebsite() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的生命周期规则")
-    @GetMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketLifecycle() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的默认保存周期策略")
-    @GetMapping(value = "/", params = {"object-lock"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"object-lock"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketObjectLockConfiguration() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶中设置的标签")
-    @GetMapping(value = "/", params = {"tagging"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"tagging"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketTagging() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的传输加速规则")
-    @GetMapping(value = "/", params = {"accelerate"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"accelerate"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketAccelerate() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶中用户的任务清单")
-    @GetMapping(value = "/", params = {"inventory", "id"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"inventory", "id"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketInventoryConfiguration(@PathVariable("id") String id) {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的访问日志保存规则")
-    @GetMapping(value = "/", params = {"logging"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"logging"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String getBucketLogging() {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶中正在进行的分片上传")
-    @GetMapping(value = "/", params = {"uploads"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"uploads"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String listMultipartUploads(@RequestParam("maxUploads") int maxUploads) {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的所有清单任务")
-    @GetMapping(value = "/", params = {"inventory", "continuationToken"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @GetMapping(value = "/", params = {"inventory", "continuationToken"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String listBucketInventoryConfigurations(@RequestParam("continuationToken") String continuationToken) {
         return WebBody.success();
     }
 
     @ApiOperation("创建或修改存储桶的回调通知配置")
-    @PutMapping(value = "/", params = {"notification"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"notification"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketNotification() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的 CORS 配置")
-    @PutMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"cors"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketCors() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的 ACL 配置")
-    @PutMapping(value = "/", params = {"acl"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"acl"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketAcl() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的加密配置")
-    @PutMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"encryption"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketEncryption() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的权限策略配置")
-    @PutMapping(value = "/", params = {"policy"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"policy"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketPolicy() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的复制配置")
-    @PutMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"replication"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketReplication() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的静态网站配置")
-    @PutMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"website"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketWebsite() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的生命周期配置")
-    @PutMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"lifecycle"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketLifecycle() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的默认保存周期策略")
-    @PutMapping(value = "/", params = {"object-lock"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"object-lock"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketObjectLockConfiguration() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶中设置的标签")
-    @PutMapping(value = "/", params = {"tagging"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"tagging"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketTagging() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶的传输加速规则")
-    @PutMapping(value = "/", params = {"accelerate"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"accelerate"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketAccelerate() {
         return WebBody.success();
     }
 
     @ApiOperation("添加或修改存储桶中用户的任务清单")
-    @PutMapping(value = "/", params = {"inventory"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"inventory"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketInventoryConfiguration(@PathVariable("id") String id) {
         return WebBody.success();
     }
 
     @ApiOperation("获取存储桶的访问日志保存规则")
-    @PutMapping(value = "/", params = {"logging"}, produces = MediaType.APPLICATION_JSON_VALUE)
+    @PutMapping(value = "/", params = {"logging"}, produces = MediaType.APPLICATION_XML_VALUE)
     public String putBucketLogging() {
         return WebBody.success();
     }

+ 21 - 12
src/main/java/cn/reghao/dfs/store/oss/controller/ObjectBasicController.java

@@ -1,12 +1,14 @@
 package cn.reghao.dfs.store.oss.controller;
 
-import cn.reghao.dfs.store.oss.model.po.object.DeleteObjects;
-import cn.reghao.dfs.store.oss.service.ObjectServiceImpl;
+import cn.reghao.dfs.store.oss.model.dto.PostObject;
+import cn.reghao.dfs.store.oss.model.dto.DeleteObjects;
+import cn.reghao.dfs.store.oss.service.ObjectBasicService;
 import cn.reghao.jutil.jdk.result.WebBody;
 import cn.reghao.jutil.web.ServletUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.rocksdb.RocksDBException;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -22,12 +24,13 @@ import java.nio.charset.StandardCharsets;
 @RestController
 @RequestMapping("/object")
 public class ObjectBasicController {
-    private final ObjectServiceImpl objectService;
+    private final ObjectBasicService objectBasicService;
 
-    public ObjectBasicController(ObjectServiceImpl objectService) {
-        this.objectService = objectService;
+    public ObjectBasicController(ObjectBasicService objectBasicService) {
+        this.objectBasicService = objectBasicService;
     }
 
+    // TODO tomcat 如何支持 PUT 请求上传文件? 目前使用的 multipart 方式
     @ApiOperation("上传对象")
     @PutMapping(value = "/**")
     public String putObject(MultipartFile file) throws Exception {
@@ -35,20 +38,24 @@ public class ObjectBasicController {
         String uri1 = URLDecoder.decode(uri, StandardCharsets.UTF_8);
 
         String objectName = uri1.replace("/object", "");
-        objectService.putObject(objectName, file);
+        objectBasicService.putObject(objectName, file);
         return WebBody.success();
     }
 
     @ApiOperation("使用 formdata 上传对象")
     @PostMapping(value = "/")
-    public String postObject(@RequestParam("key") String objectName, @RequestParam("file") MultipartFile file) {
+    public String postObject(@Validated PostObject postObject) {
         return WebBody.success();
     }
 
     @ApiOperation("获取对象的元数据")
-    @RequestMapping(value = "/{objectName}", method = RequestMethod.HEAD)
-    public String headObject(@PathVariable("objectName") String objectName) throws RocksDBException {
-        objectService.headObject(objectName);
+    @RequestMapping(value = "/**", method = RequestMethod.HEAD)
+    public String headObject() throws RocksDBException {
+        String uri = ServletUtil.getRequest().getRequestURI();
+        String uri1 = URLDecoder.decode(uri, StandardCharsets.UTF_8);
+
+        String objectName = uri1.replace("/object/", "");
+        objectBasicService.headObject(objectName);
         return WebBody.success();
     }
 
@@ -58,13 +65,14 @@ public class ObjectBasicController {
         String uri = ServletUtil.getRequest().getRequestURI();
         String uri1 = URLDecoder.decode(uri, StandardCharsets.UTF_8);
 
-        String objectName = uri1.replace("/object", "");
-        objectService.getObject(objectName);
+        String objectName = uri1.replace("/object/", "");
+        objectBasicService.getObject(objectName);
     }
 
     @ApiOperation(value = "删除对象")
     @DeleteMapping(value = "/{objectName}")
     public String deleteObject(@PathVariable("objectName") String objectName) {
+        objectBasicService.deleteObject(objectName);
         return WebBody.success();
     }
 
@@ -77,6 +85,7 @@ public class ObjectBasicController {
     @ApiOperation("创建已存在对象的副本")
     @PutMapping(value = "/{destinationObject}", params = {"destinationObject"})
     public String putObjectCopy(@PathVariable("destinationObject") String destinationObject) {
+        objectBasicService.putObjectCopy();
         return WebBody.success();
     }
 }

+ 12 - 4
src/main/java/cn/reghao/dfs/store/oss/controller/ObjectMultipartUploadController.java

@@ -1,5 +1,7 @@
 package cn.reghao.dfs.store.oss.controller;
 
+import cn.reghao.dfs.store.oss.model.vo.InitiateMultipartUploadResult;
+import cn.reghao.dfs.store.oss.model.vo.ListPartsResult;
 import cn.reghao.jutil.jdk.result.WebBody;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -16,8 +18,9 @@ import org.springframework.web.multipart.MultipartFile;
 public class ObjectMultipartUploadController {
     @ApiOperation("开启分片上传")
     @PostMapping(value = "/{objectName}", params = {"uploads"})
-    public String initiateMultipartUpload(@PathVariable("objectName") String objectName) {
-        return WebBody.success();
+    public InitiateMultipartUploadResult initiateMultipartUpload(@PathVariable("objectName") String objectName) {
+        InitiateMultipartUploadResult initiateMultipartUploadResult = new InitiateMultipartUploadResult();
+        return initiateMultipartUploadResult;
     }
 
     @ApiOperation("分片上传对象")
@@ -45,8 +48,13 @@ public class ObjectMultipartUploadController {
 
     @ApiOperation("获取分片 uploadId 下的所有分片")
     @GetMapping(value = "/{objectName}", params = {"uploadId"})
-    public String listParts(@PathVariable("objectName") String objectName, @RequestParam("uploadId") String uploadId) {
-        return WebBody.success();
+    public ListPartsResult listParts(@PathVariable("objectName") String objectName,
+                                     @RequestParam("uploadId") String uploadId,
+                                     @RequestParam(value = "encodingType", required = false) String encodingType,
+                                     @RequestParam(value = "maxParts", required = false) String maxParts,
+                                     @RequestParam(value = "partNumberMarker", required = false) String partNumberMarker) {
+        ListPartsResult listPartsResult = new ListPartsResult();
+        return listPartsResult;
     }
 
     @ApiOperation("复制已存在的对象作为源数据上传分片")

+ 1 - 2
src/main/java/cn/reghao/dfs/store/oss/model/po/object/DeleteObjects.java → src/main/java/cn/reghao/dfs/store/oss/model/dto/DeleteObjects.java

@@ -1,4 +1,4 @@
-package cn.reghao.dfs.store.oss.model.po.object;
+package cn.reghao.dfs.store.oss.model.dto;
 
 import java.io.Serializable;
 
@@ -8,5 +8,4 @@ import java.io.Serializable;
  */
 public class DeleteObjects implements Serializable {
     private static final long serialVersionUID = 1L;
-
 }

+ 39 - 0
src/main/java/cn/reghao/dfs/store/oss/model/dto/PostObject.java

@@ -0,0 +1,39 @@
+package cn.reghao.dfs.store.oss.model.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * @author reghao
+ * @date 2022-11-21 10:53:54
+ */
+@NoArgsConstructor
+@Getter
+@Setter
+public class PostObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private String cacheControl;
+    private String contentType;
+    private String contentDisposition;
+    private String contentEncoding;
+    private String expires;
+    @NotBlank
+    private String key;
+    private String policy;
+    private String successActionRedirect;
+    private String successActionStatus;
+    private String xAmzAlgorithm;
+    private String xAmzCredential;
+    private String xAmzDate;
+    private String xAmzSignature;
+    private String xAmzStorageClass;
+    @NotNull
+    private MultipartFile file;
+}

+ 0 - 24
src/main/java/cn/reghao/dfs/store/oss/model/po/object/PostObject.java

@@ -1,24 +0,0 @@
-package cn.reghao.dfs.store.oss.model.po.object;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import java.io.Serializable;
-
-/**
- * @author reghao
- * @date 2022-11-21 10:53:54
- */
-@AllArgsConstructor
-@Getter
-public class PostObject implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    @NotBlank
-    private String key;
-    @NotNull
-    private MultipartFile file;
-}

+ 2 - 0
src/main/java/cn/reghao/dfs/store/oss/model/po/service/ListAllMyBucketsResult.java

@@ -1,5 +1,7 @@
 package cn.reghao.dfs.store.oss.model.po.service;
 
+import cn.reghao.dfs.store.oss.model.vo.Owner;
+
 import java.util.List;
 
 /**

+ 0 - 10
src/main/java/cn/reghao/dfs/store/oss/model/po/service/Owner.java

@@ -1,10 +0,0 @@
-package cn.reghao.dfs.store.oss.model.po.service;
-
-/**
- * @author reghao
- * @date 2022-11-21 17:31:06
- */
-public class Owner {
-    private String id;
-    private String displayName;
-}

+ 13 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/CompleteMultipartUpload.java

@@ -0,0 +1,13 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:46:04
+ */
+@XmlRootElement(name = "CompleteMultipartUpload")
+public class CompleteMultipartUpload {
+    private List<Part> parts;
+}

+ 15 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Delete.java

@@ -0,0 +1,15 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:58:03
+ */
+public class Delete {
+    @XmlElement(name = "Quiet")
+    private boolean quiet;
+    private String key;
+    private List<Object> objects;
+}

+ 12 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/DeleteResult.java

@@ -0,0 +1,12 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:53:30
+ */
+@XmlRootElement(name = "DeleteResult")
+public class DeleteResult {
+}

+ 9 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Deleted.java

@@ -0,0 +1,9 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:56:34
+ */
+public class Deleted {
+    private String key;
+}

+ 11 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Error.java

@@ -0,0 +1,11 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:55:43
+ */
+public class Error {
+    private String key;
+    private String code;
+    private String message;
+}

+ 7 - 10
src/main/java/cn/reghao/dfs/store/oss/model/vo/InitiateMultipartUploadResult.java

@@ -1,24 +1,21 @@
 package cn.reghao.dfs.store.oss.model.vo;
 
-import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
 
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import java.io.Serializable;
 
 /**
  * @author reghao
  * @date 2022-11-21 15:45:15
  */
-@AllArgsConstructor
-@XmlRootElement
-public class InitiateMultipartUploadResult implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    @XmlElement
+@NoArgsConstructor
+@XmlRootElement(name = "InitiateMultipartUploadResult")
+public class InitiateMultipartUploadResult {
+    @XmlElement(name = "Bucket")
     private String bucket;
-    @XmlElement
+    @XmlElement(name = "Key")
     private String key;
-    @XmlElement
+    @XmlElement(name = "UploadId")
     private String uploadId;
 }

+ 16 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Initiator.java

@@ -0,0 +1,16 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:38:50
+ */
+@XmlRootElement(name = "Initiator")
+public class Initiator {
+    @XmlElement(name = "ID")
+    private String id;
+    @XmlElement(name = "DisplayName")
+    private String displayName;
+}

+ 32 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/ListPartsResult.java

@@ -0,0 +1,32 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:35:01
+ */
+@XmlRootElement(name = "ListPartsResult")
+public class ListPartsResult {
+    @XmlElement(name = "Bucket")
+    private String bucket;
+    @XmlElement(name = "Key")
+    private String key;
+    @XmlElement(name = "UploadId")
+    private String uploadId;
+    @XmlElement(name = "Initiator")
+    private Initiator initiator;
+    @XmlElement(name = "Owner")
+    private Owner owner;
+    @XmlElement(name = "StorageClass")
+    private String storageClass;
+    @XmlElement(name = "PartNumberMarker")
+    private int partNumberMarker;
+    @XmlElement(name = "NextPartNumberMarker")
+    private int nextPartNumberMarker;
+    @XmlElement(name = "IsTruncated")
+    private boolean isTruncated;
+    private List<Part> parts;
+}

+ 9 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Object.java

@@ -0,0 +1,9 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:59:27
+ */
+public class Object {
+    private String key;
+}

+ 16 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Owner.java

@@ -0,0 +1,16 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @author reghao
+ * @date 2022-11-21 17:31:06
+ */
+@XmlRootElement(name = "Owner")
+public class Owner {
+    @XmlElement(name = "ID")
+    private String id;
+    @XmlElement(name = "DisplayName")
+    private String displayName;
+}

+ 24 - 0
src/main/java/cn/reghao/dfs/store/oss/model/vo/Part.java

@@ -0,0 +1,24 @@
+package cn.reghao.dfs.store.oss.model.vo;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.time.LocalDateTime;
+
+/**
+ * @author reghao
+ * @date 2022-12-09 16:37:57
+ */
+@XmlRootElement(name = "Part")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Part {
+    @XmlElement(name = "PartNumber")
+    private int partNumber;
+    @XmlElement(name = "LastModified")
+    private LocalDateTime lastModified;
+    @XmlElement(name = "ETag")
+    private String eTag;
+    @XmlElement(name = "Size")
+    private long size;
+}

+ 0 - 11
src/main/java/cn/reghao/dfs/store/oss/service/BucketBasicService.java

@@ -1,11 +0,0 @@
-package cn.reghao.dfs.store.oss.service;
-
-import org.springframework.stereotype.Service;
-
-/**
- * @author reghao
- * @date 2022-12-08 20:43:36
- */
-@Service
-public class BucketBasicService {
-}

+ 328 - 1
src/main/java/cn/reghao/dfs/store/oss/service/ObjectBasicService.java

@@ -1,11 +1,338 @@
 package cn.reghao.dfs.store.oss.service;
 
+import cn.reghao.dfs.store.meta.RocksClient;
+import cn.reghao.dfs.store.oss.db.mapper.DataBlockMapper;
+import cn.reghao.dfs.store.oss.db.mapper.FileMetaMapper;
+import cn.reghao.dfs.store.oss.model.po.ContentRange;
+import cn.reghao.dfs.store.oss.model.po.DataBlock;
+import cn.reghao.dfs.store.oss.model.po.FileMeta;
+import cn.reghao.dfs.store.service.FileStoreService;
+import cn.reghao.dfs.store.service.FileUrlService;
+import cn.reghao.jutil.jdk.security.DigestUtil;
+import cn.reghao.jutil.tool.id.IdGenerator;
+import cn.reghao.jutil.web.ServletUtil;
+import org.rocksdb.RocksDBException;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
 
 /**
  * @author reghao
- * @date 2022-12-08 20:43:47
+ * @date 2022-11-23 09:40:18
  */
 @Service
 public class ObjectBasicService {
+    private final RocksClient rocksClient;
+    private final IdGenerator objectIdGenerator;
+    private final IdGenerator blockIdGenerator;
+    private final FileMetaMapper fileMetaMapper;
+    private final DataBlockMapper dataBlockMapper;
+    // 20MiB
+    private final int blockSize = 1024*1024*20;
+    // 10MiB
+    private final long partLength = 1024*1024*10;
+    private FileStoreService fileStoreService;
+    private FileUrlService fileUrlService;
+
+    public ObjectBasicService(RocksClient rocksClient, FileMetaMapper fileMetaMapper, DataBlockMapper dataBlockMapper,
+                              FileStoreService fileStoreService, FileUrlService fileUrlService) {
+        this.rocksClient = rocksClient;
+        this.objectIdGenerator = new IdGenerator(32, "object-id");
+        this.blockIdGenerator = new IdGenerator(32, "block-id");
+        this.fileMetaMapper = fileMetaMapper;
+        this.dataBlockMapper = dataBlockMapper;
+        this.fileStoreService = fileStoreService;
+        this.fileUrlService = fileUrlService;
+    }
+
+    public void putObject(String objectName, MultipartFile multipartFile) throws Exception {
+        String objectKey = String.format("/%s", objectName);
+        byte[] value = rocksClient.get(objectKey);
+        if (value != null) {
+            return;
+        }
+
+        String contentType = multipartFile.getContentType();
+        long len = multipartFile.getSize();
+        InputStream inputStream = multipartFile.getInputStream();
+
+        String objectId = objectIdGenerator.stringId();
+
+        List<DataBlock> list = store(objectId, len, inputStream);
+        String sha256sum = DigestUtil.sha256sum(new FileInputStream(list.get(0).getAbsolutePath()));
+        FileMeta fileMeta = fileMetaMapper.findBySha256sum(sha256sum);
+        if (fileMeta == null) {
+            fileMeta = new FileMeta(objectName, objectId, len, contentType, sha256sum);
+            dataBlockMapper.saveAll(list);
+            fileMetaMapper.save(fileMeta);
+        }
+    }
+
+    private List<DataBlock> store(String objectId, long len, InputStream inputStream) throws IOException {
+        List<DataBlock> list = new ArrayList<>();
+        String absolutePath = fileUrlService.genFilePath(len, objectId, "dat");
+        fileStoreService.saveFile(absolutePath, inputStream);
+
+        String blockId = UUID.randomUUID().toString();
+        list.add(new DataBlock(objectId, 0, blockId, absolutePath));
+        return list;
+    }
+
+    private List<DataBlock> store1(String objectId, InputStream inputStream) throws IOException, RocksDBException {
+        List<DataBlock> list = new ArrayList<>();
+        byte[] buf = new byte[blockSize];
+        int index = 0;
+        int readLen;
+        while ((readLen = inputStream.read(buf, 0, blockSize)) != -1) {
+            //String blockId = blockIdGenerator.stringId();
+            String blockId = UUID.randomUUID().toString();
+            rocksClient.put(blockId, buf);
+            list.add(new DataBlock(objectId, index, blockId, ""));
+            index++;
+        }
+        return list;
+    }
+
+    public void postObject() {
+    }
+
+    public void headObject(String objectName) throws RocksDBException {
+    }
+
+    public void getObject(String objectName) throws RocksDBException, IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        FileMeta fileMeta = fileMetaMapper.findByObjectName(objectName);
+        if (fileMeta == null) {
+            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+
+            OutputStream outputStream = response.getOutputStream();
+            outputStream.flush();
+            outputStream.close();
+            return;
+        }
+
+        String objectId = fileMeta.getObjectId();
+        String contentType = fileMeta.getContentType();
+        long len = fileMeta.getSize();
+        if (len < partLength) {
+            writeWholeContent(objectId, contentType, len);
+            return;
+        }
+
+        String range = ServletUtil.getRequest().getHeader("range");
+        if (range != null) {
+            String rangeStr = StringUtils.trimAllWhitespace(range);
+            String[] arr = rangeStr.replace("bytes=", "").split("-");
+            long start = Long.parseLong(arr[0]);
+            if (arr.length == 1) {
+                writePartialContent(objectId, contentType, start, len);
+            } else {
+                ContentRange contentRange = parseContentRange(range, len);
+                byte[] bytes = range1(objectId, contentRange.getStart(), contentRange.getEnd());
+                writePartialContent(bytes, contentType, contentRange, len);
+            }
+        } else {
+            writeAcceptRanges(contentType, len);
+            //writeDownloadContent(objectName, objectId, 0, len);
+        }
+    }
+
+    private void writeAcceptRanges(String contentType, long len) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.setContentType(contentType);
+        response.setHeader("Content-Length", ""+len);
+        response.setHeader("Accept-Ranges", "bytes");
+
+        OutputStream outputStream = response.getOutputStream();
+        outputStream.flush();
+        outputStream.close();
+    }
+
+    private ContentRange parseContentRange(String range, long len) {
+        String rangeStr = StringUtils.trimAllWhitespace(range);
+        String[] arr = rangeStr.replace("bytes=", "").split("-");
+        long start = Long.parseLong(arr[0]);
+        long end = 0;
+        if (arr.length == 2) {
+            end = Long.parseLong(arr[1]);
+        } else {
+            long l = len - start;
+            if (l > 0) {
+                end = Math.min(l, partLength) + start;
+            } else {
+                System.out.println();
+            }
+        }
+
+        return new ContentRange(start, end);
+    }
+
+    private void writePartialContent(byte[] bytes, String contentType, ContentRange contentRange, long len) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+        response.setContentType(contentType);
+        response.setHeader("Content-Length", ""+(contentRange.getEnd()-contentRange.getStart()));
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("Content-Range", "bytes "+contentRange.getStart()+"-"+contentRange.getEnd()+"/"+len);
+
+        OutputStream outputStream = response.getOutputStream();
+        outputStream.write(bytes);
+        outputStream.flush();
+        outputStream.close();
+    }
+
+    private void writePartialContent(String objectId, String contentType, long start, long len) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+        response.setContentType(contentType);
+        response.setHeader("Content-Length", ""+(len-start));
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);
+
+        OutputStream outputStream = response.getOutputStream();
+        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
+        DataBlock dataBlock = list.get(0);
+        String blockId = dataBlock.getBlockId();
+        String absolutePath = dataBlock.getAbsolutePath();
+        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+        raf.seek(start);
+
+        // 10MiB
+        int bufSize = 1024*1024*10;
+        byte[] buf = new byte[bufSize];
+        int readLen;
+        while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
+            outputStream.write(buf, 0, readLen);
+            outputStream.flush();
+        }
+        outputStream.close();
+        raf.close();
+    }
+
+    private void writeDownloadContent(String objectName, String objectId, long start, long len) {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+        response.setContentType("application/octet-stream");
+        /*response.setHeader("Content-Length", ""+(len-start));
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);*/
+
+        try {
+            response.setHeader("Content-Disposition",
+                    "attachment;filename=" + URLEncoder.encode(objectName, StandardCharsets.UTF_8.toString()));
+
+            OutputStream outputStream = response.getOutputStream();
+            List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
+            DataBlock dataBlock = list.get(0);
+            String blockId = dataBlock.getBlockId();
+            String absolutePath = dataBlock.getAbsolutePath();
+            RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+            raf.seek(start);
+
+            // 10MiB
+            int bufSize = 1024*1024*10;
+            byte[] buf = new byte[bufSize];
+            int readLen;
+            while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
+                outputStream.write(buf, 0, readLen);
+            }
+            outputStream.flush();
+            outputStream.close();
+            raf.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void writeWholeContent(String objectId, String contentType, long len) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.setContentType(contentType);
+        //response.setHeader("Content-Length", ""+len);
+
+        OutputStream outputStream = response.getOutputStream();
+        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
+        DataBlock dataBlock = list.get(0);
+        String blockId = dataBlock.getBlockId();
+        String absolutePath = dataBlock.getAbsolutePath();
+        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+
+        // 1MiB
+        int bufSize = 1024*1024;
+        byte[] buf = new byte[bufSize];
+        int readLen;
+        while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
+            outputStream.write(buf, 0, readLen);
+        }
+        outputStream.flush();
+        outputStream.close();
+        raf.close();
+    }
+
+    private byte[] range1(String objectId, long start, long end) throws IOException {
+        String absolutePath = dataBlockMapper.findByObjectId(objectId).get(0).getAbsolutePath();
+        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+        raf.seek(start);
+        long bufSize = end - start;
+        byte[] bytes = new byte[(int) bufSize];
+        int readBytes = raf.read(bytes);
+        raf.close();
+        return bytes;
+    }
+
+    private byte[] range(String objectId, long start, long end) throws RocksDBException {
+        /*int index1 = (int)(start/blockSize + start%blockSize);
+        int index2 = (int)(end/blockSize + end%blockSize);
+
+        Map<Integer, DataBlock> map = dataBlockMapper.findByObjectId(objectId).stream()
+                .collect(Collectors.toMap(DataBlock::getIndex, Function.identity()));
+        byte[] result = new byte[0];
+        for (int i = index1; i < index2; i++) {
+            DataBlock dataBlock = map.get(index1);
+            String blockId = dataBlock.getBlockId();
+            byte[] bytes = rocksClient.get(blockId);
+            result = mergeByteArray(result, bytes);
+        }*/
+
+        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
+        byte[] result = new byte[0];
+        for (int i = 0; i < 10; i++) {
+            DataBlock dataBlock = list.get(i);
+            String blockId = dataBlock.getBlockId();
+            byte[] bytes = rocksClient.get(blockId);
+            result = mergeByteArray(result, bytes);
+        }
+        /*for (DataBlock dataBlock : list) {
+            String blockId = dataBlock.getBlockId();
+            byte[] bytes = rocksClient.get(blockId);
+            result = mergeByteArray(result, bytes);
+        }*/
+
+        return result;
+    }
+
+    private byte[] mergeByteArray(byte[] arr1, byte[] arr2) {
+        byte[] arr3 = new byte[arr1.length + arr2.length];
+        System.arraycopy(arr1, 0, arr3, 0, arr1.length);
+        System.arraycopy(arr2, 0, arr3, arr1.length, arr2.length);
+        return arr3;
+    }
+
+    public void deleteObject(String objectName) {
+    }
+
+    public void deleteMultipleObjects() {
+    }
+
+    public void putObjectCopy() {
+    }
 }

+ 14 - 0
src/main/java/cn/reghao/dfs/store/oss/service/ObjectMultipartUploadService.java

@@ -8,4 +8,18 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class ObjectMultipartUploadService {
+    public void initiateMultipartUpload() {
+    }
+
+    public void uploadPart() {
+    }
+
+    public void completeMultipartUpload() {
+    }
+
+    public void abortMultipartUpload() {
+    }
+
+    public void listParts() {
+    }
 }

+ 0 - 24
src/main/java/cn/reghao/dfs/store/oss/service/ObjectService.java

@@ -1,24 +0,0 @@
-package cn.reghao.dfs.store.oss.service;
-
-import org.rocksdb.RocksDBException;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.*;
-
-/**
- * @author reghao
- * @date 2022-11-23 09:40:18
- */
-public interface ObjectService {
-    void putObject(String objectName, MultipartFile multipartFile) throws Exception;
-    void postObject();
-    void initiateMultipartUpload();
-    void uploadPart();
-    void completeMultipartUpload();
-    void abortMultipartUpload();
-    void listParts();
-    void headObject(String objectName) throws RocksDBException;
-    void getObject(String objectName) throws RocksDBException, IOException;
-    void deleteObject();
-    void deleteMultipleObjects();
-}

+ 0 - 348
src/main/java/cn/reghao/dfs/store/oss/service/ObjectServiceImpl.java

@@ -1,348 +0,0 @@
-package cn.reghao.dfs.store.oss.service;
-
-import cn.reghao.dfs.store.meta.RocksClient;
-import cn.reghao.dfs.store.oss.db.mapper.DataBlockMapper;
-import cn.reghao.dfs.store.oss.db.mapper.FileMetaMapper;
-import cn.reghao.dfs.store.oss.model.po.ContentRange;
-import cn.reghao.dfs.store.oss.model.po.DataBlock;
-import cn.reghao.dfs.store.oss.model.po.FileMeta;
-import cn.reghao.dfs.store.service.FileStoreService;
-import cn.reghao.dfs.store.service.FileUrlService;
-import cn.reghao.jutil.jdk.security.DigestUtil;
-import cn.reghao.jutil.tool.id.IdGenerator;
-import cn.reghao.jutil.web.ServletUtil;
-import org.rocksdb.RocksDBException;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.*;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-
-/**
- * @author reghao
- * @date 2022-11-23 09:40:18
- */
-@Service
-public class ObjectServiceImpl implements ObjectService {
-    private final RocksClient rocksClient;
-    private final IdGenerator objectIdGenerator;
-    private final IdGenerator blockIdGenerator;
-    private final FileMetaMapper fileMetaMapper;
-    private final DataBlockMapper dataBlockMapper;
-    // 20MiB
-    private final int blockSize = 1024*1024*20;
-    // 10MiB
-    private final long partLength = 1024*1024*10;
-    private FileStoreService fileStoreService;
-    private FileUrlService fileUrlService;
-
-    public ObjectServiceImpl(RocksClient rocksClient, FileMetaMapper fileMetaMapper, DataBlockMapper dataBlockMapper,
-                             FileStoreService fileStoreService, FileUrlService fileUrlService) {
-        this.rocksClient = rocksClient;
-        this.objectIdGenerator = new IdGenerator(32, "object-id");
-        this.blockIdGenerator = new IdGenerator(32, "block-id");
-        this.fileMetaMapper = fileMetaMapper;
-        this.dataBlockMapper = dataBlockMapper;
-        this.fileStoreService = fileStoreService;
-        this.fileUrlService = fileUrlService;
-    }
-
-    public void putObject(String objectName, MultipartFile multipartFile) throws Exception {
-        String objectKey = String.format("/%s", objectName);
-        byte[] value = rocksClient.get(objectKey);
-        if (value != null) {
-            return;
-        }
-
-        String contentType = multipartFile.getContentType();
-        long len = multipartFile.getSize();
-        InputStream inputStream = multipartFile.getInputStream();
-
-        String objectId = objectIdGenerator.stringId();
-
-        List<DataBlock> list = store(objectId, len, inputStream);
-        String sha256sum = DigestUtil.sha256sum(new FileInputStream(list.get(0).getAbsolutePath()));
-        FileMeta fileMeta = fileMetaMapper.findBySha256sum(sha256sum);
-        if (fileMeta == null) {
-            fileMeta = new FileMeta(objectName, objectId, len, contentType, sha256sum);
-            dataBlockMapper.saveAll(list);
-            fileMetaMapper.save(fileMeta);
-        }
-    }
-
-    private List<DataBlock> store(String objectId, long len, InputStream inputStream) throws IOException {
-        List<DataBlock> list = new ArrayList<>();
-        String absolutePath = fileUrlService.genFilePath(len, objectId, "dat");
-        fileStoreService.saveFile(absolutePath, inputStream);
-
-        String blockId = UUID.randomUUID().toString();
-        list.add(new DataBlock(objectId, 0, blockId, absolutePath));
-        return list;
-    }
-
-    private List<DataBlock> store1(String objectId, InputStream inputStream) throws IOException, RocksDBException {
-        List<DataBlock> list = new ArrayList<>();
-        byte[] buf = new byte[blockSize];
-        int index = 0;
-        int readLen;
-        while ((readLen = inputStream.read(buf, 0, blockSize)) != -1) {
-            //String blockId = blockIdGenerator.stringId();
-            String blockId = UUID.randomUUID().toString();
-            rocksClient.put(blockId, buf);
-            list.add(new DataBlock(objectId, index, blockId, ""));
-            index++;
-        }
-        return list;
-    }
-
-    public void postObject() {
-    }
-
-    public void initiateMultipartUpload() {
-    }
-
-    public void uploadPart() {
-    }
-
-    public void completeMultipartUpload() {
-    }
-
-    public void abortMultipartUpload() {
-    }
-
-    public void listParts() {
-    }
-
-    public void headObject(String objectName) throws RocksDBException {
-    }
-
-    public void getObject(String objectName) throws RocksDBException, IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        FileMeta fileMeta = fileMetaMapper.findByObjectName(objectName);
-        if (fileMeta == null) {
-            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
-
-            OutputStream outputStream = response.getOutputStream();
-            outputStream.flush();
-            outputStream.close();
-            return;
-        }
-
-        String objectId = fileMeta.getObjectId();
-        String contentType = fileMeta.getContentType();
-        long len = fileMeta.getSize();
-        if (len < partLength) {
-            writeWholeContent(objectId, contentType, len);
-            return;
-        }
-
-        String range = ServletUtil.getRequest().getHeader("range");
-        if (range != null) {
-            String rangeStr = StringUtils.trimAllWhitespace(range);
-            String[] arr = rangeStr.replace("bytes=", "").split("-");
-            long start = Long.parseLong(arr[0]);
-            if (arr.length == 1) {
-                writePartialContent(objectId, contentType, start, len);
-            } else {
-                ContentRange contentRange = parseContentRange(range, len);
-                byte[] bytes = range1(objectId, contentRange.getStart(), contentRange.getEnd());
-                writePartialContent(bytes, contentType, contentRange, len);
-            }
-        } else {
-            writeAcceptRanges(contentType, len);
-            //writeDownloadContent(objectName, objectId, 0, len);
-        }
-    }
-
-    private void writeAcceptRanges(String contentType, long len) throws IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.setContentType(contentType);
-        response.setHeader("Content-Length", ""+len);
-        response.setHeader("Accept-Ranges", "bytes");
-
-        OutputStream outputStream = response.getOutputStream();
-        outputStream.flush();
-        outputStream.close();
-    }
-
-    private ContentRange parseContentRange(String range, long len) {
-        String rangeStr = StringUtils.trimAllWhitespace(range);
-        String[] arr = rangeStr.replace("bytes=", "").split("-");
-        long start = Long.parseLong(arr[0]);
-        long end = 0;
-        if (arr.length == 2) {
-            end = Long.parseLong(arr[1]);
-        } else {
-            long l = len - start;
-            if (l > 0) {
-                end = Math.min(l, partLength) + start;
-            } else {
-                System.out.println();
-            }
-        }
-
-        return new ContentRange(start, end);
-    }
-
-    private void writePartialContent(byte[] bytes, String contentType, ContentRange contentRange, long len) throws IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
-        response.setContentType(contentType);
-        response.setHeader("Content-Length", ""+(contentRange.getEnd()-contentRange.getStart()));
-        response.setHeader("Accept-Ranges", "bytes");
-        response.setHeader("Content-Range", "bytes "+contentRange.getStart()+"-"+contentRange.getEnd()+"/"+len);
-
-        OutputStream outputStream = response.getOutputStream();
-        outputStream.write(bytes);
-        outputStream.flush();
-        outputStream.close();
-    }
-
-    private void writePartialContent(String objectId, String contentType, long start, long len) throws IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
-        response.setContentType(contentType);
-        response.setHeader("Content-Length", ""+(len-start));
-        response.setHeader("Accept-Ranges", "bytes");
-        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);
-
-        OutputStream outputStream = response.getOutputStream();
-        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
-        DataBlock dataBlock = list.get(0);
-        String blockId = dataBlock.getBlockId();
-        String absolutePath = dataBlock.getAbsolutePath();
-        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-        raf.seek(start);
-
-        // 10MiB
-        int bufSize = 1024*1024*10;
-        byte[] buf = new byte[bufSize];
-        int readLen;
-        while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
-            outputStream.write(buf, 0, readLen);
-            outputStream.flush();
-        }
-        outputStream.close();
-        raf.close();
-    }
-
-    private void writeDownloadContent(String objectName, String objectId, long start, long len) {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
-        response.setContentType("application/octet-stream");
-        /*response.setHeader("Content-Length", ""+(len-start));
-        response.setHeader("Accept-Ranges", "bytes");
-        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);*/
-
-        try {
-            response.setHeader("Content-Disposition",
-                    "attachment;filename=" + URLEncoder.encode(objectName, StandardCharsets.UTF_8.toString()));
-
-            OutputStream outputStream = response.getOutputStream();
-            List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
-            DataBlock dataBlock = list.get(0);
-            String blockId = dataBlock.getBlockId();
-            String absolutePath = dataBlock.getAbsolutePath();
-            RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-            raf.seek(start);
-
-            // 10MiB
-            int bufSize = 1024*1024*10;
-            byte[] buf = new byte[bufSize];
-            int readLen;
-            while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
-                outputStream.write(buf, 0, readLen);
-            }
-            outputStream.flush();
-            outputStream.close();
-            raf.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private void writeWholeContent(String objectId, String contentType, long len) throws IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.setContentType(contentType);
-        //response.setHeader("Content-Length", ""+len);
-
-        OutputStream outputStream = response.getOutputStream();
-        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
-        DataBlock dataBlock = list.get(0);
-        String blockId = dataBlock.getBlockId();
-        String absolutePath = dataBlock.getAbsolutePath();
-        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-
-        // 1MiB
-        int bufSize = 1024*1024;
-        byte[] buf = new byte[bufSize];
-        int readLen;
-        while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
-            outputStream.write(buf, 0, readLen);
-        }
-        outputStream.flush();
-        outputStream.close();
-        raf.close();
-    }
-
-    private byte[] range1(String objectId, long start, long end) throws IOException {
-        String absolutePath = dataBlockMapper.findByObjectId(objectId).get(0).getAbsolutePath();
-        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-        raf.seek(start);
-        long bufSize = end - start;
-        byte[] bytes = new byte[(int) bufSize];
-        int readBytes = raf.read(bytes);
-        raf.close();
-        return bytes;
-    }
-
-    private byte[] range(String objectId, long start, long end) throws RocksDBException {
-        /*int index1 = (int)(start/blockSize + start%blockSize);
-        int index2 = (int)(end/blockSize + end%blockSize);
-
-        Map<Integer, DataBlock> map = dataBlockMapper.findByObjectId(objectId).stream()
-                .collect(Collectors.toMap(DataBlock::getIndex, Function.identity()));
-        byte[] result = new byte[0];
-        for (int i = index1; i < index2; i++) {
-            DataBlock dataBlock = map.get(index1);
-            String blockId = dataBlock.getBlockId();
-            byte[] bytes = rocksClient.get(blockId);
-            result = mergeByteArray(result, bytes);
-        }*/
-
-        List<DataBlock> list = dataBlockMapper.findByObjectId(objectId);
-        byte[] result = new byte[0];
-        for (int i = 0; i < 10; i++) {
-            DataBlock dataBlock = list.get(i);
-            String blockId = dataBlock.getBlockId();
-            byte[] bytes = rocksClient.get(blockId);
-            result = mergeByteArray(result, bytes);
-        }
-        /*for (DataBlock dataBlock : list) {
-            String blockId = dataBlock.getBlockId();
-            byte[] bytes = rocksClient.get(blockId);
-            result = mergeByteArray(result, bytes);
-        }*/
-
-        return result;
-    }
-
-    private byte[] mergeByteArray(byte[] arr1, byte[] arr2) {
-        byte[] arr3 = new byte[arr1.length + arr2.length];
-        System.arraycopy(arr1, 0, arr3, 0, arr1.length);
-        System.arraycopy(arr2, 0, arr3, arr1.length, arr2.length);
-        return arr3;
-    }
-
-    public void deleteObject() {
-    }
-
-    public void deleteMultipleObjects() {
-    }
-}

+ 2 - 2
src/main/resources/application.yml

@@ -11,8 +11,8 @@ server:
 spring:
   servlet:
     multipart:
-      max-request-size: 10GB
-      max-file-size: 10GB
+      max-request-size: 5GB
+      max-file-size: 5GB
   application:
     name: dfs-store
   profiles: