Sfoglia il codice sorgente

feat: 增加获取文件内容功能

ChenSiTong 6 anni fa
parent
commit
e9daffda58

+ 168 - 0
src/main/java/nju/seec/helper/api/BokApi.java

@@ -0,0 +1,168 @@
+package nju.seec.helper.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import nju.seec.helper.dto.question.BaseQuestionDTO;
+import nju.seec.helper.dto.question.ChoiceQuestionDTO;
+import nju.seec.helper.dto.question.TrueOrFalseQuestionDTO;
+import nju.seec.helper.enums.ExceptionType;
+import nju.seec.helper.enums.QuestionType;
+import nju.seec.helper.exception.HelperException;
+import nju.seec.helper.util.GuavaCacheUtil;
+import nju.seec.helper.util.RestRequestUtil;
+import nju.seec.helper.vo.question.BokQuestion;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author xst
+ * <p>
+ * updated by cst
+ */
+@Slf4j
+@Component
+public class BokApi {
+    private final RestRequestUtil restRequestUtil;
+    private final GuavaCacheUtil cacheUtils;
+    @Value("${bok.tqUrl}")
+    private String tqUrl;
+    @Value("${bok.tqStemSearchUrl}")
+    private String tqStemSearchUrl;
+    @Value("${bok.tqIdSearchUrl}")
+    private String tqIdSearchUrl;
+
+    public BokApi(RestRequestUtil restRequestUtil, GuavaCacheUtil cacheUtils) {
+        this.restRequestUtil = restRequestUtil;
+        this.cacheUtils = cacheUtils;
+    }
+
+    public Page<BokQuestion> bokFindByStemLike(String stem, Pageable pageable) {
+        Map<String, String> urlParams = ImmutableMap.of(
+                "content", stem,
+                "page", String.valueOf(1 + pageable.getPageNumber()),
+                "size", String.valueOf(pageable.getPageSize())
+        );
+        BokSearchResult result = restRequestUtil.sendGetRequest(tqStemSearchUrl, BokSearchResult.class, urlParams);
+
+        List<BokQuestion> bokQuestions = result.getEmbedded().getQuestions();
+        cacheUtils.setAll(BOK_CACHE_NAME, bokQuestions.parallelStream().collect(Collectors.toMap(BokQuestion::getId, bokQuestion -> bokQuestion)));
+        return new PageImpl<>(bokQuestions, pageable, result.getPage().getTotalElements());
+    }
+
+    private static String BOK_CACHE_NAME = "BOK";
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public List<BokQuestion> bokFindByIdIn(final List<String> ids) {
+        Map<String, BokQuestion> bokQuestionsMap = Maps.newHashMapWithExpectedSize(ids.size());
+
+        final Map<String, BokQuestion> cacheBokQuestionsMap = (Map) cacheUtils.multiGet(BOK_CACHE_NAME, ids);
+        bokQuestionsMap.putAll(cacheBokQuestionsMap);
+
+        List<String> requestIds = Lists.newArrayList(ids);
+        requestIds.removeAll(cacheBokQuestionsMap.keySet());
+        //未缓存的去这里拿
+        if (!requestIds.isEmpty()) {
+            Map<String, String> urlParams = ImmutableMap.of("id", requestIds.stream().reduce((a, b) -> a + "," + b).orElse(""));
+
+            BokSearchResult result = restRequestUtil.sendGetRequest(tqIdSearchUrl, BokSearchResult.class, urlParams);
+            List<BokQuestion> bokQuestions = result.getEmbedded().getQuestions();
+
+            Map<String, BokQuestion> remoteBokQuestionsMap = bokQuestions.parallelStream().collect(Collectors.toMap(BokQuestion::getId, bokQuestion -> bokQuestion));
+
+            bokQuestionsMap.putAll(remoteBokQuestionsMap);
+            cacheUtils.setAll(BOK_CACHE_NAME, (Map) remoteBokQuestionsMap);
+        }
+
+        return ids.stream()
+                .map(bokQuestionsMap::get)
+                .collect(Collectors.toList());
+    }
+
+    public BokQuestion bokFindById(String questionId) {
+        Object cachedBokQuestion = cacheUtils.get(BOK_CACHE_NAME, questionId);
+        if (cachedBokQuestion instanceof BokQuestion) {
+            return (BokQuestion) cachedBokQuestion;
+        }
+        BokQuestion bokQuestion = restRequestUtil.sendGetRequest(tqUrl + "/" + questionId, BokQuestion.class, Collections.emptyMap());
+        cacheUtils.set(BOK_CACHE_NAME, bokQuestion.getId(), bokQuestion);
+        return bokQuestion;
+    }
+
+    public BokQuestion createQuestion(String questionId, BaseQuestionDTO baseQuestionDTO) {
+        BokQuestion bokQuestion = getQuestion(baseQuestionDTO);
+        bokQuestion.setId(questionId);
+        bokQuestion = restRequestUtil.sendPostRequest(tqUrl, bokQuestion, BokQuestion.class);
+        return bokQuestion;
+    }
+
+    public BokQuestion modifyQuestion(String questionId, BaseQuestionDTO baseQuestionDTO) {
+        BokQuestion bokQuestion = getQuestion(baseQuestionDTO);
+        bokQuestion.setId(questionId);
+        restRequestUtil.sendPutRequest(tqUrl + "/" + questionId, bokQuestion);
+        return bokFindById(questionId);
+    }
+
+    public void deleteQuestion(String questionId) {
+        restRequestUtil.sendDeleteRequest(tqUrl + "/" + questionId);
+    }
+
+    private BokQuestion getQuestion(BaseQuestionDTO baseQuestionDTO) {
+        BokQuestion bokQuestion = new BokQuestion();
+        bokQuestion.setType(baseQuestionDTO.getType());
+        bokQuestion.setStem(baseQuestionDTO.getStem());
+        bokQuestion.setKeyPoints(baseQuestionDTO.getKeyPoints());
+        bokQuestion.setTags(baseQuestionDTO.getTags());
+        bokQuestion.setKnowledgeId(baseQuestionDTO.getKnowledgeId());
+
+        final QuestionType questionType = QuestionType.getQuestionType(baseQuestionDTO.getType());
+        switch (Objects.requireNonNull(questionType)) {
+            case CHOICE:
+                ChoiceQuestionDTO choiceQuestionDTO = (ChoiceQuestionDTO) baseQuestionDTO;
+                bokQuestion.setOptions(choiceQuestionDTO.getOptions());
+                bokQuestion.setAnswer(choiceQuestionDTO.getAnswer());
+                bokQuestion.setAnalysis(choiceQuestionDTO.getAnalysis());
+                break;
+            case TRUE_FALSE:
+                TrueOrFalseQuestionDTO trueOrFalseQuestionDTO = (TrueOrFalseQuestionDTO) baseQuestionDTO;
+                bokQuestion.setAnswer(String.valueOf(trueOrFalseQuestionDTO.getAnswer()));
+                bokQuestion.setAnalysis(trueOrFalseQuestionDTO.getAnalysis());
+                break;
+            default:
+                throw HelperException.of(ExceptionType.ERROR, "不支持的题目类型");
+        }
+        return bokQuestion;
+    }
+
+    @Data
+    private static class BokSearchResult {
+        @JsonProperty("_embedded")
+        private Embedded embedded = new Embedded();
+        private Page page;
+
+        @Data
+        private static class Embedded {
+            private List<BokQuestion> questions = Collections.emptyList();
+        }
+
+        @Data
+        private static class Page {
+            private int size;
+            private int number;
+            private int totalPages;
+            private long totalElements;
+        }
+    }
+}

+ 0 - 14
src/main/java/nju/seec/helper/config/properties/MailProperties.java

@@ -1,14 +0,0 @@
-package nju.seec.helper.config.properties;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * @author cst
- */
-@Data
-@ConfigurationProperties("helper.mail")
-public class MailProperties {
-    private String from;
-    private String subject;
-}

+ 0 - 16
src/main/java/nju/seec/helper/config/properties/OssProperties.java

@@ -1,16 +0,0 @@
-package nju.seec.helper.config.properties;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * @author cst
- */
-@Data
-@ConfigurationProperties("aliyun.oss")
-public class OssProperties {
-    private String endpoint;
-    private String accessKeyId;
-    private String accessKeySecret;
-    private String bucketName;
-}

+ 0 - 16
src/main/java/nju/seec/helper/config/properties/SmsProperties.java

@@ -1,16 +0,0 @@
-package nju.seec.helper.config.properties;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * @author cst
- */
-@Data
-@ConfigurationProperties("aliyun.sms")
-public class SmsProperties {
-    private String accessKeyId;
-    private String accessSecret;
-    private String signName;
-    private String templateCode;
-}

+ 12 - 12
src/main/java/nju/seec/helper/service/impl/QuestionServiceImpl.java

@@ -12,7 +12,7 @@ import nju.seec.helper.enums.QuizState;
 import nju.seec.helper.enums.UserType;
 import nju.seec.helper.exception.HelperException;
 import nju.seec.helper.service.QuestionService;
-import nju.seec.helper.util.BokUtil;
+import nju.seec.helper.api.BokApi;
 import nju.seec.helper.vo.question.BaseQuestionVO;
 import nju.seec.helper.vo.question.BokQuestion;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -38,21 +38,21 @@ public class QuestionServiceImpl implements QuestionService {
     private final UserDAO userDAO;
     private final QuestionRecordDAO questionRecordDAO;
 
-    private final BokUtil bokUtil;
+    private final BokApi bokApi;
 
     @Autowired
     public QuestionServiceImpl(QuizDAO quizDAO
             , UserDAO userDAO
-            , QuestionRecordDAO questionRecordDAO, BokUtil bokUtil) {
+            , QuestionRecordDAO questionRecordDAO, BokApi bokApi) {
         this.quizDAO = quizDAO;
         this.userDAO = userDAO;
         this.questionRecordDAO = questionRecordDAO;
-        this.bokUtil = bokUtil;
+        this.bokApi = bokApi;
     }
 
     @Override
     public Page<BaseQuestionVO> getQuestions(LoginUser user, String stem, Pageable pageable) {
-        return bokUtil.bokFindByStemLike(stem, pageable).map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true));
+        return bokApi.bokFindByStemLike(stem, pageable).map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true));
     }
 
     @Transactional(readOnly = true)
@@ -60,7 +60,7 @@ public class QuestionServiceImpl implements QuestionService {
     public List<BaseQuestionVO> getQuestionsByQuiz(LoginUser user, Long quizId) {
         Quiz quiz = quizDAO.findQuizById(quizId);
         List<String> questionIds = quiz.getQuestions();
-        return bokUtil.bokFindByIdIn(questionIds)
+        return bokApi.bokFindByIdIn(questionIds)
                 .stream()
                 .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, quiz.getState() == QuizState.CLOSED || user.getType() == UserType.TEACHER))
                 .collect(Collectors.toList());
@@ -70,7 +70,7 @@ public class QuestionServiceImpl implements QuestionService {
     @Override
     public List<BaseQuestionVO> getQuestionsByQuiz(Quiz quiz) {
         List<String> questionIds = quiz.getQuestions();
-        return bokUtil.bokFindByIdIn(questionIds)
+        return bokApi.bokFindByIdIn(questionIds)
                 .stream()
                 .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true))
                 .collect(Collectors.toList());
@@ -78,7 +78,7 @@ public class QuestionServiceImpl implements QuestionService {
 
     @Override
     public BaseQuestionVO getOneQuestion(LoginUser user, String questionId) {
-        return BaseQuestionVO.convertBokQuestionToVO(bokUtil.bokFindById(questionId), true);
+        return BaseQuestionVO.convertBokQuestionToVO(bokApi.bokFindById(questionId), true);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -90,7 +90,7 @@ public class QuestionServiceImpl implements QuestionService {
             questionId = UUID.randomUUID().toString().replaceAll("-", "");
         } while (questionRecordDAO.existsByQuestionId(questionId));
 
-        BokQuestion bokQuestion = bokUtil.createQuestion(questionId, baseQuestionDTO);
+        BokQuestion bokQuestion = bokApi.createQuestion(questionId, baseQuestionDTO);
         questionRecordDAO.save(new QuestionRecord()
                 .setTeacher(userDAO.findUserById(user.getId()))
                 .setQuestionId(bokQuestion.getId()));
@@ -102,7 +102,7 @@ public class QuestionServiceImpl implements QuestionService {
     public BaseQuestionVO modifyQuestion(LoginUser user, String questionId, BaseQuestionDTO baseQuestionDTO) {
         QuestionRecord questionRecord = questionRecordDAO.findByTeacherAndQuestionId(userDAO.findUserById(user.getId()), questionId)
                 .orElseThrow(() -> HelperException.of(ExceptionType.FORBIDDEN, "您无权修改该问题"));
-        BokQuestion bokQuestion = bokUtil.modifyQuestion(questionId, baseQuestionDTO);
+        BokQuestion bokQuestion = bokApi.modifyQuestion(questionId, baseQuestionDTO);
         questionRecordDAO.save(questionRecord);
         return BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true);
     }
@@ -112,7 +112,7 @@ public class QuestionServiceImpl implements QuestionService {
     public void deleteQuestion(LoginUser user, String questionId) {
         QuestionRecord questionRecord = questionRecordDAO.findByTeacherAndQuestionId(userDAO.findUserById(user.getId()), questionId)
                 .orElseThrow(() -> HelperException.of(ExceptionType.FORBIDDEN, "您无权删除该问题"));
-        bokUtil.deleteQuestion(questionId);
+        bokApi.deleteQuestion(questionId);
         questionRecordDAO.delete(questionRecord);
     }
 
@@ -122,7 +122,7 @@ public class QuestionServiceImpl implements QuestionService {
         Page<String> questionIdPage = questionRecordDAO.findQuestionIdsByTeacher(userDAO.findUserById(user.getId()), pageable);
 
         return new PageImpl<>(
-                bokUtil.bokFindByIdIn(questionIdPage.getContent())
+                bokApi.bokFindByIdIn(questionIdPage.getContent())
                         .stream()
                         .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true))
                         .collect(Collectors.toList())

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

@@ -27,7 +27,7 @@ import nju.seec.helper.util.Consts;
 import nju.seec.helper.util.OssUtils;
 import nju.seec.helper.util.RedisCacheUtils;
 import nju.seec.helper.util.file.FileInfo;
-import nju.seec.helper.util.file.FileParserContext;
+import nju.seec.helper.util.file.FileUtils;
 import nju.seec.helper.vo.SlideVO;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
@@ -189,11 +189,11 @@ public class SlideServiceImpl implements SlideService {
 
     @SneakyThrows
     private FileInfo getFileInfo(MultipartFile file) {
-        return FileParserContext.getFileInfo(file);
+        return FileUtils.getFileInfo(file);
     }
 
-    private String getObjectName(Long slideId, String slideName, String suffix) {
-        return SLIDE_STORE_DIR + File.separator + slideId + File.separator + slideName + "." + suffix;
+    private String getObjectName(Long slideId, String slideName, String extension) {
+        return SLIDE_STORE_DIR + File.separator + slideId + File.separator + slideName + "." + extension;
     }
 
     @Transactional(readOnly = true)

+ 9 - 6
src/main/java/nju/seec/helper/util/MailUtils.java

@@ -1,6 +1,7 @@
 package nju.seec.helper.util;
 
-import nju.seec.helper.config.properties.MailProperties;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.stereotype.Component;
@@ -8,21 +9,23 @@ import org.springframework.stereotype.Component;
 /**
  * @author cst
  */
+@Data
 @Component
+@ConfigurationProperties("helper.mail")
 public class MailUtils {
-    private final MailProperties mailProperties;
+    private String from;
+    private String subject;
     private final JavaMailSender mailSender;
 
-    public MailUtils(MailProperties mailProperties, JavaMailSender mailSender) {
-        this.mailProperties = mailProperties;
+    public MailUtils(JavaMailSender mailSender) {
         this.mailSender = mailSender;
     }
 
     public void sendSimpleMailMessage(String text, String... to) {
         SimpleMailMessage message = new SimpleMailMessage();
-        message.setFrom(mailProperties.getFrom());
+        message.setFrom(from);
         message.setTo(to);
-        message.setSubject(mailProperties.getSubject());
+        message.setSubject(subject);
         message.setText(text);
         mailSender.send(message);
     }

+ 13 - 11
src/main/java/nju/seec/helper/util/OssUtils.java

@@ -5,10 +5,11 @@ import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClientBuilder;
 import com.aliyun.oss.OSSException;
 import com.aliyun.oss.model.PutObjectRequest;
+import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
-import nju.seec.helper.config.properties.OssProperties;
 import nju.seec.helper.enums.ExceptionType;
 import nju.seec.helper.exception.HelperException;
+import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
@@ -23,16 +24,17 @@ import java.util.Date;
  */
 @Slf4j
 @Component
+@Data
+@ConfigurationProperties("aliyun.oss")
 public class OssUtils {
-    private final OssProperties ossProperties;
-
-    public OssUtils(OssProperties ossProperties) {
-        this.ossProperties = ossProperties;
-    }
+    private String endpoint;
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String bucketName;
 
     public void upload(String objectName, InputStream inputStream) {
         OSS ossClient = getOss();
-        PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperties.getBucketName(), objectName, inputStream);
+        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
         try {
             ossClient.putObject(putObjectRequest);
         } catch (OSSException | ClientException e) {
@@ -49,7 +51,7 @@ public class OssUtils {
         OSS ossClient = getOss();
         Date expiration = new Date(System.currentTimeMillis() + seconds * 1000);
         try {
-            URL url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), objectName, expiration);
+            URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
             return url.toString();
         } catch (OSSException | ClientException e) {
             log.error(e.getMessage());
@@ -64,7 +66,7 @@ public class OssUtils {
     public void copy(String sourceObjectName, String destinationObjectName) {
         OSS ossClient = getOss();
         try {
-            ossClient.copyObject(ossProperties.getBucketName(), sourceObjectName, ossProperties.getBucketName(), destinationObjectName);
+            ossClient.copyObject(bucketName, sourceObjectName, bucketName, destinationObjectName);
         } catch (OSSException | ClientException e) {
             log.error(e.getMessage());
             throw HelperException.of(ExceptionType.ERROR, "文件复制失败");
@@ -79,7 +81,7 @@ public class OssUtils {
     public void delete(String objectName) {
         OSS ossClient = getOss();
         try {
-            ossClient.deleteObject(ossProperties.getBucketName(), objectName);
+            ossClient.deleteObject(bucketName, objectName);
         } catch (OSSException | ClientException e) {
             log.error(e.getMessage());
             throw HelperException.of(ExceptionType.ERROR, "文件删除失败");
@@ -91,6 +93,6 @@ public class OssUtils {
     }
 
     private OSS getOss() {
-        return new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
     }
 }

+ 9 - 4
src/main/java/nju/seec/helper/util/RedisCacheUtils.java

@@ -5,6 +5,7 @@ import org.springframework.stereotype.Component;
 import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -22,23 +23,27 @@ public class RedisCacheUtils {
     }
 
     public void set(String cacheName, String key, String value, long expireTime, TimeUnit timeUnit) {
-        redisTemplate.opsForValue().set(cacheName + ":" + key, value, expireTime, timeUnit);
+        redisTemplate.opsForValue().set(combineKey(cacheName, key), value, expireTime, timeUnit);
     }
 
-    public void setAll(String cacheName, String key, String value, long expireTime, TimeUnit timeUnit) {
+    public void setAll(String cacheName, Map<String, String> putAll, long expireTime, TimeUnit timeUnit) {
         throw new NotImplementedException();
     }
 
     public String get(String cacheName, String key) {
-        return redisTemplate.opsForValue().get(cacheName + ":" + key);
+        return redisTemplate.opsForValue().get(combineKey(cacheName, key));
     }
 
     public List<String> multiGet(String cacheName, List<String> keys) {
-        List<String> body = keys.stream().map(s -> cacheName + ":" + s).collect(Collectors.toList());
+        List<String> body = keys.stream().map(key -> combineKey(cacheName, key)).collect(Collectors.toList());
         return redisTemplate.opsForValue().multiGet(body);
     }
 
     public void remove(String cacheName, String key) {
         redisTemplate.delete(cacheName + ":" + key);
     }
+
+    private String combineKey(String cacheName, String key) {
+        return cacheName + ":" + key;
+    }
 }

+ 10 - 8
src/main/java/nju/seec/helper/util/SmsUtils.java

@@ -9,9 +9,9 @@ import com.aliyuncs.http.MethodType;
 import com.aliyuncs.profile.DefaultProfile;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
-import nju.seec.helper.config.properties.SmsProperties;
 import nju.seec.helper.enums.ExceptionType;
 import nju.seec.helper.exception.HelperException;
+import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
 /**
@@ -19,16 +19,18 @@ import org.springframework.stereotype.Component;
  */
 @Component
 @Slf4j
+@Data
+@ConfigurationProperties("aliyun.sms")
 public class SmsUtils {
     private static final String OK = "OK";
-    private final SmsProperties smsProperties;
 
-    public SmsUtils(SmsProperties smsProperties) {
-        this.smsProperties = smsProperties;
-    }
+    private String accessKeyId;
+    private String accessSecret;
+    private String signName;
+    private String templateCode;
 
     public void sendSmsCode(String to, String code) {
-        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", smsProperties.getAccessKeyId(), smsProperties.getAccessSecret());
+        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret);
         IAcsClient client = new DefaultAcsClient(profile);
 
         CommonRequest request = new CommonRequest();
@@ -38,8 +40,8 @@ public class SmsUtils {
         request.setAction("SendSms");
         request.putQueryParameter("RegionId", "cn-hangzhou");
         request.putQueryParameter("PhoneNumbers", to);
-        request.putQueryParameter("SignName", smsProperties.getSignName());
-        request.putQueryParameter("TemplateCode", smsProperties.getTemplateCode());
+        request.putQueryParameter("SignName", signName);
+        request.putQueryParameter("TemplateCode", templateCode);
         request.putQueryParameter("TemplateParam", "{\"code\":" + code + "}");
         try {
             CommonResponse response = client.getCommonResponse(request);

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

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