Sfoglia il codice sorgente

Merge branch 'hotfix-add-cache' into 'Release'

Hotfix add cache



See merge request !878

huangyong 7 anni fa
parent
commit
7f58e39973

+ 53 - 0
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/util/data/CacheUtil.java

@@ -0,0 +1,53 @@
+package cn.iselab.mooctest.site.util.data;
+
+import cn.iselab.mooctest.site.service.CaseGraphService;
+import cn.iselab.mooctest.site.web.data.forMongo.CaseGraphDTO;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created on 2018/10/18
+ */
+@Component
+public class CacheUtil {
+
+    @Autowired
+    CaseGraphService caseGraphService;
+
+    @Value("${cache.expire.duration}")
+    long expireDuration;
+
+    private Cache<Long, CaseGraphDTO> metaNodeCache;
+
+    @PostConstruct
+    private void init(){
+        metaNodeCache = CacheBuilder
+                .newBuilder()
+                .maximumSize(1000)
+                .expireAfterAccess(expireDuration, TimeUnit.MINUTES)
+                .build();
+    }
+
+    public CaseGraphDTO getMetaNode(long caseId) throws ExecutionException {
+        return metaNodeCache.get(caseId, () -> caseGraphService.getCaseGraph(caseId));
+    }
+
+    public void removeMetaNodeByKey(long caseId){
+        metaNodeCache.invalidate(caseId);
+    }
+
+    public void removeMetaNodeAll(){
+        metaNodeCache.invalidateAll();
+    }
+
+
+
+
+}

+ 9 - 1
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/ctrl/CaseController.java

@@ -8,6 +8,7 @@ import cn.iselab.mooctest.site.service.fromKibug.CaseTakeService;
 import cn.iselab.mooctest.site.web.data.SearchConditionVO;
 import cn.iselab.mooctest.site.web.data.UserStarCaseVO;
 import cn.iselab.mooctest.site.web.exception.HttpBadRequestException;
+import cn.iselab.mooctest.site.web.logic.GeneralCalculateScoreLogic;
 import cn.iselab.mooctest.site.web.response.ErrorResult;
 import cn.iselab.mooctest.site.web.response.ResponseMessage;
 import cn.iselab.mooctest.site.web.response.StatusCode;
@@ -52,6 +53,8 @@ public class CaseController extends BaseSearchController {
     private CaseTakeService caseTakeService;
     @Autowired
     private UserStarCaseService userStarCaseService;
+    @Autowired
+    private GeneralCalculateScoreLogic generalCalculateScoreLogic;
 
     public Page<CaseExtendsVO> search(@RequestParam(name = "isPublic", required = false) Boolean isPublic,
                                       @RequestParam(name = "subjectId", required = false) Long subjectId,
@@ -106,7 +109,12 @@ public class CaseController extends BaseSearchController {
         if (!SecurityUtils.getSubject().isPermitted(new CasePermission(permissionStr))) {
             throw new UnauthenticatedException("forbidden");
         }
-        return caseLogic.saveGraph(caseGraphDTO);
+        CaseGraphDTO caseGraph =  caseLogic.saveGraph(caseGraphDTO);
+        //修改caseGraph后执行缓存失效
+        if(caseGraph != null){
+            generalCalculateScoreLogic.expireMetaNode(caseGraph.getCaseId());
+        }
+        return caseGraph;
     }
 
     @RequiresPermissions("case:view")

+ 15 - 0
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/ctrl/ScoreController.java

@@ -164,6 +164,21 @@ public class ScoreController extends BaseController {
         generalCalculateScoreLogic.uploadCaseScore(examId, caseId, userId, score);
     }
 
+    //使缓存的元node失效
+    @RequestMapping(value = UrlConstants.API_COMMON +
+            "expireMetaNode/{caseId}", method = RequestMethod.PUT)
+    public void expireMetaNode(@PathVariable("caseId") long caseId) {
+        generalCalculateScoreLogic.expireMetaNode(caseId);
+    }
+
+    //使所有缓存的元node失效
+    @RequestMapping(value = UrlConstants.API_COMMON +
+            "expireMetaNode", method = RequestMethod.PUT)
+    public void expireMetaNodeAll() {
+        generalCalculateScoreLogic.expireMetaNodeAll();
+    }
+
+
     @RequiresRoles("manager")
     @RequestMapping(value = UrlConstants.API + "competeAnalysis", method = RequestMethod.GET)
     public List<AssignedTaskVO> competeAnalysis(@RequestParam(value = "examId") Long examId) {

+ 4 - 0
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/data/forMongo/NodeCatch/CatchDTO.java

@@ -1,6 +1,8 @@
 package cn.iselab.mooctest.site.web.data.forMongo.NodeCatch;
 
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 /**
  * @author sean
@@ -8,6 +10,8 @@ import lombok.Data;
  */
 
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class CatchDTO {
 
     private String nodeName;

+ 4 - 0
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/logic/GeneralCalculateScoreLogic.java

@@ -52,4 +52,8 @@ public interface GeneralCalculateScoreLogic {
 
 
     void uploadCaseScore(long examId, long caseId, long userId, double score);
+
+    void expireMetaNode(long caseId);
+
+    void expireMetaNodeAll();
 }

+ 2 - 2
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/logic/impl/CalculateScoreLogicImpl.java

@@ -493,7 +493,7 @@ public class CalculateScoreLogicImpl extends BaseLogic implements CalculateSocre
         }
         catchService.postBulkCatchDTOS(catchDTOList);
 
-        generalCalculateScoreComponent.saveCaughtDetails(examId, caseId, userId, source,
+        generalCalculateScoreComponent.saveCaughtDetails(examId, caseId, userId, source,uploadTime,
                 caughtNodeDTOs);
     }
 
@@ -530,7 +530,7 @@ public class CalculateScoreLogicImpl extends BaseLogic implements CalculateSocre
             userCatchService.createUserCatch(userCatchDTO);
         }
         //上传caughtNode userCatch结束,调用算分
-        generalCalculateScoreComponent.saveCaughtDetails(examId, caseId, userId, source,
+        generalCalculateScoreComponent.saveCaughtDetails(examId, caseId, userId, source,uploadTime,
                 caughtNodeDTOs);
     }
 }

+ 93 - 68
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/logic/impl/GeneralCalculateScoreComponent.java

@@ -3,6 +3,7 @@ package cn.iselab.mooctest.site.web.logic.impl;
 import cn.iselab.mooctest.site.data.GeneralGradeDTO;
 import cn.iselab.mooctest.site.data.NodeExtends;
 import cn.iselab.mooctest.site.service.*;
+import cn.iselab.mooctest.site.util.data.CacheUtil;
 import cn.iselab.mooctest.site.util.data.JSONUtil;
 import cn.iselab.mooctest.site.web.data.forMongo.CaseGraphDTO;
 import cn.iselab.mooctest.site.web.data.forMongo.NodeCatch.CatchDTO;
@@ -12,6 +13,7 @@ import cn.iselab.mooctest.site.web.data.forMongo.graph.Node;
 import cn.iselab.mooctest.site.web.logic.strategy.HighestStrategy;
 import cn.iselab.mooctest.site.web.logic.strategy.LatestStrategy;
 import cn.iselab.mooctest.site.web.logic.strategy.ScoreStrategy;
+import java.util.stream.Collectors;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
@@ -32,9 +34,6 @@ import java.util.Map;
 @Component
 public class GeneralCalculateScoreComponent {
 
-    //获取元node服务
-    @Autowired
-    CaseGraphService caseGraphService;
     //获取被命中nodes的服务
     @Autowired
     CaughtNodeService caughtNodeService;
@@ -54,6 +53,8 @@ public class GeneralCalculateScoreComponent {
     HighestStrategy highestStrategy;
     @Autowired
     CatchService catchService;
+    @Autowired
+    CacheUtil cacheUtil;
 
     public void calculateGrade(long examId, long caseId, Long userId, String source) throws Exception {
         recordTypeScore(examId, caseId, userId, source);
@@ -66,6 +67,23 @@ public class GeneralCalculateScoreComponent {
 
     }
 
+    private void calculateGradeCurrent(long examId, long caseId, long userId, String source, String
+            uploadTime, List<CaughtNodeDTO> caughtNodeDTOS) throws Exception {
+
+        CaseGraphDTO basicNode = cacheUtil.getMetaNode(caseId);
+        List<CatchDTO> catchDTOS = caughtNodeDTOS.stream().filter
+                (CaughtNodeDTO::getIfCatch).map(x -> new CatchDTO(x.getNodeName(),x.getCategory()
+                ,null)).collect(Collectors.toList());
+        Map<String, Double> typeScoreMap = calculateTypeScore(basicNode,catchDTOS);
+        List<GeneralGradeDTO> gradeDTOList = new ArrayList<>();
+        typeScoreMap.forEach((type,score) -> gradeDTOList.add(new GeneralGradeDTO(userId,examId,
+                caseId,type,score,uploadTime,source)));
+
+        generalCalculateScoreService.updateTypeGrade(gradeDTOList);
+
+        calculateCaseScore(examId, caseId, userId);
+    }
+
     private void recordTypeScore(long examId, long caseId, Long userId, String
             source) throws Exception {
 
@@ -98,28 +116,14 @@ public class GeneralCalculateScoreComponent {
 
         List<GeneralGradeDTO> generalGradeDTOList = new ArrayList<>();
         //元node数据
-        CaseGraphDTO basicNode = caseGraphService.getCaseGraph(caseId);
+        CaseGraphDTO basicNode = cacheUtil.getMetaNode(caseId);
 
         if (basicNode != null && userCatchDTOS != null && userCatchDTOS.size() != 0) {
             for (UserCatchDTO userCatchDTO : userCatchDTOS) {
                 String id = userCatchDTO.getLatestId();
                 List<CatchDTO> catchDTOs = catchService.findById(id);
-                Map<String, Double> typeScoreMap = new HashMap<>();
-                for (Node node : basicNode.getNodes()) {
-                    for (CatchDTO catchDTO : catchDTOs) {
-                        if (node.getName().equals(catchDTO.getNodeName())) {//用户命中了该node
-                            double scoreGot = 0;
-                            String key = node.getCategory();
-                            if (typeScoreMap.containsKey(key)) {
-                                scoreGot = typeScoreMap.get(key);
-                            }
-                            //获取权重
-                            double singleNodeWeight = getNodeWeight(basicNode, node);
-                            typeScoreMap.put(key, scoreGot + singleNodeWeight);
-                            break;//一旦找到命中node则跳出,无需继续遍历
-                        }
-                    }
-                }
+
+                Map<String, Double> typeScoreMap = calculateTypeScore(basicNode,catchDTOs);
 
                 for (String key : typeScoreMap.keySet()) {
                     String uploadTime = catchDTOs.get(0).getUploadTime();
@@ -128,18 +132,38 @@ public class GeneralCalculateScoreComponent {
                             .get(key), uploadTime, "");
                     generalGradeDTOList.add(generalGradeDTO);
                 }
-
-//                typeScoreMap.keySet().forEach(type -> {
-//                    GeneralGradeDTO generalGradeDTO = new GeneralGradeDTO(userCatchDTO.getUserId
-//                            (), userCatchDTO.getExamId(), userCatchDTO.getCaseId(), type, typeScoreMap
-//                            .get(type), userCatchDTO.getLatestDTOS().get(0).getUploadTime(), "");
-//                    generalGradeDTOList.add(generalGradeDTO);
-//                });
             }
         }
         return generalGradeDTOList;
     }
 
+    private Map<String, Double> calculateTypeScore(CaseGraphDTO basicNode, List<CatchDTO>
+            catchDTOS){
+        if(basicNode ==null || catchDTOS == null){
+            return new HashMap<>();
+        }
+
+        Map<String, Double> typeScoreMap = new HashMap<>();
+        for (Node node : basicNode.getNodes()) {
+            for (CatchDTO catchDTO : catchDTOS) {
+                if (node.getName().equals(catchDTO.getNodeName())) {//用户命中了该node
+                    double scoreGot = 0;
+                    String key = node.getCategory();
+                    if (typeScoreMap.containsKey(key)) {
+                        scoreGot = typeScoreMap.get(key);
+                    }
+                    //获取权重
+                    double singleNodeWeight = getNodeWeight(basicNode, node);
+                    typeScoreMap.put(key, scoreGot + singleNodeWeight);
+                    break;//一旦找到命中node则跳出,无需继续遍历
+                }
+            }
+        }
+
+        return typeScoreMap;
+
+    }
+
 
     /**
      * 获取node节点的权重
@@ -204,47 +228,48 @@ public class GeneralCalculateScoreComponent {
 
     @Async("calculateGradeAsync")
     public void saveCaughtDetails(Long examId, Long caseId, Long userId, String
-            source, List<CaughtNodeDTO> caughtNodeDTOs) throws Exception {
-
-        List<CaughtNodeDTO> caughtNodeDTOList = caughtNodeService.getCaughtNodeList(examId, caseId);
-        if (caughtNodeDTOList == null) {
-            List<CaughtNodeDTO> cns = new ArrayList<>();
-            for (CaughtNodeDTO cn : caughtNodeDTOs) {
-                List<Long> userIds = new ArrayList<>();
-                userIds.add(userId);
-
-                cn.setNodeName(cn.getNodeName());
-                cn.setExamId(examId);
-                cn.setCaseId(caseId);
-                cn.setIfCatch(cn.getIfCatch());
-
-                if (cn.getIfCatch().equals(Boolean.TRUE)) {
-                    cn.setCatchNum(1);
-                    cn.setUserIds(userIds);
-                } else {
-                    cn.setCatchNum(0);
-                    cn.setUserIds(new ArrayList<>());
-                }
-                cn.setTotalNum(1);
-                cn.setCategory(cn.getCategory());
-                cns.add(cn);
-            }
-            caughtNodeService.bulkCreateCaughtNodeDTOs(cns);
-        } else {
-            //更新totalNum
-            caughtNodeService.bulkUpdateAllCaughtNode(examId, caseId);
-
-            //更新catch到的node
-            List<String> nodeNameList = new ArrayList<>();
-            for (CaughtNodeDTO caughtNodeDTO : caughtNodeDTOs) {
-                if (caughtNodeDTO.getIfCatch().equals(Boolean.TRUE)) {
-                    String nodeName = caughtNodeDTO.getNodeName();
-                    nodeNameList.add(nodeName);
-                }
-            }
-            caughtNodeService.bulkUpdateCaughtNodes(examId, caseId, nodeNameList, userId);
-        }
-        calculateGrade(examId, caseId, userId, source);
+            source,String uploadTime, List<CaughtNodeDTO> caughtNodeDTOs) throws Exception {
+
+//        List<CaughtNodeDTO> caughtNodeDTOList = caughtNodeService.getCaughtNodeList(examId, caseId);
+//        if (caughtNodeDTOList == null) {
+//            List<CaughtNodeDTO> cns = new ArrayList<>();
+//            for (CaughtNodeDTO cn : caughtNodeDTOs) {
+//                List<Long> userIds = new ArrayList<>();
+//                userIds.add(userId);
+//
+//                cn.setNodeName(cn.getNodeName());
+//                cn.setExamId(examId);
+//                cn.setCaseId(caseId);
+//                cn.setIfCatch(cn.getIfCatch());
+//
+//                if (cn.getIfCatch().equals(Boolean.TRUE)) {
+//                    cn.setCatchNum(1);
+//                    cn.setUserIds(userIds);
+//                } else {
+//                    cn.setCatchNum(0);
+//                    cn.setUserIds(new ArrayList<>());
+//                }
+//                cn.setTotalNum(1);
+//                cn.setCategory(cn.getCategory());
+//                cns.add(cn);
+//            }
+//            caughtNodeService.bulkCreateCaughtNodeDTOs(cns);
+//        } else {
+//            //更新totalNum
+//            caughtNodeService.bulkUpdateAllCaughtNode(examId, caseId);
+//
+//            //更新catch到的node
+//            List<String> nodeNameList = new ArrayList<>();
+//            for (CaughtNodeDTO caughtNodeDTO : caughtNodeDTOs) {
+//                if (caughtNodeDTO.getIfCatch().equals(Boolean.TRUE)) {
+//                    String nodeName = caughtNodeDTO.getNodeName();
+//                    nodeNameList.add(nodeName);
+//                }
+//            }
+//            caughtNodeService.bulkUpdateCaughtNodes(examId, caseId, nodeNameList, userId);
+//        }
+//        calculateGrade(examId, caseId, userId, source);
+        calculateGradeCurrent(examId,caseId,userId,source,uploadTime, caughtNodeDTOs);
 
     }
 }

+ 14 - 0
mooctest-site-server/src/main/java/cn/iselab/mooctest/site/web/logic/impl/GeneralCalculateScoreLogicImpl.java

@@ -4,6 +4,7 @@ import cn.iselab.mooctest.site.service.Exam2CaseService;
 import cn.iselab.mooctest.site.service.GeneralCalculateScoreService;
 import cn.iselab.mooctest.site.service.SubmitRecordService;
 import cn.iselab.mooctest.site.service.WeightGeneralService;
+import cn.iselab.mooctest.site.util.data.CacheUtil;
 import cn.iselab.mooctest.site.web.logic.GeneralCalculateScoreLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -33,6 +34,9 @@ public class GeneralCalculateScoreLogicImpl implements GeneralCalculateScoreLogi
   @Autowired
   Exam2CaseService exam2CaseService;
 
+  @Autowired
+  CacheUtil cacheUtil;
+
 
   @Override
   public void calculateExamScoreFromNode(long examId, String source) throws Exception {
@@ -73,5 +77,15 @@ public class GeneralCalculateScoreLogicImpl implements GeneralCalculateScoreLogi
     generalCalculateScoreComponent.saveGrade(userId,examId,caseId,score);
   }
 
+  @Override
+  public void expireMetaNode(long caseId) {
+    cacheUtil.removeMetaNodeByKey(caseId);
+  }
+
+  @Override
+  public void expireMetaNodeAll() {
+    cacheUtil.removeMetaNodeAll();
+  }
+
 
 }

+ 30 - 0
mooctest-site-server/src/test/java/cn/iselab/mooctest/site/other/CacheTest.java

@@ -0,0 +1,30 @@
+package cn.iselab.mooctest.site.other;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+/**
+ * Created on 2018/10/18
+ */
+public class CacheTest {
+
+    Cache<Long,String> testCache = CacheBuilder.newBuilder().build();
+
+    public void getData(long id){
+        String str = testCache.getIfPresent(id);
+        System.out.println("exist, "+str);
+        if(str == null){
+            str = "str11111";
+            testCache.put(id,str);
+            System.out.println("after put:"+ testCache.getIfPresent(id));
+        }
+    }
+
+    public static void main(String[] args){
+        CacheTest cacheTest = new CacheTest();
+        cacheTest.getData(1);
+        cacheTest.getData(1);
+        cacheTest.getData(2);
+    }
+
+}

+ 3 - 0
mooctest-site-server/src/test/java/cn/iselab/mooctest/site/web/ctrl/CaseControllerTest.java

@@ -13,6 +13,7 @@ import cn.iselab.mooctest.site.web.data.forMongo.graph.Category;
 import cn.iselab.mooctest.site.web.data.forMongo.graph.Edge;
 import cn.iselab.mooctest.site.web.data.forMongo.graph.Node;
 import cn.iselab.mooctest.site.web.logic.CaseLogic;
+import cn.iselab.mooctest.site.web.logic.GeneralCalculateScoreLogic;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
 import org.json.JSONArray;
@@ -58,6 +59,8 @@ public class CaseControllerTest extends AbstractShiroTest{
     private CaseLogic caseLogic;
     @Mock
     private ExamService examService;
+    @Mock
+    private GeneralCalculateScoreLogic generalCalculateScoreLogic;
 
     private Page<CaseExtendsVO> expectPage;
     private List<CaseExtendsVO> cases = new ArrayList<>();

+ 11 - 4
mooctest-site-server/src/test/java/cn/iselab/mooctest/site/web/logic/impl/GeneralCalculateScoreComponentTest.java

@@ -3,6 +3,7 @@ package cn.iselab.mooctest.site.web.logic.impl;
 
 import cn.iselab.mooctest.site.data.GeneralGradeDTO;
 import cn.iselab.mooctest.site.service.*;
+import cn.iselab.mooctest.site.util.data.CacheUtil;
 import cn.iselab.mooctest.site.web.data.forMongo.CaseGraphDTO;
 import cn.iselab.mooctest.site.web.data.forMongo.NodeCatch.CatchDTO;
 import cn.iselab.mooctest.site.web.data.forMongo.NodeCatch.UserCatchDTO;
@@ -50,6 +51,8 @@ public class GeneralCalculateScoreComponentTest {
     private LatestStrategy latestStrategy;
     @Mock
     private HighestStrategy highestStrategy;
+    @Mock
+    private CacheUtil cacheUtil;
 
 
 
@@ -70,9 +73,9 @@ public class GeneralCalculateScoreComponentTest {
 
         //初始化反射类及其成员变量
         instance = generalCalculateScoreComponentClass.newInstance();
-        Field caseGraphServiceField = generalCalculateScoreComponentClass.getDeclaredField
-                ("caseGraphService");
-        caseGraphServiceField.set(instance, caseGraphService);
+//        Field caseGraphServiceField = generalCalculateScoreComponentClass.getDeclaredField
+//                ("caseGraphService");
+//        caseGraphServiceField.set(instance, caseGraphService);
 
         Field catchServiceField= generalCalculateScoreComponentClass.getDeclaredField("catchService");
         catchServiceField.set(instance, catchService);
@@ -84,6 +87,10 @@ public class GeneralCalculateScoreComponentTest {
                 ("highestStrategy");
         field2.set(instance, highestStrategy);
 
+        Field field3 = generalCalculateScoreComponentClass.getDeclaredField
+                ("cacheUtil");
+        field3.set(instance, cacheUtil);
+
         basicNode.setCaseId(1L);
         Category c1 = new Category("c1", 1);
         Category c2 = new Category("c2", 1);
@@ -153,7 +160,7 @@ public class GeneralCalculateScoreComponentTest {
 
     @Test
     public void should_calculateTypeScore_when_givenData() throws Exception {
-        when(caseGraphService.getCaseGraph(1L)).thenReturn(basicNode);
+        when(cacheUtil.getMetaNode(1L)).thenReturn(basicNode);
         when(catchService.findById("5b2fdac0d7fa0b6acb628193")).thenReturn(catchDTOList);
 
         Method method = generalCalculateScoreComponentClass.getDeclaredMethod("calculateTypeScore",