Pārlūkot izejas kodu

improvement: 更改课件文件存储

ChenSiTong 6 gadi atpakaļ
vecāks
revīzija
aebd6fdf9d

+ 6 - 0
src/main/java/nju/seec/helper/controller/ControllerAdvice.java

@@ -5,6 +5,7 @@ import nju.seec.helper.controller.response.ErrorResponse;
 import nju.seec.helper.util.exception.HelperException;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -28,6 +29,11 @@ public class ControllerAdvice {
         return ResponseEntity.badRequest().body(ErrorResponse.of(e.getLocalizedMessage()));
     }
 
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<ErrorResponse> handleBindException(BindException e) {
+        return ResponseEntity.badRequest().body(ErrorResponse.of(Objects.requireNonNull(e.getFieldError()).getDefaultMessage()));
+    }
+
     @ExceptionHandler(HelperException.class)
     public ResponseEntity<ErrorResponse> handleHelperException(HelperException e) {
         return ResponseEntity.status(e.getType().getStatus()).body(ErrorResponse.of(e.getMsg()));

+ 2 - 2
src/main/java/nju/seec/helper/controller/SlideController.java

@@ -63,9 +63,9 @@ public class SlideController {
     }
 
     /**
-     * 教师修改课件状态
+     * 教师修改课件文件
      */
-    @Auth(roles = UserType.TEACHER, message = "修改课件状态")
+    @Auth(roles = UserType.TEACHER, message = "修改课件文件")
     @PutMapping("/file")
     public void modifySlideFile(LoginUser user,
                                 @Validated SlideFileDTO slideFileDTO) {

+ 1 - 1
src/main/java/nju/seec/helper/entity/Slide.java

@@ -45,7 +45,7 @@ public class Slide {
     @Column(nullable = false)
     private String name;
 
-    @Column(name = "object_name", nullable = false)
+    @Column(name = "object_name")
     private String objectName;
 
     @Column(name = "create_at", nullable = false, updatable = false)

+ 36 - 24
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -1,6 +1,7 @@
 package nju.seec.helper.service.impl;
 
 import com.google.common.collect.ImmutableSet;
+import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import nju.seec.helper.dao.ChooseDAO;
 import nju.seec.helper.dao.CourseDAO;
@@ -30,7 +31,6 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
-import java.time.LocalDateTime;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit;
  */
 @Service
 public class SlideServiceImpl implements SlideService {
+    private static final String SLIDE_STORE_DIR = "slide";
     private static final long SLIDE_URL_LIVING_SECONDS = 20 * 60;
 
     private final CourseDAO courseDAO;
@@ -77,9 +78,18 @@ public class SlideServiceImpl implements SlideService {
                 .setName(slideDTO.getName())
                 .setState(slideDTO.getState());
 
-        handleFile(slide, slideDTO.getFile());
+        MultipartFile file = slideDTO.getFile();
+        FileInfo fileInfo = getFileInfo(file);
+        slide.setPages(fileInfo.pages);
+        slide = slideDAO.save(slide);
+
+        String objectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
+        slide.setObjectName(objectName);
+        slide = slideDAO.save(slide);
+
+        fileUtils.upload(objectName, file.getInputStream());
 
-        return new SlideVO(slideDAO.save(slide));
+        return new SlideVO(slide);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -92,10 +102,11 @@ public class SlideServiceImpl implements SlideService {
         if (!slideDTO.getName().equals(slide.getName())) {
             slide.setName(slideDTO.getName());
             String oldObjectName = slide.getObjectName();
-            String newObjectName = getObjectName(slide.getCourseId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
+            String newObjectName = getObjectName(slide.getId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
             slide.setObjectName(newObjectName);
-            fileUtils.move(oldObjectName, newObjectName);
             slide = slideDAO.save(slide);
+
+            fileUtils.move(oldObjectName, newObjectName);
         }
         return new SlideVO(slide);
     }
@@ -117,6 +128,7 @@ public class SlideServiceImpl implements SlideService {
     }
 
     @Transactional(rollbackFor = Exception.class)
+    @SneakyThrows
     @Override
     public void modifySlideFile(LoginUser user, SlideFileDTO slideFileDTO) {
         Slide slide = slideDAO.findSlideById(slideFileDTO.getId());
@@ -126,9 +138,19 @@ public class SlideServiceImpl implements SlideService {
             throw HelperException.of(ExceptionType.FORBIDDEN, "该课件非草稿状态,无法修改其文件");
         }
 
-        handleFile(slide, slideFileDTO.getFile());
+        MultipartFile file = slideFileDTO.getFile();
+        FileInfo fileInfo = getFileInfo(file);
+        slide.setPages(fileInfo.pages);
 
+        String oldObjectName = slide.getObjectName();
+        String newObjectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
+        slide.setObjectName(newObjectName);
         slideDAO.save(slide);
+
+        fileUtils.upload(newObjectName, file.getInputStream());
+        if (!oldObjectName.equals(newObjectName)) {
+            fileUtils.delete(oldObjectName);
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -137,41 +159,31 @@ public class SlideServiceImpl implements SlideService {
         Slide slide = slideDAO.findSlideById(slideId);
         AuthUtils.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权删除该课件");
 
-        String oldObjectName = slide.getObjectName();
-        String deleteObjectName = getDeleteObjectName(slide.getCourseId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
-        slide.setObjectName(deleteObjectName);
         slide.setDeleteAt(System.currentTimeMillis());
-        fileUtils.move(oldObjectName, deleteObjectName);
         slideDAO.save(slide);
     }
 
     @SuppressWarnings("all")
     @SneakyThrows
-    private void handleFile(Slide slide, MultipartFile file) {
+    private FileInfo getFileInfo(MultipartFile file) {
         switch (Objects.requireNonNull(file.getContentType())) {
             case "application/pdf":
                 // 解析页数
                 PDDocument doc = PDDocument.load(file.getInputStream());
-                int pages = doc.getNumberOfPages();
-                slide.setPages(pages);
-
-                // 上传文件
-                String objectName = getObjectName(slide.getCourseId(), slide.getName(), "pdf");
-                fileUtils.upload(objectName, file.getInputStream());
-                slide.setObjectName(objectName);
-
-                break;
+                return FileInfo.of(doc.getNumberOfPages(), "pdf");
             default:
                 throw HelperException.of(ExceptionType.PARAM_ERROR, "不支持的文件类型");
         }
     }
 
-    private String getObjectName(Integer courseId, String slideName, String suffix) {
-        return courseId + File.separator + slideName + "." + suffix;
+    @AllArgsConstructor(staticName = "of")
+    private static class FileInfo {
+        private int pages;
+        private String suffix;
     }
 
-    private String getDeleteObjectName(Integer courseId, String slideName, String suffix) {
-        return courseId + File.separator + "delete" + File.separator + LocalDateTime.now() + File.separator + slideName + "." + suffix;
+    private String getObjectName(Integer slideId, String slideName, String suffix) {
+        return SLIDE_STORE_DIR + File.separator + slideId + File.separator + slideName + "." + suffix;
     }
 
     @Transactional(readOnly = true)

+ 16 - 0
src/main/java/nju/seec/helper/util/FileUtils.java

@@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
 import nju.seec.helper.config.properties.OssProperties;
 import nju.seec.helper.util.enums.ExceptionType;
 import nju.seec.helper.util.exception.HelperException;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
 import java.io.InputStream;
@@ -75,6 +76,21 @@ public class FileUtils {
         }
     }
 
+    @Async
+    public void delete(String objectName) {
+        OSS ossClient = getOss();
+        try {
+            ossClient.deleteObject(ossProperties.getBucketName(), objectName);
+        } catch (OSSException | ClientException e) {
+            log.error(e.getMessage());
+            throw HelperException.of(ExceptionType.ERROR, "文件拷贝失败");
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
     private OSS getOss() {
         return new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
     }

+ 1 - 1
src/main/resources/application-dev.yml

@@ -44,7 +44,7 @@ aliyun:
     endpoint: oss-cn-hangzhou.aliyuncs.com
     accessKeyId: LTAI4Fi1qmL4iuhH8t7G7r2H
     accessKeySecret: 7tJWyQqa0cMkQGaPMMvtH6c0VLiOO2
-    bucketName: seec-helper-pdf
+    bucketName: seec-helper-dev
   sms:
     accessKeyId: LTAI4FiAXXyNfYJLweBXpKPx
     accessSecret: IBoC7KGkZHOvxZQIfQgp98ZY48AVjW