Ver Fonte

improvement: 可上传ppt、pptx课件

ChenSiTong há 6 anos atrás
pai
commit
e599b68dff

+ 10 - 1
pom.xml

@@ -17,7 +17,6 @@
 
     <properties>
         <java.version>1.8</java.version>
-        <swagger.version>2.8.0</swagger.version>
     </properties>
 
     <dependencies>
@@ -78,6 +77,16 @@
             <artifactId>pdfbox</artifactId>
             <version>2.0.18</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-scratchpad</artifactId>
+            <version>4.1.2</version>
+        </dependency>
         <dependency>
             <groupId>com.aliyun.oss</groupId>
             <artifactId>aliyun-sdk-oss</artifactId>

+ 1 - 1
src/main/java/nju/seec/helper/service/CourseFileService.java

@@ -24,7 +24,7 @@ public interface CourseFileService {
      * @param user
      * @param courseFileId
      */
-    void  deleteCourseFile(LoginUser user, Long courseFileId);
+    void deleteCourseFile(LoginUser user, Long courseFileId);
 
     /**
      * 取得课程附件

+ 1 - 1
src/main/java/nju/seec/helper/service/MessageService.java

@@ -29,7 +29,7 @@ public interface MessageService {
      * @param user
      * @param messageDTO
      */
-    void  deleteMessages(LoginUser user, MessageDTO messageDTO);
+    void deleteMessages(LoginUser user, MessageDTO messageDTO);
 
     /**
      * 设置消息已阅

+ 1 - 1
src/main/java/nju/seec/helper/service/NoticeService.java

@@ -46,7 +46,7 @@ public interface NoticeService {
      * @param user
      * @param noticeId
      */
-    void  deleteNotice(LoginUser user, Long noticeId);
+    void deleteNotice(LoginUser user, Long noticeId);
 
     /**
      * 取得某一公告

+ 1 - 1
src/main/java/nju/seec/helper/service/QuizService.java

@@ -44,7 +44,7 @@ public interface QuizService {
      * @param quizId
      * @return
      */
-    void  deleteQuiz(LoginUser user, Long quizId);
+    void deleteQuiz(LoginUser user, Long quizId);
 
     /**
      * 教师基于课件获取测试

+ 7 - 7
src/main/java/nju/seec/helper/service/impl/CourseFileServiceImpl.java

@@ -11,7 +11,7 @@ import nju.seec.helper.service.CourseFileService;
 import nju.seec.helper.service.CourseService;
 import nju.seec.helper.service.util.AuthUtils;
 import nju.seec.helper.util.Consts;
-import nju.seec.helper.util.FileUtils;
+import nju.seec.helper.util.OssUtils;
 import nju.seec.helper.util.RedisCacheUtils;
 import nju.seec.helper.util.enums.ExceptionType;
 import nju.seec.helper.util.exception.HelperException;
@@ -38,14 +38,14 @@ public class CourseFileServiceImpl implements CourseFileService {
 
     private final CourseService courseService;
 
-    private final FileUtils fileUtils;
+    private final OssUtils ossUtils;
     private final RedisCacheUtils cacheUtils;
 
-    public CourseFileServiceImpl(CourseDAO courseDAO, CourseFileDAO courseFileDAO, CourseService courseService, FileUtils fileUtils, RedisCacheUtils cacheUtils) {
+    public CourseFileServiceImpl(CourseDAO courseDAO, CourseFileDAO courseFileDAO, CourseService courseService, OssUtils ossUtils, RedisCacheUtils cacheUtils) {
         this.courseDAO = courseDAO;
         this.courseFileDAO = courseFileDAO;
         this.courseService = courseService;
-        this.fileUtils = fileUtils;
+        this.ossUtils = ossUtils;
         this.cacheUtils = cacheUtils;
     }
 
@@ -73,7 +73,7 @@ public class CourseFileServiceImpl implements CourseFileService {
 
         courseFileDAO.save(courseFile);
 
-        fileUtils.upload(objectName, file.getInputStream());
+        ossUtils.upload(objectName, file.getInputStream());
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -82,7 +82,7 @@ public class CourseFileServiceImpl implements CourseFileService {
         CourseFile courseFile = courseFileDAO.findCourseFileById(courseFileId);
         AuthUtils.checkDataAuth(user.getId(), courseFile.getTeacherId(), "您无权删除该附件");
         courseFileDAO.delete(courseFile);
-        fileUtils.delete(courseFile.getObjectName());
+        ossUtils.delete(courseFile.getObjectName());
     }
 
     @Transactional(readOnly = true)
@@ -107,7 +107,7 @@ public class CourseFileServiceImpl implements CourseFileService {
         if (url != null) {
             return url;
         }
-        url = fileUtils.getUrl(courseFile.getObjectName(), COURSE_FILE_URL_LIVING_SECONDS);
+        url = ossUtils.getUrl(courseFile.getObjectName(), COURSE_FILE_URL_LIVING_SECONDS);
         cacheUtils.set(Consts.COURSE_FILE_URL_CACHE_NAME, courseFile.getObjectName(), url, COURSE_FILE_URL_LIVING_SECONDS, TimeUnit.SECONDS);
         return url;
     }

+ 19 - 33
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -1,7 +1,7 @@
 package nju.seec.helper.service.impl;
 
 import com.google.common.collect.ImmutableSet;
-import lombok.AllArgsConstructor;
+import com.google.common.io.Files;
 import lombok.SneakyThrows;
 import nju.seec.helper.dao.ChooseDAO;
 import nju.seec.helper.dao.CourseDAO;
@@ -20,14 +20,15 @@ import nju.seec.helper.service.SlideService;
 import nju.seec.helper.service.util.AuthUtils;
 import nju.seec.helper.service.util.StringUtils;
 import nju.seec.helper.util.Consts;
-import nju.seec.helper.util.FileUtils;
+import nju.seec.helper.util.OssUtils;
 import nju.seec.helper.util.RedisCacheUtils;
 import nju.seec.helper.util.enums.ExceptionType;
 import nju.seec.helper.util.enums.MessageType;
 import nju.seec.helper.util.enums.SlideState;
 import nju.seec.helper.util.exception.HelperException;
+import nju.seec.helper.util.file.FileInfo;
+import nju.seec.helper.util.file.FileParserContext;
 import nju.seec.helper.vo.SlideVO;
-import org.apache.pdfbox.pdmodel.PDDocument;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.domain.Specification;
@@ -36,7 +37,6 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
@@ -54,18 +54,18 @@ public class SlideServiceImpl implements SlideService {
     private final UserDAO userDAO;
 
     private final QuizService quizService;
-    private final FileUtils fileUtils;
+    private final OssUtils ossUtils;
     private final RedisCacheUtils cacheUtils;
 
     private final MessageService messageService;
     private final CourseService courseService;
 
-    public SlideServiceImpl(CourseDAO courseDAO, SlideDAO slideDAO, ChooseDAO chooseDAO, UserDAO userDAO, FileUtils fileUtils, RedisCacheUtils cacheUtils, MessageService messageService, QuizService quizService, CourseService courseService) {
+    public SlideServiceImpl(CourseDAO courseDAO, SlideDAO slideDAO, ChooseDAO chooseDAO, UserDAO userDAO, OssUtils ossUtils, RedisCacheUtils cacheUtils, MessageService messageService, QuizService quizService, CourseService courseService) {
         this.courseDAO = courseDAO;
         this.slideDAO = slideDAO;
         this.chooseDAO = chooseDAO;
         this.userDAO = userDAO;
-        this.fileUtils = fileUtils;
+        this.ossUtils = ossUtils;
         this.cacheUtils = cacheUtils;
         this.messageService = messageService;
         this.quizService = quizService;
@@ -89,15 +89,15 @@ public class SlideServiceImpl implements SlideService {
 
         MultipartFile file = slideDTO.getFile();
         FileInfo fileInfo = getFileInfo(file);
-        slide.setPages(fileInfo.pages);
+        slide.setPages(fileInfo.getPages());
         slide.setObjectName("temp");
         slide = slideDAO.save(slide);
 
-        String objectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
+        String objectName = getObjectName(slide.getId(), slide.getName(), fileInfo.getExtension());
         slide.setObjectName(objectName);
         slide = slideDAO.save(slide);
 
-        fileUtils.upload(objectName, file.getInputStream());
+        ossUtils.upload(objectName, file.getInputStream());
 
         return new SlideVO(slide);
     }
@@ -112,13 +112,13 @@ public class SlideServiceImpl implements SlideService {
 
         slide.setName(slideDTO.getName());
         String oldObjectName = slide.getObjectName();
-        String newObjectName = getObjectName(slide.getId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
+        String newObjectName = getObjectName(slide.getId(), slide.getName(), Files.getFileExtension(oldObjectName));
         slide.setObjectName(newObjectName);
         slide = slideDAO.save(slide);
 
         if (!oldObjectName.equals(newObjectName)) {
-            fileUtils.copy(oldObjectName, newObjectName);
-            fileUtils.delete(oldObjectName);
+            ossUtils.copy(oldObjectName, newObjectName);
+            ossUtils.delete(oldObjectName);
         }
 
         return new SlideVO(slide);
@@ -164,16 +164,16 @@ public class SlideServiceImpl implements SlideService {
 
         MultipartFile file = slideFileDTO.getFile();
         FileInfo fileInfo = getFileInfo(file);
-        slide.setPages(fileInfo.pages);
+        slide.setPages(fileInfo.getPages());
 
         String oldObjectName = slide.getObjectName();
-        String newObjectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
+        String newObjectName = getObjectName(slide.getId(), slide.getName(), fileInfo.getExtension());
         slide.setObjectName(newObjectName);
         slideDAO.save(slide);
 
-        fileUtils.upload(newObjectName, file.getInputStream());
+        ossUtils.upload(newObjectName, file.getInputStream());
         if (!oldObjectName.equals(newObjectName)) {
-            fileUtils.delete(oldObjectName);
+            ossUtils.delete(oldObjectName);
         }
     }
 
@@ -187,23 +187,9 @@ public class SlideServiceImpl implements SlideService {
         slideDAO.save(slide);
     }
 
-    @SuppressWarnings("all")
     @SneakyThrows
     private FileInfo getFileInfo(MultipartFile file) {
-        switch (Objects.requireNonNull(file.getContentType())) {
-            case "application/pdf":
-                // 解析页数
-                PDDocument doc = PDDocument.load(file.getInputStream());
-                return FileInfo.of(doc.getNumberOfPages(), "pdf");
-            default:
-                throw HelperException.of(ExceptionType.PARAM_ERROR, "不支持的文件类型");
-        }
-    }
-
-    @AllArgsConstructor(staticName = "of")
-    private static class FileInfo {
-        private int pages;
-        private String suffix;
+        return FileParserContext.getFileInfo(file);
     }
 
     private String getObjectName(Long slideId, String slideName, String suffix) {
@@ -254,7 +240,7 @@ public class SlideServiceImpl implements SlideService {
         if (url != null) {
             return url;
         }
-        url = fileUtils.getUrl(slide.getObjectName(), SLIDE_URL_LIVING_SECONDS);
+        url = ossUtils.getUrl(slide.getObjectName(), SLIDE_URL_LIVING_SECONDS);
         cacheUtils.set(Consts.SLIDE_URL_CACHE_NAME, slide.getObjectName(), url, SLIDE_URL_LIVING_SECONDS, TimeUnit.SECONDS);
         return url;
     }

+ 96 - 0
src/main/java/nju/seec/helper/util/OssUtils.java

@@ -0,0 +1,96 @@
+package nju.seec.helper.util;
+
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.PutObjectRequest;
+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;
+import java.net.URL;
+import java.util.Date;
+
+/**
+ * use oss
+ *
+ * @author cst
+ */
+@Slf4j
+@Component
+public class OssUtils {
+    private final OssProperties ossProperties;
+
+    public OssUtils(OssProperties ossProperties) {
+        this.ossProperties = ossProperties;
+    }
+
+    public void upload(String objectName, InputStream inputStream) {
+        OSS ossClient = getOss();
+        PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperties.getBucketName(), objectName, inputStream);
+        try {
+            ossClient.putObject(putObjectRequest);
+        } catch (OSSException | ClientException e) {
+            log.error(e.getMessage());
+            throw HelperException.of(ExceptionType.ERROR, "文件上传失败");
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+    public String getUrl(String objectName, long seconds) {
+        OSS ossClient = getOss();
+        Date expiration = new Date(System.currentTimeMillis() + seconds * 1000);
+        try {
+            URL url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), objectName, expiration);
+            return url.toString();
+        } catch (OSSException | ClientException e) {
+            log.error(e.getMessage());
+            throw HelperException.of(ExceptionType.ERROR, "获取文件链接失败");
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+    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());
+    }
+}

+ 14 - 0
src/main/java/nju/seec/helper/util/file/FileInfo.java

@@ -0,0 +1,14 @@
+package nju.seec.helper.util.file;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author cst
+ */
+@Getter
+@AllArgsConstructor(staticName = "of")
+public class FileInfo {
+    private int pages;
+    private String extension;
+}

+ 59 - 0
src/main/java/nju/seec/helper/util/file/FileParserContext.java

@@ -0,0 +1,59 @@
+package nju.seec.helper.util.file;
+
+import com.google.common.collect.ImmutableMap;
+import lombok.SneakyThrows;
+import lombok.experimental.UtilityClass;
+import nju.seec.helper.util.enums.ExceptionType;
+import nju.seec.helper.util.exception.HelperException;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author cst
+ */
+@UtilityClass
+public class FileParserContext {
+    private static final Map<String, FileParser> FILE_PARSER_MAP;
+
+    static {
+        FILE_PARSER_MAP = ImmutableMap.of(
+                "application/pdf", file -> {
+                    PDDocument pdf = PDDocument.load(file.getInputStream());
+                    return FileInfo.of(pdf.getNumberOfPages(), "pdf");
+                }
+                , "application/vnd.ms-powerpoint", file -> {
+                    HSLFSlideShow ppt = new HSLFSlideShow(file.getInputStream());
+                    return FileInfo.of(ppt.getSlides().size(), "ppt");
+                }
+                , "application/vnd.openxmlformats-officedocument.presentationml.presentation", file -> {
+                    XMLSlideShow pptx = new XMLSlideShow(file.getInputStream());
+                    return FileInfo.of(pptx.getSlides().size(), "pptx");
+                }
+        );
+    }
+
+    @SneakyThrows
+    public FileInfo getFileInfo(MultipartFile file) {
+        return Optional.ofNullable(FILE_PARSER_MAP.get(file.getContentType()))
+                .orElseThrow(() -> HelperException.of(ExceptionType.FORBIDDEN, "不支持的文件类型"))
+                .parse(file);
+    }
+
+    @FunctionalInterface
+    private interface FileParser {
+        /**
+         * 解析文件信息
+         *
+         * @param file
+         * @return
+         * @throws IOException
+         */
+        FileInfo parse(MultipartFile file) throws IOException;
+    }
+}