Преглед на файлове

分离 putObject 和 getObject 操作

reghao преди 2 години
родител
ревизия
59ac4aae1a

+ 11 - 8
dfs-store/src/main/java/cn/reghao/dfs/store/controller/ObjectBasicController.java

@@ -4,7 +4,8 @@ import cn.reghao.dfs.store.model.dto.PostObject;
 import cn.reghao.dfs.store.model.dto.DeleteObjects;
 import cn.reghao.dfs.store.model.vo.PostResponse;
 import cn.reghao.dfs.store.redis.ds.RedisString;
-import cn.reghao.dfs.store.service.ObjectBasicService;
+import cn.reghao.dfs.store.service.GetObjectService;
+import cn.reghao.dfs.store.service.PutObjectService;
 import cn.reghao.jutil.jdk.converter.ByteHex;
 import cn.reghao.jutil.jdk.result.WebResult;
 import cn.reghao.jutil.jdk.security.Base64Util;
@@ -38,11 +39,13 @@ import java.util.*;
 @Api(tags = "对象基础操作接口")
 @RestController
 public class ObjectBasicController {
-    private final ObjectBasicService objectBasicService;
+    private final PutObjectService putObjectService;
+    private final GetObjectService getObjectService;
     private final RedisString redisString;
 
-    public ObjectBasicController(ObjectBasicService objectBasicService, RedisString redisString) {
-        this.objectBasicService = objectBasicService;
+    public ObjectBasicController(PutObjectService putObjectService, GetObjectService getObjectService, RedisString redisString) {
+        this.putObjectService = putObjectService;
+        this.getObjectService = getObjectService;
         this.redisString = redisString;
     }
 
@@ -86,7 +89,7 @@ public class ObjectBasicController {
         }
 
         String objectName = OssUtil.getObjectName();
-        objectBasicService.putObject(objectName, file, sha256sum);
+        putObjectService.putObject(objectName, file, sha256sum);
 
         DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", Locale.CHINA);
         df.setTimeZone(TimeZone.getTimeZone("GMT"));
@@ -123,7 +126,7 @@ public class ObjectBasicController {
         MultipartFile file = postObject.getFile();
         long len = file.getSize();
         InputStream inputStream = file.getInputStream();
-        objectBasicService.postObject(objectName, len, contentType, inputStream);
+        putObjectService.postObject(objectName, len, contentType, inputStream);
         PostResponse postResponse = new PostResponse();
         return WebResult.success(postResponse);
     }
@@ -135,7 +138,7 @@ public class ObjectBasicController {
         String uri1 = URLDecoder.decode(uri, StandardCharsets.UTF_8);
 
         String objectName = uri1.replaceFirst("/", "");
-        objectBasicService.headObject(objectName);
+        getObjectService.headObject(objectName);
         return WebResult.success();
     }
 
@@ -149,7 +152,7 @@ public class ObjectBasicController {
         String uri1 = URLDecoder.decode(uri, StandardCharsets.UTF_8);
 
         String objectName = uri1.replaceFirst("/", "");
-        objectBasicService.getObject(objectName);
+        getObjectService.getObject(objectName);
     }
 
     @ApiOperation(value = "删除对象")

+ 234 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/service/GetObjectService.java

@@ -0,0 +1,234 @@
+package cn.reghao.dfs.store.service;
+
+import cn.reghao.dfs.store.cache.LocalCache;
+import cn.reghao.dfs.store.db.mapper.FileMetaMapper;
+import cn.reghao.dfs.store.model.po.ContentRange;
+import cn.reghao.dfs.store.model.po.FileMeta;
+import cn.reghao.dfs.store.model.vo.ObjectMeta;
+import cn.reghao.dfs.store.redis.ds.RedisStringObj;
+import cn.reghao.jutil.web.ServletUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * @author reghao
+ * @date 2023-05-10 13:28:18
+ */
+@Slf4j
+@Service
+public class GetObjectService {
+    private final FileMetaMapper fileMetaMapper;
+    // 10MiB
+    private final int bufSize = 1024*1024*10;
+    private final LocalCache localCache;
+    private final RedisStringObj redisStringObj;
+
+    public GetObjectService(FileMetaMapper fileMetaMapper, LocalCache localCache, RedisStringObj redisStringObj) {
+        this.fileMetaMapper = fileMetaMapper;
+        this.localCache = localCache;
+        this.redisStringObj = redisStringObj;
+    }
+    
+    public void headObject(String objectName) throws 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();
+        }
+    }
+
+    public void getObject(String objectName) throws IOException {
+        String userAgent = ServletUtil.getRequest().getHeader("user-agent");
+        String host = ServletUtil.getRequest().getHeader("host");
+        HttpServletResponse response = ServletUtil.getResponse();
+
+        ObjectMeta objectMeta;
+        Object object = redisStringObj.get(objectName);
+        if (object != null) {
+            objectMeta = (ObjectMeta) object;
+        } else {
+            objectMeta = fileMetaMapper.findObjectMeta1(objectName);
+        }
+
+        if (objectMeta == null) {
+            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+            OutputStream outputStream = response.getOutputStream();
+            outputStream.flush();
+            outputStream.close();
+            return;
+        }
+
+        long len = objectMeta.getSize();
+        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) {
+                writeContentRange(objectMeta, start, objectMeta.getSize());
+            } else {
+                ContentRange contentRange = parseContentRange(range, len);
+                writeContentRange(objectMeta, contentRange.getStart(), contentRange.getEnd());
+            }
+        } else {
+            if (userAgent.contains("aws-sdk-java") || host.contains("oss.reghao.cn")) {
+                writeDownloadContent(objectMeta);
+            } else {
+                writeWholeContent(objectMeta);
+            }
+        }
+    }
+
+    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, bufSize) + start;
+            } else {
+                System.out.println();
+            }
+        }
+
+        return new ContentRange(start, end);
+    }
+
+    private void writeContentRange(ObjectMeta objectMeta, long start, long end) throws IOException {
+        long contentLength = objectMeta.getSize();
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+        response.setContentType(objectMeta.getContentType());
+        response.setHeader("Content-Length", ""+contentLength);
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("Content-Range", "bytes "+start+"-"+(end-1)+"/"+contentLength);
+
+        String cachePath = localCache.getCache(objectMeta.getObjectId());
+        if (cachePath == null || !Files.exists(Path.of(cachePath))) {
+            cachePath = objectMeta.getAbsolutePath();
+        }
+
+        OutputStream outputStream = response.getOutputStream();
+        writeResponse(outputStream, cachePath, start, end);
+
+        /*RandomAccessFile raf = new RandomAccessFile(cachePath, "r");
+        raf.seek(start);
+        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(ObjectMeta objectMeta) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.setContentType(objectMeta.getContentType());
+        response.setHeader("Content-Length", ""+objectMeta.getSize());
+        /*response.setHeader("Content-Length", ""+(len-start));
+        response.setHeader("Accept-Ranges", "bytes");
+        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);*/
+        response.setHeader("Content-Disposition", "attachment;filename=" +
+                URLEncoder.encode(objectMeta.getObjectName(), StandardCharsets.UTF_8.toString()));
+
+        OutputStream outputStream = response.getOutputStream();
+        writeResponse(outputStream, objectMeta.getAbsolutePath(), 0, objectMeta.getSize());
+
+        /*String absolutePath = objectMeta.getAbsolutePath();
+        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+        raf.seek(0);
+        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 writeWholeContent(ObjectMeta objectMeta) throws IOException {
+        HttpServletResponse response = ServletUtil.getResponse();
+        response.setStatus(HttpServletResponse.SC_OK);
+        response.setContentType(objectMeta.getContentType());
+        response.setHeader("Content-Length", ""+objectMeta.getSize());
+
+        OutputStream outputStream = response.getOutputStream();
+        writeResponse(outputStream, objectMeta.getAbsolutePath(), 0, objectMeta.getSize());
+
+        /*RandomAccessFile raf = new RandomAccessFile(objectMeta.getAbsolutePath(), "r");
+        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 writeResponse(OutputStream outputStream, String absolutePath, long start, long end) throws IOException {
+        RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
+        raf.seek(start);
+
+        long len = end-start+1;
+        if (len < bufSize) {
+            int len1 = (int) len;
+            byte[] buf1 = new byte[len1];
+            int readLen1 = raf.read(buf1, 0, len1);
+            outputStream.write(buf1, 0, readLen1);
+        } else {
+            byte[] buf = new byte[bufSize];
+            long totalRead = 0;
+            int readLen;
+            while ((readLen = raf.read(buf, 0, bufSize)) != -1) {
+                outputStream.write(buf, 0, readLen);
+                totalRead += readLen;
+
+                long left = len - totalRead;
+                if (left < bufSize) {
+                    int left1 = (int) left;
+                    byte[] buf1 = new byte[left1];
+                    int readLen1 = raf.read(buf1, 0, left1);
+                    outputStream.write(buf1, 0, readLen1);
+                    break;
+                }
+            }
+        }
+
+        outputStream.flush();
+        outputStream.close();
+        raf.close();
+    }
+}

+ 0 - 377
dfs-store/src/main/java/cn/reghao/dfs/store/service/ObjectBasicService.java

@@ -1,377 +0,0 @@
-package cn.reghao.dfs.store.service;
-
-import cn.reghao.dfs.store.cache.LocalCache;
-import cn.reghao.dfs.store.db.mapper.DataBlockMapper;
-import cn.reghao.dfs.store.db.mapper.FileContentMapper;
-import cn.reghao.dfs.store.db.mapper.FileMetaMapper;
-import cn.reghao.dfs.store.model.po.ContentRange;
-import cn.reghao.dfs.store.model.po.DataBlock;
-import cn.reghao.dfs.store.model.po.FileContent;
-import cn.reghao.dfs.store.model.po.FileMeta;
-import cn.reghao.dfs.store.model.vo.ObjectMeta;
-import cn.reghao.dfs.store.redis.ds.RedisStringObj;
-import cn.reghao.jutil.jdk.security.DigestUtil;
-import cn.reghao.jutil.tool.id.IdGenerator;
-import cn.reghao.jutil.web.ServletUtil;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.tika.Tika;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.*;
-import java.net.URLEncoder;
-import java.nio.channels.FileChannel;
-import java.nio.channels.WritableByteChannel;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * @author reghao
- * @date 2022-11-23 09:40:18
- */
-@Slf4j
-@Service
-public class ObjectBasicService {
-    private final IdGenerator objectIdGenerator;
-    private final IdGenerator blockIdGenerator;
-    private final FileMetaMapper fileMetaMapper;
-    private FileContentMapper fileContentMapper;
-    private final DataBlockMapper dataBlockMapper;
-    // 10MiB
-    private final int partLength = 1024*1024*10;
-    private final FileStoreService fileStoreService;
-    private final FileUrlService fileUrlService;
-    private final FileTypeService fileTypeService;
-    private final LocalCache localCache;
-    private final RedisStringObj redisStringObj;
-    private Tika tika = new Tika();
-
-    public ObjectBasicService(FileMetaMapper fileMetaMapper, FileContentMapper fileContentMapper,
-                              DataBlockMapper dataBlockMapper,
-                              FileStoreService fileStoreService, FileUrlService fileUrlService,
-                              FileTypeService fileTypeService, LocalCache localCache,
-                              RedisStringObj redisStringObj) {
-        this.objectIdGenerator = new IdGenerator(32, "object-id");
-        this.blockIdGenerator = new IdGenerator(32, "block-id");
-        this.fileMetaMapper = fileMetaMapper;
-        this.fileContentMapper = fileContentMapper;
-        this.dataBlockMapper = dataBlockMapper;
-        this.fileStoreService = fileStoreService;
-        this.fileUrlService = fileUrlService;
-        this.fileTypeService = fileTypeService;
-        this.localCache = localCache;
-        this.redisStringObj = redisStringObj;
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    public void putObject(String objectName, File file, String sha256sum) throws Exception {
-        String[] names = objectName.split("/");
-        String filename = names[names.length-1];
-
-        String contentType = tika.detect(file);
-        FileMeta fileMeta2 = fileMetaMapper.findByObjectName(objectName);
-        if (fileMeta2 != null) {
-            String sha256sum1 = fileMeta2.getSha256sum();
-            if (sha256sum1.equals(sha256sum)) {
-                log.info("{} 内容没有变化", objectName);
-                return;
-            }
-
-            log.info("更新对象操作暂未实现");
-            return;
-        }
-
-        addParent(objectName);
-        List<FileMeta> list = fileMetaMapper.findBySha256sum(sha256sum);
-        if (list.isEmpty()) {
-            String objectId = objectIdGenerator.stringId();
-            String contentId = UUID.randomUUID().toString().replace("-", "");
-            FileContent fileContent = new FileContent(contentId, objectId);
-            long len = file.length();
-            List<DataBlock> blocks = store(objectId, len, file);
-            int fileTypeId = fileTypeService.getFileType1(contentType);
-            FileMeta fileMeta = new FileMeta(objectName, objectId, filename, len, fileTypeId, contentType, sha256sum, "tnb", 2);
-
-            fileMetaMapper.save(fileMeta);
-            fileContentMapper.save(fileContent);
-            dataBlockMapper.saveAll(blocks);
-        } else {
-            FileMeta fileMeta = list.get(0);
-            String contentId = fileContentMapper.findContentId(fileMeta.getObjectId());
-            String objectId = UUID.randomUUID().toString().replace("-", "");
-            FileContent fileContent = new FileContent(contentId, objectId);
-            FileMeta fileMeta1 = new FileMeta(objectName, objectId, filename, fileMeta);
-
-            fileMetaMapper.save(fileMeta1);
-            fileContentMapper.save(fileContent);
-        }
-    }
-
-    private void addParent(String objectName) {
-        List<String> list = getParent(objectName);
-        List<FileMeta> fileMetas = new ArrayList<>();
-        list.forEach(parentName -> {
-            FileMeta fileMeta = fileMetaMapper.findByObjectName(parentName);
-            if (fileMeta == null) {
-                fileMetas.add(new FileMeta(parentName, 2));
-            }
-        });
-
-        if (!fileMetas.isEmpty()) {
-            fileMetaMapper.saveAll(fileMetas);
-        }
-    }
-
-    private List<String> getParent(String objectName) {
-        String[] arr = objectName.split("/");
-        List<String> list = new ArrayList<>();
-        list.add(arr[0] + "/");
-        for (int i = 1; i < arr.length-1; i++) {
-            list.add(list.get(i-1) + arr[i] + "/");
-        }
-        return list;
-    }
-
-    public void postObject(String objectName, long len, String contentType, InputStream inputStream) throws Exception {
-    }
-
-    private List<DataBlock> store(String objectId, long len, File file) throws IOException {
-        FileInputStream fis = new FileInputStream(file);
-        FileChannel inputChannel = fis.getChannel();
-
-        List<DataBlock> list = new ArrayList<>();
-        String absolutePath = fileUrlService.genFilePath(len, objectId, "dat");
-        FileOutputStream fos = new FileOutputStream(absolutePath);
-        WritableByteChannel targetChannel = fos.getChannel();
-        inputChannel.transferTo(0, inputChannel.size(), targetChannel);
-        Files.delete(file.toPath());
-
-        String blockId = UUID.randomUUID().toString();
-        list.add(new DataBlock(objectId, 0, blockId, absolutePath));
-        return list;
-    }
-
-    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;
-    }
-
-    public void headObject(String objectName) throws 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();
-        }
-    }
-
-    public void getObject(String objectName) throws IOException {
-        String userAgent = ServletUtil.getRequest().getHeader("user-agent");
-        String host = ServletUtil.getRequest().getHeader("host");
-        HttpServletResponse response = ServletUtil.getResponse();
-
-        ObjectMeta objectMeta;
-        Object object = redisStringObj.get(objectName);
-        if (object != null) {
-            objectMeta = (ObjectMeta) object;
-        } else {
-            objectMeta = fileMetaMapper.findObjectMeta(objectName);
-        }
-
-        if (objectMeta == null) {
-            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
-            OutputStream outputStream = response.getOutputStream();
-            outputStream.flush();
-            outputStream.close();
-            return;
-        }
-
-        long len = objectMeta.getSize();
-        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) {
-                writeContentRange(objectMeta, start, objectMeta.getSize());
-            } else {
-                ContentRange contentRange = parseContentRange(range, len);
-                writeContentRange(objectMeta, contentRange.getStart(), contentRange.getEnd());
-            }
-        } else {
-            if (userAgent.contains("aws-sdk-java") || host.contains("oss.reghao.cn")) {
-                writeDownloadContent(objectMeta);
-            } else {
-                writeWholeContent(objectMeta);
-            }
-        }
-    }
-
-    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 writeContentRange(ObjectMeta objectMeta, long start, long end) throws IOException {
-        long contentLength = objectMeta.getSize();
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
-        response.setContentType(objectMeta.getContentType());
-        response.setHeader("Content-Length", ""+contentLength);
-        response.setHeader("Accept-Ranges", "bytes");
-        response.setHeader("Content-Range", "bytes "+start+"-"+(end-1)+"/"+contentLength);
-
-        OutputStream outputStream = response.getOutputStream();
-        RandomAccessFile raf;
-        String cachePath = localCache.getCache(objectMeta.getObjectId());
-        if (cachePath != null && Files.exists(Path.of(cachePath))) {
-            raf = new RandomAccessFile(cachePath, "r");
-        } else {
-            raf = new RandomAccessFile(objectMeta.getAbsolutePath(), "r");
-        }
-        raf.seek(start);
-
-        byte[] buf = new byte[partLength];
-        int readLen;
-        while ((readLen = raf.read(buf, 0, partLength)) != -1) {
-            outputStream.write(buf, 0, readLen);
-            outputStream.flush();
-        }
-        outputStream.close();
-        raf.close();
-    }
-
-    private void writeDownloadContent(ObjectMeta objectMeta) {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.setContentType(objectMeta.getContentType());
-        response.setHeader("Content-Length", ""+objectMeta.getSize());
-        /*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(objectMeta.getObjectName(), StandardCharsets.UTF_8.toString()));
-
-            OutputStream outputStream = response.getOutputStream();
-            String absolutePath = objectMeta.getAbsolutePath();
-            RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-            raf.seek(0);
-
-            byte[] buf = new byte[partLength];
-            int readLen;
-            while ((readLen = raf.read(buf, 0, partLength)) != -1) {
-                outputStream.write(buf, 0, readLen);
-            }
-            outputStream.flush();
-            outputStream.close();
-            raf.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private void writeDownloadContentSdk(ObjectMeta objectMeta) {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.setContentType(objectMeta.getContentType());
-        response.setHeader("Content-Length", ""+objectMeta.getSize());
-        /*response.setHeader("Accept-Ranges", "bytes");
-        response.setHeader("Content-Range", "bytes "+start+"-"+(len-1)+"/"+len);*/
-
-        try {
-            response.setHeader("Content-Disposition", "attachment;filename=" +
-                    URLEncoder.encode(objectMeta.getObjectName(), StandardCharsets.UTF_8.toString()));
-
-            OutputStream outputStream = response.getOutputStream();
-            String absolutePath = objectMeta.getAbsolutePath();
-            RandomAccessFile raf = new RandomAccessFile(absolutePath, "r");
-            raf.seek(0);
-
-            byte[] buf = new byte[partLength];
-            int readLen;
-            while ((readLen = raf.read(buf, 0, partLength)) != -1) {
-                outputStream.write(buf, 0, readLen);
-            }
-            outputStream.flush();
-            outputStream.close();
-            raf.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private void writeWholeContent(ObjectMeta objectMeta) throws IOException {
-        HttpServletResponse response = ServletUtil.getResponse();
-        response.setStatus(HttpServletResponse.SC_OK);
-        response.setContentType(objectMeta.getContentType());
-        response.setHeader("Content-Length", ""+objectMeta.getSize());
-
-        OutputStream outputStream = response.getOutputStream();
-        RandomAccessFile raf = new RandomAccessFile(objectMeta.getAbsolutePath(), "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 void writeResponse(String absolutePath, long start, long end) {
-    }
-
-    public void deleteObject(String objectName) {
-    }
-
-    public void deleteMultipleObjects() {
-    }
-
-    public void putObjectCopy() {
-    }
-}

+ 167 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/service/PutObjectService.java

@@ -0,0 +1,167 @@
+package cn.reghao.dfs.store.service;
+
+import cn.reghao.dfs.store.cache.LocalCache;
+import cn.reghao.dfs.store.db.mapper.DataBlockMapper;
+import cn.reghao.dfs.store.db.mapper.FileContentMapper;
+import cn.reghao.dfs.store.db.mapper.FileMetaMapper;
+import cn.reghao.dfs.store.model.po.DataBlock;
+import cn.reghao.dfs.store.model.po.FileContent;
+import cn.reghao.dfs.store.model.po.FileMeta;
+import cn.reghao.dfs.store.redis.ds.RedisStringObj;
+import cn.reghao.jutil.tool.id.IdGenerator;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tika.Tika;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author reghao
+ * @date 2023-05-10 13:28:18
+ */
+@Slf4j
+@Service
+public class PutObjectService {
+    private final IdGenerator objectIdGenerator;
+    private final IdGenerator blockIdGenerator;
+    private final FileMetaMapper fileMetaMapper;
+    private FileContentMapper fileContentMapper;
+    private final DataBlockMapper dataBlockMapper;
+    private final FileStoreService fileStoreService;
+    private final FileUrlService fileUrlService;
+    private final FileTypeService fileTypeService;
+    private final LocalCache localCache;
+    private final RedisStringObj redisStringObj;
+    private Tika tika = new Tika();
+
+    public PutObjectService(FileMetaMapper fileMetaMapper, FileContentMapper fileContentMapper,
+                            DataBlockMapper dataBlockMapper,
+                            FileStoreService fileStoreService, FileUrlService fileUrlService,
+                            FileTypeService fileTypeService, LocalCache localCache,
+                            RedisStringObj redisStringObj) {
+        this.objectIdGenerator = new IdGenerator(32, "object-id");
+        this.blockIdGenerator = new IdGenerator(32, "block-id");
+        this.fileMetaMapper = fileMetaMapper;
+        this.fileContentMapper = fileContentMapper;
+        this.dataBlockMapper = dataBlockMapper;
+        this.fileStoreService = fileStoreService;
+        this.fileUrlService = fileUrlService;
+        this.fileTypeService = fileTypeService;
+        this.localCache = localCache;
+        this.redisStringObj = redisStringObj;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void putObject(String objectName, File file, String sha256sum) throws Exception {
+        String[] names = objectName.split("/");
+        String filename = names[names.length-1];
+
+        String contentType = tika.detect(file);
+        FileMeta fileMeta2 = fileMetaMapper.findByObjectName(objectName);
+        if (fileMeta2 != null) {
+            String sha256sum1 = fileMeta2.getSha256sum();
+            if (sha256sum1.equals(sha256sum)) {
+                log.info("{} 内容没有变化", objectName);
+                return;
+            }
+
+            log.info("更新对象操作暂未实现");
+            return;
+        }
+
+        addParent(objectName);
+        List<FileMeta> list = fileMetaMapper.findBySha256sum(sha256sum);
+        if (list.isEmpty()) {
+            String objectId = objectIdGenerator.stringId();
+            String contentId = UUID.randomUUID().toString().replace("-", "");
+            FileContent fileContent = new FileContent(contentId, objectId);
+            long len = file.length();
+            List<DataBlock> blocks = store(objectId, len, file);
+            int fileTypeId = fileTypeService.getFileType1(contentType);
+            FileMeta fileMeta = new FileMeta(objectName, objectId, filename, len, fileTypeId, contentType, sha256sum, "tnb", 2);
+
+            fileMetaMapper.save(fileMeta);
+            fileContentMapper.save(fileContent);
+            dataBlockMapper.saveAll(blocks);
+        } else {
+            FileMeta fileMeta = list.get(0);
+            String contentId = fileContentMapper.findContentId(fileMeta.getObjectId());
+            String objectId = UUID.randomUUID().toString().replace("-", "");
+            FileContent fileContent = new FileContent(contentId, objectId);
+            FileMeta fileMeta1 = new FileMeta(objectName, objectId, filename, fileMeta);
+
+            fileMetaMapper.save(fileMeta1);
+            fileContentMapper.save(fileContent);
+        }
+    }
+
+    private void addParent(String objectName) {
+        List<String> list = getParent(objectName);
+        List<FileMeta> fileMetas = new ArrayList<>();
+        list.forEach(parentName -> {
+            FileMeta fileMeta = fileMetaMapper.findByObjectName(parentName);
+            if (fileMeta == null) {
+                fileMetas.add(new FileMeta(parentName, 2));
+            }
+        });
+
+        if (!fileMetas.isEmpty()) {
+            fileMetaMapper.saveAll(fileMetas);
+        }
+    }
+
+    private List<String> getParent(String objectName) {
+        String[] arr = objectName.split("/");
+        List<String> list = new ArrayList<>();
+        list.add(arr[0] + "/");
+        for (int i = 1; i < arr.length-1; i++) {
+            list.add(list.get(i-1) + arr[i] + "/");
+        }
+        return list;
+    }
+
+    public void postObject(String objectName, long len, String contentType, InputStream inputStream) throws Exception {
+    }
+
+    private List<DataBlock> store(String objectId, long len, File file) throws IOException {
+        FileInputStream fis = new FileInputStream(file);
+        FileChannel inputChannel = fis.getChannel();
+
+        List<DataBlock> list = new ArrayList<>();
+        String absolutePath = fileUrlService.genFilePath(len, objectId, "dat");
+        FileOutputStream fos = new FileOutputStream(absolutePath);
+        WritableByteChannel targetChannel = fos.getChannel();
+        inputChannel.transferTo(0, inputChannel.size(), targetChannel);
+        Files.delete(file.toPath());
+
+        String blockId = UUID.randomUUID().toString();
+        list.add(new DataBlock(objectId, 0, blockId, absolutePath));
+        return list;
+    }
+
+    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;
+    }
+
+    public void deleteObject(String objectName) {
+    }
+
+    public void deleteMultipleObjects() {
+    }
+
+    public void putObjectCopy() {
+    }
+}