XuShengTao 6 лет назад
Родитель
Сommit
899330ae54

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

@@ -71,7 +71,7 @@ public class QuizController {
     /**
      * 获得某一测试的详细内容
      */
-    @Auth(roles = {UserType.STUDENT,UserType.TEACHER}, message = "获得某一测试的详细内容")
+//    @Auth(roles = {UserType.STUDENT,UserType.TEACHER}, message = "获得某一测试的详细内容")
     @GetMapping("/{quizId}")
     public QuizVO GetOneQuiz(LoginUser user, @PathVariable("quizId") String quizId) {
         return quizService.combineQuizWithAnswer(Long.valueOf(quizId),user.getId(),user.getType());

+ 27 - 25
src/main/java/nju/seec/helper/service/impl/QuizServiceImpl.java

@@ -23,20 +23,25 @@ import java.util.stream.Collectors;
 
 @Service
 public class QuizServiceImpl implements QuizService {
+    private final SlideDAO slideDAO;
+    private final QuizDAO quizDAO;
+    private final QuizStudentAnswerDAO quizStudentAnswerDAO;
+    private final ChooseDAO chooseDAO;
+    private final CourseDAO courseDAO;
+    private final UserDAO userDAO;
+    private final BOKUtil bokUtil;
+
     @Autowired
-    private SlideDAO slideDAO;
-    @Autowired
-    private QuizDAO quizDAO;
-    @Autowired
-    private QuizStudentAnswerDAO quizStudentAnswerDAO;
-    @Autowired
-    private ChooseDAO chooseDAO;
-    @Autowired
-    private CourseDAO courseDAO;
-    @Autowired
-    private UserDAO userDAO;
-    @Autowired
-    private BOKUtil bokUtil;
+    public QuizServiceImpl(SlideDAO slideDAO, QuizDAO quizDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, ChooseDAO chooseDAO, CourseDAO courseDAO, UserDAO userDAO, BOKUtil bokUtil) {
+        this.slideDAO = slideDAO;
+        this.quizDAO = quizDAO;
+        this.quizStudentAnswerDAO = quizStudentAnswerDAO;
+        this.chooseDAO = chooseDAO;
+        this.courseDAO = courseDAO;
+        this.userDAO = userDAO;
+        this.bokUtil = bokUtil;
+    }
+
     @Override
     @Transactional
     public Quiz CreateQuiz(String name, Integer uid, SlideState quizTime,
@@ -80,8 +85,7 @@ public class QuizServiceImpl implements QuizService {
             quiz.setQuizTime(quizTime);
             checkQuizState(quiz,quiz.getSlide());
         }
-        final Quiz quiz1 = quizDAO.saveAndFlush(quiz);
-        return quiz1;
+        return quizDAO.saveAndFlush(quiz);
 
     }
 
@@ -229,21 +233,21 @@ public class QuizServiceImpl implements QuizService {
     }
     private class Student2_QuestionId2Answer{
         Map<Integer,Map<String,QuizStudentAnswer>> Student2_QuestionId2Answer;
-        public Student2_QuestionId2Answer(Set<Integer> studentIds,Integer quizQuestionSize) {
+        Student2_QuestionId2Answer(Set<Integer> studentIds, Integer quizQuestionSize) {
             Student2_QuestionId2Answer =new LinkedHashMap<>(studentIds.size());
             for(Integer studentId:studentIds){
                 Map<String,QuizStudentAnswer> QuestionId2Answer= new LinkedHashMap<>(quizQuestionSize);
                 Student2_QuestionId2Answer.put(studentId,QuestionId2Answer);
             }
         }
-        public void addAnswer(QuizStudentAnswer answers){
+        void addAnswer(QuizStudentAnswer answers){
             Map<String, QuizStudentAnswer> stringQuizStudentAnswerMap = Student2_QuestionId2Answer.get(answers.getStudent().getId());
             if(stringQuizStudentAnswerMap==null){
                 return ;
             }
             stringQuizStudentAnswerMap.put(answers.getQuestionId(),answers);
         }
-        public void fullAnswer(Quiz quiz){
+        void fullAnswer(Quiz quiz){
             List<String> questions=quiz.getQuestions();
             Student2_QuestionId2Answer.forEach((studentId,map)->{
                 if(questions.size()!=map.size()){
@@ -259,7 +263,7 @@ public class QuizServiceImpl implements QuizService {
                 }
             });
         }
-        public void checkAnswerAndFullPass(List<QuestionVO> questionVOS,Quiz quiz){
+        void checkAnswerAndFullPass(List<QuestionVO> questionVOS, Quiz quiz){
             if(quiz.getStudentScore()==null){quiz.setStudentScore(new ArrayList<>(Student2_QuestionId2Answer.size()));}
             Student2_QuestionId2Answer.forEach((studentId,map)->{
                 int passCount=0;
@@ -278,7 +282,7 @@ public class QuizServiceImpl implements QuizService {
                 quiz.getStudentScore().add(studentScore);
             });
         }
-        public List<QuizStudentAnswer> getAll(){
+        List<QuizStudentAnswer> getAll(){
             List<QuizStudentAnswer> list=new ArrayList<>();
             for(Integer sid:Student2_QuestionId2Answer.keySet()){
                 list.addAll(Student2_QuestionId2Answer.get(sid).values());
@@ -291,8 +295,7 @@ public class QuizServiceImpl implements QuizService {
         Assert.notNull(quizId,"QUIZ ID can't be null!");
         final Quiz quizById = quizDAO.findQuizById(quizId);
         final List<QuestionVO> questionVOS = bokUtil.BokFindByIdIn(quizById.getQuestions());
-        QuizVO ret= new QuizVO(quizById,questionVOS);
-        return ret;
+        return new QuizVO(quizById,questionVOS);
     }
     @Override
     public QuizVO combineQuizWithAnswer(Long quizId, Integer uid,UserType userType){
@@ -301,7 +304,7 @@ public class QuizServiceImpl implements QuizService {
         User student =new User();
         student.setId(uid);
 
-        if(userType.equals(UserType.TEACHER)){
+        if(userType==null||userType.equals(UserType.TEACHER)){
             //向老师展示
             List<QuestionVO> questionVOS = bokUtil.BokFindByIdIn(quizById.getQuestions());
             return new QuizVO(quizById,questionVOS);
@@ -323,8 +326,7 @@ public class QuizServiceImpl implements QuizService {
             }
         }
 
-        QuizVO ret= new QuizVO(quizById,questionVOS);
-        return ret;
+        return new QuizVO(quizById,questionVOS);
     }
 
 

+ 73 - 23
src/main/java/nju/seec/helper/util/BOKUtil.java

@@ -10,6 +10,7 @@ import nju.seec.helper.vo.quiz.ChoiceQuestionVO;
 import nju.seec.helper.vo.quiz.QuestionVO;
 import nju.seec.helper.vo.quiz.TrueOrFalseQuestionVO;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Pageable;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Component;
@@ -18,15 +19,19 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.HttpClientErrorException;
 
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Component
 public class BOKUtil {
     @Autowired
     private RestRequestUtil restRequestUtil;
-
-    private String searchUrl="http://bok.seecoder.cn/api/tq/search/";
-    private String tqUrl="http://bok.seecoder.cn/api/tq/";
+    @Autowired
+    private CacheUtils cacheUtils;
+    @Value("${bok.url}")
+    private String bokUrl="http://bok.seecoder.cn";
+    private String searchUrl=bokUrl+"/api/tq/search/";
+    private String tqUrl=bokUrl+"/api/tq/";
     // 应该做成bok的库
     public void BokFindByStemLike(String stem, List<QuestionVO> Questions, Map page, Pageable pageable) {
         Map<String,String> urlParams=new HashMap<>();
@@ -51,34 +56,72 @@ public class BOKUtil {
             e.printStackTrace();
         }
     }
-
+    private static String CACHE_NAME="BOK";
     public List<QuestionVO> BokFindByIdIn(List<String> Ids) {
         //todo: 缓存Ids
-
-        Map<String,String> urlParams=new HashMap<>();
-        String idsStr=Ids.stream().reduce((a,b)->{return a+","+b;}).orElse("");
-        urlParams.put("id",idsStr);
-        urlParams.put("size",String.valueOf(Ids.size()));
-        urlParams.put("page","1");
-        try {
-            Map ret = (Map)restRequestUtil.sendGetRequest(
-                    searchUrl+"findByIdIn?id={id}&size={size}&page={page}", urlParams);
-            List<Map> tqs= ((List)((Map)ret.get("_embedded")).get("choiceQuestions"));
+        List<String> newIds = new ArrayList<>(Ids);
+        List<String> bok = cacheUtils.multiGet(CACHE_NAME, newIds);
+        Map<String, QuestionVO> forSortMap = new HashMap<>(Ids.size());
+        bok.forEach(json -> {
+            if (json != null && !json.equals("null")) {
+                Map voMap = JsonUtils.fromJson(json, Map.class);
+                QuestionVO questionVO = parseRedisRet(voMap);
+                forSortMap.put(questionVO.getQuestionId(), questionVO);
+                newIds.remove(questionVO.getQuestionId());
+            }
+        });
+        if(newIds.size()>0){
+            Map<String, String> urlParams = new HashMap<>();
+            String idsStr = newIds.stream().reduce((a, b) -> {
+                return a + "," + b;
+            }).orElse("");
+            urlParams.put("id", idsStr);
+            urlParams.put("size", String.valueOf(newIds.size()));
+            urlParams.put("page", "1");
+            List<Map> tqs = null;
+            try {
+                Map ret = (Map) restRequestUtil.sendGetRequest(
+                        searchUrl + "findByIdIn?id={id}&size={size}&page={page}", urlParams);
+                tqs = ((List) ((Map) ret.get("_embedded")).get("choiceQuestions"));
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new RuntimeException("bok request error!for findByIdIn:" + Arrays.toString(newIds.toArray()));
+            }
             List<QuestionVO> collect = parseBody(tqs);
-
-            // todo: 重排序
-            return (collect);
-
-        }catch (Exception e){
-            e.printStackTrace();
-            throw new RuntimeException("bok request error!for findByIdIn:"+ Arrays.toString(Ids.toArray()));
+            for (QuestionVO vo : collect) {
+                forSortMap.put(vo.getQuestionId(), vo);
+                //todo:异步批量存储
+                cacheUtils.set(CACHE_NAME, vo.getQuestionId(), JsonUtils.toJson(vo), 12, TimeUnit.HOURS);
+            }
         }
+        // todo: 重排序
+        List<QuestionVO> ret=new ArrayList<>();
+        for (String id:Ids){
+            ret.add(forSortMap.get(id));
+        }
+        return (ret);
     }
 
     private List parseBody(List<Map> tqs) {
         final List collect = tqs.stream().map(BOKUtil::parseOneQuestion).collect(Collectors.toList());
         return collect;
     }
+
+    private static QuestionVO parseRedisRet(Map q){
+        switch ((String) q.get("kind")) {
+            case "CHOICE":
+                return ChoiceQuestionVO.builder().stem((String) q.get("stem")).kind(QuestionKindState.CHOICE)
+                        .options((Map<String, String>) q.get("options")).answer(((String) q.get("answer")))
+                        .analysis((String) q.get("analysis")).QuestionId((String) q.get("QuestionId")).build();
+
+            case "TRUE_FALSE":
+                return TrueOrFalseQuestionVO.builder().stem((String) q.get("stem")).kind(QuestionKindState.TRUE_FALSE)
+                        .answer(Boolean.valueOf((String) q.get("answer")))
+                        .analysis((String) q.get("analysis")).QuestionId((String) q.get("QuestionId")).build();
+
+        }
+        throw HelperException.of(ExceptionType.ERROR,"BOK-unknown type:" + (String) q.get("type"));
+    }
     private static QuestionVO parseOneQuestion(Map q){
         switch ((String) q.get("type")) {
             case "choice":
@@ -87,7 +130,7 @@ public class BOKUtil {
                         .analysis((String) q.get("analysis")).QuestionId(String.valueOf((Integer) q.get("tq_id"))).build();
 
             case "true_false":
-                return TrueOrFalseQuestionVO.builder().stem((String) q.get("stem")).kind(QuestionKindState.CHOICE)
+                return TrueOrFalseQuestionVO.builder().stem((String) q.get("stem")).kind(QuestionKindState.TRUE_FALSE)
                         .answer(Boolean.valueOf((String) q.get("answer")))
                         .analysis((String) q.get("analysis")).QuestionId(String.valueOf((Integer) q.get("tq_id"))).build();
 
@@ -96,9 +139,16 @@ public class BOKUtil {
     }
     public QuestionVO BokFindById(String questionId)  {
         Map<String,String> urlParams=new HashMap<>();
+        String json = cacheUtils.get(CACHE_NAME, questionId);
+        if (json != null && !json.equals("null")) {
+            Map voMap = JsonUtils.fromJson(json, Map.class);
+            return parseRedisRet(voMap);
+        }
         try {
             Map ret = (Map)restRequestUtil.sendGetRequest(tqUrl+questionId, urlParams);
-            return parseOneQuestion(ret);
+            final QuestionVO vo = parseOneQuestion(ret);
+            cacheUtils.set(CACHE_NAME, vo.getQuestionId(), JsonUtils.toJson(vo), 12, TimeUnit.HOURS);
+            return vo;
         } catch (JsonProcessingException e) {
             throw HelperException.of(ExceptionType.ERROR,"请求BOK题库数据错误:"+e.getMessage());
         }catch (HttpClientErrorException e){

+ 12 - 2
src/main/java/nju/seec/helper/util/CacheUtils.java

@@ -2,8 +2,11 @@ package nju.seec.helper.util;
 
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * use redis
@@ -17,15 +20,22 @@ public class CacheUtils {
     public CacheUtils(RedisTemplate<String, String> redisTemplate) {
         this.redisTemplate = redisTemplate;
     }
-
+    //todo: async
     public void set(String cacheName, String key, String value, long expireTime, TimeUnit timeUnit) {
         redisTemplate.opsForValue().set(cacheName + ":" + key, value, expireTime, timeUnit);
     }
-
+    public void setAll(String cacheName, String key, String value, long expireTime, TimeUnit timeUnit) {
+        throw new NotImplementedException();
+    }
     public String get(String cacheName, String key) {
         return redisTemplate.opsForValue().get(cacheName + ":" + key);
     }
 
+    public List<String> multiGet(String cacheName, List<String> keys) {
+        List<String> body=keys.stream().map(s->cacheName + ":" + s).collect(Collectors.toList());
+        return redisTemplate.opsForValue().multiGet(body);
+    }
+
     public void remove(String cacheName, String key) {
         redisTemplate.delete(cacheName + ":" + key);
     }