Procházet zdrojové kódy

feat: 增加做题时间记录时间切面

ChenSiTong před 6 roky
rodič
revize
a8b303babd

+ 1 - 1
src/main/java/nju/seec/helper/api/dataanalysis/Event.java

@@ -8,7 +8,7 @@ import lombok.experimental.Accessors;
 import java.time.LocalDateTime;
 
 /**
- * @author cst
+ * @author seec data analysis
  */
 @Data
 @Accessors(chain = true)

+ 3 - 3
src/main/java/nju/seec/helper/api/dataanalysis/EventApi.java

@@ -41,7 +41,7 @@ public class EventApi {
      * @param course
      * @return
      */
-    public Event getParticipateClassEvent(String userId, LocalDateTime time, Course course) {
+    public Event createParticipateClassEvent(String userId, LocalDateTime time, Course course) {
         return new Event().setUserId(userId).setTime(time).setType(EventType.LESSON).setAction(EventAction.PARTICIPATE).setDescription(course.getName());
     }
 
@@ -53,7 +53,7 @@ public class EventApi {
      * @param title
      * @return
      */
-    public Event getInitPostEvent(String userId, LocalDateTime time, String title) {
+    public Event createInitPostEvent(String userId, LocalDateTime time, String title) {
         return new Event().setUserId(userId).setTime(time).setType(EventType.POST).setAction(EventAction.INITIATE).setDescription(title);
     }
 
@@ -65,7 +65,7 @@ public class EventApi {
      * @param quiz
      * @return
      */
-    public Event getCompleteQuizEvent(String userId, LocalDateTime time, Quiz quiz) {
+    public Event createCompleteQuizEvent(String userId, LocalDateTime time, Quiz quiz) {
         return new Event().setUserId(userId).setTime(time).setType(EventType.QUIZ).setAction(EventAction.COMPLETE).setDescription(StrUtil.join(":", quiz.getCourse().getName(), quiz.getName()));
     }
 }

+ 38 - 0
src/main/java/nju/seec/helper/api/dataanalysis/ExerciseApi.java

@@ -0,0 +1,38 @@
+package nju.seec.helper.api.dataanalysis;
+
+import nju.seec.helper.util.RestRequestUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @author cst
+ */
+@Component
+public class ExerciseApi {
+    @Value("${data-analysis.exerciseReportUrl}")
+    private String exerciseReportUrl;
+    private final RestRequestUtil restRequestUtil;
+
+    public ExerciseApi(RestRequestUtil restRequestUtil) {
+        this.restRequestUtil = restRequestUtil;
+    }
+
+    @Async
+    public void reportExercise(List<ExerciseRecord> exerciseRecords) {
+        try {
+            System.out.println(exerciseRecords);
+//            restRequestUtil.sendPostRequest(exerciseReportUrl, exerciseRecord, Boolean.class);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public ExerciseRecord createExerciseRecord(String userId, String questionId, LocalDateTime startAt, LocalDateTime endAt, Boolean pass) {
+        return new ExerciseRecord().setUserId(userId).setQuestionId(questionId).setStartAt(startAt).setEndAt(endAt).setDurationSeconds(Duration.between(startAt, endAt).getSeconds()).setPass(pass);
+    }
+}

+ 41 - 0
src/main/java/nju/seec/helper/api/dataanalysis/ExerciseRecord.java

@@ -0,0 +1,41 @@
+package nju.seec.helper.api.dataanalysis;
+
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author seec data analysis
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor(access = AccessLevel.PACKAGE)
+public class ExerciseRecord {
+    /**
+     * 问题的ID
+     */
+    private String questionId;
+    /**
+     * 用户的ID
+     */
+    private String userId;
+    /**
+     * 做题开始时间
+     */
+    private LocalDateTime startAt;
+    /**
+     * 做题结束时间
+     */
+    private LocalDateTime endAt;
+    /**
+     * 做题的时间(秒)
+     */
+    private long durationSeconds;
+    /**
+     * 该题是否通过
+     */
+    private Boolean pass;
+}

+ 3 - 3
src/main/java/nju/seec/helper/aspect/event/EventAspect.java

@@ -45,7 +45,7 @@ public class EventAspect {
                                     courseId = (Long) arg;
                                 }
                             }
-                            eventApi.reportEvent(eventApi.getParticipateClassEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), courseDAO.findCourseById(courseId)));
+                            eventApi.reportEvent(eventApi.createParticipateClassEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), courseDAO.findCourseById(courseId)));
                         })),
                 EventType.POST, ImmutableMap.of(
                         EventAction.INITIATE, (joinPoint -> {
@@ -59,7 +59,7 @@ public class EventAspect {
                                     commentDTO = (CommentDTO) arg;
                                 }
                             }
-                            eventApi.reportEvent(eventApi.getInitPostEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), Objects.requireNonNull(commentDTO).getTitle()));
+                            eventApi.reportEvent(eventApi.createInitPostEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), Objects.requireNonNull(commentDTO).getTitle()));
                         })
                 ),
                 EventType.QUIZ, ImmutableMap.of(
@@ -74,7 +74,7 @@ public class EventAspect {
                                     quizId = (Long) arg;
                                 }
                             }
-                            eventApi.reportEvent(eventApi.getCompleteQuizEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), quizDAO.findQuizById(quizId)));
+                            eventApi.reportEvent(eventApi.createCompleteQuizEvent(String.valueOf(Objects.requireNonNull(user).getPid()), LocalDateTime.now(), quizDAO.findQuizById(quizId)));
                         })
                 )
         );

+ 12 - 0
src/main/java/nju/seec/helper/aspect/event/ExerciseRecordEvent.java

@@ -0,0 +1,12 @@
+package nju.seec.helper.aspect.event;
+
+import java.lang.annotation.*;
+
+/**
+ * @author cst
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ExerciseRecordEvent {
+}

+ 57 - 0
src/main/java/nju/seec/helper/aspect/event/ExerciseRecordEventAspect.java

@@ -0,0 +1,57 @@
+package nju.seec.helper.aspect.event;
+
+import nju.seec.helper.api.dataanalysis.ExerciseApi;
+import nju.seec.helper.api.dataanalysis.ExerciseRecord;
+import nju.seec.helper.aspect.auth.LoginUser;
+import nju.seec.helper.dto.quiz.QuizStudentAnswerDTO;
+import nju.seec.helper.vo.quiz.QuizStudentAnswerVO;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author cst
+ */
+@Aspect
+@Component
+public class ExerciseRecordEventAspect {
+    private final ExerciseApi exerciseApi;
+
+    public ExerciseRecordEventAspect(ExerciseApi exerciseApi) {
+        this.exerciseApi = exerciseApi;
+    }
+
+    @AfterReturning(pointcut = "@annotation(exerciseRecordEvent)", returning = "quizStudentAnswerVO")
+    public void reportExerciseRecordEvent(JoinPoint joinPoint, ExerciseRecordEvent exerciseRecordEvent, QuizStudentAnswerVO quizStudentAnswerVO) {
+        Object[] args = joinPoint.getArgs();
+        LoginUser user = null;
+        QuizStudentAnswerDTO quizStudentAnswerDTO = null;
+        for (Object arg : args) {
+            if (arg instanceof LoginUser) {
+                user = (LoginUser) arg;
+            }
+            if (arg instanceof QuizStudentAnswerDTO) {
+                quizStudentAnswerDTO = (QuizStudentAnswerDTO) arg;
+            }
+        }
+        String userId = String.valueOf(Objects.requireNonNull(user).getPid());
+        Map<String, QuizStudentAnswerVO.QuestionStudentAnswerInfo> questionStudentAnswerInfoMap = quizStudentAnswerVO.getAnswers();
+        List<ExerciseRecord> exerciseRecords =
+                Objects.requireNonNull(quizStudentAnswerDTO)
+                        .getRecords()
+                        .entrySet()
+                        .stream()
+                        .map(answerRecordEntry ->
+                                exerciseApi.createExerciseRecord(
+                                        userId, answerRecordEntry.getKey(), answerRecordEntry.getValue().getStartAt(), answerRecordEntry.getValue().getEndAt(), questionStudentAnswerInfoMap.get(answerRecordEntry.getKey()).getCorrect()
+                                ))
+                        .collect(Collectors.toList());
+        exerciseApi.reportExercise(exerciseRecords);
+    }
+}

+ 22 - 22
src/main/java/nju/seec/helper/dao/AdminDAO.java

@@ -1,22 +1,22 @@
-package nju.seec.helper.dao;
-
-import nju.seec.helper.entity.Admin;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.Optional;
-
-/**
- * @author cst
- */
-@Repository
-public interface AdminDAO extends JpaRepository<Admin, Long> {
-    /**
-     * 用户名密码查询
-     *
-     * @param username
-     * @param password
-     * @return
-     */
-    Optional<Admin> findByUsernameAndPassword(String username, String password);
-}
+//package nju.seec.helper.dao;
+//
+//import nju.seec.helper.entity.Admin;
+//import org.springframework.data.jpa.repository.JpaRepository;
+//import org.springframework.stereotype.Repository;
+//
+//import java.util.Optional;
+//
+///**
+// * @author cst
+// */
+//@Repository
+//public interface AdminDAO extends JpaRepository<Admin, Long> {
+//    /**
+//     * 用户名密码查询
+//     *
+//     * @param username
+//     * @param password
+//     * @return
+//     */
+//    Optional<Admin> findByUsernameAndPassword(String username, String password);
+//}

+ 7 - 7
src/main/java/nju/seec/helper/dto/quiz/QuizStudentAnswerDTO.java

@@ -1,6 +1,7 @@
 package nju.seec.helper.dto.quiz;
 
 import lombok.Data;
+import lombok.Getter;
 
 import javax.validation.Valid;
 import javax.validation.constraints.NotEmpty;
@@ -22,13 +23,12 @@ public class QuizStudentAnswerDTO implements Serializable {
     private Map<String, AnswerRecordDTO> records;
 
     @Data
+    @Getter
     public static class AnswerRecordDTO {
-        @NotNull(message = "做题记录缺少做题日期")
-        private LocalDateTime answerAt;
-        /**
-         * 秒数
-         */
-        @NotNull(message = "做题记录缺少时长")
-        private Long answerSeconds;
+        @NotNull(message = "缺少做题开始时间")
+        private LocalDateTime startAt;
+
+        @NotNull(message = "缺少做题结束时间")
+        private LocalDateTime endAt;
     }
 }

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

@@ -47,7 +47,7 @@ public class EventServiceImpl implements EventService {
                     choose -> {
                         User student = userDAO.findUserById(choose.getStudentId());
                         if (student.getPid() != null) {
-                            events.add(eventApi.getParticipateClassEvent(String.valueOf(Objects.requireNonNull(student).getPid()), LocalDateTime.now(), course));
+                            events.add(eventApi.createParticipateClassEvent(String.valueOf(Objects.requireNonNull(student).getPid()), LocalDateTime.now(), course));
                         }
                     }
             );
@@ -56,7 +56,7 @@ public class EventServiceImpl implements EventService {
         comments.forEach(comment -> {
             User user = comment.getUser();
             if (user.getPid() != null && user.getRole() == UserRole.STUDENT) {
-                events.add(eventApi.getInitPostEvent(String.valueOf(user.getPid()), comment.getCreateAt(), comment.getTitle()));
+                events.add(eventApi.createInitPostEvent(String.valueOf(user.getPid()), comment.getCreateAt(), comment.getTitle()));
             }
         });
         List<QuizStudentAnswer> quizStudentAnswers = quizStudentAnswerDAO.findAll();
@@ -64,7 +64,7 @@ public class EventServiceImpl implements EventService {
             User student = quizStudentAnswer.getStudent();
             if (student.getPid() != null) {
                 Quiz quiz = quizStudentAnswer.getQuiz();
-                events.add(eventApi.getCompleteQuizEvent(String.valueOf(student.getPid()), quizStudentAnswer.getSubmitAt(), quiz));
+                events.add(eventApi.createCompleteQuizEvent(String.valueOf(student.getPid()), quizStudentAnswer.getSubmitAt(), quiz));
             }
         });
         return events;

+ 5 - 3
src/main/java/nju/seec/helper/service/impl/QuizStudentAnswerServiceImpl.java

@@ -5,6 +5,7 @@ import nju.seec.helper.api.dataanalysis.EventAction;
 import nju.seec.helper.api.dataanalysis.EventType;
 import nju.seec.helper.aspect.auth.LoginUser;
 import nju.seec.helper.aspect.event.Event;
+import nju.seec.helper.aspect.event.ExerciseRecordEvent;
 import nju.seec.helper.dao.QuizDAO;
 import nju.seec.helper.dao.QuizStudentAnswerDAO;
 import nju.seec.helper.dao.UserDAO;
@@ -28,7 +29,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * @author cst
@@ -48,6 +49,7 @@ public class QuizStudentAnswerServiceImpl implements QuizStudentAnswerService {
         this.questionService = questionService;
     }
 
+    @ExerciseRecordEvent
     @Event(type = EventType.QUIZ, action = EventAction.PARTICIPATE)
     @Transactional(rollbackFor = Exception.class)
     @Override
@@ -74,13 +76,13 @@ public class QuizStudentAnswerServiceImpl implements QuizStudentAnswerService {
         // 计算得分
         List<BaseQuestionVO> questionVOList = questionService.getQuestionsByQuiz(quiz);
 
-        AtomicReference<Integer> correct = new AtomicReference<>(0);
+        AtomicInteger correct = new AtomicInteger();
 
         Map<String, Object> answers = quizStudentAnswerDTO.getAnswers();
         questionVOList.forEach(baseQuestionVO -> {
             Object answer;
             if ((answer = answers.get(baseQuestionVO.getId())) != null && baseQuestionVO.pass(answer)) {
-                correct.getAndSet(correct.get() + 1);
+                correct.getAndIncrement();
             }
         });
 

+ 1 - 1
src/main/java/nju/seec/helper/vo/quiz/QuizStudentAnswerVO.java

@@ -62,7 +62,7 @@ public class QuizStudentAnswerVO {
 
     @Data
     @AllArgsConstructor(staticName = "of")
-    private static class QuestionStudentAnswerInfo {
+    public static class QuestionStudentAnswerInfo {
         private String questionId;
         private Object answer;
         private Boolean correct;

+ 3 - 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: true
+  #    show-sql: true
   http:
     encoding:
       force: true
@@ -66,6 +66,8 @@ data-analysis:
   url: http://dataanalysis.seecoder.cn
   eventUrl: ${data-analysis.url}/api/event
   eventReportUrl: ${data-analysis.eventUrl}/report
+  exerciseUrl: ${data-analysis.url}/api/exercise
+  exerciseReportUrl: ${data-analysis.exerciseUrl}/report
 guavaCache:
   maximumSize: 1000
   expireAfterAccessInSeconds: 0