QuizServiceImpl.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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.QuestionVO;
  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
  44. public Quiz CreateQuiz(String name, Integer uid, SlideState quizTime,
  45. Integer 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
  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) quiz.setName(name);
  75. if(questions!=null) quiz.setQuestions(questions);
  76. if(quizTime!=null) {
  77. quiz.setQuizTime(quizTime);
  78. checkQuizState(quiz,quiz.getSlide());
  79. }
  80. return quizDAO.saveAndFlush(quiz);
  81. }
  82. @Override
  83. public Page<Quiz> getAllBasicQuizByUser(Pageable pageable, QuizState state, Integer uid) {
  84. User user=userDAO.findUserById(uid);
  85. //todo: 这里写的太狗屎了,可以用重写sql或者用实例查询
  86. if(user.getType().equals(UserType.STUDENT)){
  87. final Set<Integer> courseIdsByStudentId = chooseDAO.findCourseIdsByStudentId(uid);
  88. final Set<Course> collect = courseIdsByStudentId.stream().map(i -> {
  89. Course c = new Course();
  90. c.setId(i);
  91. return c;
  92. }).collect(Collectors.toSet());
  93. if(state!=null){
  94. return quizDAO.findAllByCourseInAndState(collect,state,pageable);
  95. }else{
  96. return quizDAO.findAllByCourseIn(collect,pageable);
  97. }
  98. }else{
  99. if(state!=null){
  100. return quizDAO.findByTeacherAndState(user,state,pageable);
  101. }else{
  102. return quizDAO.findByTeacher(user,pageable);
  103. }
  104. }
  105. }
  106. @Override
  107. public List<QuizResultVO> getQuizResult(Long quizId) {
  108. Assert.notNull(quizId,"错误的测试!");
  109. final Quiz quiz = quizDAO.findQuizById(quizId);
  110. if(quiz.getState()!=QuizState.CLOSED){throw new RuntimeException("测试未关闭,无法得到测试结果");}
  111. List<QuizResultVO> retList=new ArrayList<>();
  112. final List<StudentScore> studentScoreList = quiz.getStudentScore();
  113. Map<Integer,List<QuizStudentAnswer>> IdQuizStudentAnswerMap=new HashMap<>();
  114. for(QuizStudentAnswer qsa:quizStudentAnswerDAO.findAllByQuiz(quiz)){
  115. IdQuizStudentAnswerMap.computeIfAbsent(qsa.getStudent().getId(), k -> new ArrayList<>());
  116. IdQuizStudentAnswerMap.get(qsa.getStudent().getId()).add(qsa);
  117. }
  118. for(StudentScore studentScore:studentScoreList){
  119. final User student = studentScore.getStudent();
  120. final List<QuizStudentAnswer> list = IdQuizStudentAnswerMap.get(student.getId());
  121. retList.add(new QuizResultVO(studentScore,student,list));
  122. }
  123. return retList;
  124. }
  125. @Override
  126. public void modifySlideState(Slide slide) {
  127. final List<Quiz> quizzes = quizDAO.findAllBySlide(slide);
  128. quizzes.forEach(quiz->checkQuizState(quiz,slide));
  129. }
  130. @Override
  131. @Transactional
  132. public Integer upStudentAnswer(Long quizId, Integer uid, List<QuestionStudentAnswerDTO> answers) {
  133. Assert.notNull(quizId,"错误的测试!");
  134. final Quiz quiz = quizDAO.findQuizById(quizId);
  135. if(quiz.getState()!=QuizState.ONGOING){throw HelperException.of(ExceptionType.FORBIDDEN,"不能提交尚未开始的作业!");}
  136. User student =new User();student.setId(uid);
  137. Set<QuizStudentAnswer> QuizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quiz);
  138. Set<String> questionIdSet = new HashSet<>(quiz.getQuestions());
  139. Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(questionIdSet.size());
  140. for(QuizStudentAnswer qsa: QuizAnswers){
  141. qsaMap.put(qsa.getQuestionId(),qsa);
  142. }
  143. //确定被更新或者新建的学生答案提交
  144. List<QuizStudentAnswer> toSaveQSA=new ArrayList<>();
  145. for(QuestionStudentAnswerDTO studentAnswer:answers){
  146. String id = studentAnswer.getQuestionId();
  147. String answer = studentAnswer.getStudentAnswer().toString();
  148. if(!questionIdSet.contains(id)){break;}
  149. if(qsaMap.get(id)!=null){
  150. if(qsaMap.get(id).getStudentAnswer().equals(answer)){
  151. continue;
  152. }
  153. qsaMap.get(id).setStudentAnswer(answer);
  154. System.out.println(answer);
  155. toSaveQSA.add(qsaMap.get(id));
  156. }else {
  157. QuizStudentAnswer qsa=QuizStudentAnswer.builder()
  158. .questionId(id).quiz(quiz).student(student).studentAnswer(answer)
  159. .build();
  160. toSaveQSA.add(qsa);
  161. }
  162. }
  163. Integer savedNum=toSaveQSA.size();
  164. quizStudentAnswerDAO.saveAll(toSaveQSA);
  165. return savedNum;
  166. }
  167. @Override
  168. public Page<Quiz> getAllBasicQuizBySlide(Integer slideId, Pageable pageable, QuizState state, Integer uid) {
  169. Assert.notNull(slideId,"错误的幻灯片!");
  170. Slide slide=new Slide();
  171. slide.setId(slideId);
  172. if(state!=null)
  173. return quizDAO.findAllBySlideAndState(slide,state, pageable);
  174. else
  175. return quizDAO.findAllBySlide(slide,pageable);
  176. }
  177. @Override
  178. @Transactional
  179. public QuizState checkQuizState(Quiz quiz, Slide slide) {
  180. int QuizTime = quiz.getQuizTime().getNum();
  181. int slideTime = slide.getState().getNum();
  182. if (quiz.getId() == null)
  183. //未持久化的quiz
  184. quiz.setState(slideTime < QuizTime ? QuizState.NOT_STARTED : QuizState.ONGOING);
  185. else {
  186. //持久化后,不仅仅需要推进状态,还需要判分,保存等步骤
  187. if (slideTime < QuizTime) {
  188. if(quiz.getState().equals(QuizState.NOT_STARTED)){return QuizState.NOT_STARTED;}
  189. //未开始
  190. quiz.setState(QuizState.NOT_STARTED);
  191. } else if (slideTime == QuizTime) {
  192. if(quiz.getState().equals(QuizState.ONGOING)){return QuizState.ONGOING;}
  193. quiz.setState(QuizState.ONGOING);
  194. } else {
  195. if(quiz.getState().equals(QuizState.CLOSED)){return QuizState.CLOSED;}
  196. quiz.setState(QuizState.CLOSED);
  197. Set<QuizStudentAnswer> QuizAnswers = quizStudentAnswerDAO.findAllByQuiz(quiz);
  198. final Set<Integer> studentIds = chooseDAO.findStudentIdsByCourseId(slide.getCourseId());
  199. Student2_QuestionId2Answer triadMap = new Student2_QuestionId2Answer(studentIds, quiz.getQuestions().size());
  200. //将已经作答的学生答案加入
  201. for (QuizStudentAnswer answers : QuizAnswers) {
  202. triadMap.addAnswer(answers);
  203. }
  204. //生成未作答的学生答案
  205. triadMap.fullAnswer(quiz);
  206. //检查答案,赋分
  207. triadMap.checkAnswerAndFullPass(bokUtil.BokFindByIdIn(quiz.getQuestions()), quiz);
  208. //保存现场
  209. quizStudentAnswerDAO.saveAll(triadMap.getAll());
  210. }
  211. quizDAO.save(quiz);
  212. }
  213. return quiz.getState();
  214. }
  215. @Override
  216. public QuizState checkQuizState(Long quizId, Integer slideId){
  217. Quiz quiz=quizDAO.findQuizById(quizId);
  218. Slide slide=slideDAO.findSlideById(slideId);
  219. return checkQuizState(quiz,slide);
  220. }
  221. private class Student2_QuestionId2Answer{
  222. Map<Integer,Map<String,QuizStudentAnswer>> Student2_QuestionId2Answer;
  223. Student2_QuestionId2Answer(Set<Integer> studentIds, Integer quizQuestionSize) {
  224. Student2_QuestionId2Answer =new LinkedHashMap<>(studentIds.size());
  225. for(Integer studentId:studentIds){
  226. Map<String,QuizStudentAnswer> QuestionId2Answer= new LinkedHashMap<>(quizQuestionSize);
  227. Student2_QuestionId2Answer.put(studentId,QuestionId2Answer);
  228. }
  229. }
  230. void addAnswer(QuizStudentAnswer answers){
  231. Map<String, QuizStudentAnswer> stringQuizStudentAnswerMap = Student2_QuestionId2Answer.get(answers.getStudent().getId());
  232. if(stringQuizStudentAnswerMap==null){
  233. return ;
  234. }
  235. stringQuizStudentAnswerMap.put(answers.getQuestionId(),answers);
  236. }
  237. void fullAnswer(Quiz quiz){
  238. List<String> questions=quiz.getQuestions();
  239. Student2_QuestionId2Answer.forEach((studentId,map)->{
  240. if(questions.size()!=map.size()){
  241. for(String questionId:questions){
  242. if(map.get(questionId)==null){
  243. User student =new User();student.setId(studentId);
  244. QuizStudentAnswer qsa=QuizStudentAnswer.builder()
  245. .questionId(questionId).quiz(quiz).student(student)
  246. .build();
  247. map.put(questionId,qsa);
  248. }
  249. }
  250. }
  251. });
  252. }
  253. void checkAnswerAndFullPass(List<QuestionVO> questionVOS, Quiz quiz){
  254. if(quiz.getStudentScore()==null){quiz.setStudentScore(new ArrayList<>(Student2_QuestionId2Answer.size()));}
  255. Student2_QuestionId2Answer.forEach((studentId,map)->{
  256. int passCount=0;
  257. for(QuestionVO vo:questionVOS){
  258. final String studentAnswer = map.get(vo.getQuestionId()).getStudentAnswer();
  259. boolean pass=vo.checkAnswer(studentAnswer);
  260. if(pass){passCount++;}
  261. map.get(vo.getQuestionId()).setPass(pass);
  262. }
  263. Double score = (100.0*passCount)/questionVOS.size();
  264. User student =new User();student.setId(studentId);
  265. StudentScore studentScore=new StudentScore();
  266. studentScore.setQuizId(quiz.getId());
  267. studentScore.setScore(Long.valueOf(Math.round(score)).intValue());
  268. studentScore.setStudent(student);
  269. quiz.getStudentScore().add(studentScore);
  270. });
  271. }
  272. List<QuizStudentAnswer> getAll(){
  273. List<QuizStudentAnswer> list=new ArrayList<>();
  274. for(Integer sid:Student2_QuestionId2Answer.keySet()){
  275. list.addAll(Student2_QuestionId2Answer.get(sid).values());
  276. }
  277. return list;
  278. }
  279. }
  280. @Override
  281. public QuizVO combineQuiz(Long quizId){
  282. Assert.notNull(quizId,"错误的测试!");
  283. final Quiz quizById = quizDAO.findQuizById(quizId);
  284. final List<QuestionVO> questionVOS = bokUtil.BokFindByIdIn(quizById.getQuestions());
  285. return new QuizVO(quizById,questionVOS);
  286. }
  287. @Override
  288. public QuizVO combineQuizWithAnswer(Long quizId, Integer uid,UserType userType){
  289. Assert.notNull(quizId,"错误的测试!");
  290. final Quiz quizById = quizDAO.findQuizById(quizId);
  291. User student =new User();
  292. student.setId(uid);
  293. if(userType==null||userType.equals(UserType.TEACHER)){
  294. //向老师展示
  295. List<QuestionVO> questionVOS = bokUtil.BokFindByIdIn(quizById.getQuestions());
  296. return new QuizVO(quizById,questionVOS);
  297. }
  298. if(quizById.getState().equals(QuizState.NOT_STARTED)){
  299. //未开始看不到题目
  300. return new QuizVO(quizById);
  301. }
  302. List<QuestionVO> questionVOS = bokUtil.BokFindByIdIn(quizById.getQuestions());
  303. final Set<QuizStudentAnswer> QuizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quizById);
  304. Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(QuizAnswers.size());
  305. for(QuizStudentAnswer qsa: QuizAnswers){
  306. qsaMap.put(qsa.getQuestionId(),qsa);
  307. }
  308. for(QuestionVO vo:questionVOS){
  309. if(qsaMap.get(vo.getQuestionId())!=null){
  310. vo.exAddAnswer(qsaMap.get(vo.getQuestionId()));
  311. }
  312. }
  313. return new QuizVO(quizById,questionVOS);
  314. }
  315. }