QuizServiceImpl.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package nju.seec.helper.service.impl;
  2. import nju.seec.helper.dao.*;
  3. import nju.seec.helper.dto.QuestionStudentAnswerDTO;
  4. import nju.seec.helper.entity.*;
  5. import nju.seec.helper.service.QuizService;
  6. import nju.seec.helper.util.BokUtil;
  7. import nju.seec.helper.util.enums.ExceptionType;
  8. import nju.seec.helper.util.enums.QuizState;
  9. import nju.seec.helper.util.enums.SlideState;
  10. import nju.seec.helper.util.enums.UserType;
  11. import nju.seec.helper.util.exception.HelperException;
  12. import nju.seec.helper.vo.quiz.BaseQuestionVO;
  13. import nju.seec.helper.vo.quiz.QuizResultVO;
  14. import nju.seec.helper.vo.quiz.QuizVO;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.data.domain.Page;
  17. import org.springframework.data.domain.Pageable;
  18. import org.springframework.stereotype.Service;
  19. import org.springframework.transaction.annotation.Transactional;
  20. import org.springframework.util.Assert;
  21. import java.util.*;
  22. import java.util.stream.Collectors;
  23. @Service
  24. public class QuizServiceImpl implements QuizService {
  25. private final SlideDAO slideDAO;
  26. private final QuizDAO quizDAO;
  27. private final QuizStudentAnswerDAO quizStudentAnswerDAO;
  28. private final ChooseDAO chooseDAO;
  29. private final CourseDAO courseDAO;
  30. private final UserDAO userDAO;
  31. private final BokUtil bokUtil;
  32. @Autowired
  33. public QuizServiceImpl(SlideDAO slideDAO, QuizDAO quizDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, ChooseDAO chooseDAO, CourseDAO courseDAO, UserDAO userDAO, BokUtil bokUtil) {
  34. this.slideDAO = slideDAO;
  35. this.quizDAO = quizDAO;
  36. this.quizStudentAnswerDAO = quizStudentAnswerDAO;
  37. this.chooseDAO = chooseDAO;
  38. this.courseDAO = courseDAO;
  39. this.userDAO = userDAO;
  40. this.bokUtil = bokUtil;
  41. }
  42. @Override
  43. @Transactional(rollbackFor = Exception.class)
  44. public Quiz createQuiz(String name, Long uid, SlideState quizTime,
  45. Long slideId, List<String> questions){
  46. User teacher =new User();
  47. teacher.setId(uid);
  48. Slide slide = slideDAO.findSlideById(slideId);
  49. Course course = new Course();
  50. course.setId(slide.getCourseId());
  51. Quiz quiz = new Quiz();
  52. quiz.setCourse(course);
  53. quiz.setName(name);
  54. quiz.setQuestions(questions);
  55. quiz.setQuizTime(quizTime);
  56. quiz.setSlide(slide);
  57. quiz.setTeacher(teacher);
  58. checkQuizState(quiz,slide);
  59. quiz=quizDAO.saveAndFlush(quiz);
  60. return quiz;
  61. }
  62. @Override
  63. public String deleteQuiz(Long quizId) {
  64. Quiz quiz =quizDAO.findQuizById(quizId);
  65. if(quiz.getState()!=QuizState.NOT_STARTED){throw HelperException.of(ExceptionType.FORBIDDEN,"不能删除已经开始的测试!");}
  66. quizDAO.delete(quiz);
  67. return "delete success";
  68. }
  69. @Override
  70. @Transactional(rollbackFor = Exception.class)
  71. public Quiz modifyQuiz(Long quizId, String name, List<String> questions, SlideState quizTime, String slideId) {
  72. Quiz quiz =quizDAO.findQuizById(quizId);
  73. if(quiz.getState()!=QuizState.NOT_STARTED){throw HelperException.of(ExceptionType.FORBIDDEN,"不能修改已经开始的测试!");}
  74. if(name!=null) {
  75. quiz.setName(name);
  76. }
  77. if(questions!=null) {
  78. quiz.setQuestions(questions);
  79. }
  80. if(quizTime!=null) {
  81. quiz.setQuizTime(quizTime);
  82. checkQuizState(quiz,quiz.getSlide());
  83. }
  84. return quizDAO.saveAndFlush(quiz);
  85. }
  86. @Override
  87. public Page<Quiz> getAllBasicQuizByUser(Pageable pageable, QuizState state, Long uid) {
  88. User user=userDAO.findUserById(uid);
  89. //todo: 这里写的太狗屎了,可以用重写sql或者用实例查询
  90. if(user.getType().equals(UserType.STUDENT)){
  91. final Set<Long> courseIdsByStudentId = chooseDAO.findCourseIdsByStudentId(uid);
  92. final Set<Course> collect = courseIdsByStudentId.stream().map(i -> {
  93. Course c = new Course();
  94. c.setId(i);
  95. return c;
  96. }).collect(Collectors.toSet());
  97. if(state!=null){
  98. return quizDAO.findAllByCourseInAndState(collect,state,pageable);
  99. }else{
  100. return quizDAO.findAllByCourseIn(collect,pageable);
  101. }
  102. }else{
  103. if(state!=null){
  104. return quizDAO.findByTeacherAndState(user,state,pageable);
  105. }else{
  106. return quizDAO.findByTeacher(user,pageable);
  107. }
  108. }
  109. }
  110. @Override
  111. public List<QuizResultVO> getQuizResult(Long quizId) {
  112. Assert.notNull(quizId,"错误的测试!");
  113. final Quiz quiz = quizDAO.findQuizById(quizId);
  114. if(quiz.getState()!=QuizState.CLOSED){throw new RuntimeException("测试未关闭,无法得到测试结果");}
  115. List<QuizResultVO> retList=new ArrayList<>();
  116. final List<StudentScore> studentScoreList = quiz.getStudentScore();
  117. Map<Long,List<QuizStudentAnswer>> idQuizStudentAnswerMap=new HashMap<>();
  118. for(QuizStudentAnswer qsa:quizStudentAnswerDAO.findAllByQuiz(quiz)){
  119. idQuizStudentAnswerMap.computeIfAbsent(qsa.getStudent().getId(), k -> new ArrayList<>());
  120. idQuizStudentAnswerMap.get(qsa.getStudent().getId()).add(qsa);
  121. }
  122. for(StudentScore studentScore:studentScoreList){
  123. final User student = studentScore.getStudent();
  124. final List<QuizStudentAnswer> list = idQuizStudentAnswerMap.get(student.getId());
  125. retList.add(new QuizResultVO(studentScore,student,list));
  126. }
  127. return retList;
  128. }
  129. @Override
  130. public void modifySlideState(Slide slide) {
  131. final List<Quiz> quizzes = quizDAO.findAllBySlide(slide);
  132. quizzes.forEach(quiz->checkQuizState(quiz,slide));
  133. }
  134. @Override
  135. @Transactional(rollbackFor = Exception.class)
  136. public Integer upStudentAnswer(Long quizId, Long uid, List<QuestionStudentAnswerDTO> answers) {
  137. Assert.notNull(quizId,"错误的测试!");
  138. final Quiz quiz = quizDAO.findQuizById(quizId);
  139. if(quiz.getState()!=QuizState.ONGOING){throw HelperException.of(ExceptionType.FORBIDDEN,"不能提交尚未开始的作业!");}
  140. User student =new User();student.setId(uid);
  141. Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quiz);
  142. Set<String> questionIdSet = new HashSet<>(quiz.getQuestions());
  143. Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(questionIdSet.size());
  144. for(QuizStudentAnswer qsa: quizAnswers){
  145. qsaMap.put(qsa.getQuestionId(),qsa);
  146. }
  147. //确定被更新或者新建的学生答案提交
  148. List<QuizStudentAnswer> quizStudentAnswers=new ArrayList<>();
  149. for(QuestionStudentAnswerDTO studentAnswer:answers){
  150. String id = studentAnswer.getQuestionId();
  151. String answer = studentAnswer.getStudentAnswer().toString();
  152. if(!questionIdSet.contains(id)){break;}
  153. if(qsaMap.get(id)!=null){
  154. if(qsaMap.get(id).getStudentAnswer().equals(answer)){
  155. continue;
  156. }
  157. qsaMap.get(id).setStudentAnswer(answer);
  158. System.out.println(answer);
  159. quizStudentAnswers.add(qsaMap.get(id));
  160. }else {
  161. QuizStudentAnswer qsa=QuizStudentAnswer.builder()
  162. .questionId(id).quiz(quiz).student(student).studentAnswer(answer)
  163. .build();
  164. quizStudentAnswers.add(qsa);
  165. }
  166. }
  167. Integer savedNum=quizStudentAnswers.size();
  168. quizStudentAnswerDAO.saveAll(quizStudentAnswers);
  169. return savedNum;
  170. }
  171. @Override
  172. public Page<Quiz> getAllBasicQuizBySlide(Long slideId, Pageable pageable, QuizState state, Long uid) {
  173. Assert.notNull(slideId,"错误的幻灯片!");
  174. Slide slide=new Slide();
  175. slide.setId(slideId);
  176. if(state!=null) {
  177. return quizDAO.findAllBySlideAndState(slide, state, pageable);
  178. }
  179. else {
  180. return quizDAO.findAllBySlide(slide, pageable);
  181. }
  182. }
  183. @Override
  184. @Transactional(rollbackFor = Exception.class)
  185. public QuizState checkQuizState(Quiz quiz, Slide slide) {
  186. int quizTime = quiz.getQuizTime().getNum();
  187. int slideTime = slide.getState().getNum();
  188. if (quiz.getId() == null){
  189. //未持久化的quiz
  190. quiz.setState(slideTime < quizTime ? QuizState.NOT_STARTED : QuizState.ONGOING);
  191. }
  192. else {
  193. //持久化后,不仅仅需要推进状态,还需要判分,保存等步骤
  194. if (slideTime < quizTime) {
  195. if(quiz.getState().equals(QuizState.NOT_STARTED)){return QuizState.NOT_STARTED;}
  196. //未开始
  197. quiz.setState(QuizState.NOT_STARTED);
  198. } else if (slideTime == quizTime) {
  199. if(quiz.getState().equals(QuizState.ONGOING)){return QuizState.ONGOING;}
  200. quiz.setState(QuizState.ONGOING);
  201. } else {
  202. if(quiz.getState().equals(QuizState.CLOSED)){return QuizState.CLOSED;}
  203. quiz.setState(QuizState.CLOSED);
  204. Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findAllByQuiz(quiz);
  205. final Set<Long> studentIds = chooseDAO.findStudentIdsByCourseId(slide.getCourseId());
  206. Student2QuestionId2Answer triadMap = new Student2QuestionId2Answer(studentIds, quiz.getQuestions().size());
  207. //将已经作答的学生答案加入
  208. for (QuizStudentAnswer answers : quizAnswers) {
  209. triadMap.addAnswer(answers);
  210. }
  211. //生成未作答的学生答案
  212. triadMap.fullAnswer(quiz);
  213. //检查答案,赋分
  214. triadMap.checkAnswerAndFullPass(bokUtil.bokFindByIdIn(quiz.getQuestions()), quiz);
  215. //保存现场
  216. quizStudentAnswerDAO.saveAll(triadMap.getAll());
  217. }
  218. quizDAO.save(quiz);
  219. }
  220. return quiz.getState();
  221. }
  222. @Override
  223. public QuizState checkQuizState(Long quizId, Long slideId){
  224. Quiz quiz=quizDAO.findQuizById(quizId);
  225. Slide slide=slideDAO.findSlideById(slideId);
  226. return checkQuizState(quiz,slide);
  227. }
  228. private class Student2QuestionId2Answer {
  229. Map<Long,Map<String,QuizStudentAnswer>> student2QuestionId2Answer;
  230. Student2QuestionId2Answer(Set<Long> studentIds, Integer quizQuestionSize) {
  231. student2QuestionId2Answer =new LinkedHashMap<>(studentIds.size());
  232. for(Long studentId:studentIds){
  233. Map<String,QuizStudentAnswer> questionId2Answer= new LinkedHashMap<>(quizQuestionSize);
  234. student2QuestionId2Answer.put(studentId,questionId2Answer);
  235. }
  236. }
  237. void addAnswer(QuizStudentAnswer answers){
  238. Map<String, QuizStudentAnswer> stringQuizStudentAnswerMap = student2QuestionId2Answer.get(answers.getStudent().getId());
  239. if(stringQuizStudentAnswerMap==null){
  240. return ;
  241. }
  242. stringQuizStudentAnswerMap.put(answers.getQuestionId(),answers);
  243. }
  244. void fullAnswer(Quiz quiz){
  245. List<String> questions=quiz.getQuestions();
  246. student2QuestionId2Answer.forEach((studentId, map)->{
  247. if(questions.size()!=map.size()){
  248. for(String questionId:questions){
  249. if(map.get(questionId)==null){
  250. User student =new User();student.setId(studentId);
  251. QuizStudentAnswer qsa=QuizStudentAnswer.builder()
  252. .questionId(questionId).quiz(quiz).student(student)
  253. .build();
  254. map.put(questionId,qsa);
  255. }
  256. }
  257. }
  258. });
  259. }
  260. void checkAnswerAndFullPass(List<BaseQuestionVO> questionVos, Quiz quiz){
  261. if(quiz.getStudentScore()==null){quiz.setStudentScore(new ArrayList<>(student2QuestionId2Answer.size()));}
  262. student2QuestionId2Answer.forEach((studentId, map)->{
  263. int passCount=0;
  264. for(BaseQuestionVO vo:questionVos){
  265. final String studentAnswer = map.get(vo.getQuestionId()).getStudentAnswer();
  266. boolean pass=vo.checkAnswer(studentAnswer);
  267. if(pass){passCount++;}
  268. map.get(vo.getQuestionId()).setPass(pass);
  269. }
  270. Double score = (100.0*passCount)/questionVos.size();
  271. User student =new User();student.setId(studentId);
  272. StudentScore studentScore=new StudentScore();
  273. studentScore.setQuizId(quiz.getId());
  274. studentScore.setScore(Long.valueOf(Math.round(score)).intValue());
  275. studentScore.setStudent(student);
  276. quiz.getStudentScore().add(studentScore);
  277. });
  278. }
  279. List<QuizStudentAnswer> getAll(){
  280. List<QuizStudentAnswer> list=new ArrayList<>();
  281. for(Long sid: student2QuestionId2Answer.keySet()){
  282. list.addAll(student2QuestionId2Answer.get(sid).values());
  283. }
  284. return list;
  285. }
  286. }
  287. @Override
  288. public QuizVO combineQuiz(Long quizId){
  289. Assert.notNull(quizId,"错误的测试!");
  290. final Quiz quizById = quizDAO.findQuizById(quizId);
  291. final List<BaseQuestionVO> questionVoS = bokUtil.bokFindByIdIn(quizById.getQuestions());
  292. return new QuizVO(quizById,questionVoS);
  293. }
  294. @Override
  295. public QuizVO combineQuizWithAnswer(Long quizId, Long uid,UserType userType){
  296. Assert.notNull(quizId,"错误的测试!");
  297. final Quiz quizById = quizDAO.findQuizById(quizId);
  298. User student =new User();
  299. student.setId(uid);
  300. if(userType==null||userType.equals(UserType.TEACHER)){
  301. //向老师展示
  302. List<BaseQuestionVO> questionVoS = bokUtil.bokFindByIdIn(quizById.getQuestions());
  303. return new QuizVO(quizById,questionVoS);
  304. }
  305. if(quizById.getState().equals(QuizState.NOT_STARTED)){
  306. //未开始看不到题目
  307. return new QuizVO(quizById);
  308. }
  309. List<BaseQuestionVO> questionVos = bokUtil.bokFindByIdIn(quizById.getQuestions());
  310. final Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quizById);
  311. Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(quizAnswers.size());
  312. for(QuizStudentAnswer qsa: quizAnswers){
  313. qsaMap.put(qsa.getQuestionId(),qsa);
  314. }
  315. for(BaseQuestionVO vo:questionVos){
  316. if(qsaMap.get(vo.getQuestionId())!=null){
  317. vo.exAddAnswer(qsaMap.get(vo.getQuestionId()));
  318. }
  319. }
  320. return new QuizVO(quizById,questionVos);
  321. }
  322. }