Prechádzať zdrojové kódy

improvement: 同步更新课件文件

ChenSiTong 6 rokov pred
rodič
commit
d6f0f98d95

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

@@ -10,10 +10,9 @@ import nju.seec.helper.util.enums.UserType;
 import nju.seec.helper.vo.CommentVO;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.web.PageableDefault;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
-
 /**
  * 评论
  *
@@ -34,7 +33,7 @@ public class CommentController {
     @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "发表评论")
     @PostMapping
     public CommentVO createComment(LoginUser user,
-                                   @Valid @RequestBody CommentDTO commentDTO) {
+                                   @Validated @RequestBody CommentDTO commentDTO) {
         CommentVO commentVO = commentService.createComment(user, commentDTO);
         CommentWebsocket.sendAllMessage(commentDTO.getSlideId(), JsonUtils.toJson(commentVO));
         return commentVO;

+ 10 - 3
src/main/java/nju/seec/helper/controller/ControllerAdvice.java

@@ -8,6 +8,7 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
 
 import java.util.Objects;
 
@@ -18,8 +19,14 @@ import java.util.Objects;
 @RestControllerAdvice
 public class ControllerAdvice {
     @ExceptionHandler(MethodArgumentNotValidException.class)
-    public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
-        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage()));
+    public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidatedException(MethodArgumentNotValidException e) {
+        return ResponseEntity.badRequest().body(ErrorResponse.of(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage()));
+    }
+
+    @ExceptionHandler(NoHandlerFoundException.class)
+    public ResponseEntity<ErrorResponse> handlerNoFoundException(Exception e) {
+        log.error(e.getMessage(), e);
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of("路径不存在,请检查路径是否正确"));
     }
 
     @ExceptionHandler(HelperException.class)
@@ -29,7 +36,7 @@ public class ControllerAdvice {
 
     @ExceptionHandler(Exception.class)
     public ResponseEntity<ErrorResponse> handleException(Exception e) {
-        log.error(e.getLocalizedMessage());
+        log.error(e.getLocalizedMessage(), e);
         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ErrorResponse.of("系统异常,请重试"));
     }
 }

+ 4 - 5
src/main/java/nju/seec/helper/controller/CourseController.java

@@ -11,10 +11,9 @@ import nju.seec.helper.util.enums.UserType;
 import nju.seec.helper.vo.CourseVO;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.web.PageableDefault;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
-
 /**
  * 课程
  *
@@ -35,7 +34,7 @@ public class CourseController {
     @Auth(roles = UserType.TEACHER, message = "创建课程")
     @PostMapping
     public CourseVO createCourse(LoginUser user,
-                                 @Valid @RequestBody CourseDTO courseDTO) {
+                                 @Validated @RequestBody CourseDTO courseDTO) {
         return courseService.createCourse(user, courseDTO);
     }
 
@@ -55,7 +54,7 @@ public class CourseController {
     @Auth(roles = UserType.TEACHER, message = "修改课程")
     @PutMapping
     public CourseVO modifyCourse(LoginUser user,
-                                 @Valid @RequestBody ModifyCourseDTO modifyCourseDTO) {
+                                 @Validated @RequestBody ModifyCourseDTO modifyCourseDTO) {
         return courseService.modifyCourse(user, modifyCourseDTO);
     }
 
@@ -65,7 +64,7 @@ public class CourseController {
     @Auth(roles = UserType.STUDENT, message = "选课")
     @PostMapping("/choose")
     public void chooseCourse(LoginUser user,
-                             @Valid @RequestBody ChooseDTO chooseDTO) {
+                             @Validated @RequestBody ChooseDTO chooseDTO) {
         courseService.chooseCourse(user, chooseDTO);
     }
 

+ 3 - 4
src/main/java/nju/seec/helper/controller/MessageController.java

@@ -9,10 +9,9 @@ import nju.seec.helper.service.MessageService;
 import nju.seec.helper.util.enums.UserType;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.web.PageableDefault;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
-
 /**
  * @author cst
  */
@@ -28,14 +27,14 @@ public class MessageController {
     @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "设置已读")
     @PutMapping("/read")
     public void readMessages(LoginUser user,
-                             @Valid @RequestBody MessageDTO messageDTO) {
+                             @Validated @RequestBody MessageDTO messageDTO) {
         messageService.readMessages(user, messageDTO);
     }
 
     @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "删除消息")
     @PutMapping("/delete")
     public void deleteMessages(LoginUser user,
-                               @Valid @RequestBody MessageDTO messageDTO) {
+                               @Validated @RequestBody MessageDTO messageDTO) {
         messageService.deleteMessages(user, messageDTO);
     }
 

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

@@ -6,10 +6,9 @@ import nju.seec.helper.dto.ReplyDTO;
 import nju.seec.helper.service.ReplyService;
 import nju.seec.helper.util.enums.UserType;
 import nju.seec.helper.vo.ReplyVO;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
-
 /**
  * @author cst
  */
@@ -28,7 +27,7 @@ public class ReplyController {
     @Auth(roles = UserType.TEACHER, message = "回复")
     @PostMapping
     public ReplyVO createReply(LoginUser user,
-                               @Valid @RequestBody ReplyDTO replyDTO) {
+                               @Validated @RequestBody ReplyDTO replyDTO) {
         return replyService.createReply(user, replyDTO);
     }
 

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

@@ -12,8 +12,6 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
-
 /**
  * 课件
  *
@@ -34,7 +32,7 @@ public class SlideController {
     @Auth(roles = UserType.TEACHER, message = "创建课件")
     @PostMapping
     public ResponseEntity<SlideVO> createSlide(LoginUser user,
-                                               @Valid SlideDTO slideDTO) {
+                                               @Validated SlideDTO slideDTO) {
         SlideVO slideVO = slideService.createSlide(user, slideDTO);
         return ResponseEntity.ok(slideVO);
     }

+ 3 - 4
src/main/java/nju/seec/helper/controller/UserController.java

@@ -10,7 +10,6 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpSession;
-import javax.validation.Valid;
 
 /**
  * 用户
@@ -38,7 +37,7 @@ public class UserController {
      * 邮箱登录
      */
     @PostMapping("/login/email")
-    public UserVO loginByEmail(@Valid @RequestBody LoginDTO loginDTO,
+    public UserVO loginByEmail(@Validated @RequestBody LoginDTO loginDTO,
                                HttpSession session) {
         UserVO userVO = userService.getUserByEmailAndPassword(loginDTO.getUsername(), loginDTO.getPassword());
 
@@ -68,7 +67,7 @@ public class UserController {
     @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "修改个人信息")
     @PutMapping
     public UserVO modifyUser(LoginUser user,
-                             @Valid @RequestBody ModifyUserDTO modifyUserDTO,
+                             @Validated @RequestBody ModifyUserDTO modifyUserDTO,
                              HttpSession session) {
         UserVO userVO = userService.modifyUser(user, modifyUserDTO);
         user = ((LoginUser) session.getAttribute(Consts.SESSION_USER_NAME))
@@ -83,7 +82,7 @@ public class UserController {
      * 重设密码
      */
     @PutMapping("/resetPassword/email")
-    public void resetPasswordByEmail(@Valid @RequestBody ResetPasswordDTO resetPasswordDTO) {
+    public void resetPasswordByEmail(@Validated @RequestBody ResetPasswordDTO resetPasswordDTO) {
         userService.resetPasswordByEmail(resetPasswordDTO);
     }
 

+ 1 - 0
src/main/java/nju/seec/helper/dao/CourseDAO.java

@@ -26,6 +26,7 @@ public interface CourseDAO extends JpaRepository<Course, Integer> {
      */
     default Course findCourseById(Integer id) {
         return this.findById(id)
+                .filter(course -> course.getDeleteAt() == 0)
                 .orElseThrow(() -> HelperException.of(ExceptionType.NOT_FOUND, "找不到课程"));
     }
 

+ 1 - 0
src/main/java/nju/seec/helper/dao/SlideDAO.java

@@ -27,6 +27,7 @@ public interface SlideDAO extends JpaRepository<Slide, Integer> {
      */
     default Slide findSlideById(Integer id) {
         return this.findById(id)
+                .filter(slide -> slide.getDeleteAt() == 0)
                 .orElseThrow(() -> HelperException.of(ExceptionType.NOT_FOUND, "找不到课件"));
     }
 

+ 2 - 0
src/main/java/nju/seec/helper/dto/CourseDTO.java

@@ -13,6 +13,8 @@ import java.io.Serializable;
 @Data
 public class CourseDTO implements Serializable {
     private static final long serialVersionUID = -5583485560614228661L;
+    @NotNull(message = "缺少课程ID")
+    private Integer id;
     @NotBlank(message = "课程名不能为空")
     @Length(max = 50, message = "课程名长度不能超过50")
     private String name;

+ 0 - 1
src/main/java/nju/seec/helper/dto/SlideDTO.java

@@ -14,7 +14,6 @@ import java.io.Serializable;
  */
 @Data
 public class SlideDTO implements Serializable {
-    private static final long serialVersionUID = 1346490046140163371L;
     @NotNull(message = "缺少课程ID")
     private Integer courseId;
     @NotBlank(message = "课件名不能为空")

+ 9 - 0
src/main/java/nju/seec/helper/dto/groups/Create.java

@@ -0,0 +1,9 @@
+package nju.seec.helper.dto.groups;
+
+import javax.validation.groups.Default;
+
+/**
+ * @author cst
+ */
+public interface Create extends Default {
+}

+ 9 - 0
src/main/java/nju/seec/helper/dto/groups/Modify.java

@@ -0,0 +1,9 @@
+package nju.seec.helper.dto.groups;
+
+import javax.validation.groups.Default;
+
+/**
+ * @author cst
+ */
+public interface Modify extends Default {
+}

+ 3 - 1
src/main/java/nju/seec/helper/service/impl/MessageServiceImpl.java

@@ -5,13 +5,16 @@ import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.MessageDTO;
 import nju.seec.helper.entity.Message;
 import nju.seec.helper.service.MessageService;
+import nju.seec.helper.util.enums.ExceptionType;
 import nju.seec.helper.util.enums.MessageType;
+import nju.seec.helper.util.exception.HelperException;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -27,7 +30,6 @@ public class MessageServiceImpl implements MessageService {
     }
 
     @Async
-    @Transactional(rollbackFor = Exception.class)
     @Override
     public void createMessage(Set<Integer> toUserIds, MessageType type, String content, Integer slideId) {
         messageDAO.saveAll(

+ 32 - 10
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -27,6 +27,7 @@ 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;
@@ -85,8 +86,15 @@ public class SlideServiceImpl implements SlideService {
         AuthUtils.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权修改该课件");
 
         checkSameName(slide.getId(), slide.getCourseId(), modifySlideDTO.getName());
-        slide.setName(modifySlideDTO.getName());
-        slide = slideDAO.save(slide);
+        if (!modifySlideDTO.getName().equals(slide.getName())) {
+            slide.setName(modifySlideDTO.getName());
+            String oldObjectName = slide.getObjectName();
+            String newObjectName = getObjectName(slide.getCourseId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
+            slide.setObjectName(newObjectName);
+            fileUtils.copy(oldObjectName, newObjectName);
+            slide = slideDAO.save(slide);
+            fileUtils.delete(oldObjectName);
+        }
         return new SlideVO(slide);
     }
 
@@ -121,6 +129,22 @@ public class SlideServiceImpl implements SlideService {
         slideDAO.save(slide);
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void removeSlide(LoginUser user, Integer slideId) {
+        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.copy(oldObjectName, deleteObjectName);
+        slideDAO.save(slide);
+        fileUtils.delete(oldObjectName);
+    }
+
+    @SuppressWarnings("all")
     @SneakyThrows
     private void handleFile(Slide slide, MultipartFile file) {
         switch (Objects.requireNonNull(file.getContentType())) {
@@ -131,7 +155,7 @@ public class SlideServiceImpl implements SlideService {
                 slide.setPages(pages);
 
                 // 上传文件
-                String objectName = slide.getCourseId() + File.separator + slide.getName() + ".pdf";
+                String objectName = getObjectName(slide.getCourseId(), slide.getName(), "pdf");
                 fileUtils.upload(objectName, file.getInputStream());
                 slide.setObjectName(objectName);
 
@@ -141,14 +165,12 @@ public class SlideServiceImpl implements SlideService {
         }
     }
 
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public void removeSlide(LoginUser user, Integer slideId) {
-        Slide slide = slideDAO.findSlideById(slideId);
-        AuthUtils.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权删除该课件");
+    private String getObjectName(Integer courseId, String slideName, String suffix) {
+        return courseId + File.separator + slideName + "." + suffix;
+    }
 
-        slide.setDeleteAt(System.currentTimeMillis());
-        slideDAO.save(slide);
+    private String getDeleteObjectName(Integer courseId, String slideName, String suffix) {
+        return courseId + File.separator + "delete" + File.separator + LocalDateTime.now() + File.separator + slideName + "." + suffix;
     }
 
     @Transactional(readOnly = true)

+ 36 - 2
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;
@@ -30,7 +31,7 @@ public class FileUtils {
     }
 
     public void upload(String objectName, InputStream inputStream) {
-        OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+        OSS ossClient = getOss();
         PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperties.getBucketName(), objectName, inputStream);
         try {
             ossClient.putObject(putObjectRequest);
@@ -45,7 +46,7 @@ public class FileUtils {
     }
 
     public String getUrl(String objectName, long seconds) {
-        OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+        OSS ossClient = getOss();
         Date expiration = new Date(System.currentTimeMillis() + seconds * 1000);
         try {
             URL url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), objectName, expiration);
@@ -59,4 +60,37 @@ public class FileUtils {
             }
         }
     }
+
+    public void copy(String sourceObjectName, String destinationObjectName) {
+        OSS ossClient = getOss();
+        try {
+            ossClient.copyObject(ossProperties.getBucketName(), sourceObjectName, ossProperties.getBucketName(), destinationObjectName);
+        } catch (OSSException | ClientException e) {
+            log.error(e.getMessage());
+            throw HelperException.of(ExceptionType.ERROR, "文件拷贝失败");
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+    @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

@@ -10,7 +10,7 @@ spring:
       ddl-auto: update
     database: mysql
     database-platform: org.hibernate.dialect.MySQL8Dialect
-    show-sql: false
+    show-sql: true
   http:
     encoding:
       force: true