feat(enlish-service): 新增自动判卷功能及学生单词记忆管理模块
- 支持数据库多语句查询,修改数据源连接配置增加allowMultiQueries参数 - 添加定时任务AutoJudgeExamWordsTask,实现每5秒自动触发判卷 - 增加ExamWordsJudge接口及其实现类ExamWordsJudgeImpl,完成考试判卷逻辑 - 新增多张数据库映射文件及对应Mapper,如ExamWordsDOMapper、ExamWordsJudgeResultDOMapper、StudentExamWordsDOMapper和WordMasteryLogDOMapper,支持相关数据操作 - 扩展PngUtil工具类,支持从答题卡图片中解析学生考试信息和识别未记忆单词 - 修改数据库表结构映射,新增word_mastery_log表和相关字段,管理学生单词记忆强度及复习次数 - 配置@EnableScheduling以启用定时任务调度功能 - 增加测试用例包括ExamWordsJudgeTest和WordMasteryLogInsertTest,验证判卷和学生单词记忆初始化功能 - 重命名测试类TestInsert为TestVocabularyBankInsert,提升代码语义清晰度
This commit is contained in:
@@ -3,9 +3,11 @@ package com.yinlihupo.enlish.service;
|
|||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@MapperScan("com.yinlihupo.enlish.service.domain.mapper")
|
@MapperScan("com.yinlihupo.enlish.service.domain.mapper")
|
||||||
|
@EnableScheduling
|
||||||
public class EnlishServiceApplication {
|
public class EnlishServiceApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class WordMasteryLogDO {
|
public class WordMasteryLogDO {
|
||||||
|
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
private Integer studentId;
|
private Integer studentId;
|
||||||
@@ -20,6 +21,8 @@ public class WordMasteryLogDO {
|
|||||||
|
|
||||||
private Integer reviewCount;
|
private Integer reviewCount;
|
||||||
|
|
||||||
private BigDecimal memoryStrength;
|
private Double memoryStrength;
|
||||||
|
|
||||||
|
private LocalDateTime update_time;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,4 +5,6 @@ import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsDO;
|
|||||||
public interface ExamWordsDOMapper {
|
public interface ExamWordsDOMapper {
|
||||||
|
|
||||||
int insert(ExamWordsDO record);
|
int insert(ExamWordsDO record);
|
||||||
|
|
||||||
|
ExamWordsDO selectById(Integer id);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
package com.yinlihupo.enlish.service.domain.mapper;
|
package com.yinlihupo.enlish.service.domain.mapper;
|
||||||
|
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsJudgeResultDO;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface ExamWordsJudgeResultDOMapper {
|
public interface ExamWordsJudgeResultDOMapper {
|
||||||
|
|
||||||
int insert(@Param("path") String path);
|
int insert(@Param("path") String path);
|
||||||
|
|
||||||
|
List<ExamWordsJudgeResultDO> selectUnfinishedExamWordsJudgeResultDOList(int count);
|
||||||
|
|
||||||
|
int updateErrorMsg(@Param("id") Integer id, @Param("errorMsg") String errorMsg);
|
||||||
|
|
||||||
|
int updateExamWordsJudgeResultDO(@Param("examWordsJudgeResultDO") ExamWordsJudgeResultDO examWordsJudgeResultDO);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.yinlihupo.enlish.service.domain.mapper;
|
package com.yinlihupo.enlish.service.domain.mapper;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.StudentExamWordsDO;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -8,4 +9,8 @@ import java.util.List;
|
|||||||
public interface StudentExamWordsDOMapper {
|
public interface StudentExamWordsDOMapper {
|
||||||
|
|
||||||
int insertStudentsExam(@Param("studentIds") List<Integer> studentIds, @Param("examWordsId") Integer examWordsId);
|
int insertStudentsExam(@Param("studentIds") List<Integer> studentIds, @Param("examWordsId") Integer examWordsId);
|
||||||
|
|
||||||
|
StudentExamWordsDO selectByStudentIdAndExamWordsId(@Param("studentId") Integer studentId, @Param("examWordsId") Integer examWordsId);
|
||||||
|
|
||||||
|
int updateStudentExamWordsFinished(@Param("studentId") Integer studentId, @Param("examWordsId") Integer examWordsId);
|
||||||
}
|
}
|
||||||
@@ -12,4 +12,6 @@ public interface VocabularyBankDOMapper {
|
|||||||
List<VocabularyBankDO> selectVocabularyBankDOListByUnitId(@Param("unitId") Integer unitId, @Param("wordCount") Integer wordCount);
|
List<VocabularyBankDO> selectVocabularyBankDOListByUnitId(@Param("unitId") Integer unitId, @Param("wordCount") Integer wordCount);
|
||||||
|
|
||||||
List<VocabularyBankDO> selectVocabularyBankDOListByIds(@Param("ids") List<Integer> ids);
|
List<VocabularyBankDO> selectVocabularyBankDOListByIds(@Param("ids") List<Integer> ids);
|
||||||
|
|
||||||
|
List<Integer> selectAllIds();
|
||||||
}
|
}
|
||||||
@@ -9,4 +9,9 @@ public interface WordMasteryLogDOMapper {
|
|||||||
|
|
||||||
// 查询指定学生指定单元的词,根据记忆强度排序
|
// 查询指定学生指定单元的词,根据记忆强度排序
|
||||||
List<WordMasteryLogDO> selectByStudentIdAndUnitIdOrderByMemoryStrength(@Param("studentId") Integer studentId, @Param("unitId") Integer unitId, @Param("limit") Integer limit);
|
List<WordMasteryLogDO> selectByStudentIdAndUnitIdOrderByMemoryStrength(@Param("studentId") Integer studentId, @Param("unitId") Integer unitId, @Param("limit") Integer limit);
|
||||||
|
|
||||||
|
// 初始化、批量学生单词记忆
|
||||||
|
int batchInsertInitialization(@Param("wordIds") List<Integer> wordIds, @Param("studentId") Integer studentId);
|
||||||
|
|
||||||
|
int batchUpdateStudentMastery(@Param("wordMasteryLogDOs") List<WordMasteryLogDO> wordMasteryLogDOs);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yinlihupo.enlish.service.job;
|
||||||
|
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AutoJudgeExamWordsTask {
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 5000)
|
||||||
|
public void autoJudgeExamWords() {
|
||||||
|
System.out.println("【固定频率】开始自动判卷,时间:" + LocalDateTime.now());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.yinlihupo.enlish.service.service;
|
||||||
|
|
||||||
|
public interface ExamWordsJudge {
|
||||||
|
|
||||||
|
void judgeExamWords(int count);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.yinlihupo.enlish.service.service.judge;
|
||||||
|
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsDO;
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsJudgeResultDO;
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.StudentExamWordsDO;
|
||||||
|
import com.yinlihupo.enlish.service.domain.dataobject.WordMasteryLogDO;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.ExamWordsDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.ExamWordsJudgeResultDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.StudentExamWordsDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.WordMasteryLogDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.model.bo.CoordinatesXY;
|
||||||
|
import com.yinlihupo.enlish.service.model.bo.StudentExamId;
|
||||||
|
import com.yinlihupo.enlish.service.service.ExamWordsJudge;
|
||||||
|
import com.yinlihupo.enlish.service.utils.PngUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ExamWordsJudgeImpl implements ExamWordsJudge {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ExamWordsJudgeResultDOMapper examWordsJudgeResultDOMapper;
|
||||||
|
@Resource
|
||||||
|
private StudentExamWordsDOMapper studentExamWordsDOMapper;
|
||||||
|
@Resource
|
||||||
|
private ExamWordsDOMapper examWordsDOMapper;
|
||||||
|
@Resource
|
||||||
|
private WordMasteryLogDOMapper wordMasteryLogDOMapper;
|
||||||
|
|
||||||
|
@Value("${templates.data}")
|
||||||
|
private String tessdataPath;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void judgeExamWords(int count) {
|
||||||
|
List<ExamWordsJudgeResultDO> examWordsJudgeResultDOS = examWordsJudgeResultDOMapper.selectUnfinishedExamWordsJudgeResultDOList(count);
|
||||||
|
for (ExamWordsJudgeResultDO examWordsJudgeResultDO : examWordsJudgeResultDOS) {
|
||||||
|
String ansSheetPath = examWordsJudgeResultDO.getAnsSheetPath();
|
||||||
|
List<CoordinatesXY> coordinatesXIES = PngUtil.analysisXY(ansSheetPath);
|
||||||
|
// 从图片中获取学生 id 和考试 id
|
||||||
|
StudentExamId studentExamId = PngUtil.analyzeExamWordsIdAndStudentId(ansSheetPath, tessdataPath, coordinatesXIES);
|
||||||
|
Integer examWordsJudgeResultDOId = examWordsJudgeResultDO.getId();
|
||||||
|
if (studentExamId == null) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "未识别学生 id 和考试 id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer studentId = studentExamId.getStudentId();
|
||||||
|
Integer examWordsId = studentExamId.getExamId();
|
||||||
|
StudentExamWordsDO studentExamWordsDO = studentExamWordsDOMapper.selectByStudentIdAndExamWordsId(studentId, examWordsId);
|
||||||
|
if (studentExamWordsDO == null) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "未找到学生 id 和考试 id 对应的考试记录");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log.info("studentId:{},examWordsId:{}", studentId, examWordsId);
|
||||||
|
if (studentExamWordsDO.getIsCompleted() == 1) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "考试记录此前已识别");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExamWordsDO examWordsDO = examWordsDOMapper.selectById(examWordsId);
|
||||||
|
if(examWordsDO == null) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "未找到考试");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> wordIds = examWordsDO.getWordIds();
|
||||||
|
List<Integer> unmemorizedWordIds = PngUtil.analyzePngForUnmemorizedWordIds(ansSheetPath, wordIds, coordinatesXIES);
|
||||||
|
List<Integer> memorizedWordIds = wordIds.stream().filter(wordId -> !unmemorizedWordIds.contains(wordId)).toList();
|
||||||
|
|
||||||
|
ExamWordsJudgeResultDO wordsJudgeResultDO = ExamWordsJudgeResultDO.builder()
|
||||||
|
.id(examWordsJudgeResultDOId)
|
||||||
|
.studentId(studentId)
|
||||||
|
.examWordsId(examWordsId)
|
||||||
|
.correctWordIds(memorizedWordIds)
|
||||||
|
.wrongWordIds(unmemorizedWordIds)
|
||||||
|
.correctWordCount(memorizedWordIds.size())
|
||||||
|
.wrongWordCount(unmemorizedWordIds.size())
|
||||||
|
.isFinished(1)
|
||||||
|
.build();
|
||||||
|
int updated = examWordsJudgeResultDOMapper.updateExamWordsJudgeResultDO(wordsJudgeResultDO);
|
||||||
|
if (updated != 1) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "更新考试记录失败");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log.info("更新考试记录成功");
|
||||||
|
|
||||||
|
List<WordMasteryLogDO> wordMasteryLogDOS = new ArrayList<>(unmemorizedWordIds.stream().map(wordId -> WordMasteryLogDO.builder()
|
||||||
|
.wordId(wordId)
|
||||||
|
.studentId(studentId)
|
||||||
|
.reviewCount(1)
|
||||||
|
.memoryStrength(-0.5)
|
||||||
|
.update_time(LocalDateTime.now())
|
||||||
|
.build()
|
||||||
|
).toList());
|
||||||
|
|
||||||
|
wordMasteryLogDOS.addAll(memorizedWordIds.stream().map(wordId -> WordMasteryLogDO.builder()
|
||||||
|
.wordId(wordId)
|
||||||
|
.studentId(studentId)
|
||||||
|
.reviewCount(1)
|
||||||
|
.memoryStrength(0.5)
|
||||||
|
.update_time(LocalDateTime.now())
|
||||||
|
.build()
|
||||||
|
).toList());
|
||||||
|
int batched = wordMasteryLogDOMapper.batchUpdateStudentMastery(wordMasteryLogDOS);
|
||||||
|
if (batched == 0) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "更新学生记忆力记录失败");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int updateStudentExamWordsFinished = studentExamWordsDOMapper.updateStudentExamWordsFinished(studentId, examWordsId);
|
||||||
|
if (updateStudentExamWordsFinished != 1) {
|
||||||
|
examWordsJudgeResultDOMapper.updateErrorMsg(examWordsJudgeResultDOId, "更新学生考试为结束时失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean delete = new File(ansSheetPath).delete();
|
||||||
|
if (delete) {
|
||||||
|
log.info("删除文件成功:{}", ansSheetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -120,7 +120,7 @@ public class PngUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取(未背熟)单词的 id
|
// 获取(未背熟)单词的 id
|
||||||
public static List<Integer> analyzePngForUnmemorizedWordIds(String filePath, List<Word> words, List<CoordinatesXY> coordinatesXYList) {
|
public static List<Integer> analyzePngForUnmemorizedWordIds(String filePath, List<Integer> wordIds, List<CoordinatesXY> coordinatesXYList) {
|
||||||
|
|
||||||
Mat src = Imgcodecs.imread(filePath);
|
Mat src = Imgcodecs.imread(filePath);
|
||||||
if (src.empty()) {
|
if (src.empty()) {
|
||||||
@@ -153,7 +153,7 @@ public class PngUtil {
|
|||||||
// 内层循环:遍历这一列的每一行
|
// 内层循环:遍历这一列的每一行
|
||||||
for (int j = 0; j < count; j++) {
|
for (int j = 0; j < count; j++) {
|
||||||
// 安全检查:防止单词列表比格子少导致越界
|
// 安全检查:防止单词列表比格子少导致越界
|
||||||
if (words_index >= words.size()) {
|
if (words_index >= wordIds.size()) {
|
||||||
log.warn("单词列表耗尽,停止检测。格子数多于单词数。");
|
log.warn("单词列表耗尽,停止检测。格子数多于单词数。");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -172,9 +172,9 @@ public class PngUtil {
|
|||||||
int countNonZero = Core.countNonZero(region);
|
int countNonZero = Core.countNonZero(region);
|
||||||
|
|
||||||
if (countNonZero > 800) {
|
if (countNonZero > 800) {
|
||||||
Word currentWord = words.get(words_index);
|
Integer id = wordIds.get(words_index);
|
||||||
answer.add(currentWord.getId());
|
answer.add(id);
|
||||||
log.info("检测到标记(未背熟):ID={}, 词={}", currentWord.getId(), currentWord.getTitle());
|
log.info("检测到标记(未背熟):ID={}", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
region.release();
|
region.release();
|
||||||
@@ -193,7 +193,7 @@ public class PngUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StudentExamId analyzeExamWordsId(String imagePath, String tessdataPath, List<CoordinatesXY> coordinatesXIES) {
|
public static StudentExamId analyzeExamWordsIdAndStudentId(String imagePath, String tessdataPath, List<CoordinatesXY> coordinatesXIES) {
|
||||||
// 1. 读取图片
|
// 1. 读取图片
|
||||||
Mat src = Imgcodecs.imread(imagePath);
|
Mat src = Imgcodecs.imread(imagePath);
|
||||||
if (src.empty()) {
|
if (src.empty()) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ spring:
|
|||||||
datasource:
|
datasource:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver # 指定数据库驱动类
|
driver-class-name: com.mysql.cj.jdbc.Driver # 指定数据库驱动类
|
||||||
# 数据库连接信息
|
# 数据库连接信息
|
||||||
url: jdbc:mysql://124.220.58.5:3306/enlish
|
url: jdbc:mysql://124.220.58.5:3306/enlish?allowMultiQueries=true
|
||||||
username: root # 数据库用户名
|
username: root # 数据库用户名
|
||||||
password: YLHP@admin123 # 数据库密码
|
password: YLHP@admin123 # 数据库密码
|
||||||
data:
|
data:
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
targetProject="src/main/java"/>
|
targetProject="src/main/java"/>
|
||||||
|
|
||||||
<!-- 需要生成的表-实体类 -->
|
<!-- 需要生成的表-实体类 -->
|
||||||
<table tableName="exam_words_judge_result" domainObjectName="ExamWordsJudgeResultDO"
|
<table tableName="word_mastery_log" domainObjectName="WordMasteryLogDO"
|
||||||
enableCountByExample="false"
|
enableCountByExample="false"
|
||||||
enableUpdateByExample="false"
|
enableUpdateByExample="false"
|
||||||
enableDeleteByExample="false"
|
enableDeleteByExample="false"
|
||||||
|
|||||||
@@ -17,5 +17,9 @@
|
|||||||
VALUES (#{gradeId}, #{level}, #{title}, #{wordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler}, #{createdAt})
|
VALUES (#{gradeId}, #{level}, #{title}, #{wordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler}, #{createdAt})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectById" resultMap="ResultMapWithBLOBs">
|
||||||
|
select * from exam_words where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -19,11 +19,36 @@
|
|||||||
<result column="wrong_word_ids" jdbcType="LONGVARCHAR" property="wrongWordIds" typeHandler="com.yinlihupo.enlish.service.config.ListWordIdTypeHandler" />
|
<result column="wrong_word_ids" jdbcType="LONGVARCHAR" property="wrongWordIds" typeHandler="com.yinlihupo.enlish.service.config.ListWordIdTypeHandler" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<insert id="insert" parameterType="com.yinlihupo.enlish.service.domain.dataobject.ExamWordsJudgeResultDO">
|
<insert id="insert">
|
||||||
insert into exam_words_judge_result
|
insert into exam_words_judge_result
|
||||||
(ans_sheet_path, is_finished, start_date)
|
(ans_sheet_path, is_finished, start_date)
|
||||||
values (#{path}, 0, now())
|
values (#{path}, 0, now())
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectUnfinishedExamWordsJudgeResultDOList" resultMap="BaseResultMap">
|
||||||
|
select * from exam_words_judge_result
|
||||||
|
where is_finished = 0
|
||||||
|
limit #{count}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateErrorMsg">
|
||||||
|
update exam_words_judge_result
|
||||||
|
set error_msg = #{errorMsg}
|
||||||
|
and is_finished = 2
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updateExamWordsJudgeResultDO">
|
||||||
|
update exam_words_judge_result
|
||||||
|
set student_id = #{examWordsJudgeResultDO.studentId},
|
||||||
|
exam_words_id = #{examWordsJudgeResultDO.examWordsId},
|
||||||
|
correct_word_ids = #{examWordsJudgeResultDO.correctWordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler},
|
||||||
|
wrong_word_ids = #{examWordsJudgeResultDO.wrongWordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler},
|
||||||
|
correct_word_count = #{examWordsJudgeResultDO.correctWordCount},
|
||||||
|
wrong_word_count = #{examWordsJudgeResultDO.wrongWordCount},
|
||||||
|
is_finished = 1
|
||||||
|
where id = #{examWordsJudgeResultDO.id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
<result column="is_completed" jdbcType="INTEGER" property="isCompleted" />
|
<result column="is_completed" jdbcType="INTEGER" property="isCompleted" />
|
||||||
<result column="start_data" jdbcType="TIMESTAMP" property="startData" />
|
<result column="start_data" jdbcType="TIMESTAMP" property="startData" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<insert id="insertStudentsExam">
|
<insert id="insertStudentsExam">
|
||||||
insert into student_exam_words
|
insert into student_exam_words
|
||||||
(student_id, exam_words_id, is_completed, start_data)
|
(student_id, exam_words_id, is_completed, start_data)
|
||||||
@@ -17,5 +18,20 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectByStudentIdAndExamWordsId" resultMap="BaseResultMap">
|
||||||
|
select *
|
||||||
|
from student_exam_words
|
||||||
|
where student_id = #{studentId}
|
||||||
|
and exam_words_id = #{examWordsId}
|
||||||
|
and is_completed = 0
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateStudentExamWordsFinished">
|
||||||
|
update student_exam_words
|
||||||
|
set is_completed = 1
|
||||||
|
where student_id = #{studentId}
|
||||||
|
and exam_words_id = #{examWordsId}
|
||||||
|
and is_completed = 0
|
||||||
|
</update>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -54,6 +54,7 @@
|
|||||||
where unit_id = #{unitId}
|
where unit_id = #{unitId}
|
||||||
limit #{wordCount}
|
limit #{wordCount}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectVocabularyBankDOListByIds" resultMap="BaseResultMap">
|
<select id="selectVocabularyBankDOListByIds" resultMap="BaseResultMap">
|
||||||
select *
|
select *
|
||||||
from vocabulary_bank
|
from vocabulary_bank
|
||||||
@@ -63,4 +64,9 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAllIds" resultType="java.lang.Integer">
|
||||||
|
select id
|
||||||
|
from vocabulary_bank
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -7,12 +7,9 @@
|
|||||||
<result column="word_id" jdbcType="INTEGER" property="wordId" />
|
<result column="word_id" jdbcType="INTEGER" property="wordId" />
|
||||||
<result column="review_count" jdbcType="INTEGER" property="reviewCount" />
|
<result column="review_count" jdbcType="INTEGER" property="reviewCount" />
|
||||||
<result column="memory_strength" jdbcType="DECIMAL" property="memoryStrength" />
|
<result column="memory_strength" jdbcType="DECIMAL" property="memoryStrength" />
|
||||||
|
<result column="update_time" jdbcType="TIMESTAMP" property="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="Base_Column_List">
|
|
||||||
id, student_id, word_id, review_count, memory_strength
|
|
||||||
</sql>
|
|
||||||
|
|
||||||
<select id="selectByStudentIdAndUnitIdOrderByMemoryStrength" resultMap="BaseResultMap">
|
<select id="selectByStudentIdAndUnitIdOrderByMemoryStrength" resultMap="BaseResultMap">
|
||||||
select *
|
select *
|
||||||
from word_mastery_log
|
from word_mastery_log
|
||||||
@@ -26,4 +23,27 @@
|
|||||||
limit #{limit}
|
limit #{limit}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<insert id="batchInsertInitialization">
|
||||||
|
insert into word_mastery_log (student_id, word_id, update_time)
|
||||||
|
VALUES
|
||||||
|
<!-- 增加if判断,防止wordIds为空时生成错误SQL -->
|
||||||
|
<if test="wordIds != null and wordIds.size() > 0">
|
||||||
|
<foreach collection="wordIds" item="id" separator=",">
|
||||||
|
(#{studentId}, #{id}, now())
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="batchUpdateStudentMastery">
|
||||||
|
<foreach collection="wordMasteryLogDOs" item="wordMasteryLog" separator=";">
|
||||||
|
update word_mastery_log
|
||||||
|
set
|
||||||
|
memory_strength = memory_strength + #{wordMasteryLog.memoryStrength},
|
||||||
|
review_count = review_count + #{wordMasteryLog.reviewCount},
|
||||||
|
update_time = now()
|
||||||
|
where student_id = #{wordMasteryLog.studentId}
|
||||||
|
and word_id = #{wordMasteryLog.wordId}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -4,6 +4,7 @@ import com.yinlihupo.enlish.service.domain.dataobject.UnitDO;
|
|||||||
import com.yinlihupo.enlish.service.domain.dataobject.VocabularyBankDO;
|
import com.yinlihupo.enlish.service.domain.dataobject.VocabularyBankDO;
|
||||||
import com.yinlihupo.enlish.service.domain.mapper.UnitDOMapper;
|
import com.yinlihupo.enlish.service.domain.mapper.UnitDOMapper;
|
||||||
import com.yinlihupo.enlish.service.domain.mapper.VocabularyBankDOMapper;
|
import com.yinlihupo.enlish.service.domain.mapper.VocabularyBankDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.WordMasteryLogDOMapper;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
@@ -20,12 +21,14 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TestInsert {
|
public class TestVocabularyBankInsert {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private VocabularyBankDOMapper vocabularyBankMapper;
|
private VocabularyBankDOMapper vocabularyBankMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private UnitDOMapper unitDOMapper;
|
private UnitDOMapper unitDOMapper;
|
||||||
|
@Resource
|
||||||
|
private WordMasteryLogDOMapper wordMasteryLogDOMapper;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test() {
|
void test() {
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.yinlihupo.enlish.service.mapper;
|
||||||
|
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.UnitDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.VocabularyBankDOMapper;
|
||||||
|
import com.yinlihupo.enlish.service.domain.mapper.WordMasteryLogDOMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
public class WordMasteryLogInsertTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VocabularyBankDOMapper vocabularyBankMapper;
|
||||||
|
@Resource
|
||||||
|
private UnitDOMapper unitDOMapper;
|
||||||
|
@Resource
|
||||||
|
private WordMasteryLogDOMapper wordMasteryLogDOMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
List<Integer> integers = vocabularyBankMapper.selectAllIds();
|
||||||
|
wordMasteryLogDOMapper.batchInsertInitialization(integers, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public class TestOmr {
|
|||||||
public void testInteger(){
|
public void testInteger(){
|
||||||
String filePath = "C:\\project\\java\\enlish_edu\\enlish\\enlish-service\\src\\main\\resources\\templates\\p3.png";
|
String filePath = "C:\\project\\java\\enlish_edu\\enlish\\enlish-service\\src\\main\\resources\\templates\\p3.png";
|
||||||
List<CoordinatesXY> coordinatesXIES = PngUtil.analysisXY(filePath);
|
List<CoordinatesXY> coordinatesXIES = PngUtil.analysisXY(filePath);
|
||||||
StudentExamId studentExamId = PngUtil.analyzeExamWordsId(filePath, tessdataPath, coordinatesXIES);
|
StudentExamId studentExamId = PngUtil.analyzeExamWordsIdAndStudentId(filePath, tessdataPath, coordinatesXIES);
|
||||||
log.info("studentExamId:{}",studentExamId);
|
log.info("studentExamId:{}",studentExamId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.yinlihupo.enlish.service.service.exam;
|
||||||
|
|
||||||
|
import com.yinlihupo.enlish.service.service.ExamWordsJudge;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
public class ExamWordsJudgeTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ExamWordsJudge examWordsJudge;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void judgeExamWords() {
|
||||||
|
examWordsJudge.judgeExamWords(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user