【新增】mysql,win文件读取文件设置考点后端接口,题型增加判分规则

This commit is contained in:
YOHO\20373
2025-05-18 00:00:49 +08:00
parent 1dcff7cc07
commit d8ada119ca
36 changed files with 788 additions and 176 deletions

View File

@@ -1,33 +0,0 @@
package pc.exam.pp.module.exam.controller.admin.getpoints;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pc.exam.pp.framework.common.pojo.CommonResult;
import pc.exam.pp.module.exam.service.getpoints.ExamGetPointsService;
import java.io.IOException;
@RestController
@RequestMapping("/exam/getopints")
public class GetPointsController {
@Autowired
private ExamGetPointsService examGetPointsService;
/**
* 得出文件操作考点
* @return 得分
*/
@PostMapping("/get_filePoint")
//todo 后期需要素材文件和答案文件的 父目录 如D:/exam/3/shucai,D:/exam/3/win
public CommonResult get_file_point() throws IOException {
return CommonResult.success(examGetPointsService.get_file_point());
}
@PostMapping("/get_mysql_point")
//todo 后期需要素材文件和答案文件的 父目录 如D:/exam/3/shucai,D:/exam/3/win
public CommonResult get_mysql_point() throws IOException {
return CommonResult.success(examGetPointsService.get_mysql_point());
}
}

View File

@@ -1,5 +1,6 @@
package pc.exam.pp.module.exam.controller.admin.paper.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import pc.exam.pp.framework.common.pojo.CommonResult;
import pc.exam.pp.framework.common.util.object.BeanUtils;
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialRolesVo;
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtListReqVo;
import pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtyQueryVo;
import pc.exam.pp.module.exam.dal.dataobject.knowledge.ExamKnowledgePoints;
@@ -154,4 +155,19 @@ public class ExamSpecialtyController{
}
return success(examSpecialtyService.deleteExamSpecialtyBySpIds(spIds));
}
@PostMapping("/setRole")
public CommonResult setRole(@RequestBody SpecialRolesVo specialRolesVo) {
System.out.println(specialRolesVo);
ExamSpecialty examSpecialty = examSpecialtyService.selectExamSpecialtyBySpId(Long.valueOf(specialRolesVo.getId()));
examSpecialty.setRoles(specialRolesVo.getRoles());
examSpecialtyService.updateExamSpecialty(examSpecialty);
return success("设置成功");
}
@GetMapping(value = "/getRole/{id}")
public CommonResult getRole(@PathVariable("id") String id) {
String roles= examSpecialtyService.getRoleById(id);
return success(Integer.parseInt(roles));
}
}

View File

@@ -0,0 +1,13 @@
package pc.exam.pp.module.exam.controller.admin.specialty.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SpecialRolesVo {
private String id;
private String roles;
}

View File

@@ -22,4 +22,6 @@ public class SpecialtyQueryVo {
private Integer orderNum;
private LocalDateTime createTime;
private String roles;
}

View File

@@ -59,4 +59,6 @@ public class EducationPaperTask extends TenantBaseDO
@TableField(exist = false)
EducationPaperParam educationPaperParam;
@TableField(exist = false)
private String score;
}

View File

@@ -1,9 +1,11 @@
package pc.exam.pp.module.exam.dal.dataobject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.info.Contact;
import jdk.dynalink.linker.LinkerServices;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -13,6 +15,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import pc.exam.pp.framework.mybatis.core.dataobject.BaseDO;
import java.util.List;
/**
* 试题答案选项(hyc)对象 exam_question_answer
*
@@ -61,6 +65,18 @@ public class ExamQuestionAnswer
// @Excel(name = "排序")
private String sort;
@TableField(exist = false)
@JsonInclude(value = JsonInclude.Include.NON_EMPTY)
private List<ExamMysqlKeyword> examMysqlKeywordList;
public ExamQuestionAnswer(String answerId, String quId, String isRight, String image, String content, String contentIn, String scoreRate, String sort) {
this.answerId = answerId;
this.quId = quId;
this.isRight = isRight;
this.image = image;
this.content = content;
this.contentIn = contentIn;
this.scoreRate = scoreRate;
this.sort = sort;
}
}

View File

@@ -34,4 +34,7 @@ public class ExamSpecialty extends TenantBaseDO {
/** 子树数量 */
private Long treeNum;
/** 判分规则*/
private String roles;
}

View File

@@ -1,6 +1,7 @@
package pc.exam.pp.module.exam.dal.mysql.monitor;
import org.apache.ibatis.annotations.Param;
import pc.exam.pp.framework.common.pojo.PageResult;
import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
@@ -49,4 +50,8 @@ return selectPage(reqVO, new LambdaQueryWrapperX<MonitorDO>()
}
String selectByStuIdAndTaskIdTop(@Param("stuId")Long stuId, @Param("taskId") String taskId);
String selectByStuIdAndTaskIdNew(Long stuId, String taskId);
}

View File

@@ -0,0 +1,20 @@
package pc.exam.pp.module.exam.dal.mysql.mysqlkeyword;
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
import pc.exam.pp.module.exam.dal.dataobject.ExamMysqlKeyword;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* MYSQL判分关键字考点 Mapper
*
* @author 管理员
*/
@Mapper
public interface MysqlKeywordMapper extends BaseMapperX<ExamMysqlKeyword> {
void deleteByAnswerId(String answerId);
}

View File

@@ -71,4 +71,8 @@ public interface ExamQuestionAnswerMapper extends BaseMapperX<ExamQuestionAnswe
public int deleteExamQuestionAnswerByQuesId(String firstQuId);
public int deleteExamQuestionAnswerByQuesIds(@Param("ids") String[] ids);
List<String> selectExamQuestionAnswerIdByQuId(String quId);
}

View File

@@ -122,4 +122,8 @@ public interface ExamQuestionMapper extends BaseMapperX<ExamQuestion>
int selectExamQuestionCountByQuId(String quId);
List<TenantVo> getSchoolNameNaPage();
long selectTenantId();
}

View File

@@ -96,4 +96,6 @@ public interface ExamSpecialtyMapper extends BaseMapperX<ExamSpecialty>
public int deleteExamSpecialtyBySpIds(Long[] spIds);
String getRoleById(String id);
}

View File

@@ -2,9 +2,12 @@ package pc.exam.pp.module.exam.job;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import pc.exam.pp.framework.quartz.core.handler.JobHandler;
import pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils;
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper;
import pc.exam.pp.module.exam.service.question.IExamQuestionService;
import pc.exam.pp.module.exam.utils.rabbitmq.RabbitmqUtils;
@@ -21,44 +24,55 @@ public class QuestionDownJob implements JobHandler {
private ExamQuestionMapper examQuestionMapper;
@Resource
private IExamQuestionService examQuestionService;
@Value("${server.role}")
private String serverRole;
@Override
public String execute(String param) throws Exception {
if ("center".equals(serverRole)){
List<String> queueNames= examQuestionMapper.seleAllQueueName();
log.info(queueNames.toString()+"所有学校队列名");
if (queueNames!=null){
List<String> failedQueues = new ArrayList<>();
List<String> successQueues = new ArrayList<>();
List<String> failedQueues1 = new ArrayList<>();
List<String> successQueues2 = new ArrayList<>();
for (String queueName : queueNames) {
boolean examQuestionToRabbitMQ = rabbitMqService.connectSchool(queueName);
if (!examQuestionToRabbitMQ) {
failedQueues.add(queueName);
}else {
successQueues.add(queueName);
}
}
for (String queueName : successQueues) {
try {
boolean examQuestionToRabbitMQ = examQuestionService.getExamQuestionToRabbitMQ(queueName);
if (!examQuestionToRabbitMQ) {
failedQueues1.add(queueName);
} else {
successQueues2.add(queueName);
}
} catch (Exception e) {
log.error("拉取队列 {} 时异常:{}", queueName, e.getMessage());
failedQueues1.add(queueName);
}
}
log.info(failedQueues.toString()+"连接失败的学校");
log.info(successQueues.toString()+"连接成功的学校");
log.info(failedQueues1.toString()+"拉取失败的学校");
log.info(successQueues2.toString()+"拉取成功的学校");
rabbitMqService.disconnect();
}
}else {
System.out.println("不走定时任务测试==========================");
}
List<String> queueNames= examQuestionMapper.seleAllQueueName();
log.info(queueNames.toString()+"所有学校队列名");
if (queueNames!=null){
List<String> failedQueues = new ArrayList<>();
List<String> successQueues = new ArrayList<>();
List<String> failedQueues1 = new ArrayList<>();
List<String> successQueues2 = new ArrayList<>();
for (String queueName : queueNames) {
boolean examQuestionToRabbitMQ = rabbitMqService.connectSchool(queueName);
if (!examQuestionToRabbitMQ) {
failedQueues.add(queueName);
}else {
successQueues.add(queueName);
}
}
for (String queueName : successQueues) {
try {
boolean examQuestionToRabbitMQ = examQuestionService.getExamQuestionToRabbitMQ(queueName);
if (!examQuestionToRabbitMQ) {
failedQueues1.add(queueName);
} else {
successQueues2.add(queueName);
}
} catch (Exception e) {
log.error("拉取队列 {} 时异常:{}", queueName, e.getMessage());
failedQueues1.add(queueName);
}
}
log.info(failedQueues.toString()+"连接失败的学校");
log.info(successQueues.toString()+"连接成功的学校");
log.info(failedQueues1.toString()+"拉取失败的学校");
log.info(successQueues2.toString()+"拉取成功的学校");
rabbitMqService.disconnect();
}
return null;
}

View File

@@ -1,15 +0,0 @@
package pc.exam.pp.module.exam.service.getpoints;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import java.io.IOException;
import java.util.List;
public interface ExamGetPointsService {
List<ExamQuestionAnswer> get_file_point() throws IOException;
List<ExamQuestionAnswer> get_mysql_point();
}

View File

@@ -1,62 +0,0 @@
package pc.exam.pp.module.exam.service.getpoints;
import org.springframework.stereotype.Service;
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
import pc.exam.pp.module.exam.utils.file.GetDifferencesBetweenFolders;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
public class ExamGetPointsServiceImpl implements ExamGetPointsService{
static final String BASE_DIR = "D:/exam/3/";
@Override
public List<ExamQuestionAnswer> get_file_point() throws IOException {
List<ExamQuestionAnswer> answerList = new ArrayList<>();
AtomicInteger sortCounter = new AtomicInteger(1); // 计数器
String path1 = BASE_DIR + "shucai";
String path2 = BASE_DIR + "win";
// 获取 shucai 和 win 文件夹的差异
Map<String, String> differences = GetDifferencesBetweenFolders.getDifferencesBetweenFolders(path1, path2);
List<ExamQuestionAnswer> formattedDifferences = differences.entrySet().stream()
.map(entry -> {
String key = entry.getKey();
String value = entry.getValue();
ExamQuestionAnswer answer = new ExamQuestionAnswer();
answer.setContent(key); // 设置文件路径
answer.setScoreRate("1");
//这里设置answer的排序按照循环次数来
answer.setSort(String.valueOf(sortCounter.getAndIncrement())); // 按顺序设置排序值
if (value.startsWith("仅存在于 "+path1)) {
answer.setContentIn("考察删除");
} else if (value.startsWith("仅存在于 "+path2)) {
answer.setContentIn("考察名称");
} else if (value.startsWith("属性不同")) {
answer.setContentIn("考察属性");
// answer.setContent(key + " -> " + value.split(" vs ")[1]); // 设置属性信息
}
return answer;
})
.sorted(Comparator.comparingInt(answer -> Integer.parseInt(answer.getSort()))) // 按 sort 排序
.collect(Collectors.toList());
answerList.addAll(formattedDifferences);
return answerList;
}
@Override
public List<ExamQuestionAnswer> get_mysql_point() {
return null;
}
}

View File

@@ -177,7 +177,7 @@ public class MonitorServiceImpl implements MonitorService {
info.setRemainingTime(remainingSeconds > 0 ? remainingSeconds : 0);
//todo 考虑加点时间,或判分后删除
//判分后删除
// stringRedisTemplate.opsForValue().set("userCache:"+stuMonitorPaperVo.getTaskId()+":"+stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info), remainingSeconds, TimeUnit.SECONDS);
stringRedisTemplate.opsForValue().set("userCache:"+stuMonitorPaperVo.getTaskId()+":"+stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info));

View File

@@ -1,4 +1,5 @@
package pc.exam.pp.module.exam.service.paper;
import java.sql.Time;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -19,12 +20,14 @@ import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPersonVo;
import pc.exam.pp.module.exam.controller.admin.paper.vo.SessionStuPageReqVO;
import pc.exam.pp.module.exam.controller.admin.paper.vo.StudentSessionReqVO;
import pc.exam.pp.module.exam.controller.admin.student.vo.StudentPageReqVO;
import pc.exam.pp.module.exam.dal.dataobject.EducationPaperParam;
import pc.exam.pp.module.exam.dal.dataobject.EducationPaperPerson;
import pc.exam.pp.module.exam.dal.dataobject.EducationPaperSession;
import pc.exam.pp.module.exam.dal.dataobject.EducationPaperTask;
import pc.exam.pp.module.exam.dal.dataobject.monitor.MonitorDO;
import pc.exam.pp.module.exam.dal.dataobject.student.StudentDO;
import pc.exam.pp.module.exam.dal.mysql.monitor.MonitorMapper;
import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperParamMapper;
import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperPersonMapper;
import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperSessionMapper;
import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperTaskMapper;
@@ -57,6 +60,8 @@ public class EducationPaperPersonServiceImpl implements IEducationPaperPersonSer
private EducationPaperSessionMapper educationPaperSessionMapper;
@Resource
private MonitorMapper monitorMapper;
@Resource
private EducationPaperParamMapper educationPaperParamMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
@@ -200,10 +205,11 @@ public class EducationPaperPersonServiceImpl implements IEducationPaperPersonSer
monitorMapper.updateById(info);
} else if (existing == null) {
}
if (existing == null) {
EducationPaperTask educationPaperTask = educationPaperTaskMapper.selectEducationPaperTaskByTaskId(taskId);
String name= educationPaperTaskMapper.selectEducationPaperTaskNameByid(taskId);
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId);
EducationPaperPerson educationPaperPerson=new EducationPaperPerson();
String key = "userCache:" + taskId+":"+studentId;
@@ -215,6 +221,11 @@ public class EducationPaperPersonServiceImpl implements IEducationPaperPersonSer
info.setStuId(studentId);
info.setUsername(personRepDto.getUsername());
info.setNickname(personRepDto.getNickname());
//判断是否开启测评时长限制
if ("0".equals(educationPaperParam.getIsTime())){
Time examTime = educationPaperParam.getExamTime();
info.setRemainingTime((long) examTime.toLocalTime().toSecondOfDay());
}
//设置学生班级
if (StringUtils.isNotBlank(personRepDto.getClassId().toString())){
String className=educationPaperTaskMapper.selectStuClassNameByClassId(personRepDto.getClassId());

View File

@@ -16,6 +16,7 @@ import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperTaskPageVo;
import pc.exam.pp.module.exam.controller.admin.paper.vo.StuInfoPaper;
import pc.exam.pp.module.exam.dal.dataobject.*;
import pc.exam.pp.module.exam.dal.mysql.monitor.MonitorMapper;
import pc.exam.pp.module.exam.dal.mysql.paper.*;
import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper;
import pc.exam.pp.module.exam.dal.mysql.question.SysFileMapper;
@@ -58,6 +59,8 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
@Autowired
private SysFileMapper sysFileMapper;
@Autowired
private MonitorMapper monitorMapper;
//@Autowired
//private ExamQuestionMapper
@@ -441,6 +444,8 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
@Override
public PageResult<EducationPaperTask> selectEducationPaperTaskListByStu(PaperTaskPageVo educationPaperTask) {
String taskType = educationPaperTask.getTaskType();
PageResult<EducationPaperTask> educationPaperTasks = educationPaperTaskMapper.selectEducationPaperTaskList(educationPaperTask);
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
@@ -450,6 +455,32 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
list = list.stream()
.filter(task -> taskIds.contains(task.getTaskId()))
.collect(Collectors.toList());
if ("0".equals(taskType)){
for (EducationPaperTask paperTask : list) {
String taskId = paperTask.getTaskId();
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId);
//最高成绩
Long stuId= SecurityFrameworkUtils.getLoginUserId();
if ("0".equals(educationPaperParam.getSaveGrades())){
String score= monitorMapper.selectByStuIdAndTaskIdTop(stuId,taskId);
if (StringUtils.isNotBlank(score)){
paperTask.setScore(score);
}else {
paperTask.setScore("0.0");
}
}else {
String score= monitorMapper.selectByStuIdAndTaskIdNew(stuId,taskId);
if (StringUtils.isNotBlank(score)){
paperTask.setScore(score);
}else {
paperTask.setScore("0.0");
}
}
}
}
educationPaperTasks.setList(list);
return educationPaperTasks;
}else {

View File

@@ -77,4 +77,6 @@ public interface ExamSpecialtyService
* @return 结果
*/
public int deleteExamSpecialtyBySpId(Long spId);
String getRoleById(String id);
}

View File

@@ -120,4 +120,9 @@ public class ExamSpecialtyServiceImpl implements ExamSpecialtyService {
{
return examSpecialtyMapper.deleteExamSpecialtyBySpId(spId);
}
@Override
public String getRoleById(String id) {
return examSpecialtyMapper.getRoleById(id);
}
}

View File

@@ -89,6 +89,9 @@
</where>
ORDER BY sort ASC
</select>
<select id="selectExamQuestionAnswerIdByQuId" resultType="java.lang.String">
select answer_id from exam_question_answer where qu_id =#{quId}
</select>
<insert id="insertExamQuestionAnswerList">
insert into exam_question_answer
(answer_id, qu_id, is_right, image, content,contentIn,score_rate,sort)

View File

@@ -115,6 +115,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM system_tenant
WHERE deleted = 0
</select>
<select id="selectTenantId" resultType="java.lang.Long">
select tenant_id from system_users limit 1
</select>
<insert id="insertExamQuestion" parameterType="ExamQuestion">

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pc.exam.pp.module.exam.dal.mysql.monitor.MonitorMapper">
<select id="selectByStuIdAndTaskIdTop" resultType="java.lang.String">
select score from exam_monitor where stu_id =#{stuId} and task_id=#{taskId} ORDER BY score DESC
LIMIT 1
</select>
<select id="selectByStuIdAndTaskIdNew" resultType="java.lang.String">
select score from exam_monitor where stu_id =#{stuId} and task_id=#{taskId} ORDER BY create_time DESC
LIMIT 1
</select>
</mapper>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pc.exam.pp.module.exam.dal.mysql.mysqlkeyword.MysqlKeywordMapper">
<delete id="deleteByAnswerId">
delete from exam_mysql_keyword where answer_id=#{answerId}
</delete>
</mapper>

View File

@@ -13,14 +13,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" />
<result property="unite" column="unite" />
<result property="treeNum" column="tree_num" />
<result property="roles" column="roles" />
</resultMap>
<sql id="selectExamSpecialtyVo">
select sp_id, parent_id, ancestors, sp_name, order_num, status, creator, create_time, updater, update_time, unite, tree_num, tenant_id from exam_specialty
select sp_id, parent_id, ancestors, sp_name, order_num, status, creator, create_time, updater, update_time, unite, tree_num, roles,tenant_id from exam_specialty
</sql>
<select id="selectExamSpecialtyListVo" resultType="pc.exam.pp.module.exam.controller.admin.specialty.vo.SpecialtyQueryVo">
select sp_id as id, sp_name as name, parent_id, status, create_time from exam_specialty
select sp_id as id, sp_name as name, parent_id, status, create_time,roles from exam_specialty
<where>
<if test="name != null and name != ''"> and sp_name like concat('%', #{name}, '%')</if>
<if test="status != null and status != ''"> and status = #{status}</if>
@@ -90,6 +91,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectExamSpecialtyVo"/>
where sp_id = #{spId}
</select>
<select id="getRoleById" resultType="java.lang.String">
select roles
from exam_specialty where sp_id =#{id};
</select>
<update id="deleteExamSpecialtyBySpId" parameterType="Long">
update exam_specialty