|
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStream;
|
|
|
|
+import java.math.BigDecimal;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
@@ -23,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
@@ -65,795 +67,815 @@ import cn.com.qmth.am.utils.ImageUtil;
|
|
|
|
|
|
@Service
|
|
@Service
|
|
public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, StudentScoreEntity>
|
|
public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, StudentScoreEntity>
|
|
- implements StudentScoreService {
|
|
|
|
- private static final Logger log = LoggerFactory.getLogger(StudentScoreService.class);
|
|
|
|
- private static BlockingQueue<StudentScoreImageDto> queue;
|
|
|
|
- private static final String[] EXCEL_HEADER = new String[] { "考试ID", "科目代码", "考生编号", "大题号", "小题号", "评分" };
|
|
|
|
- @Autowired
|
|
|
|
- private SysProperty sysProperty;
|
|
|
|
- @Autowired
|
|
|
|
- private SolarService solarService;
|
|
|
|
- @Autowired
|
|
|
|
- private StudentService studentService;
|
|
|
|
- @Autowired
|
|
|
|
- private OcrApiClient ocrApiClient;
|
|
|
|
- @Autowired
|
|
|
|
- private AiService aiService;
|
|
|
|
- @Autowired
|
|
|
|
- private QuestionService questionService;
|
|
|
|
- static {
|
|
|
|
- int threadCount = Runtime.getRuntime().availableProcessors();
|
|
|
|
- queue = new ArrayBlockingQueue<>(threadCount * 2);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void importScore() {
|
|
|
|
- File dir = new File(sysProperty.getDataDir());
|
|
|
|
- File[] fs = dir.listFiles();
|
|
|
|
- if (fs == null || fs.length == 0) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- for (File file : fs) {
|
|
|
|
- if (!file.isFile() || !file.getName().equals(ImportFileName.SCORE_IMPORT.getName())) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- InputStream inputStream = null;
|
|
|
|
- ImportResult ret = null;
|
|
|
|
- try {
|
|
|
|
- inputStream = new FileInputStream(file);
|
|
|
|
- ret = disposeFile(inputStream);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- String errMsg;
|
|
|
|
- if (e instanceof FileNotFoundException) {
|
|
|
|
- errMsg = "未找到文件:" + file.getAbsolutePath();
|
|
|
|
- } else {
|
|
|
|
- errMsg = "系统错误:" + e.getMessage();
|
|
|
|
- }
|
|
|
|
- ret = new ImportResult(errMsg);
|
|
|
|
- } finally {
|
|
|
|
- if (inputStream != null) {
|
|
|
|
- try {
|
|
|
|
- inputStream.close();
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- moveFile(dir, file, ret);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void moveFile(File dir, File file, ImportResult ret) {
|
|
|
|
- try {
|
|
|
|
- boolean succss = CollectionUtils.isEmpty(ret.getErrMsg());
|
|
|
|
- if (succss) {
|
|
|
|
- File sucDir = new File(dir.getAbsoluteFile() + "/success/");
|
|
|
|
- if (!sucDir.exists()) {
|
|
|
|
- sucDir.mkdir();
|
|
|
|
- }
|
|
|
|
- File targetFile = new File(sucDir.getAbsoluteFile() + "/" + file.getName());
|
|
|
|
- if (targetFile.exists()) {
|
|
|
|
- targetFile.delete();
|
|
|
|
- }
|
|
|
|
- FileUtils.copyFile(file, targetFile);
|
|
|
|
- file.delete();
|
|
|
|
- String fname = file.getName().substring(0, file.getName().lastIndexOf("."));
|
|
|
|
- File msgFile = new File(sucDir.getAbsoluteFile() + "/" + fname + "_info.txt");
|
|
|
|
- if (msgFile.exists()) {
|
|
|
|
- msgFile.delete();
|
|
|
|
- }
|
|
|
|
- FileUtils.write(msgFile, ret.getCountInfo(), "utf-8");
|
|
|
|
- } else {
|
|
|
|
- File sucDir = new File(dir.getAbsoluteFile() + "/failed/");
|
|
|
|
- if (!sucDir.exists()) {
|
|
|
|
- sucDir.mkdir();
|
|
|
|
- }
|
|
|
|
- File targetFile = new File(sucDir.getAbsoluteFile() + "/" + file.getName());
|
|
|
|
- if (targetFile.exists()) {
|
|
|
|
- targetFile.delete();
|
|
|
|
- }
|
|
|
|
- FileUtils.copyFile(file, targetFile);
|
|
|
|
- file.delete();
|
|
|
|
- String fname = file.getName().substring(0, file.getName().lastIndexOf("."));
|
|
|
|
- File msgFile = new File(sucDir.getAbsoluteFile() + "/" + fname + "_info.txt");
|
|
|
|
- if (msgFile.exists()) {
|
|
|
|
- msgFile.delete();
|
|
|
|
- }
|
|
|
|
- FileUtils.writeLines(msgFile, StandardCharsets.UTF_8.name(), ret.getErrMsg());
|
|
|
|
- }
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- throw new StatusException("文件处理出错", e);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String errorMsg(int lineNum, String msg) {
|
|
|
|
- return "第" + lineNum + "行 " + msg;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String trimAndNullIfBlank(String s) {
|
|
|
|
- if (StringUtils.isBlank(s)) {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- return s.trim();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private ImportResult disposeFile(InputStream inputStream) {
|
|
|
|
- List<DataMap> lineList = null;
|
|
|
|
- ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
|
|
|
|
- try {
|
|
|
|
- lineList = reader.getDataMapList();
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- throw new StatusException("Excel 解析失败");
|
|
|
|
- }
|
|
|
|
- if (!Arrays.equals(EXCEL_HEADER, reader.getColumnNames())) {
|
|
|
|
- throw new StatusException("Excel表头错误");
|
|
|
|
- }
|
|
|
|
- if (CollectionUtils.isEmpty(lineList)) {
|
|
|
|
- throw new StatusException("Excel无内容");
|
|
|
|
- }
|
|
|
|
- if (100001 < lineList.size()) {
|
|
|
|
- throw new StatusException("数据行数不能超过100000");
|
|
|
|
- }
|
|
|
|
- List<StudentScoreDto> ss = new ArrayList<>();
|
|
|
|
- ImportResult ret = new ImportResult();
|
|
|
|
- List<String> failRecords = new ArrayList<>();
|
|
|
|
- ret.setErrMsg(failRecords);
|
|
|
|
- for (int i = 0; i < lineList.size(); i++) {
|
|
|
|
- DataMap line = lineList.get(i);
|
|
|
|
-
|
|
|
|
- StringBuilder msg = new StringBuilder();
|
|
|
|
-
|
|
|
|
- StudentScoreDto imp = new StudentScoreDto();
|
|
|
|
- String examId = trimAndNullIfBlank(line.get(EXCEL_HEADER[0]));
|
|
|
|
- if (StringUtils.isBlank(examId)) {
|
|
|
|
- msg.append(" 考试ID不能为空");
|
|
|
|
- } else if (examId.length() > 20) {
|
|
|
|
- msg.append(" 考试ID不能超过20个字符");
|
|
|
|
- } else {
|
|
|
|
- try {
|
|
|
|
- Long examIdVal = Long.parseLong(examId);
|
|
|
|
- imp.setExamId(examIdVal);
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
- msg.append(" 考试ID只能是数字");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String subjectCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[1]));
|
|
|
|
- if (StringUtils.isBlank(subjectCode)) {
|
|
|
|
- msg.append(" 科目代码不能为空");
|
|
|
|
- } else if (subjectCode.length() > 100) {
|
|
|
|
- msg.append(" 科目代码不能超过100个字符");
|
|
|
|
- }
|
|
|
|
- imp.setSubjectCode(subjectCode);
|
|
|
|
-
|
|
|
|
- String studentCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[2]));
|
|
|
|
- if (StringUtils.isBlank(studentCode)) {
|
|
|
|
- msg.append(" 考生编号不能为空");
|
|
|
|
- } else if (studentCode.length() > 100) {
|
|
|
|
- msg.append(" 考生编号不能超过100个字符");
|
|
|
|
- }
|
|
|
|
- imp.setStudentCode(studentCode);
|
|
|
|
-
|
|
|
|
- String mainNum = trimAndNullIfBlank(line.get(EXCEL_HEADER[3]));
|
|
|
|
- if (StringUtils.isBlank(mainNum)) {
|
|
|
|
- msg.append(" 大题号不能为空");
|
|
|
|
- } else if (mainNum.length() > 10) {
|
|
|
|
- msg.append(" 大题号不能超过10个字符");
|
|
|
|
- } else {
|
|
|
|
- try {
|
|
|
|
- Integer mainNumVal = Integer.parseInt(mainNum);
|
|
|
|
- if (mainNumVal <= 0) {
|
|
|
|
- msg.append(" 大题号必须大于0");
|
|
|
|
- }
|
|
|
|
- imp.setMainNumber(mainNumVal);
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
- msg.append(" 大题号格式错误");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String subNum = trimAndNullIfBlank(line.get(EXCEL_HEADER[4]));
|
|
|
|
- if (StringUtils.isBlank(subNum)) {
|
|
|
|
- msg.append(" 小题号不能为空");
|
|
|
|
- } else if (subNum.length() > 10) {
|
|
|
|
- msg.append(" 小题号不能超过10个字符");
|
|
|
|
- }
|
|
|
|
- imp.setSubNumber(subNum);
|
|
|
|
-
|
|
|
|
- String score = trimAndNullIfBlank(line.get(EXCEL_HEADER[5]));
|
|
|
|
- if (StringUtils.isBlank(score)) {
|
|
|
|
- msg.append(" 评分不能为空");
|
|
|
|
- } else if (score.length() > 10) {
|
|
|
|
- msg.append(" 评分不能超过10个字符");
|
|
|
|
- } else {
|
|
|
|
- try {
|
|
|
|
- Double scoreVal = Double.parseDouble(score);
|
|
|
|
- imp.setMarkingScore(scoreVal);
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
- msg.append(" 评分格式错误");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (msg.length() > 0) {
|
|
|
|
- failRecords.add(errorMsg(i + 2, msg.toString()));
|
|
|
|
- } else {
|
|
|
|
- ss.add(imp);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (CollectionUtils.isNotEmpty(failRecords)) {
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- try {
|
|
|
|
- updateScoreBatch(ret, ss);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- failRecords.add("系统错误:" + e.getMessage());
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void updateScoreBatch(ImportResult ret, List<StudentScoreDto> ss) {
|
|
|
|
- if (CollectionUtils.isEmpty(ss)) {
|
|
|
|
- ret.setCountInfo("更新数量:0");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- int count = 0;
|
|
|
|
- for (StudentScoreDto s : ss) {
|
|
|
|
- count = count + updateScore(s);
|
|
|
|
- }
|
|
|
|
- ret.setCountInfo("更新数量:" + count);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private int updateScore(StudentScoreDto dto) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getMarkingScore, dto.getMarkingScore());
|
|
|
|
- lw.eq(StudentScoreEntity::getExamId, dto.getExamId());
|
|
|
|
- lw.eq(StudentScoreEntity::getSubjectCode, dto.getSubjectCode());
|
|
|
|
- lw.eq(StudentScoreEntity::getStudentCode, dto.getStudentCode());
|
|
|
|
- lw.eq(StudentScoreEntity::getMainNumber, dto.getMainNumber());
|
|
|
|
- lw.eq(StudentScoreEntity::getSubNumber, dto.getSubNumber());
|
|
|
|
- return this.update(wrapper) ? 1 : 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public List<StudentScoreEntity> getByStudentId(Long studentId) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
- return this.list(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Transactional
|
|
|
|
- @Override
|
|
|
|
- public void add(StudentEntity student, Map<Long, QuestionEntity> quetions,
|
|
|
|
- List<StudentScoreEntity> oldscores) {
|
|
|
|
- List<StudentScoreEntity> adds = new ArrayList<>();
|
|
|
|
- for (QuestionEntity q : quetions.values()) {
|
|
|
|
- if (!exists(q, oldscores)) {
|
|
|
|
- StudentScoreEntity s = new StudentScoreEntity();
|
|
|
|
- adds.add(s);
|
|
|
|
- s.setQuestionId(q.getId());
|
|
|
|
- s.setExamId(student.getExamId());
|
|
|
|
- s.setAnswerStatus(DataStatus.WAITING);
|
|
|
|
- s.setMainNumber(q.getMainNumber());
|
|
|
|
- s.setScoreStatus(DataStatus.WAITING);
|
|
|
|
- s.setStudentCode(student.getStudentCode());
|
|
|
|
- s.setStudentId(student.getId());
|
|
|
|
- s.setSubjectCode(student.getSubjectCode());
|
|
|
|
- s.setSubNumber(q.getSubNumber());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if(CollectionUtils.isNotEmpty(adds)) {
|
|
|
|
- this.saveBatch(adds);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean exists(QuestionEntity q, List<StudentScoreEntity> oldscores) {
|
|
|
|
- if(CollectionUtils.isEmpty(oldscores)) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- for (StudentScoreEntity s : oldscores) {
|
|
|
|
- if (s.getExamId().equals(q.getExamId()) && s.getSubjectCode().equals(q.getSubjectCode())
|
|
|
|
- && s.getMainNumber().equals(q.getMainNumber()) && s.getSubNumber().equals(q.getSubNumber())) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Transactional
|
|
|
|
- @Override
|
|
|
|
- public void updateAnswerErr(Long id, String err) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.FAILED);
|
|
|
|
- lw.set(StudentScoreEntity::getErrMsg, err);
|
|
|
|
- lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void createSlice(StudentScoreEntity score, QuestionEntity q, Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
- StudentScoreImageDto dto = new StudentScoreImageDto();
|
|
|
|
- dto.setStudentId(score.getStudentId());
|
|
|
|
- dto.setStudentScoreId(score.getId());
|
|
|
|
- dto.setImage(getSlice(score, q, answerImages));
|
|
|
|
-// saveSliceImage(score, dto.getImage());
|
|
|
|
- try {
|
|
|
|
- queue.put(dto);
|
|
|
|
- } catch (InterruptedException e) {
|
|
|
|
- throw new RuntimeException(e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private byte[] getSlice(StudentScoreEntity score, QuestionEntity q, Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
- List<byte[]> ret = new ArrayList<>();
|
|
|
|
- String suff = null;
|
|
|
|
- for (ImageSlice s : q.getImageSlice()) {
|
|
|
|
- AnswerImageDto sheet = getSheet(score, q, s.getI(), answerImages);
|
|
|
|
- suff = sheet.getSuff();
|
|
|
|
- ret.add(ImageUtil.cutImage(sheet.getImage(), sheet.getSuff(), s.getX().intValue(), s.getY().intValue(),
|
|
|
|
- s.getW().intValue(), s.getH().intValue()));
|
|
|
|
- }
|
|
|
|
- if (ret.size() > 1) {
|
|
|
|
- return ImageUtil.joinImages(ret, suff);
|
|
|
|
- } else {
|
|
|
|
- return ret.get(0);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private AnswerImageDto getSheet(StudentScoreEntity score, QuestionEntity q, Integer pageIndex,
|
|
|
|
- Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
- AnswerImageDto ret = answerImages.get(pageIndex);
|
|
|
|
- if (ret != null) {
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- try {
|
|
|
|
- ret = new AnswerImageDto();
|
|
|
|
- String url = getImageUrl(score, q, pageIndex);
|
|
|
|
- String tem = url.split("\\?")[0];
|
|
|
|
- String suff = tem.substring(tem.lastIndexOf(".") + 1).toLowerCase();
|
|
|
|
- ret.setImage(ByteArray.fromUrl(url).value());
|
|
|
|
-// saveSheetImage(score,pageIndex, ret.getImage());
|
|
|
|
- ret.setPageIndex(pageIndex);
|
|
|
|
- ret.setSuff(suff);
|
|
|
|
- answerImages.put(pageIndex, ret);
|
|
|
|
- return ret;
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- throw new RuntimeException(e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-// private void saveSheetImage(StudentScoreEntity s,Integer page,byte[] bs) {
|
|
|
|
-// File dir=new File(sysProperty.getDataDir()+"/"+"sheet");
|
|
|
|
-// if(!dir.exists()) {
|
|
|
|
-// dir.mkdir();
|
|
|
|
-// }
|
|
|
|
-// File image=new File(dir.getAbsolutePath()+"/"+s.getStudentCode()+"-"+page+".jpg");
|
|
|
|
-// if(image.exists()) {
|
|
|
|
-// image.delete();
|
|
|
|
-// }
|
|
|
|
-// FileOutputStream out=null;
|
|
|
|
-// try {
|
|
|
|
-// out = new FileOutputStream(image);
|
|
|
|
-// out.write(bs, 0, bs.length);
|
|
|
|
-// out.flush();
|
|
|
|
-// } catch (Exception e) {
|
|
|
|
-// }finally {
|
|
|
|
-// if(out!=null) {
|
|
|
|
-// try {
|
|
|
|
-// out.close();
|
|
|
|
-// } catch (IOException e) {
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// private void saveSliceImage(StudentScoreEntity s,byte[] bs) {
|
|
|
|
-// File dir=new File(sysProperty.getDataDir()+"/"+"slice");
|
|
|
|
-// if(!dir.exists()) {
|
|
|
|
-// dir.mkdir();
|
|
|
|
-// }
|
|
|
|
-// File image=new File(dir.getAbsolutePath()+"/"+s.getStudentCode()+"-"+s.getMainNumber()+"-"+s.getSubNumber()+".jpg");
|
|
|
|
-// if(image.exists()) {
|
|
|
|
-// image.delete();
|
|
|
|
-// }
|
|
|
|
-// FileOutputStream out=null;
|
|
|
|
-// try {
|
|
|
|
-// out = new FileOutputStream(image);
|
|
|
|
-// out.write(bs, 0, bs.length);
|
|
|
|
-// out.flush();
|
|
|
|
-// } catch (Exception e) {
|
|
|
|
-// }finally {
|
|
|
|
-// if(out!=null) {
|
|
|
|
-// try {
|
|
|
|
-// out.close();
|
|
|
|
-// } catch (IOException e) {
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-
|
|
|
|
- private String getImageUrl(StudentScoreEntity score, QuestionEntity q, Integer pageIndex) {
|
|
|
|
- if (DataType.MARKING_CLOUD.equals(sysProperty.getDataType())) {
|
|
|
|
- return getImageUrlFromMarkingCloud(score, pageIndex);
|
|
|
|
- } else if (DataType.TEACH_CLOUD.equals(sysProperty.getDataType())) {
|
|
|
|
- return getImageUrlFromTeachCloud(score, q, pageIndex);
|
|
|
|
- } else {
|
|
|
|
- throw new StatusException("数据类型错误");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String getImageUrlFromMarkingCloud(StudentScoreEntity score, Integer pageIndex) {
|
|
|
|
- return sysProperty.getImageServer() + "/" + getMarkingCloudPath(score.getExamId(),
|
|
|
|
- getSuffix(score.getStudentCode()), score.getStudentCode(), pageIndex, "jpg");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static String getSuffix(String input) {
|
|
|
|
- return StringUtils.trimToEmpty(input).substring(Math.max(0, input.length() - 3));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String getImageUrlFromTeachCloud(StudentScoreEntity score, QuestionEntity q, Integer pageIndex) {
|
|
|
|
- int paperNum = (pageIndex + 1) / 2;
|
|
|
|
- int page = 1;
|
|
|
|
- if (pageIndex % 2 == 0) {
|
|
|
|
- page = 2;
|
|
|
|
- }
|
|
|
|
- return sysProperty.getImageServer() + "/" + getTeachCloudPath(score.getExamId(), score.getSubjectCode(),
|
|
|
|
- score.getStudentCode(), paperNum, page, "jpg");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String getTeachCloudPath(Object... param) {
|
|
|
|
- return String.format("sheet/%d/%s/%s/%d-%d.%s", param);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static String getMarkingCloudPath(Object... param) {
|
|
|
|
- return String.format("sheet/%d/%s/%s-%d.%s", param);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static void main(String[] args) {
|
|
|
|
-// Pattern pattern = Pattern.compile("\\[\\[([0-9](.[0-9]+){0,1})分\\]\\]");
|
|
|
|
-// String d="[[1.1分]]中国共产党是中国特色社会主义事业的坚强领导核心。\n"
|
|
|
|
-// + "[[1.2分]]中国共产党的领导地位是在历史奋斗中形成的。\n"
|
|
|
|
-// + "[[1.3分]]中国共产党领导是人民当家作主的可靠保障。\n"
|
|
|
|
-// + "[[1.4分]]中国共产党领导关系中国特色社会主义的性质、方向和命运。\n"
|
|
|
|
-// + "[[2分]]中国共产党领导是实现中华民族伟大复兴的根本保证。";
|
|
|
|
-// Matcher matcher = pattern.matcher(d);
|
|
|
|
-// int start=0;
|
|
|
|
-// double score=0.0;
|
|
|
|
-// while (matcher.find()) {
|
|
|
|
-// if(start!=0) {
|
|
|
|
-// System.out.println(score+d.substring(start,matcher.start()));
|
|
|
|
-// }
|
|
|
|
-// score=Double.valueOf(matcher.group(1));
|
|
|
|
-// start=matcher.end();
|
|
|
|
-// }
|
|
|
|
-// if(start<d.length()) {
|
|
|
|
-// System.out.println(score+d.substring(start,d.length()));
|
|
|
|
-// }
|
|
|
|
-// String[] items = d.split("\\[\\[[0-9](.[0-9]+){0,1}分\\]\\]");
|
|
|
|
- String code = "2021113801";
|
|
|
|
- String s = "https://file.markingcloud.com/" + getMarkingCloudPath(1379, getSuffix(code), code, 1, "jpg");
|
|
|
|
- System.out.println(s);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public StudentScoreImageDto pollStudentScoreImage() {
|
|
|
|
- try {
|
|
|
|
- return queue.take();
|
|
|
|
- } catch (InterruptedException e) {
|
|
|
|
- throw new RuntimeException(e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Transactional
|
|
|
|
- @Override
|
|
|
|
- public void ocr(StudentScoreImageDto dto) {
|
|
|
|
- try {
|
|
|
|
- OrgInfo org = solarService.getOrgList().get(0);
|
|
|
|
- String ret = ocrDispose(dto, org);
|
|
|
|
- if (ret != null) {
|
|
|
|
- updateAnswer(dto.getStudentScoreId(), ret);
|
|
|
|
- } else {
|
|
|
|
- ocrErr(dto, "ocr失败,返回null");
|
|
|
|
- }
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- ocrErr(dto, e.getMessage());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void updateAnswer(Long id, String answer) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
- lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
- lw.set(StudentScoreEntity::getAnswer, answer);
|
|
|
|
- lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private String ocrDispose(StudentScoreImageDto dto, OrgInfo org) {
|
|
|
|
- SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
|
|
|
|
- try {
|
|
|
|
- return ocrApiClient.forImage(signature, OcrType.HANDWRITING, UploadFile.build("image", "", dto.getImage()));
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- log.error("ocr异常", e);
|
|
|
|
- if (e instanceof RetrofitResponseError) {
|
|
|
|
- RetrofitResponseError tem = (RetrofitResponseError) e;
|
|
|
|
- if (tem.getCode() == 503) {
|
|
|
|
- if (dto.getRetry() <= 3) {
|
|
|
|
- try {
|
|
|
|
- Thread.sleep(3000);
|
|
|
|
- } catch (InterruptedException e1) {
|
|
|
|
- }
|
|
|
|
- dto.setRetry(dto.getRetry() + 1);
|
|
|
|
- return ocrDispose(dto, org);
|
|
|
|
- } else {
|
|
|
|
- throw new StatusException("重试次数过多");
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- throw e;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- throw e;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void ocrErr(StudentScoreImageDto dto, String err) {
|
|
|
|
- updateAnswerErr(dto.getStudentScoreId(), err);
|
|
|
|
- studentService.updateStatus(dto.getStudentId(), DataStatus.FAILED);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public List<StudentScoreEntity> findAllToAiMarking() {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
- lw.in(StudentScoreEntity::getScoreStatus, DataStatus.WAITING, DataStatus.FAILED);
|
|
|
|
- return this.list(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public List<StudentScoreEntity> findToAiMarking(Long studentId) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
- lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
- lw.in(StudentScoreEntity::getScoreStatus, DataStatus.WAITING, DataStatus.FAILED);
|
|
|
|
- return this.list(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Transactional
|
|
|
|
- @Override
|
|
|
|
- public void aiMarking(StudentScoreEntity score) {
|
|
|
|
- AiMarkingDto dto = new AiMarkingDto();
|
|
|
|
- dto.setScoreInfo(score);
|
|
|
|
- try {
|
|
|
|
- OrgInfo org = solarService.getOrgList().get(0);
|
|
|
|
- QuestionEntity q = questionService.getById(score.getQuestionId());
|
|
|
|
- if (q == null) {
|
|
|
|
- throw new StatusException("未找到试题信息");
|
|
|
|
- }
|
|
|
|
- if (CollectionUtils.isEmpty(q.getAnswer())) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- AutoScoreRequest req = new AutoScoreRequest();
|
|
|
|
- req.setQuestionBody(q.getContent());
|
|
|
|
- req.setStandardAnswer(q.getAnswer());
|
|
|
|
- req.setStudentAnswer(score.getAnswer());
|
|
|
|
- req.setSubjectName(q.getSubjectName());
|
|
|
|
- req.setTotalScore(q.getFullScore());
|
|
|
|
- req.setIntervalScore(0.5);
|
|
|
|
- AutoScoreResult ret = aiMarkingDispose(dto, org, req);
|
|
|
|
- if (ret != null) {
|
|
|
|
- updateScore(score.getId(), ret.getTotalScore(), null);
|
|
|
|
- } else {
|
|
|
|
- updateScoreNone(score.getId(), 0.0, 0.0);
|
|
|
|
- }
|
|
|
|
- if (allSuccess(score.getStudentId())) {
|
|
|
|
- studentService.updateStatus(score.getStudentId(), DataStatus.SUCCESS);
|
|
|
|
- }
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- aiScoreErr(dto, e.getMessage());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean allSuccess(Long studentId) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
- List<StudentScoreEntity> list = this.list(wrapper);
|
|
|
|
- for (StudentScoreEntity s : list) {
|
|
|
|
- if (!DataStatus.SUCCESS.equals(s.getScoreStatus())) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private AutoScoreResult aiMarkingDispose(AiMarkingDto dto, OrgInfo org, AutoScoreRequest req) {
|
|
|
|
- SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
|
|
|
|
- try {
|
|
|
|
- return aiService.autoScore(req, signature);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- log.error("aiScore异常", e);
|
|
|
|
- if (e instanceof RetrofitResponseError) {
|
|
|
|
- RetrofitResponseError tem = (RetrofitResponseError) e;
|
|
|
|
- if (tem.getCode() == 503) {
|
|
|
|
- if (dto.getRetry() <= 3) {
|
|
|
|
- try {
|
|
|
|
- Thread.sleep(3000);
|
|
|
|
- } catch (InterruptedException e1) {
|
|
|
|
- }
|
|
|
|
- dto.setRetry(dto.getRetry() + 1);
|
|
|
|
- return aiMarkingDispose(dto, org, req);
|
|
|
|
- } else {
|
|
|
|
- throw new StatusException("重试次数过多");
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- throw e;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- throw e;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void updateScore(Long id, Double aiScore, Double scoreRatio) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getScoreStatus, DataStatus.SUCCESS);
|
|
|
|
- lw.set(StudentScoreEntity::getAiScore, aiScore);
|
|
|
|
- lw.set(StudentScoreEntity::getScoreRatio, scoreRatio);
|
|
|
|
- lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
- lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void updateScoreNone(Long id, Double aiScore, Double scoreRatio) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getScoreStatus, DataStatus.SUCCESS);
|
|
|
|
- lw.set(StudentScoreEntity::getAiScore, aiScore);
|
|
|
|
- lw.set(StudentScoreEntity::getScoreRatio, scoreRatio);
|
|
|
|
- lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
- lw.set(StudentScoreEntity::getScoreNone, true);
|
|
|
|
- lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void aiScoreErr(AiMarkingDto dto, String err) {
|
|
|
|
- updateScoreErr(dto.getScoreInfo().getId(), err);
|
|
|
|
- studentService.updateStatus(dto.getScoreInfo().getStudentId(), DataStatus.FAILED);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void updateScoreErr(Long id, String err) {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getScoreStatus, DataStatus.FAILED);
|
|
|
|
- lw.set(StudentScoreEntity::getErrMsg, err);
|
|
|
|
- lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void resetAnswerStatus() {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.WAITING);
|
|
|
|
- lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.PROCESSING);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void resetScoreStatus() {
|
|
|
|
- UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
- LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.set(StudentScoreEntity::getScoreStatus, DataStatus.WAITING);
|
|
|
|
- lw.eq(StudentScoreEntity::getScoreStatus, DataStatus.PROCESSING);
|
|
|
|
- this.update(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void resetStatus() {
|
|
|
|
- resetAnswerStatus();
|
|
|
|
- resetScoreStatus();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public int countBy(Long examId, DataStatus status) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- if (status != null) {
|
|
|
|
- lw.eq(StudentScoreEntity::getScoreStatus, status);
|
|
|
|
- }
|
|
|
|
- lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
- return this.count(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Transactional
|
|
|
|
- @Override
|
|
|
|
- public void removeBy(Long examId, String subjectCode) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- if (subjectCode != null) {
|
|
|
|
- lw.eq(StudentScoreEntity::getSubjectCode, subjectCode);
|
|
|
|
- }
|
|
|
|
- lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
- this.remove(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public int countOcrBy(Long examId, DataStatus status) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- if (status != null) {
|
|
|
|
- lw.eq(StudentScoreEntity::getAnswerStatus, status);
|
|
|
|
- }
|
|
|
|
- lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
- return this.count(wrapper);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public List<StudentScoreEntity> findBy(Long examId, String subjectCode, Integer mainNumber, String subNumber,
|
|
|
|
- Boolean exZero, Integer count, Integer score) {
|
|
|
|
- QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
- LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
- lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
- lw.eq(StudentScoreEntity::getSubjectCode, subjectCode);
|
|
|
|
- lw.eq(StudentScoreEntity::getMainNumber, mainNumber);
|
|
|
|
- lw.eq(StudentScoreEntity::getSubNumber, subNumber);
|
|
|
|
- lw.isNotNull(StudentScoreEntity::getAiScore);
|
|
|
|
- lw.isNotNull(StudentScoreEntity::getMarkingScore);
|
|
|
|
- lw.and(wq -> {
|
|
|
|
- wq.or(wq1 -> wq1.isNull(StudentScoreEntity::getScoreNone));
|
|
|
|
- wq.or(wq2 -> wq2.eq(StudentScoreEntity::getScoreNone, false));
|
|
|
|
- });
|
|
|
|
- if (exZero != null && exZero) {
|
|
|
|
- lw.and(wq -> {
|
|
|
|
- wq.or(wq1 -> wq1.ne(StudentScoreEntity::getAiScore, 0));
|
|
|
|
- wq.or(wq2 -> wq2.eq(StudentScoreEntity::getMarkingScore, 0));
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- List<StudentScoreEntity> ret = this.list(wrapper);
|
|
|
|
- if (CollectionUtils.isEmpty(ret)) {
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- if (score != null) {
|
|
|
|
- List<StudentScoreEntity> tem = new ArrayList<>();
|
|
|
|
- for (StudentScoreEntity s : ret) {
|
|
|
|
- if (getSubtract(s.getAiScore(), s.getMarkingScore()) <= score) {
|
|
|
|
- tem.add(s);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- ret = tem;
|
|
|
|
- }
|
|
|
|
- if (CollectionUtils.isEmpty(ret)) {
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- if (count != null) {
|
|
|
|
- ret.sort(new Comparator<StudentScoreEntity>() {
|
|
|
|
- @Override
|
|
|
|
- public int compare(StudentScoreEntity o1, StudentScoreEntity o2) {
|
|
|
|
- String c1 = o1.getStudentCode();
|
|
|
|
- String c2 = o2.getStudentCode();
|
|
|
|
- return c1.compareTo(c2);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- if (ret.size() <= count) {
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- return ret.subList(0, count);
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Double getSubtract(Double d1, Double d2) {
|
|
|
|
- if (d1 == null || d2 == null) {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- Double r = d1 - d2;
|
|
|
|
- if (r < 0) {
|
|
|
|
- r = 0 - r;
|
|
|
|
- }
|
|
|
|
- return r;
|
|
|
|
- }
|
|
|
|
|
|
+ implements StudentScoreService {
|
|
|
|
+
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(StudentScoreService.class);
|
|
|
|
+
|
|
|
|
+ private static BlockingQueue<StudentScoreImageDto> queue;
|
|
|
|
+
|
|
|
|
+ private static final String[] EXCEL_HEADER = new String[] { "考试ID", "科目代码", "考生编号", "大题号", "小题号", "评分" };
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private SysProperty sysProperty;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private SolarService solarService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private StudentService studentService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private OcrApiClient ocrApiClient;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private AiService aiService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private QuestionService questionService;
|
|
|
|
+ static {
|
|
|
|
+ int threadCount = Runtime.getRuntime().availableProcessors();
|
|
|
|
+ queue = new ArrayBlockingQueue<>(threadCount * 2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void importScore() {
|
|
|
|
+ File dir = new File(sysProperty.getDataDir());
|
|
|
|
+ File[] fs = dir.listFiles();
|
|
|
|
+ if (fs == null || fs.length == 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (File file : fs) {
|
|
|
|
+ if (!file.isFile() || !file.getName().equals(ImportFileName.SCORE_IMPORT.getName())) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ InputStream inputStream = null;
|
|
|
|
+ ImportResult ret = null;
|
|
|
|
+ try {
|
|
|
|
+ inputStream = new FileInputStream(file);
|
|
|
|
+ ret = disposeFile(inputStream);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ String errMsg;
|
|
|
|
+ if (e instanceof FileNotFoundException) {
|
|
|
|
+ errMsg = "未找到文件:" + file.getAbsolutePath();
|
|
|
|
+ } else {
|
|
|
|
+ errMsg = "系统错误:" + e.getMessage();
|
|
|
|
+ }
|
|
|
|
+ ret = new ImportResult(errMsg);
|
|
|
|
+ } finally {
|
|
|
|
+ if (inputStream != null) {
|
|
|
|
+ try {
|
|
|
|
+ inputStream.close();
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ moveFile(dir, file, ret);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void moveFile(File dir, File file, ImportResult ret) {
|
|
|
|
+ try {
|
|
|
|
+ boolean succss = CollectionUtils.isEmpty(ret.getErrMsg());
|
|
|
|
+ if (succss) {
|
|
|
|
+ File sucDir = new File(dir.getAbsoluteFile() + "/success/");
|
|
|
|
+ if (!sucDir.exists()) {
|
|
|
|
+ sucDir.mkdir();
|
|
|
|
+ }
|
|
|
|
+ File targetFile = new File(sucDir.getAbsoluteFile() + "/" + file.getName());
|
|
|
|
+ if (targetFile.exists()) {
|
|
|
|
+ targetFile.delete();
|
|
|
|
+ }
|
|
|
|
+ FileUtils.copyFile(file, targetFile);
|
|
|
|
+ file.delete();
|
|
|
|
+ String fname = file.getName().substring(0, file.getName().lastIndexOf("."));
|
|
|
|
+ File msgFile = new File(sucDir.getAbsoluteFile() + "/" + fname + "_info.txt");
|
|
|
|
+ if (msgFile.exists()) {
|
|
|
|
+ msgFile.delete();
|
|
|
|
+ }
|
|
|
|
+ FileUtils.write(msgFile, ret.getCountInfo(), "utf-8");
|
|
|
|
+ } else {
|
|
|
|
+ File sucDir = new File(dir.getAbsoluteFile() + "/failed/");
|
|
|
|
+ if (!sucDir.exists()) {
|
|
|
|
+ sucDir.mkdir();
|
|
|
|
+ }
|
|
|
|
+ File targetFile = new File(sucDir.getAbsoluteFile() + "/" + file.getName());
|
|
|
|
+ if (targetFile.exists()) {
|
|
|
|
+ targetFile.delete();
|
|
|
|
+ }
|
|
|
|
+ FileUtils.copyFile(file, targetFile);
|
|
|
|
+ file.delete();
|
|
|
|
+ String fname = file.getName().substring(0, file.getName().lastIndexOf("."));
|
|
|
|
+ File msgFile = new File(sucDir.getAbsoluteFile() + "/" + fname + "_info.txt");
|
|
|
|
+ if (msgFile.exists()) {
|
|
|
|
+ msgFile.delete();
|
|
|
|
+ }
|
|
|
|
+ FileUtils.writeLines(msgFile, StandardCharsets.UTF_8.name(), ret.getErrMsg());
|
|
|
|
+ }
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ throw new StatusException("文件处理出错", e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String errorMsg(int lineNum, String msg) {
|
|
|
|
+ return "第" + lineNum + "行 " + msg;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String trimAndNullIfBlank(String s) {
|
|
|
|
+ if (StringUtils.isBlank(s)) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ return s.trim();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private ImportResult disposeFile(InputStream inputStream) {
|
|
|
|
+ List<DataMap> lineList = null;
|
|
|
|
+ ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
|
|
|
|
+ try {
|
|
|
|
+ lineList = reader.getDataMapList();
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new StatusException("Excel 解析失败");
|
|
|
|
+ }
|
|
|
|
+ if (!Arrays.equals(EXCEL_HEADER, reader.getColumnNames())) {
|
|
|
|
+ throw new StatusException("Excel表头错误");
|
|
|
|
+ }
|
|
|
|
+ if (CollectionUtils.isEmpty(lineList)) {
|
|
|
|
+ throw new StatusException("Excel无内容");
|
|
|
|
+ }
|
|
|
|
+ if (100001 < lineList.size()) {
|
|
|
|
+ throw new StatusException("数据行数不能超过100000");
|
|
|
|
+ }
|
|
|
|
+ List<StudentScoreDto> ss = new ArrayList<>();
|
|
|
|
+ ImportResult ret = new ImportResult();
|
|
|
|
+ List<String> failRecords = new ArrayList<>();
|
|
|
|
+ ret.setErrMsg(failRecords);
|
|
|
|
+ for (int i = 0; i < lineList.size(); i++) {
|
|
|
|
+ DataMap line = lineList.get(i);
|
|
|
|
+
|
|
|
|
+ StringBuilder msg = new StringBuilder();
|
|
|
|
+
|
|
|
|
+ StudentScoreDto imp = new StudentScoreDto();
|
|
|
|
+ String examId = trimAndNullIfBlank(line.get(EXCEL_HEADER[0]));
|
|
|
|
+ if (StringUtils.isBlank(examId)) {
|
|
|
|
+ msg.append(" 考试ID不能为空");
|
|
|
|
+ } else if (examId.length() > 20) {
|
|
|
|
+ msg.append(" 考试ID不能超过20个字符");
|
|
|
|
+ } else {
|
|
|
|
+ try {
|
|
|
|
+ Long examIdVal = Long.parseLong(examId);
|
|
|
|
+ imp.setExamId(examIdVal);
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
+ msg.append(" 考试ID只能是数字");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String subjectCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[1]));
|
|
|
|
+ if (StringUtils.isBlank(subjectCode)) {
|
|
|
|
+ msg.append(" 科目代码不能为空");
|
|
|
|
+ } else if (subjectCode.length() > 100) {
|
|
|
|
+ msg.append(" 科目代码不能超过100个字符");
|
|
|
|
+ }
|
|
|
|
+ imp.setSubjectCode(subjectCode);
|
|
|
|
+
|
|
|
|
+ String studentCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[2]));
|
|
|
|
+ if (StringUtils.isBlank(studentCode)) {
|
|
|
|
+ msg.append(" 考生编号不能为空");
|
|
|
|
+ } else if (studentCode.length() > 100) {
|
|
|
|
+ msg.append(" 考生编号不能超过100个字符");
|
|
|
|
+ }
|
|
|
|
+ imp.setStudentCode(studentCode);
|
|
|
|
+
|
|
|
|
+ String mainNum = trimAndNullIfBlank(line.get(EXCEL_HEADER[3]));
|
|
|
|
+ if (StringUtils.isBlank(mainNum)) {
|
|
|
|
+ msg.append(" 大题号不能为空");
|
|
|
|
+ } else if (mainNum.length() > 10) {
|
|
|
|
+ msg.append(" 大题号不能超过10个字符");
|
|
|
|
+ } else {
|
|
|
|
+ try {
|
|
|
|
+ Integer mainNumVal = Integer.parseInt(mainNum);
|
|
|
|
+ if (mainNumVal <= 0) {
|
|
|
|
+ msg.append(" 大题号必须大于0");
|
|
|
|
+ }
|
|
|
|
+ imp.setMainNumber(mainNumVal);
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
+ msg.append(" 大题号格式错误");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String subNum = trimAndNullIfBlank(line.get(EXCEL_HEADER[4]));
|
|
|
|
+ if (StringUtils.isBlank(subNum)) {
|
|
|
|
+ msg.append(" 小题号不能为空");
|
|
|
|
+ } else if (subNum.length() > 10) {
|
|
|
|
+ msg.append(" 小题号不能超过10个字符");
|
|
|
|
+ }
|
|
|
|
+ imp.setSubNumber(subNum);
|
|
|
|
+
|
|
|
|
+ String score = trimAndNullIfBlank(line.get(EXCEL_HEADER[5]));
|
|
|
|
+ if (StringUtils.isBlank(score)) {
|
|
|
|
+ msg.append(" 评分不能为空");
|
|
|
|
+ } else if (score.length() > 10) {
|
|
|
|
+ msg.append(" 评分不能超过10个字符");
|
|
|
|
+ } else {
|
|
|
|
+ try {
|
|
|
|
+ Double scoreVal = Double.parseDouble(score);
|
|
|
|
+ imp.setMarkingScore(scoreVal);
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
+ msg.append(" 评分格式错误");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (msg.length() > 0) {
|
|
|
|
+ failRecords.add(errorMsg(i + 2, msg.toString()));
|
|
|
|
+ } else {
|
|
|
|
+ ss.add(imp);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (CollectionUtils.isNotEmpty(failRecords)) {
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ updateScoreBatch(ret, ss);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ failRecords.add("系统错误:" + e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void updateScoreBatch(ImportResult ret, List<StudentScoreDto> ss) {
|
|
|
|
+ if (CollectionUtils.isEmpty(ss)) {
|
|
|
|
+ ret.setCountInfo("更新数量:0");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ int count = 0;
|
|
|
|
+ for (StudentScoreDto s : ss) {
|
|
|
|
+ count = count + updateScore(s);
|
|
|
|
+ }
|
|
|
|
+ ret.setCountInfo("更新数量:" + count);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int updateScore(StudentScoreDto dto) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getMarkingScore, dto.getMarkingScore());
|
|
|
|
+ lw.eq(StudentScoreEntity::getExamId, dto.getExamId());
|
|
|
|
+ lw.eq(StudentScoreEntity::getSubjectCode, dto.getSubjectCode());
|
|
|
|
+ lw.eq(StudentScoreEntity::getStudentCode, dto.getStudentCode());
|
|
|
|
+ lw.eq(StudentScoreEntity::getMainNumber, dto.getMainNumber());
|
|
|
|
+ lw.eq(StudentScoreEntity::getSubNumber, dto.getSubNumber());
|
|
|
|
+ return this.update(wrapper) ? 1 : 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<StudentScoreEntity> getByStudentId(Long studentId) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
+ return this.list(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Transactional
|
|
|
|
+ @Override
|
|
|
|
+ public void add(StudentEntity student, Map<Long, QuestionEntity> quetions, List<StudentScoreEntity> oldscores) {
|
|
|
|
+ List<StudentScoreEntity> adds = new ArrayList<>();
|
|
|
|
+ for (QuestionEntity q : quetions.values()) {
|
|
|
|
+ if (!exists(q, oldscores)) {
|
|
|
|
+ StudentScoreEntity s = new StudentScoreEntity();
|
|
|
|
+ adds.add(s);
|
|
|
|
+ s.setQuestionId(q.getId());
|
|
|
|
+ s.setExamId(student.getExamId());
|
|
|
|
+ s.setAnswerStatus(DataStatus.WAITING);
|
|
|
|
+ s.setMainNumber(q.getMainNumber());
|
|
|
|
+ s.setScoreStatus(DataStatus.WAITING);
|
|
|
|
+ s.setStudentCode(student.getStudentCode());
|
|
|
|
+ s.setStudentId(student.getId());
|
|
|
|
+ s.setSubjectCode(student.getSubjectCode());
|
|
|
|
+ s.setSubNumber(q.getSubNumber());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (CollectionUtils.isNotEmpty(adds)) {
|
|
|
|
+ this.saveBatch(adds);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean exists(QuestionEntity q, List<StudentScoreEntity> oldscores) {
|
|
|
|
+ if (CollectionUtils.isEmpty(oldscores)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ for (StudentScoreEntity s : oldscores) {
|
|
|
|
+ if (s.getExamId().equals(q.getExamId()) && s.getSubjectCode().equals(q.getSubjectCode())
|
|
|
|
+ && s.getMainNumber().equals(q.getMainNumber()) && s.getSubNumber().equals(q.getSubNumber())) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Transactional
|
|
|
|
+ @Override
|
|
|
|
+ public void updateAnswerErr(Long id, String err) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.FAILED);
|
|
|
|
+ lw.set(StudentScoreEntity::getErrMsg, err);
|
|
|
|
+ lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void createSlice(StudentScoreEntity score, QuestionEntity q, Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
+ StudentScoreImageDto dto = new StudentScoreImageDto();
|
|
|
|
+ dto.setStudentId(score.getStudentId());
|
|
|
|
+ dto.setStudentScoreId(score.getId());
|
|
|
|
+ dto.setImage(getSlice(score, q, answerImages));
|
|
|
|
+ // saveSliceImage(score, dto.getImage());
|
|
|
|
+ try {
|
|
|
|
+ queue.put(dto);
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private byte[] getSlice(StudentScoreEntity score, QuestionEntity q, Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
+ List<byte[]> ret = new ArrayList<>();
|
|
|
|
+ String suff = null;
|
|
|
|
+ for (ImageSlice s : q.getImageSlice()) {
|
|
|
|
+ AnswerImageDto sheet = getSheet(score, q, s.getI(), answerImages);
|
|
|
|
+ suff = sheet.getSuff();
|
|
|
|
+ ret.add(ImageUtil.cutImage(sheet.getImage(), sheet.getSuff(), s.getX().intValue(), s.getY().intValue(),
|
|
|
|
+ s.getW().intValue(), s.getH().intValue()));
|
|
|
|
+ }
|
|
|
|
+ if (ret.size() > 1) {
|
|
|
|
+ return ImageUtil.joinImages(ret, suff);
|
|
|
|
+ } else {
|
|
|
|
+ return ret.get(0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private AnswerImageDto getSheet(StudentScoreEntity score, QuestionEntity q, Integer pageIndex,
|
|
|
|
+ Map<Integer, AnswerImageDto> answerImages) {
|
|
|
|
+ AnswerImageDto ret = answerImages.get(pageIndex);
|
|
|
|
+ if (ret != null) {
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ ret = new AnswerImageDto();
|
|
|
|
+ String url = getImageUrl(score, q, pageIndex);
|
|
|
|
+ String tem = url.split("\\?")[0];
|
|
|
|
+ String suff = tem.substring(tem.lastIndexOf(".") + 1).toLowerCase();
|
|
|
|
+ ret.setImage(ByteArray.fromUrl(url).value());
|
|
|
|
+ // saveSheetImage(score,pageIndex, ret.getImage());
|
|
|
|
+ ret.setPageIndex(pageIndex);
|
|
|
|
+ ret.setSuff(suff);
|
|
|
|
+ answerImages.put(pageIndex, ret);
|
|
|
|
+ return ret;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // private void saveSheetImage(StudentScoreEntity s,Integer page,byte[] bs)
|
|
|
|
+ // {
|
|
|
|
+ // File dir=new File(sysProperty.getDataDir()+"/"+"sheet");
|
|
|
|
+ // if(!dir.exists()) {
|
|
|
|
+ // dir.mkdir();
|
|
|
|
+ // }
|
|
|
|
+ // File image=new
|
|
|
|
+ // File(dir.getAbsolutePath()+"/"+s.getStudentCode()+"-"+page+".jpg");
|
|
|
|
+ // if(image.exists()) {
|
|
|
|
+ // image.delete();
|
|
|
|
+ // }
|
|
|
|
+ // FileOutputStream out=null;
|
|
|
|
+ // try {
|
|
|
|
+ // out = new FileOutputStream(image);
|
|
|
|
+ // out.write(bs, 0, bs.length);
|
|
|
|
+ // out.flush();
|
|
|
|
+ // } catch (Exception e) {
|
|
|
|
+ // }finally {
|
|
|
|
+ // if(out!=null) {
|
|
|
|
+ // try {
|
|
|
|
+ // out.close();
|
|
|
|
+ // } catch (IOException e) {
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // private void saveSliceImage(StudentScoreEntity s,byte[] bs) {
|
|
|
|
+ // File dir=new File(sysProperty.getDataDir()+"/"+"slice");
|
|
|
|
+ // if(!dir.exists()) {
|
|
|
|
+ // dir.mkdir();
|
|
|
|
+ // }
|
|
|
|
+ // File image=new
|
|
|
|
+ // File(dir.getAbsolutePath()+"/"+s.getStudentCode()+"-"+s.getMainNumber()+"-"+s.getSubNumber()+".jpg");
|
|
|
|
+ // if(image.exists()) {
|
|
|
|
+ // image.delete();
|
|
|
|
+ // }
|
|
|
|
+ // FileOutputStream out=null;
|
|
|
|
+ // try {
|
|
|
|
+ // out = new FileOutputStream(image);
|
|
|
|
+ // out.write(bs, 0, bs.length);
|
|
|
|
+ // out.flush();
|
|
|
|
+ // } catch (Exception e) {
|
|
|
|
+ // }finally {
|
|
|
|
+ // if(out!=null) {
|
|
|
|
+ // try {
|
|
|
|
+ // out.close();
|
|
|
|
+ // } catch (IOException e) {
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ private String getImageUrl(StudentScoreEntity score, QuestionEntity q, Integer pageIndex) {
|
|
|
|
+ if (DataType.MARKING_CLOUD.equals(sysProperty.getDataType())) {
|
|
|
|
+ return getImageUrlFromMarkingCloud(score, pageIndex);
|
|
|
|
+ } else if (DataType.TEACH_CLOUD.equals(sysProperty.getDataType())) {
|
|
|
|
+ return getImageUrlFromTeachCloud(score, q, pageIndex);
|
|
|
|
+ } else {
|
|
|
|
+ throw new StatusException("数据类型错误");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getImageUrlFromMarkingCloud(StudentScoreEntity score, Integer pageIndex) {
|
|
|
|
+ return sysProperty.getImageServer() + "/" + getMarkingCloudPath(score.getExamId(),
|
|
|
|
+ getSuffix(score.getStudentCode()), score.getStudentCode(), pageIndex, "jpg");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static String getSuffix(String input) {
|
|
|
|
+ return StringUtils.trimToEmpty(input).substring(Math.max(0, input.length() - 3));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getImageUrlFromTeachCloud(StudentScoreEntity score, QuestionEntity q, Integer pageIndex) {
|
|
|
|
+ int paperNum = (pageIndex + 1) / 2;
|
|
|
|
+ int page = 1;
|
|
|
|
+ if (pageIndex % 2 == 0) {
|
|
|
|
+ page = 2;
|
|
|
|
+ }
|
|
|
|
+ return sysProperty.getImageServer() + "/" + getTeachCloudPath(score.getExamId(), score.getSubjectCode(),
|
|
|
|
+ score.getStudentCode(), paperNum, page, "jpg");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getTeachCloudPath(Object... param) {
|
|
|
|
+ return String.format("sheet/%d/%s/%s/%d-%d.%s", param);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static String getMarkingCloudPath(Object... param) {
|
|
|
|
+ return String.format("sheet/%d/%s/%s-%d.%s", param);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
+ // Pattern pattern =
|
|
|
|
+ // Pattern.compile("\\[\\[([0-9](.[0-9]+){0,1})分\\]\\]");
|
|
|
|
+ // String d="[[1.1分]]中国共产党是中国特色社会主义事业的坚强领导核心。\n"
|
|
|
|
+ // + "[[1.2分]]中国共产党的领导地位是在历史奋斗中形成的。\n"
|
|
|
|
+ // + "[[1.3分]]中国共产党领导是人民当家作主的可靠保障。\n"
|
|
|
|
+ // + "[[1.4分]]中国共产党领导关系中国特色社会主义的性质、方向和命运。\n"
|
|
|
|
+ // + "[[2分]]中国共产党领导是实现中华民族伟大复兴的根本保证。";
|
|
|
|
+ // Matcher matcher = pattern.matcher(d);
|
|
|
|
+ // int start=0;
|
|
|
|
+ // double score=0.0;
|
|
|
|
+ // while (matcher.find()) {
|
|
|
|
+ // if(start!=0) {
|
|
|
|
+ // System.out.println(score+d.substring(start,matcher.start()));
|
|
|
|
+ // }
|
|
|
|
+ // score=Double.valueOf(matcher.group(1));
|
|
|
|
+ // start=matcher.end();
|
|
|
|
+ // }
|
|
|
|
+ // if(start<d.length()) {
|
|
|
|
+ // System.out.println(score+d.substring(start,d.length()));
|
|
|
|
+ // }
|
|
|
|
+ // String[] items = d.split("\\[\\[[0-9](.[0-9]+){0,1}分\\]\\]");
|
|
|
|
+ String code = "2021113801";
|
|
|
|
+ String s = "https://file.markingcloud.com/" + getMarkingCloudPath(1379, getSuffix(code), code, 1, "jpg");
|
|
|
|
+ System.out.println(s);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public StudentScoreImageDto pollStudentScoreImage() {
|
|
|
|
+ try {
|
|
|
|
+ return queue.take();
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Transactional
|
|
|
|
+ @Override
|
|
|
|
+ public void ocr(StudentScoreImageDto dto) {
|
|
|
|
+ try {
|
|
|
|
+ OrgInfo org = solarService.getOrgList().get(0);
|
|
|
|
+ String ret = ocrDispose(dto, org);
|
|
|
|
+ if (ret != null) {
|
|
|
|
+ updateAnswer(dto.getStudentScoreId(), ret);
|
|
|
|
+ } else {
|
|
|
|
+ ocrErr(dto, "ocr失败,返回null");
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ ocrErr(dto, e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void updateAnswer(Long id, String answer) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
+ lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
+ lw.set(StudentScoreEntity::getAnswer, answer);
|
|
|
|
+ lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String ocrDispose(StudentScoreImageDto dto, OrgInfo org) {
|
|
|
|
+ SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
|
|
|
|
+ try {
|
|
|
|
+ return ocrApiClient.forImage(signature, OcrType.HANDWRITING, UploadFile.build("image", "", dto.getImage()));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("ocr异常", e);
|
|
|
|
+ if (e instanceof RetrofitResponseError) {
|
|
|
|
+ RetrofitResponseError tem = (RetrofitResponseError) e;
|
|
|
|
+ if (tem.getCode() == 503) {
|
|
|
|
+ if (dto.getRetry() <= 3) {
|
|
|
|
+ try {
|
|
|
|
+ Thread.sleep(3000);
|
|
|
|
+ } catch (InterruptedException e1) {
|
|
|
|
+ }
|
|
|
|
+ dto.setRetry(dto.getRetry() + 1);
|
|
|
|
+ return ocrDispose(dto, org);
|
|
|
|
+ } else {
|
|
|
|
+ throw new StatusException("重试次数过多");
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void ocrErr(StudentScoreImageDto dto, String err) {
|
|
|
|
+ updateAnswerErr(dto.getStudentScoreId(), err);
|
|
|
|
+ studentService.updateStatus(dto.getStudentId(), DataStatus.FAILED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<StudentScoreEntity> findAllToAiMarking() {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
+ lw.in(StudentScoreEntity::getScoreStatus, DataStatus.WAITING, DataStatus.FAILED);
|
|
|
|
+ return this.list(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<StudentScoreEntity> findToAiMarking(Long studentId) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
+ lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
|
|
|
|
+ lw.in(StudentScoreEntity::getScoreStatus, DataStatus.WAITING, DataStatus.FAILED);
|
|
|
|
+ return this.list(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Transactional
|
|
|
|
+ @Override
|
|
|
|
+ public void aiMarking(StudentScoreEntity score) {
|
|
|
|
+ AiMarkingDto dto = new AiMarkingDto();
|
|
|
|
+ dto.setScoreInfo(score);
|
|
|
|
+ try {
|
|
|
|
+ OrgInfo org = solarService.getOrgList().get(0);
|
|
|
|
+ QuestionEntity q = questionService.getById(score.getQuestionId());
|
|
|
|
+ if (q == null) {
|
|
|
|
+ throw new StatusException("未找到试题信息");
|
|
|
|
+ }
|
|
|
|
+ if (CollectionUtils.isEmpty(q.getAnswer())) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ AutoScoreRequest req = new AutoScoreRequest();
|
|
|
|
+ req.setQuestionBody(q.getContent());
|
|
|
|
+ req.setStandardAnswer(q.getAnswer());
|
|
|
|
+ req.setStudentAnswer(score.getAnswer());
|
|
|
|
+ req.setSubjectName(q.getSubjectName());
|
|
|
|
+ req.setTotalScore(q.getFullScore());
|
|
|
|
+ req.setIntervalScore(0.5);
|
|
|
|
+ AutoScoreResult ret = aiMarkingDispose(dto, org, req);
|
|
|
|
+ if (ret != null) {
|
|
|
|
+ List<Double> stepScore = new ArrayList<>();
|
|
|
|
+ for (Double d : ret.getStepScore()) {
|
|
|
|
+ stepScore.add(d);
|
|
|
|
+ }
|
|
|
|
+ double total = Arrays.stream(ret.getStepScore()).mapToObj(BigDecimal::valueOf)
|
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue();
|
|
|
|
+ updateScore(score.getId(), total, stepScore);
|
|
|
|
+ } else {
|
|
|
|
+ updateScoreNone(score.getId(), 0.0);
|
|
|
|
+ }
|
|
|
|
+ if (allSuccess(score.getStudentId())) {
|
|
|
|
+ studentService.updateStatus(score.getStudentId(), DataStatus.SUCCESS);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ aiScoreErr(dto, e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean allSuccess(Long studentId) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.eq(StudentScoreEntity::getStudentId, studentId);
|
|
|
|
+ List<StudentScoreEntity> list = this.list(wrapper);
|
|
|
|
+ for (StudentScoreEntity s : list) {
|
|
|
|
+ if (!DataStatus.SUCCESS.equals(s.getScoreStatus())) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private AutoScoreResult aiMarkingDispose(AiMarkingDto dto, OrgInfo org, AutoScoreRequest req) {
|
|
|
|
+ SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
|
|
|
|
+ try {
|
|
|
|
+ return aiService.autoScore(req, signature);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("aiScore异常", e);
|
|
|
|
+ if (e instanceof RetrofitResponseError) {
|
|
|
|
+ RetrofitResponseError tem = (RetrofitResponseError) e;
|
|
|
|
+ if (tem.getCode() == 503) {
|
|
|
|
+ if (dto.getRetry() <= 3) {
|
|
|
|
+ try {
|
|
|
|
+ Thread.sleep(3000);
|
|
|
|
+ } catch (InterruptedException e1) {
|
|
|
|
+ }
|
|
|
|
+ dto.setRetry(dto.getRetry() + 1);
|
|
|
|
+ return aiMarkingDispose(dto, org, req);
|
|
|
|
+ } else {
|
|
|
|
+ throw new StatusException("重试次数过多");
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void updateScore(Long id, Double aiScore, List<Double> scoreStep) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreStatus, DataStatus.SUCCESS);
|
|
|
|
+ lw.set(StudentScoreEntity::getAiScore, aiScore);
|
|
|
|
+ lw.set(StudentScoreEntity::getStepScore, JSONArray.toJSONString(scoreStep));
|
|
|
|
+ lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreNone, false);
|
|
|
|
+ lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void updateScoreNone(Long id, Double aiScore) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreStatus, DataStatus.SUCCESS);
|
|
|
|
+ lw.set(StudentScoreEntity::getAiScore, aiScore);
|
|
|
|
+ lw.set(StudentScoreEntity::getStepScore, null);
|
|
|
|
+ lw.set(StudentScoreEntity::getErrMsg, null);
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreNone, true);
|
|
|
|
+ lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void aiScoreErr(AiMarkingDto dto, String err) {
|
|
|
|
+ updateScoreErr(dto.getScoreInfo().getId(), err);
|
|
|
|
+ studentService.updateStatus(dto.getScoreInfo().getStudentId(), DataStatus.FAILED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void updateScoreErr(Long id, String err) {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreStatus, DataStatus.FAILED);
|
|
|
|
+ lw.set(StudentScoreEntity::getErrMsg, err);
|
|
|
|
+ lw.eq(StudentScoreEntity::getId, id);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void resetAnswerStatus() {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.WAITING);
|
|
|
|
+ lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.PROCESSING);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void resetScoreStatus() {
|
|
|
|
+ UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
|
|
|
|
+ LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.set(StudentScoreEntity::getScoreStatus, DataStatus.WAITING);
|
|
|
|
+ lw.eq(StudentScoreEntity::getScoreStatus, DataStatus.PROCESSING);
|
|
|
|
+ this.update(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void resetStatus() {
|
|
|
|
+ resetAnswerStatus();
|
|
|
|
+ resetScoreStatus();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int countBy(Long examId, DataStatus status) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ if (status != null) {
|
|
|
|
+ lw.eq(StudentScoreEntity::getScoreStatus, status);
|
|
|
|
+ }
|
|
|
|
+ lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
+ return this.count(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Transactional
|
|
|
|
+ @Override
|
|
|
|
+ public void removeBy(Long examId, String subjectCode) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ if (subjectCode != null) {
|
|
|
|
+ lw.eq(StudentScoreEntity::getSubjectCode, subjectCode);
|
|
|
|
+ }
|
|
|
|
+ lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
+ this.remove(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int countOcrBy(Long examId, DataStatus status) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ if (status != null) {
|
|
|
|
+ lw.eq(StudentScoreEntity::getAnswerStatus, status);
|
|
|
|
+ }
|
|
|
|
+ lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
+ return this.count(wrapper);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<StudentScoreEntity> findBy(Long examId, String subjectCode, Integer mainNumber, String subNumber,
|
|
|
|
+ Boolean exZero, Integer count, Integer score) {
|
|
|
|
+ QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
|
|
|
|
+ LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
|
|
|
|
+ lw.eq(StudentScoreEntity::getExamId, examId);
|
|
|
|
+ lw.eq(StudentScoreEntity::getSubjectCode, subjectCode);
|
|
|
|
+ lw.eq(StudentScoreEntity::getMainNumber, mainNumber);
|
|
|
|
+ lw.eq(StudentScoreEntity::getSubNumber, subNumber);
|
|
|
|
+ lw.isNotNull(StudentScoreEntity::getAiScore);
|
|
|
|
+ lw.isNotNull(StudentScoreEntity::getMarkingScore);
|
|
|
|
+ lw.and(wq -> {
|
|
|
|
+ wq.or(wq1 -> wq1.isNull(StudentScoreEntity::getScoreNone));
|
|
|
|
+ wq.or(wq2 -> wq2.eq(StudentScoreEntity::getScoreNone, false));
|
|
|
|
+ });
|
|
|
|
+ if (exZero != null && exZero) {
|
|
|
|
+ lw.and(wq -> {
|
|
|
|
+ wq.or(wq1 -> wq1.ne(StudentScoreEntity::getAiScore, 0));
|
|
|
|
+ wq.or(wq2 -> wq2.eq(StudentScoreEntity::getMarkingScore, 0));
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ List<StudentScoreEntity> ret = this.list(wrapper);
|
|
|
|
+ if (CollectionUtils.isEmpty(ret)) {
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ if (score != null) {
|
|
|
|
+ List<StudentScoreEntity> tem = new ArrayList<>();
|
|
|
|
+ for (StudentScoreEntity s : ret) {
|
|
|
|
+ if (getSubtract(s.getAiScore(), s.getMarkingScore()) <= score) {
|
|
|
|
+ tem.add(s);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ret = tem;
|
|
|
|
+ }
|
|
|
|
+ if (CollectionUtils.isEmpty(ret)) {
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ if (count != null) {
|
|
|
|
+ ret.sort(new Comparator<StudentScoreEntity>() {
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int compare(StudentScoreEntity o1, StudentScoreEntity o2) {
|
|
|
|
+ String c1 = o1.getStudentCode();
|
|
|
|
+ String c2 = o2.getStudentCode();
|
|
|
|
+ return c1.compareTo(c2);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ if (ret.size() <= count) {
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ return ret.subList(0, count);
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Double getSubtract(Double d1, Double d2) {
|
|
|
|
+ if (d1 == null || d2 == null) {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ Double r = d1 - d2;
|
|
|
|
+ if (r < 0) {
|
|
|
|
+ r = 0 - r;
|
|
|
|
+ }
|
|
|
|
+ return r;
|
|
|
|
+ }
|
|
}
|
|
}
|