zouxuan před 5 roky
rodič
revize
70d49f2ffd
15 změnil soubory, kde provedl 213 přidání a 156 odebrání
  1. 5 14
      edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/client/ImFeignService.java
  2. 6 4
      edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/client/callback/ImFeignServiceFallback.java
  3. 24 10
      edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/entity/ReqUserData.java
  4. 1 0
      edu-im/edu-im-server/src/main/java/com/keao/edu/im/controller/RoomController.java
  5. 13 0
      edu-user/edu-user-client-api/src/main/java/com/keao/edu/user/api/entity/ExamRoomStudentRelation.java
  6. 7 0
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/ExamRoomStudentRelationController.java
  7. 0 44
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/WebSocketController.java
  8. 88 71
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/WebSocketServer.java
  9. 16 1
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/dao/ExamRoomStudentRelationDao.java
  10. 1 1
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/entity/ExamRegistration.java
  11. 9 0
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/ExamRoomStudentRelationService.java
  12. 0 2
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/ExamRegistrationServiceImpl.java
  13. 20 0
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/ExamRoomStudentRelationServiceImpl.java
  14. 2 4
      edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/TenantInfoServiceImpl.java
  15. 21 5
      edu-user/edu-user-server/src/main/resources/config/mybatis/ExamRoomStudentRelationMapper.xml

+ 5 - 14
edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/client/ImFeignService.java

@@ -2,6 +2,7 @@ package com.keao.edu.im.api.client;
 
 import java.util.List;
 
+import com.keao.edu.im.api.entity.*;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -9,10 +10,6 @@ import org.springframework.web.bind.annotation.RequestBody;
 
 import com.keao.edu.common.config.FeignConfiguration;
 import com.keao.edu.im.api.client.callback.ImFeignServiceFallback;
-import com.keao.edu.im.api.entity.ImGroupModel;
-import com.keao.edu.im.api.entity.ImPrivateMessage;
-import com.keao.edu.im.api.entity.ImResult;
-import com.keao.edu.im.api.entity.ImUserModel;
 
 @FeignClient(name = "im-server", configuration = FeignConfiguration.class, fallback = ImFeignServiceFallback.class)
 public interface ImFeignService {
@@ -95,19 +92,13 @@ public interface ImFeignService {
 	 * @return
 	 */
 	@PostMapping(value = "private/send")
-	//body模板
-	//{"senderId":"325","targetId":[1094986],"objectName":"RC:TxtMsg",
-	// "content":{"content":"www.baidu.com"}}
 	Object privateSend(@RequestBody ImPrivateMessage privateMessage);
 
 	/**
-	 * 发送群组自定义消息
-	 * @param groupMessage
+	 * 发送私聊消息
+	 * @param reqUserData
 	 * @return
 	 */
-//	@PostMapping(value = "private/sendCustom")
-	//body模板
-	//{"senderId":"325","targetId":[1094986],"objectName":"RC:TxtMsg",
-	// "content":{"content":"www.baidu.com"}}
-//	Object privateSendCustom(@RequestBody ImGroupMessage groupMessage);
+	@PostMapping(value = "room/leave")
+	void leaveRoom(@RequestBody ReqUserData reqUserData);
 }

+ 6 - 4
edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/client/callback/ImFeignServiceFallback.java

@@ -2,13 +2,10 @@ package com.keao.edu.im.api.client.callback;
 
 import java.util.List;
 
+import com.keao.edu.im.api.entity.*;
 import org.springframework.stereotype.Component;
 
 import com.keao.edu.im.api.client.ImFeignService;
-import com.keao.edu.im.api.entity.ImGroupModel;
-import com.keao.edu.im.api.entity.ImPrivateMessage;
-import com.keao.edu.im.api.entity.ImResult;
-import com.keao.edu.im.api.entity.ImUserModel;
 
 @Component
 public class ImFeignServiceFallback implements ImFeignService {
@@ -62,6 +59,11 @@ public class ImFeignServiceFallback implements ImFeignService {
     public Object privateSend(ImPrivateMessage privateMessage) {
         return null;
     }
+
+    @Override
+    public void leaveRoom(ReqUserData reqUserData) {
+
+    }
 /*
     @Override
     public Object privateSendCustom(ImGroupMessage groupMessage) {

+ 24 - 10
edu-im/edu-im-server/src/main/java/com/keao/edu/im/pojo/ReqUserData.java → edu-im/edu-im-api/src/main/java/com/keao/edu/im/api/entity/ReqUserData.java

@@ -1,11 +1,6 @@
-package com.keao.edu.im.pojo;
+package com.keao.edu.im.api.entity;
 
-import lombok.Data;
 
-/**
- * Created by weiqinxiao on 2019/3/1.
- */
-@Data
 public class ReqUserData {
 	private String userName;
 	private String roomId;
@@ -13,41 +8,60 @@ public class ReqUserData {
 	private boolean audience;
 	private boolean disableCamera;
 	private boolean musicMode;
-	public boolean isMusicMode() {
-		return musicMode;
+
+	public ReqUserData(String roomId, String userId) {
+		this.roomId = roomId;
+		this.userId = userId;
 	}
-	public void setMusicMode(boolean musicMode) {
-		this.musicMode = musicMode;
+
+	public ReqUserData() {
 	}
+
 	public String getUserName() {
 		return userName;
 	}
+
 	public void setUserName(String userName) {
 		this.userName = userName;
 	}
+
 	public String getRoomId() {
 		return roomId;
 	}
+
 	public void setRoomId(String roomId) {
 		this.roomId = roomId;
 	}
+
 	public String getUserId() {
 		return userId;
 	}
+
 	public void setUserId(String userId) {
 		this.userId = userId;
 	}
+
 	public boolean isAudience() {
 		return audience;
 	}
+
 	public void setAudience(boolean audience) {
 		this.audience = audience;
 	}
+
 	public boolean isDisableCamera() {
 		return disableCamera;
 	}
+
 	public void setDisableCamera(boolean disableCamera) {
 		this.disableCamera = disableCamera;
 	}
 
+	public boolean isMusicMode() {
+		return musicMode;
+	}
+
+	public void setMusicMode(boolean musicMode) {
+		this.musicMode = musicMode;
+	}
 }

+ 1 - 0
edu-im/edu-im-server/src/main/java/com/keao/edu/im/controller/RoomController.java

@@ -2,6 +2,7 @@ package com.keao.edu.im.controller;
 
 import com.alibaba.fastjson.JSONObject;
 import com.keao.edu.auth.api.client.SysUserFeignService;
+import com.keao.edu.im.api.entity.ReqUserData;
 import com.keao.edu.im.common.ApiException;
 import com.keao.edu.im.common.BaseResponse;
 import com.keao.edu.im.common.ErrorEnum;

+ 13 - 0
edu-user/edu-user-client-api/src/main/java/com/keao/edu/user/api/entity/ExamRoomStudentRelation.java

@@ -4,6 +4,8 @@ import com.keao.edu.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 
+import java.util.Date;
+
 /**
  * 对应数据库表(exam_room_student_relation):
  */
@@ -23,6 +25,9 @@ public class ExamRoomStudentRelation {
 	@ApiModelProperty(value = "学员编号")
 	private Integer studentId;
 
+	@ApiModelProperty(value = "签到时间")
+	private java.util.Date signInTime;
+
 	private java.util.Date createTime;
 
 	private java.util.Date updateTime;
@@ -32,6 +37,14 @@ public class ExamRoomStudentRelation {
 	@ApiModelProperty(value = "房间是否开启")
 	private YesOrNoEnum classroomSwitch;
 
+	public Date getSignInTime() {
+		return signInTime;
+	}
+
+	public void setSignInTime(Date signInTime) {
+		this.signInTime = signInTime;
+	}
+
 	public YesOrNoEnum getClassroomSwitch() {
 		return classroomSwitch;
 	}

+ 7 - 0
edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/ExamRoomStudentRelationController.java

@@ -40,6 +40,13 @@ public class ExamRoomStudentRelationController extends BaseController {
         return succeed();
     }
 
+    @ApiOperation("下一位")
+    @PostMapping(value = "/nextBit")
+    public HttpResponseResult nextBit(Integer currentUserId,Integer nextStudentId,Long roomId,Integer examStatus) {
+        examRoomStudentRelationService.nextBit(currentUserId,nextStudentId,roomId,examStatus);
+        return succeed();
+    }
+
     @ApiOperation("获取教室学员关联")
     @PostMapping(value = "/getExamRoomStudentRelation")
     public ExamRoomStudentRelation getExamRoomStudentRelation(Integer basicId, String roomId, Integer studentId) {

+ 0 - 44
edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/WebSocketController.java

@@ -1,44 +0,0 @@
-package com.keao.edu.user.controller;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.IOException;
-
-@RestController
-@RequestMapping("/api/ws")
-public class WebSocketController {
-
-    /**
-     * 群发消息内容
-     * @param message
-     * @return
-     */
-    @RequestMapping(value="/sendAll", method= RequestMethod.GET)
-    public String sendAllMessage(@RequestParam(required=true) String message){
-        try {
-            WebSocketServer.BroadCastInfo(message);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        return "ok";
-    }
-
-    /**
-     * 指定会话ID发消息
-     * @param message 消息内容
-     * @param id 连接会话ID
-     * @return
-     */
-    @RequestMapping(value="/sendOne", method=RequestMethod.GET)
-    public String sendOneMessage(@RequestParam(required=true) String message,@RequestParam(required=true) String id){
-        try {
-            WebSocketServer.SendMessage(message,id);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        return "ok";
-    }
-}

+ 88 - 71
edu-user/edu-user-server/src/main/java/com/keao/edu/user/controller/WebSocketServer.java

@@ -1,122 +1,139 @@
 package com.keao.edu.user.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
 import javax.websocket.*;
+import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
 import java.io.IOException;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.ConcurrentHashMap;
 
-@ServerEndpoint(value = "/ws/asset")
+@ServerEndpoint(value = "/ws/{userId}")
 @Component
 public class WebSocketServer {
 
-    @PostConstruct
-    public void init() {
-        System.out.println("websocket 加载");
-    }
     private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
-    private static final AtomicInteger OnlineCount = new AtomicInteger(0);
-    // concurrent包的线程安全Set,用来存放每个客户端对应的Session对象。
-    private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
-
+    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
+    private static int onlineCount = 0;
+    /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
+    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
+    /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
+    private Session session;
+    /**接收userId*/
+    private String userId="";
 
     /**
-     * 连接建立成功调用的方法
-     */
+     * 连接建立成功调用的方法*/
     @OnOpen
-    public void onOpen(Session session) {
-        SessionSet.add(session);
-        int cnt = OnlineCount.incrementAndGet(); // 在线数加1
-        log.info("有连接加入,当前连接数为:{}", cnt);
-        SendMessage(session, "连接成功");
+    public void onOpen(Session session,@PathParam("userId") String userId) {
+        this.session = session;
+        this.userId=userId;
+        if(webSocketMap.containsKey(userId)){
+            webSocketMap.remove(userId);
+            webSocketMap.put(userId,this);
+            //加入set中
+        }else{
+            webSocketMap.put(userId,this);
+            //加入set中
+            addOnlineCount();
+            //在线数加1
+        }
+
+        log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
+
+        try {
+            sendMessage("连接成功");
+        } catch (IOException e) {
+            log.error("用户:"+userId+",网络异常!!!!!!");
+        }
     }
 
     /**
      * 连接关闭调用的方法
      */
     @OnClose
-    public void onClose(Session session) {
-        SessionSet.remove(session);
-        int cnt = OnlineCount.decrementAndGet();
-        log.info("有连接关闭,当前连接数为:{}", cnt);
+    public void onClose() {
+        if(webSocketMap.containsKey(userId)){
+            webSocketMap.remove(userId);
+            //从set中删除
+            subOnlineCount();
+        }
+        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
     }
 
     /**
      * 收到客户端消息后调用的方法
      *
-     * @param message
-     *            客户端发送过来的消息
-     */
+     * @param message 客户端发送过来的消息*/
     @OnMessage
     public void onMessage(String message, Session session) {
-        log.info("来自客户端的消息:{}",message);
-        SendMessage(session, "收到消息,消息内容:"+message);
-
+        log.info("用户消息:"+userId+",报文:"+message);
+        //可以群发消息
+        //消息保存到数据库、redis
+        if(StringUtils.isNotBlank(message)){
+            try {
+                //解析发送的报文
+                JSONObject jsonObject = JSON.parseObject(message);
+                //追加发送人(防止串改)
+                jsonObject.put("fromUserId",this.userId);
+                String toUserId=jsonObject.getString("toUserId");
+                //传送给对应toUserId用户的websocket
+                if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
+                    webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
+                }else{
+                    log.error("请求的userId:"+toUserId+"不在该服务器上");
+                    //否则不在这个服务器上,发送到mysql或者redis
+                }
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+        }
     }
 
     /**
-     * 出现错误
+     *
      * @param session
      * @param error
      */
     @OnError
     public void onError(Session session, Throwable error) {
-        log.error("发生错误:{},Session ID: {}",error.getMessage(),session.getId());
+        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
         error.printStackTrace();
     }
-
     /**
-     * 发送消息,实践表明,每次浏览器刷新,session会发生变化。
-     * @param session
-     * @param message
+     * 实现服务器主动推送
      */
-    public static void SendMessage(Session session, String message) {
-        try {
-            session.getBasicRemote().sendText(String.format("%s (From Server,Session ID=%s)",message,session.getId()));
-        } catch (IOException e) {
-            log.error("发送消息出错:{}", e.getMessage());
-            e.printStackTrace();
-        }
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
     }
 
+
     /**
-     * 群发消息
-     * @param message
-     * @throws IOException
-     */
-    public static void BroadCastInfo(String message) throws IOException {
-        for (Session session : SessionSet) {
-            if(session.isOpen()){
-                SendMessage(session, message);
-            }
+     * 发送自定义消息
+     * */
+    public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
+        log.info("发送消息到:"+userId+",报文:"+message);
+        if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
+            webSocketMap.get(userId).sendMessage(message);
+        }else{
+            log.error("用户"+userId+",不在线!");
         }
     }
 
-    /**
-     * 指定Session发送消息
-     * @param sessionId
-     * @param message
-     * @throws IOException
-     */
-    public static void SendMessage(String message,String sessionId) throws IOException {
-        Session session = null;
-        for (Session s : SessionSet) {
-            if(s.getId().equals(sessionId)){
-                session = s;
-                break;
-            }
-        }
-        if(session!=null){
-            SendMessage(session, message);
-        }
-        else{
-            log.warn("没有找到你指定ID的会话:{}",sessionId);
-        }
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketServer.onlineCount++;
     }
 
+    public static synchronized void subOnlineCount() {
+        WebSocketServer.onlineCount--;
+    }
 }

+ 16 - 1
edu-user/edu-user-server/src/main/java/com/keao/edu/user/dao/ExamRoomStudentRelationDao.java

@@ -1,8 +1,8 @@
 package com.keao.edu.user.dao;
 
 import com.keao.edu.common.dal.BaseDAO;
-import com.keao.edu.user.dto.ExamRoomStudentRelationDto;
 import com.keao.edu.user.api.entity.ExamRoomStudentRelation;
+import com.keao.edu.user.dto.ExamRoomStudentRelationDto;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -78,4 +78,19 @@ public interface ExamRoomStudentRelationDao extends BaseDAO<Long, ExamRoomStuden
      * @return com.keao.edu.user.api.entity.ExamRoomStudentRelation
      */
     ExamRoomStudentRelation getStudentExamRoom(@Param("registId") Long registId);
+
+    /**
+     * 获取教室
+     * @param roomId
+     * @param currentUserId
+     * @return
+     */
+    ExamRoomStudentRelation findByStudentIdAndRoomId(@Param("roomId") Long roomId, @Param("currentUserId") Integer currentUserId);
+
+    /**
+     * 清除签到时间
+     * @param roomId
+     * @param currentUserId
+     */
+    void cleanSignInTime(@Param("roomId") Long roomId, @Param("currentUserId") Integer currentUserId);
 }

+ 1 - 1
edu-user/edu-user-server/src/main/java/com/keao/edu/user/entity/ExamRegistration.java

@@ -91,7 +91,7 @@ public class ExamRegistration {
 	private java.util.Date updateTime;
 
 	private String tenantId;
-	
+
 	public void setId(Integer id){
 		this.id = id;
 	}

+ 9 - 0
edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/ExamRoomStudentRelationService.java

@@ -63,4 +63,13 @@ public interface ExamRoomStudentRelationService extends BaseService<Long, ExamRo
      * @return
      */
     ExamRoomStudentRelation getExamRoomStudentRelation(Integer basicId, String roomId, Integer studentId);
+
+    /**
+     * 下一位
+     * @param currentUserId 当前学员
+     * @param nextStudentId 下一位学员
+     * @param roomId 考试编号
+     * @param examStatus 是否完成考试1是0否
+     */
+    void nextBit(Integer currentUserId, Integer nextStudentId, Long roomId, Integer examStatus);
 }

+ 0 - 2
edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/ExamRegistrationServiceImpl.java

@@ -36,8 +36,6 @@ public class ExamRegistrationServiceImpl extends BaseServiceImpl<Long, ExamRegis
     @Autowired
     private ExamRegistrationDao examRegistrationDao;
     @Autowired
-    private StudentDao studentDao;
-    @Autowired
     private ExaminationBasicDao examinationBasicDao;
     @Autowired
     private OrganizationService organizationService;

+ 20 - 0
edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/ExamRoomStudentRelationServiceImpl.java

@@ -8,6 +8,8 @@ import com.keao.edu.common.page.PageInfo;
 import com.keao.edu.common.service.IdGeneratorService;
 import com.keao.edu.common.service.impl.BaseServiceImpl;
 import com.keao.edu.common.tenant.TenantContextHolder;
+import com.keao.edu.im.api.client.ImFeignService;
+import com.keao.edu.im.api.entity.ReqUserData;
 import com.keao.edu.user.api.entity.ExamRoom;
 import com.keao.edu.user.api.entity.ExamRoomStudentRelation;
 import com.keao.edu.user.api.enums.ExamModeEnum;
@@ -50,6 +52,8 @@ public class ExamRoomStudentRelationServiceImpl extends BaseServiceImpl<Long, Ex
 	private ExamRegistrationDao examRegistrationDao;
 	@Autowired
 	private ExamTeacherSalaryService examTeacherSalaryService;
+	@Autowired
+	private ImFeignService imFeignService;
 
 	@Override
 	public BaseDAO<Long, ExamRoomStudentRelation> getDAO() {
@@ -244,4 +248,20 @@ public class ExamRoomStudentRelationServiceImpl extends BaseServiceImpl<Long, Ex
 	public ExamRoomStudentRelation getExamRoomStudentRelation(Integer basicId, String roomId, Integer studentId) {
 		return examRoomStudentRelationDao.getExamRoomStudentRelation(basicId,roomId,studentId);
 	}
+
+	@Override
+	public void nextBit(Integer currentUserId, Integer nextStudentId, Long roomId, Integer examStatus) {
+//		ExamRoomStudentRelation byStudentIdAndRoomId = examRoomStudentRelationDao.findByStudentIdAndRoomId(roomId, currentUserId);
+		if(currentUserId != null){
+			//将当前学员退出教室并添加参考状态,如果考试未完成,清除签到时间,重新签到
+			imFeignService.leaveRoom(new ReqUserData(roomId.toString(),currentUserId.toString()));
+			if(examStatus == 0){
+				//未完成
+				examRoomStudentRelationDao.cleanSignInTime(roomId, currentUserId);
+			}else {
+//				examRoomStudentRelationDao.endExam();
+			}
+
+		}
+	}
 }

+ 2 - 4
edu-user/edu-user-server/src/main/java/com/keao/edu/user/service/impl/TenantInfoServiceImpl.java

@@ -104,12 +104,10 @@ public class TenantInfoServiceImpl extends BaseServiceImpl<Integer, TenantInfo>
 			throw new BizException("机构不存在");
 		}
 		SysUser sysUser = sysUserDao.queryByPhone(existTenantInfo.getContactPhone());
-		if(Objects.isNull(sysUser)){
-			throw new BizException("机构账户不存在");
+		if(Objects.nonNull(sysUser) && !newTenantInfo.getContactPhone().equals(sysUser.getPhone())){
+			throw new BizException("手机号已被占用");
 		}
 		if(newTenantInfo.getRoleIds() != null){
-
-//			Set<Integer> roleIds = Arrays.stream(newTenantInfo.getRoleIds().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toSet());
 			//删除当前用户角色
 			sysUserDao.delEmployeeRole(sysUser.getId());
 			//新增用户角色

+ 21 - 5
edu-user/edu-user-server/src/main/resources/config/mybatis/ExamRoomStudentRelationMapper.xml

@@ -13,6 +13,7 @@
 		<result column="exam_room_id_" property="examRoomId" />
 		<result column="student_id_" property="studentId" />
 		<result column="classroom_switch_" property="classroomSwitch" typeHandler="com.keao.edu.common.dal.CustomEnumTypeHandler"/>
+		<result column="sign_in_time_" property="signInTime" />
 		<result column="create_time_" property="createTime" />
 		<result column="update_time_" property="updateTime" />
 		<result column="tenant_id_" property="tenantId" />
@@ -36,15 +37,19 @@
 	
 	<!-- 向数据库增加一条记录 -->
 	<insert id="insert" parameterType="com.keao.edu.user.api.entity.ExamRoomStudentRelation" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
-		INSERT INTO exam_room_student_relation (id_,examination_basic_id_,exam_registration_id_,exam_room_id_,student_id_,create_time_,update_time_,tenant_id_)
-		VALUES(#{id},#{examinationBasicId},#{examRegistrationId},#{examRoomId},#{studentId},NOW(),NOW(),#{tenantId})
+		INSERT INTO exam_room_student_relation (id_,examination_basic_id_,exam_registration_id_,
+		exam_room_id_,student_id_,create_time_,update_time_,tenant_id_,sign_in_time_)
+		VALUES(#{id},#{examinationBasicId},#{examRegistrationId},#{examRoomId},
+		#{studentId},NOW(),NOW(),#{tenantId},#{signInTime})
 	</insert>
 
 	<insert id="batchInsert" parameterType="com.keao.edu.user.api.entity.ExamRoomStudentRelation" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
-		INSERT INTO exam_room_student_relation (examination_basic_id_,exam_registration_id_,exam_room_id_,student_id_,create_time_,update_time_,tenant_id_)
+		INSERT INTO exam_room_student_relation (examination_basic_id_,exam_registration_id_,
+		exam_room_id_,student_id_,create_time_,update_time_,tenant_id_,sign_in_time_)
 		VALUES
 		<foreach collection="roomStudents" item="roomStudent" separator=",">
-			(#{roomStudent.examinationBasicId},#{roomStudent.examRegistrationId},#{roomStudent.examRoomId},#{roomStudent.studentId},NOW(),NOW(),#{roomStudent.tenantId})
+			(#{roomStudent.examinationBasicId},#{roomStudent.examRegistrationId},
+			#{roomStudent.examRoomId},#{roomStudent.studentId},NOW(),NOW(),#{roomStudent.tenantId},#{roomStudent.signInTime})
 		</foreach>
 	</insert>
 	
@@ -55,6 +60,9 @@
 			<if test="examinationBasicId != null">
 				examination_basic_id_ = #{examinationBasicId},
 			</if>
+			<if test="signInTime != null">
+				sign_in_time_ = #{signInTime},
+			</if>
 			<if test="examRegistrationId != null">
 				exam_registration_id_ = #{examRegistrationId},
 			</if>
@@ -77,8 +85,12 @@
 		UPDATE exam_room_student_relation SET classroom_switch_ = #{openFlag},update_time_ = NOW()
 		WHERE examination_basic_id_ = #{examinationBasicId} AND student_id_ = #{studentId}
 	</update>
+	<update id="cleanSignInTime">
+		UPDATE exam_room_student_relation SET sign_in_time_ = NULL,update_time_ = NOW()
+		WHERE exam_room_id_ = #{roomId} AND student_id_ = #{currentUserId}
+	</update>
 
-    <!-- 根据主键删除一条记录 -->
+	<!-- 根据主键删除一条记录 -->
 	<delete id="delete" >
 		DELETE FROM exam_room_student_relation WHERE id_ = #{id} 
 	</delete>
@@ -174,4 +186,8 @@
     <select id="getStudentExamRoom" resultMap="ExamRoomStudentRelation">
 		SELECT * FROM exam_room_student_relation WHERE exam_registration_id_=#{registId}
     </select>
+	<select id="findByStudentIdAndRoomId" resultMap="ExamRoomStudentRelation">
+		SELECT ersr.* FROM exam_room_student_relation ersr
+		WHERE ersr.exam_room_id_ = #{roomId} AND ersr.student_id_ = #{currentUserId} LIMIT 1
+	</select>
 </mapper>