Index: forgon-tools/src/main/java/com/forgon/Constants.java =================================================================== diff -u -r38722 -r38870 --- forgon-tools/src/main/java/com/forgon/Constants.java (.../Constants.java) (revision 38722) +++ forgon-tools/src/main/java/com/forgon/Constants.java (.../Constants.java) (revision 38870) @@ -28,7 +28,7 @@ "4.9.45","4.9.46","4.9.47","4.9.48","4.9.49","4.9.50","4.9.51","4.9.52","4.9.53","4.9.54","4.9.55","4.9.56","4.9.57","4.9.58","4.9.59","4.9.60","4.9.61","4.9.62", "4.9.63","4.9.64","4.9.65","4.9.66","4.9.67","4.9.68","4.9.69","4.9.70","4.9.71","4.9.72","4.9.73","4.9.74","4.9.75","4.9.76","4.9.77","4.9.78","4.9.79","4.9.80","4.9.81","4.9.82","4.9.83","4.9.84","4.9.85", "4.9.86","4.9.87","4.9.88","4.9.89","4.9.90","4.9.91","4.9.92","4.9.93","4.9.94","4.9.95","4.9.96","4.9.97","4.9.98","4.9.99","5.0.0","5.0.1","5.0.2","5.0.3","5.0.4","5.0.5","5.0.6","5.0.7", - "5.0.8","5.0.9","5.0.10","5.0.11","5.0.12","5.0.13","5.0.14","5.0.15","5.0.16","5.0.17","5.0.18","5.0.19","5.0.20","5.0.21","5.0.22","5.0.23","5.0.24","5.0.25","5.0.26","5.0.27","5.0.28","5.0.29"}; + "5.0.8","5.0.9","5.0.10","5.0.11","5.0.12","5.0.13","5.0.14","5.0.15","5.0.16","5.0.17","5.0.18","5.0.19","5.0.20","5.0.21","5.0.22","5.0.23","5.0.24","5.0.25","5.0.26","5.0.27","5.0.28","5.0.29","5.0.30"}; // 版本列表(4.0版本升级4.1版需要分两步:先从4.0升到4.1.0、然后从4.1.0升级4.1最新版本) /*public final static String[] SOFTWARE_VERSION_ARRAY = new String[] { Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/answersheet/AnswerSheet.java =================================================================== diff -u -r38383 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/answersheet/AnswerSheet.java (.../AnswerSheet.java) (revision 38383) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/answersheet/AnswerSheet.java (.../AnswerSheet.java) (revision 38870) @@ -53,6 +53,11 @@ private Integer totalSocre; // 总分 + /** + * 简答题分数 + */ + private Integer shortAnswerScore; + private Integer examCount=0; //答题次数 private ExamDefinition examDefinition; // 考试定义 @@ -63,6 +68,14 @@ private String fltNums; + /** + * 试卷状态 + */ + private String examPaperStatus = PAPER_STATUS_NOT_SUBMITTED; + public static final String PAPER_STATUS_NOT_SUBMITTED = "未交卷"; + public static final String PAPER_STATUS_TO_BE_RATED = "待评分"; + public static final String PAPER_STATUS_RATED = "已评分"; + //private Person person; @@ -222,6 +235,22 @@ this.fltNums = fltNums; } + public Integer getShortAnswerScore() { + return shortAnswerScore; + } + + public void setShortAnswerScore(Integer shortAnswerScore) { + this.shortAnswerScore = shortAnswerScore; + } + + public String getExamPaperStatus() { + return examPaperStatus; + } + + public void setExamPaperStatus(String examPaperStatus) { + this.examPaperStatus = examPaperStatus; + } + /*public Person getPerson() { return person; } Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/controller/NormalExamAnswerFormController.java =================================================================== diff -u -r38432 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/controller/NormalExamAnswerFormController.java (.../NormalExamAnswerFormController.java) (revision 38432) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/controller/NormalExamAnswerFormController.java (.../NormalExamAnswerFormController.java) (revision 38870) @@ -18,6 +18,7 @@ import com.forgon.disinfectsystem.basedatamanager.onlineexams.examanswer.service.AnswerManager; import com.forgon.disinfectsystem.entity.onlineexams.answersheet.AnswerSheet; import com.forgon.disinfectsystem.entity.onlineexams.examdefinition.ExamQuestion; +import com.forgon.disinfectsystem.entity.onlineexams.question.Question; import com.forgon.tools.json.JSONUtil; /** @@ -78,9 +79,7 @@ if(CollectionUtils.isNotEmpty(examQuestions)){ for (ExamQuestion examQuestion : examQuestions) { //还没作答的题目,不显示答案 - if(examQuestion.getScoreGained() == null){ - examQuestion.getQuestion().setAnswer(""); - } + hideQuestionAnswer(examQuestion); } } result.put("answerSheetId", answerSheet.getId()); @@ -102,6 +101,60 @@ } return result; } + + /** + * 还没作答的题目,不显示答案 + * @param examQuestion + */ + private void hideQuestionAnswer(ExamQuestion examQuestion) { + Question question = examQuestion.getQuestion(); + if(question == null){ + return; + } + if(examQuestion.getScoreGained() != null){ + return; + } + if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SINGLE_CHOICE) + || StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_MULTIPLE_CHOICE) + || StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_TRUE_OR_FALSE) + || StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER)){ + question.setAnswer(""); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_FILL_BLANKS)){ + question.setFillBlankAnswers(null); + } + } + /** + * 简答题评分 + */ + @RequestMapping("/markExamPaperShortAnswerScore") + public String markExamPaperShortAnswerScore(Long answerSheetId, Long examQuestionId, Integer score){ + JSONObject result = JSONUtil.buildJsonObject(true, "提交成功"); + try { + answerManager.markExamPaperShortAnswerScore(answerSheetId, examQuestionId, score); + } catch (Exception e) { + e.printStackTrace(); + result = JSONUtil.buildJsonObject(false, e.getMessage()); + } + return result.toString(); + } + + /** + * 查看简答题“参考答案” + * @return + */ + @RequestMapping("/loadShortAnswerQuestionAnswer") + public String loadShortAnswerQuestionAnswer(Long answerSheetId, Long examQuestionId){ + JSONObject result = JSONUtil.buildJsonObject(true); + try { + String answer = answerManager.loadShortAnswerQuestionAnswer(answerSheetId, examQuestionId); + result.put("answer", answer); + } catch (Exception e) { + e.printStackTrace(); + result = JSONUtil.buildJsonObject(false, e.getMessage()); + } + return result.toString(); + } + } Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/FillBlankAnswer.java =================================================================== diff -u --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/FillBlankAnswer.java (revision 0) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/FillBlankAnswer.java (revision 38870) @@ -0,0 +1,56 @@ +package com.forgon.disinfectsystem.entity.onlineexams.question; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +/** + * 填空题的答案 + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class FillBlankAnswer { + + private Long id; + + /** + * 对应的空格顺序 + */ + private Integer sequece; + + /** + * 填空题的答案,字数最长不能超过50个中英文字符 + */ + private String answer; + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getSequece() { + return sequece; + } + + public void setSequece(Integer sequece) { + this.sequece = sequece; + } + + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + +} Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/service/QuestionManagerImpl.java =================================================================== diff -u -r38772 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/service/QuestionManagerImpl.java (.../QuestionManagerImpl.java) (revision 38772) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/service/QuestionManagerImpl.java (.../QuestionManagerImpl.java) (revision 38870) @@ -14,6 +14,7 @@ import org.apache.commons.lang.StringUtils; import org.jsoup.helper.StringUtil; +import com.forgon.disinfectsystem.entity.onlineexams.question.FillBlankAnswer; import com.forgon.disinfectsystem.entity.onlineexams.question.Question; import com.forgon.disinfectsystem.vo.QuestionVo; import com.forgon.exception.SystemException; @@ -67,9 +68,11 @@ objectDao.saveOrUpdate(question); } + @SuppressWarnings("unchecked") public List findBySql(String sql) { ResultSet rs = objectDao.executeSql(sql); List questions = new ArrayList(); + List questionIdList = new ArrayList(); try { if (rs != null) { while (rs.next()) { @@ -106,6 +109,7 @@ //question.setTypeForDisplay(type.getCurrentNodePathNoRoot()); //question.setTypeId(type.getId()); questions.add(question); + questionIdList.add(id); } } } catch (SQLException e) { @@ -121,6 +125,9 @@ e.printStackTrace(); } } + if(CollectionUtils.isNotEmpty(questionIdList)){ + questions = objectDao.findByIds(Question.class.getSimpleName(), questionIdList); + } return questions; } @@ -185,14 +192,37 @@ } } question.setTitle(questionVo.getTitle()); - question.setOptionA(questionVo.getOptionA()); - question.setOptionB(questionVo.getOptionB()); - question.setOptionC(questionVo.getOptionC()); - question.setOptionD(questionVo.getOptionD()); - question.setOptionE(questionVo.getOptionE()); question.setQuestionType(questionVo.getQuestionType()); - question.setAnswer(questionVo.getAnswer()); question.setIsAssuredAnswer(questionVo.getIsAssuredAnswer()); + if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SINGLE_CHOICE) + || StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_MULTIPLE_CHOICE)){ + //单选题/多选题 + question.setOptionA(questionVo.getOptionA()); + question.setOptionB(questionVo.getOptionB()); + question.setOptionC(questionVo.getOptionC()); + question.setOptionD(questionVo.getOptionD()); + question.setOptionE(questionVo.getOptionE()); + question.setAnswer(questionVo.getAnswer()); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_TRUE_OR_FALSE)){ + //判断题 + question.setOptionTrue(questionVo.getOptionTrue()); + question.setOptionFalse(questionVo.getOptionFalse()); + question.setAnswer(questionVo.getAnswer()); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_FILL_BLANKS)){ + //填空题 + List dbFillBlankAnswers = question.getFillBlankAnswers(); + if(CollectionUtils.isNotEmpty(dbFillBlankAnswers)){ + objectDao.deleteAll(dbFillBlankAnswers); + } + List fillBlankAnswers = questionVo.getFillBlankAnswers(); + if(CollectionUtils.isNotEmpty(fillBlankAnswers)){ + question.setFillBlankAnswers(fillBlankAnswers); + } + + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER)){ + //简答题 + question.setAnswer(questionVo.getAnswer()); + } //校验题目信息 validateQuestion(question); this.saveOrUpdate(question); @@ -209,6 +239,9 @@ if(StringUtil.isBlank(question.getTitle())){ throw new SystemException("题目不能为空!"); } + if(question.getTitle().length() > 700){ + throw new SystemException("题目标题过长!"); + } if(question.getPublishTime() == null){ throw new SystemException("发布时间不能为空!"); } @@ -233,7 +266,125 @@ if(question.getExpDt().before(question.getEffDt())){ throw new SystemException("“失效日期”不得早于“生效日期”!"); } + + if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SINGLE_CHOICE) + || StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_MULTIPLE_CHOICE)){ + //选择题的校验 + validateChoiceQuestion(question); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_TRUE_OR_FALSE)){ + //判断题的校验 + validateTrueOrFalseQuestion(question); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_FILL_BLANKS)){ + //填空题的校验 + validateFillBlankQuestion(question); + }else if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER)){ + //简答题的校验 + validateShortAnswerQuestion(question); + }else{ + throw new SystemException("不支持的题型:" + question.getQuestionType()); + } + } + + /** + * 简答题的校验: + * 答案非必填项; + * 简答题文字长度为最多支持3000个; + * @param question + */ + private void validateShortAnswerQuestion(Question question) { + if(StringUtils.isNotBlank(question.getAnswer()) && question.getAnswer().length() > 3000){ + throw new SystemException("简答题文字长度为最多支持3000个中英文字符"); + } + } + + /** + * 填空题的校验 + * 答案不能为空; + * 每个填空符都要有对应的答案; + * @param question + */ + private void validateFillBlankQuestion(Question question) { + //题目的填空位置个数 + int blankSize = getFillBlankQuestionBlankSize(question); + if(blankSize <= 0){ + throw new SystemException("填空题不能没有填空符"); + } + List fillBlankAnswers = question.getFillBlankAnswers(); + if(CollectionUtils.isEmpty(fillBlankAnswers)){ + throw new SystemException("填空题答案不能为空"); + } + if(fillBlankAnswers.size() != blankSize){ + throw new SystemException("填空题答案数量必须等于填空符数量"); + } + for (FillBlankAnswer fillBlankAnswer : fillBlankAnswers) { + if(StringUtils.isEmpty(fillBlankAnswer.getAnswer())){ + throw new SystemException("填空题答案不能为空"); + } + if(StringUtils.isNotBlank(fillBlankAnswer.getAnswer()) + && fillBlankAnswer.getAnswer().length() > 50){ + throw new SystemException("简答题答案字数最长不能超过50个中英文字符"); + } + } + } + + /** + * 获取填空题的填空符数量 + * @param question + * @return + */ + private int getFillBlankQuestionBlankSize(Question question) { + String title = question.getTitle(); + title = ";" + title + ";"; + int tagCount = 0; + String[] splits = title.split(Question.FILL_BLANKS_TAG); + if(splits == null || splits.length <= 0){ + return tagCount; + } + tagCount = splits.length - 1; + /*for (String split : splits) { + if(StringUtils.isBlank(split)){ + tagCount--; + } + }*/ + return tagCount; + } + + /** + * 判断题的校验: + * 必须有正确和错误两个选项; + * 答案不能为空并且必须为true/false; + * @param question + */ + private void validateTrueOrFalseQuestion(Question question) { + String optionTrue = question.getOptionTrue(); + String optionFalse = question.getOptionFalse(); + String answer = question.getAnswer(); if("有".equals(question.getIsAssuredAnswer())) { + if(StringUtils.isBlank(answer)){ + throw new SystemException("答案不允许为空!"); + } + if(!StringUtils.equals(answer, optionTrue) + && !StringUtils.equals(answer, optionFalse)){ + throw new SystemException("答案异常!"); + } + } + if(StringUtils.isBlank(optionTrue)){ + throw new SystemException("选项不允许为空!"); + } + if(StringUtils.isBlank(optionFalse)){ + throw new SystemException("选项不允许为空!"); + } + if(StringUtils.equals(optionTrue.trim(), optionFalse.trim())){ + throw new SystemException("选项不允许相同!"); + } + } + + /** + * 选择题的校验 + * @param question + */ + private void validateChoiceQuestion(Question question) { + if("有".equals(question.getIsAssuredAnswer())) { Map optionMap = new HashMap(); Set optionSet = new HashSet(); if(StringUtils.isNotBlank(question.getOptionA())){ Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/Question.java =================================================================== diff -u -r38772 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/Question.java (.../Question.java) (revision 38772) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/question/Question.java (.../Question.java) (revision 38870) @@ -1,17 +1,26 @@ package com.forgon.disinfectsystem.entity.onlineexams.question; import java.io.Serializable; +import java.util.ArrayList; import java.util.Date; +import java.util.List; +import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; import com.forgon.systemsetting.model.HttpOption; import com.forgon.systemsetting.model.HttpTreeOption; @@ -59,8 +68,36 @@ private String optionD; // 选项D private String optionE; // 选项E + + /** + * 判断题-正确选项 + */ + private String optionTrue; + + /** + * 判断题-错误选项 + */ + private String optionFalse; + + /** + * 填空题的答案 + */ + private List fillBlankAnswers = new ArrayList(); - private String questionType; // 题型 (单选或多选) + /** + * 题型 + */ + private String questionType; + + public static final String QUESTION_TYPE_SINGLE_CHOICE = "单选"; + public static final String QUESTION_TYPE_MULTIPLE_CHOICE = "多选"; + public static final String QUESTION_TYPE_TRUE_OR_FALSE = "判断题"; + public static final String QUESTION_TYPE_FILL_BLANKS = "填空题"; + public static final String QUESTION_TYPE_SHORT_ANSWER = "简答题"; + /** + * 填空符,用连续3个“_”来标识 + */ + public static final String FILL_BLANKS_TAG = "___"; private String answer; // 答案 @@ -136,6 +173,7 @@ this.difficulty = difficulty; } + @Column(length = 3072) public String getTitle() { return title; } @@ -184,6 +222,34 @@ this.optionE = optionE; } + public String getOptionTrue() { + return optionTrue; + } + + public void setOptionTrue(String optionTrue) { + this.optionTrue = optionTrue; + } + + public String getOptionFalse() { + return optionFalse; + } + + public void setOptionFalse(String optionFalse) { + this.optionFalse = optionFalse; + } + + @OneToMany(fetch = FetchType.LAZY) + @Cascade(value = { CascadeType.ALL }) + @JoinColumn(name = "question_ID") + @OrderBy("sequece asc") + public List getFillBlankAnswers() { + return fillBlankAnswers; + } + + public void setFillBlankAnswers(List fillBlankAnswers) { + this.fillBlankAnswers = fillBlankAnswers; + } + public String getQuestionType() { return questionType; } @@ -192,6 +258,7 @@ this.questionType = questionType; } + @Lob public String getAnswer() { return answer; } Index: ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_mysql.sql =================================================================== diff -u --- ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_mysql.sql (revision 0) +++ ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_mysql.sql (revision 38870) @@ -0,0 +1,5 @@ +ALTER TABLE Question MODIFY title varchar(3072); +ALTER TABLE Question MODIFY answer text; +ALTER TABLE ExamQuestion MODIFY answerChoosen text; +UPDATE AnswerSheet SET examPaperStatus = '已评分' WHERE endTime is not null and examPaperStatus is null; +UPDATE AnswerSheet SET examPaperStatus = '未交卷' WHERE endTime is null and examPaperStatus is null; \ No newline at end of file Index: ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_sqlserver.sql =================================================================== diff -u --- ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_sqlserver.sql (revision 0) +++ ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_sqlserver.sql (revision 38870) @@ -0,0 +1,5 @@ +ALTER TABLE Question ALTER COLUMN title varchar(3072); +ALTER TABLE Question ALTER COLUMN answer text; +ALTER TABLE ExamQuestion ALTER COLUMN answerChoosen text; +UPDATE AnswerSheet SET examPaperStatus = '已评分' WHERE endTime is not null and examPaperStatus is null; +UPDATE AnswerSheet SET examPaperStatus = '未交卷' WHERE endTime is null and examPaperStatus is null; \ No newline at end of file Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/vo/QuestionVo.java =================================================================== diff -u -r38775 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/vo/QuestionVo.java (.../QuestionVo.java) (revision 38775) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/vo/QuestionVo.java (.../QuestionVo.java) (revision 38870) @@ -1,5 +1,10 @@ package com.forgon.disinfectsystem.vo; +import java.util.ArrayList; +import java.util.List; + +import com.forgon.disinfectsystem.entity.onlineexams.question.FillBlankAnswer; + /** * 题目的vo */ @@ -86,6 +91,21 @@ * 选项E */ private String optionE; + + /** + * 判断题-正确选项 + */ + private String optionTrue; + + /** + * 判断题-错误选项 + */ + private String optionFalse; + + /** + * 填空题-答案 + */ + private List fillBlankAnswers = new ArrayList(); /** * 答案 @@ -228,6 +248,30 @@ this.optionE = optionE; } + public String getOptionTrue() { + return optionTrue; + } + + public void setOptionTrue(String optionTrue) { + this.optionTrue = optionTrue; + } + + public String getOptionFalse() { + return optionFalse; + } + + public void setOptionFalse(String optionFalse) { + this.optionFalse = optionFalse; + } + + public List getFillBlankAnswers() { + return fillBlankAnswers; + } + + public void setFillBlankAnswers(List fillBlankAnswers) { + this.fillBlankAnswers = fillBlankAnswers; + } + public String getAnswer() { return answer; } Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/dwr/ExamAnswerTableManager.java =================================================================== diff -u -r38383 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/dwr/ExamAnswerTableManager.java (.../ExamAnswerTableManager.java) (revision 38383) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/dwr/ExamAnswerTableManager.java (.../ExamAnswerTableManager.java) (revision 38870) @@ -87,6 +87,11 @@ + "' and name != '" + Constants.PREPARATION_FLY_TECHNICALTEST + "' and "+gridSql+""; }*/ + Map sqlWhereParamMap = gridManager.getParamFromView(parameterMap); + String examPaperStatus = sqlWhereParamMap.get("examPaperStatus"); + if(StringUtils.isNotBlank(examPaperStatus)){ + sql += " and examPaperStatus = '" + examPaperStatus + "' "; + } return gridManager.renderGrid(parameterMap, AnswerSheet.class .getName(), sql, new String[] { "examQuestions" }); } Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/ExamQuestion.java =================================================================== diff -u -r38383 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/ExamQuestion.java (.../ExamQuestion.java) (revision 38383) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/ExamQuestion.java (.../ExamQuestion.java) (revision 38870) @@ -1,16 +1,24 @@ package com.forgon.disinfectsystem.entity.onlineexams.examdefinition; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; import com.forgon.disinfectsystem.entity.onlineexams.question.Question; @@ -30,6 +38,11 @@ private Question question; private String answerChoosen; // 考生选择的答案 + + /** + * 考试填写的填空题答案 + */ + private List fillBlankAnswers = new ArrayList(); private Integer scoreGained; // 得分 @@ -63,6 +76,7 @@ this.question = question; } + @Lob public String getAnswerChoosen() { return answerChoosen; } @@ -71,6 +85,18 @@ this.answerChoosen = answerChoosen; } + @OneToMany(fetch = FetchType.LAZY) + @Cascade(value = { CascadeType.ALL }) + @JoinColumn(name = "examQuestion_ID") + @OrderBy("sequece asc") + public List getFillBlankAnswers() { + return fillBlankAnswers; + } + + public void setFillBlankAnswers(List fillBlankAnswers) { + this.fillBlankAnswers = fillBlankAnswers; + } + public Integer getScoreGained() { return scoreGained; } Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/controller/QuestionFormController.java =================================================================== diff -u -r38772 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/controller/QuestionFormController.java (.../QuestionFormController.java) (revision 38772) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/question/controller/QuestionFormController.java (.../QuestionFormController.java) (revision 38870) @@ -5,6 +5,7 @@ import net.sf.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -78,6 +79,9 @@ vo.setOptionC(question.getOptionC()); vo.setOptionD(question.getOptionD()); vo.setOptionE(question.getOptionE()); + vo.setOptionTrue(question.getOptionTrue()); + vo.setOptionFalse(question.getOptionFalse()); + vo.setFillBlankAnswers(question.getFillBlankAnswers()); vo.setAnswer(question.getAnswer()); return vo; } @@ -87,7 +91,7 @@ * @return */ @RequestMapping("/saveQuestion") - public String saveQuestion(QuestionVo vo){ + public String saveQuestion(@RequestBody QuestionVo vo){ JSONObject result = JSONUtil.buildJsonObject(true, "保存成功"); try { questionManager.saveOrUpdateQuestion(vo); Index: ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_oracle.sql =================================================================== diff -u --- ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_oracle.sql (revision 0) +++ ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_oracle.sql (revision 38870) @@ -0,0 +1,20 @@ +UPDATE AnswerSheet SET examPaperStatus = '已评分' WHERE endTime is not null and examPaperStatus is null; +UPDATE AnswerSheet SET examPaperStatus = '未交卷' WHERE endTime is null and examPaperStatus is null; +execute immediate 'alter table Question add (foo varchar(3072))'; +execute immediate 'update Question set foo = title'; +execute immediate 'commit'; +execute immediate 'alter table Question drop column title'; +execute immediate 'alter table Question rename column foo to title'; +execute immediate 'commit'; +execute immediate 'alter table Question add (foo clob)'; +execute immediate 'update Question set foo = answer'; +execute immediate 'commit'; +execute immediate 'alter table Question drop column answer'; +execute immediate 'alter table Question rename column foo to answer'; +execute immediate 'commit'; +execute immediate 'alter table ExamQuestion add (foo clob)'; +execute immediate 'update ExamQuestion set foo = answerChoosen'; +execute immediate 'commit'; +execute immediate 'alter table ExamQuestion drop column answerChoosen'; +execute immediate 'alter table ExamQuestion rename column foo to answerChoosen'; +execute immediate 'commit'; \ No newline at end of file Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManager.java =================================================================== diff -u -r38383 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManager.java (.../AnswerManager.java) (revision 38383) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManager.java (.../AnswerManager.java) (revision 38870) @@ -89,5 +89,20 @@ * @param request */ public void submitAnswer(AnswerSheet form, HttpServletRequest request); + + /** + * 简答题评分 + * @param answerSheetId 试卷ID + * @param examQuestionId 试卷题目ID + */ + public void markExamPaperShortAnswerScore(Long answerSheetId, Long examQuestionId, Integer score); + + /** + * 查看简答题答案 + * @param answerSheetId 试卷ID + * @param examQuestionId 试卷题目ID + * @return + */ + public String loadShortAnswerQuestionAnswer(Long answerSheetId, Long examQuestionId); } \ No newline at end of file Index: ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_tidb.sql =================================================================== diff -u --- ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_tidb.sql (revision 0) +++ ssts-web/src/main/webapp/dataUpdater/sqls/5.0.29_5.0.30_tidb.sql (revision 38870) @@ -0,0 +1,5 @@ +ALTER TABLE Question MODIFY title varchar(3072); +ALTER TABLE Question MODIFY answer text; +ALTER TABLE ExamQuestion MODIFY answerChoosen text; +UPDATE AnswerSheet SET examPaperStatus = '已评分' WHERE endTime is not null and examPaperStatus is null; +UPDATE AnswerSheet SET examPaperStatus = '未交卷' WHERE endTime is null and examPaperStatus is null; \ No newline at end of file Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/FillBlankAnswerChoosen.java =================================================================== diff -u --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/FillBlankAnswerChoosen.java (revision 0) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/onlineexams/examdefinition/FillBlankAnswerChoosen.java (revision 38870) @@ -0,0 +1,57 @@ +package com.forgon.disinfectsystem.entity.onlineexams.examdefinition; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +/** + * 考生填入的填空题答案 + */ +@Entity +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class FillBlankAnswerChoosen { + + + private Long id; + + /** + * 对应的空格顺序 + */ + private Integer sequece; + + /** + * 填空题的答案,字数最长不能超过50个中英文字符 + */ + private String answer; + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getSequece() { + return sequece; + } + + public void setSequece(Integer sequece) { + this.sequece = sequece; + } + + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + +} Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManagerImpl.java =================================================================== diff -u -r38772 -r38870 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManagerImpl.java (.../AnswerManagerImpl.java) (revision 38772) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/onlineexams/examanswer/service/AnswerManagerImpl.java (.../AnswerManagerImpl.java) (revision 38870) @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletRequest; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.FastDateFormat; import org.apache.log4j.Logger; @@ -25,8 +26,12 @@ import com.forgon.disinfectsystem.entity.onlineexams.answersheet.AnswerSheet; import com.forgon.disinfectsystem.entity.onlineexams.examdefinition.ExamDefinition; import com.forgon.disinfectsystem.entity.onlineexams.examdefinition.ExamQuestion; +import com.forgon.disinfectsystem.entity.onlineexams.examdefinition.FillBlankAnswerChoosen; +import com.forgon.disinfectsystem.entity.onlineexams.question.FillBlankAnswer; import com.forgon.disinfectsystem.entity.onlineexams.question.Question; import com.forgon.excel.service.CommonExportManager; +import com.forgon.exception.SystemException; +import com.forgon.tools.db.DatabaseUtil; import com.forgon.tools.hibernate.ObjectDao; public class AnswerManagerImpl implements AnswerManager { @@ -267,14 +272,15 @@ // 实际得分 Integer totalScore = 0; List examQuestions = new ArrayList(); + boolean includeShortAnswer = false; for (int i = 1; i <= Integer.parseInt(request.getParameter("maxRow")); i++) { String questionId = request.getParameter("questionId" + i); Question question = questionManager.getById(questionId); String examQuestionId = request.getParameter("examQuestionId" + i); ExamQuestion examQuestion = examQuestionManager .getById(examQuestionId); String answer = question.getAnswer(); - if ("多选".equals(question.getQuestionType())) { + if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getQuestionType())) { String answerChosen = ""; String answerA = request.getParameter("answerA" + i); String answerB = request.getParameter("answerB" + i); @@ -333,7 +339,7 @@ } // examQuestionManager.saveOrUpdate(examQuestion); examQuestions.add(examQuestion); - } else { + } else if(Question.QUESTION_TYPE_SINGLE_CHOICE.equals(question.getQuestionType())){ String answerChosen = request.getParameter("answer" + i); examQuestion.setAnswerChoosen(answerChosen); @@ -356,6 +362,58 @@ // examQuestionManager.saveOrUpdate(examQuestion); examQuestions.add(examQuestion); + } else if(Question.QUESTION_TYPE_TRUE_OR_FALSE.equals(question.getQuestionType())){ + //判断题 + String answerChosen = request.getParameter("answer" + i); + examQuestion.setAnswerChoosen(answerChosen); + if ("有".equals(form.getExamDefinition().getIsAssuredAnswer())) { + // 未作答时,答案为空 + if (answerChosen != null + && answerChosen.equals(question.getAnswer())) { + correct++; + examQuestion.setScoreGained(examQuestion.getScore()); + // 实际得分 + totalScore += examQuestion.getScore(); + } else { + incorrect++; + examQuestion.setScoreGained(0); + } + } + // examQuestionManager.saveOrUpdate(examQuestion); + examQuestions.add(examQuestion); + } else if(Question.QUESTION_TYPE_FILL_BLANKS.equals(question.getQuestionType())){ + //填空题 + List fillBlankAnswers = question.getFillBlankAnswers(); + List fillBlankAnswerChoosens = new ArrayList(); + //填空题的答案判断,需要用户填写的内容和答案中提供的内容完全一样才算正确,否则视为错误; + boolean incorrectFillBlank = false; + for (FillBlankAnswer fillBlankAnswer : fillBlankAnswers) { + Integer sequece = fillBlankAnswer.getSequece(); + String answerChoosen = request.getParameter("answer" + i + "_" + sequece); + if(!StringUtils.equals(fillBlankAnswer.getAnswer(), answerChoosen)){ + incorrectFillBlank = true; + } + FillBlankAnswerChoosen fillBlankAnswerChoosen = new FillBlankAnswerChoosen(); + fillBlankAnswerChoosen.setAnswer(answerChoosen); + fillBlankAnswerChoosen.setSequece(sequece); + fillBlankAnswerChoosens.add(fillBlankAnswerChoosen); + } + if(!incorrectFillBlank){ + correct++; + totalScore += examQuestion.getScore(); + examQuestion.setScoreGained(examQuestion.getScore()); + }else{ + incorrect++; + examQuestion.setScoreGained(0); + } + examQuestion.setFillBlankAnswers(fillBlankAnswerChoosens); + examQuestions.add(examQuestion); + } else if(Question.QUESTION_TYPE_SHORT_ANSWER.equals(question.getQuestionType())){ + //简答题 + String answerChosen = request.getParameter("answer" + i); + examQuestion.setAnswerChoosen(answerChosen); + includeShortAnswer = true; + examQuestions.add(examQuestion); } if (i == Integer.parseInt(request.getParameter("maxRow"))) { @@ -366,6 +424,10 @@ form.setScoreGained(totalScore); // form.setTotalSocre(totalScore); form.setExamQuestions(examQuestions); + if(includeShortAnswer && StringUtils.equals(form.getExamPaperStatus(), AnswerSheet.PAPER_STATUS_NOT_SUBMITTED)){ + //已交卷后,存在未评分的简答题时,显示的状态为“待评分”; + form.setExamPaperStatus(AnswerSheet.PAPER_STATUS_TO_BE_RATED); + } } /** @@ -742,4 +804,102 @@ form.setExamCount(examCount+1); this.saveOrUpdate(form); } + + @Override + public void markExamPaperShortAnswerScore(Long answerSheetId, Long examQuestionId, Integer scoreGained) { + if(!DatabaseUtil.isPoIdValid(answerSheetId) || !DatabaseUtil.isPoIdValid(examQuestionId)){ + throw new SystemException("id无效"); + } + if(scoreGained == null || scoreGained < 0){ + throw new SystemException("分数无效"); + } + AnswerSheet answerSheet = this.getById(answerSheetId.toString()); + if(answerSheet == null){ + throw new SystemException("试卷id无效"); + } + //还没有交卷的试卷不允许给简答题评分 + if(StringUtils.equals(answerSheet.getExamPaperStatus(), AnswerSheet.PAPER_STATUS_NOT_SUBMITTED)){ + throw new SystemException("试卷未交卷"); + } + ExamQuestion examQuestion = null; + List examQuestions = answerSheet.getExamQuestions(); + if(CollectionUtils.isEmpty(examQuestions)){ + throw new SystemException("试卷没有题目"); + } + for (ExamQuestion examQuestion2 : examQuestions) { + if(examQuestion2.getId().longValue() == examQuestionId.longValue()){ + examQuestion = examQuestion2; + break; + } + } + if(examQuestion == null){ + throw new SystemException("试卷题目id无效"); + } + if(!StringUtils.equals(examQuestion.getQuestion().getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER)){ + throw new SystemException("只有简答题需要评分"); + } + //设置的分数最少为0分,最多不能超过该题目设置的分数; + Integer score = examQuestion.getScore(); + if(scoreGained > score){ + throw new SystemException("分数不能大于题目分数:" + score); + } + Integer oldScoreGained = examQuestion.getScoreGained(); + //修改试卷简答题得分 + examQuestion.setScoreGained(scoreGained); + //修改试卷简答题分数、总得分; + Integer totalSocreGained = answerSheet.getScoreGained() == null ? 0 : answerSheet.getScoreGained(); + Integer shortAnswerScore = answerSheet.getShortAnswerScore() == null ? 0 : answerSheet.getShortAnswerScore(); + if(oldScoreGained != null){ + if(totalSocreGained > 0){ + totalSocreGained -= oldScoreGained; + } + if(shortAnswerScore > 0){ + shortAnswerScore -= oldScoreGained; + } + } + totalSocreGained += scoreGained; + shortAnswerScore += scoreGained; + answerSheet.setScoreGained(totalSocreGained); + answerSheet.setShortAnswerScore(shortAnswerScore); + //修改试卷状态 + for (ExamQuestion examQuestion2 : examQuestions) { + Question question = examQuestion2.getQuestion(); + if(StringUtils.equals(question.getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER) + && examQuestion2.getScoreGained() == null){ + answerSheet.setExamPaperStatus(AnswerSheet.PAPER_STATUS_TO_BE_RATED); + break; + } + answerSheet.setExamPaperStatus(AnswerSheet.PAPER_STATUS_RATED); + } + } + + @Override + public String loadShortAnswerQuestionAnswer(Long answerSheetId, Long examQuestionId) { + AnswerSheet answerSheet = this.getById(answerSheetId.toString()); + if(answerSheet == null){ + throw new SystemException("试卷id无效"); + } + //还没有交卷的试卷不允许给简答题评分 + if(StringUtils.equals(answerSheet.getExamPaperStatus(), AnswerSheet.PAPER_STATUS_NOT_SUBMITTED)){ + throw new SystemException("试卷未交卷"); + } + ExamQuestion examQuestion = null; + List examQuestions = answerSheet.getExamQuestions(); + if(CollectionUtils.isEmpty(examQuestions)){ + throw new SystemException("试卷没有题目"); + } + for (ExamQuestion examQuestion2 : examQuestions) { + if(examQuestion2.getId().longValue() == examQuestionId.longValue()){ + examQuestion = examQuestion2; + break; + } + } + if(examQuestion == null){ + throw new SystemException("试卷题目id无效"); + } + if(!StringUtils.equals(examQuestion.getQuestion().getQuestionType(), Question.QUESTION_TYPE_SHORT_ANSWER)){ + throw new SystemException("只有简答题需要查看参考答案"); + } + return examQuestion.getQuestion().getAnswer(); + } }