WANG преди 6 години
родител
ревизия
99260289f4

+ 48 - 61
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/StudentController.java

@@ -8,6 +8,8 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -37,14 +39,15 @@ import cn.com.qmth.examcloud.core.basic.api.controller.bean.StudentDomain;
 import cn.com.qmth.examcloud.core.basic.base.constants.BasicConsts;
 import cn.com.qmth.examcloud.core.basic.base.constants.PropKeys;
 import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
+import cn.com.qmth.examcloud.core.basic.dao.StudentCodeRepo;
 import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
 import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
 import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
+import cn.com.qmth.examcloud.core.basic.dao.entity.StudentCodeEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
 import cn.com.qmth.examcloud.core.basic.service.StudentService;
 import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
 import cn.com.qmth.examcloud.task.api.DataSyncCloudService;
-import cn.com.qmth.examcloud.task.api.request.SyncStudentReq;
 import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.config.SystemConfig;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
@@ -62,6 +65,9 @@ public class StudentController extends ControllerSupport {
 	@Autowired
 	StudentRepo studentRepo;
 
+	@Autowired
+	StudentCodeRepo studentCodeRepo;
+
 	@Autowired
 	SystemConfig systemConfig;
 
@@ -115,9 +121,6 @@ public class StudentController extends ControllerSupport {
 			if (StringUtils.isNotEmpty(name)) {
 				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
 			}
-			if (StringUtils.isNotEmpty(studentCode)) {
-				predicates.add(cb.like(root.get("studentCode"), toSqlSearchPattern(studentCode)));
-			}
 			if (StringUtils.isNotEmpty(identityNumber)) {
 				predicates.add(
 						cb.like(root.get("identityNumber"), toSqlSearchPattern(identityNumber)));
@@ -132,6 +135,16 @@ public class StudentController extends ControllerSupport {
 					}
 				}
 			}
+
+			if (StringUtils.isNotEmpty(studentCode)) {
+				Subquery<StudentCodeEntity> subquery = query.subquery(StudentCodeEntity.class);
+				Root<StudentCodeEntity> subRoot = subquery.from(StudentCodeEntity.class);
+				subquery.select(subRoot.get("id"));
+				Predicate p1 = cb.equal(subRoot.get("studentId"), root.get("id"));
+				Predicate p2 = cb.like(subRoot.get("studentCode"), toSqlSearchPattern(studentCode));
+				subquery.where(cb.and(p1, p2));
+				predicates.add(cb.exists(subquery));
+			}
 			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
 		};
 
@@ -159,7 +172,13 @@ public class StudentController extends ControllerSupport {
 			bean.setUpdateTime(next.getUpdateTime());
 			bean.setCreationTime(next.getCreationTime());
 			bean.setEnable(next.getEnable());
-			bean.setStudentCode(next.getStudentCode());
+			List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo
+					.findByStudentId(next.getId());
+			List<String> studentCodeList = Lists.newArrayList();
+			for (StudentCodeEntity cur : studentCodeEntityList) {
+				studentCodeList.add(cur.getStudentCode());
+			}
+			bean.setStudentCodeList(studentCodeList);
 			bean.setIdentityNumber(next.getIdentityNumber());
 			if (StringUtils.isNotBlank(next.getPhotoPath())) {
 				bean.setPhotoPath(urlPrefix + next.getPhotoPath());
@@ -209,9 +228,6 @@ public class StudentController extends ControllerSupport {
 			if (StringUtils.isNotEmpty(name)) {
 				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
 			}
-			if (StringUtils.isNotEmpty(studentCode)) {
-				predicates.add(cb.like(root.get("studentCode"), toSqlSearchPattern(studentCode)));
-			}
 			if (StringUtils.isNotEmpty(identityNumber)) {
 				predicates.add(
 						cb.like(root.get("identityNumber"), toSqlSearchPattern(identityNumber)));
@@ -226,6 +242,17 @@ public class StudentController extends ControllerSupport {
 					}
 				}
 			}
+
+			if (StringUtils.isNotEmpty(studentCode)) {
+				Subquery<StudentCodeEntity> subquery = query.subquery(StudentCodeEntity.class);
+				Root<StudentCodeEntity> subRoot = subquery.from(StudentCodeEntity.class);
+				subquery.select(subRoot.get("id"));
+				Predicate p1 = cb.equal(subRoot.get("studentId"), root.get("id"));
+				Predicate p2 = cb.like(subRoot.get("studentCode"), toSqlSearchPattern(studentCode));
+				subquery.where(cb.and(p1, p2));
+				predicates.add(cb.exists(subquery));
+			}
+
 			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
 		};
 
@@ -250,8 +277,17 @@ public class StudentController extends ControllerSupport {
 					orgName = org.getName();
 				}
 			}
-			datas.add(new Object[]{cur.getId(), cur.getName(), cur.getStudentCode(),
-					cur.getIdentityNumber(), orgCode, orgName});
+
+			List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo
+					.findByStudentId(cur.getId());
+			List<String> studentCodeList = Lists.newArrayList();
+			for (StudentCodeEntity sc : studentCodeEntityList) {
+				studentCodeList.add(sc.getStudentCode());
+			}
+
+			datas.add(
+					new Object[]{cur.getId(), cur.getName(), StringUtils.join(studentCodeList, ";"),
+							cur.getIdentityNumber(), orgCode, orgName});
 		}
 
 		String filePath = systemConfig.getTempDataDir() + File.separator
@@ -461,34 +497,8 @@ public class StudentController extends ControllerSupport {
 			}
 			validateRootOrgIsolation(s.getRootOrgId());
 
-			s.setStudentCode(null);
-			studentRepo.saveAndFlush(s);
+			studentService.unbindStudentCode(s.getRootOrgId(), null, s.getIdentityNumber());
 		}
-
-		for (Long cur : studentIds) {
-			StudentEntity saved = GlobalHelper.getEntity(studentRepo, cur, StudentEntity.class);
-			SyncStudentReq req = new SyncStudentReq();
-			req.setEnable(saved.getEnable());
-			req.setId(saved.getId());
-			req.setIdentityNumber(saved.getIdentityNumber());
-			req.setName(saved.getName());
-
-			req.setOrgId(saved.getOrgId());
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, saved.getOrgId(), OrgEntity.class);
-			req.setOrgCode(org.getCode());
-			req.setOrgName(org.getName());
-
-			req.setPhoneNumber(saved.getPhoneNumber());
-			req.setPhotoPath(saved.getPhotoPath());
-			req.setRootOrgId(saved.getRootOrgId());
-			req.setSecurityPhone(saved.getSecurityPhone());
-			req.setStudentCode(saved.getStudentCode());
-
-			req.setSyncType("update");
-
-			dataSyncCloudService.syncStudent(req);
-		}
-
 	}
 
 	@ApiOperation(value = "解绑学号", notes = "")
@@ -524,33 +534,10 @@ public class StudentController extends ControllerSupport {
 				throw new StatusException("450110", "学生不存在");
 			}
 			validateRootOrgIsolation(s.getRootOrgId());
-
-			s.setSecurityPhone(null);
-			studentRepo.saveAndFlush(s);
 		}
 
 		for (Long cur : studentIds) {
-			StudentEntity saved = GlobalHelper.getEntity(studentRepo, cur, StudentEntity.class);
-			SyncStudentReq req = new SyncStudentReq();
-			req.setEnable(saved.getEnable());
-			req.setId(saved.getId());
-			req.setIdentityNumber(saved.getIdentityNumber());
-			req.setName(saved.getName());
-
-			req.setOrgId(saved.getOrgId());
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, saved.getOrgId(), OrgEntity.class);
-			req.setOrgCode(org.getCode());
-			req.setOrgName(org.getName());
-
-			req.setPhoneNumber(saved.getPhoneNumber());
-			req.setPhotoPath(saved.getPhotoPath());
-			req.setRootOrgId(saved.getRootOrgId());
-			req.setSecurityPhone(saved.getSecurityPhone());
-			req.setStudentCode(saved.getStudentCode());
-
-			req.setSyncType("update");
-
-			dataSyncCloudService.syncStudent(req);
+			studentService.unbindSecurityPhone(cur);
 		}
 
 	}

+ 6 - 5
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/bean/StudentDomain.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.examcloud.core.basic.api.controller.bean;
 
 import java.util.Date;
+import java.util.List;
 
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 
@@ -21,7 +22,7 @@ public class StudentDomain implements JsonSerializable {
 
 	private String password;
 
-	private String studentCode;
+	private List<String> studentCodeList;
 
 	private String identityNumber;
 
@@ -69,12 +70,12 @@ public class StudentDomain implements JsonSerializable {
 		this.password = password;
 	}
 
-	public String getStudentCode() {
-		return studentCode;
+	public List<String> getStudentCodeList() {
+		return studentCodeList;
 	}
 
-	public void setStudentCode(String studentCode) {
-		this.studentCode = studentCode;
+	public void setStudentCodeList(List<String> studentCodeList) {
+		this.studentCodeList = studentCodeList;
 	}
 
 	public String getIdentityNumber() {

+ 8 - 44
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/StudentCloudServiceProvider.java

@@ -19,7 +19,6 @@ import cn.com.qmth.examcloud.core.basic.api.request.UnbindStudentCodeReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetStudentResp;
 import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
 import cn.com.qmth.examcloud.core.basic.api.response.UnbindStudentCodeResp;
-import cn.com.qmth.examcloud.core.basic.base.constants.PropKeys;
 import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
 import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
 import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
@@ -27,7 +26,6 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
 import cn.com.qmth.examcloud.core.basic.service.StudentService;
 import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
-import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.ApiOperation;
@@ -68,7 +66,7 @@ public class StudentCloudServiceProvider extends ControllerSupport implements St
 		StudentInfo studentInfo = new StudentInfo();
 		studentInfo.setName(req.getName());
 		studentInfo.setIdentityNumber(req.getIdentityNumber());
-		studentInfo.setStudentCode(req.getStudentCode());
+		studentInfo.setStudentCodeList(req.getStudentCodeList());
 		studentInfo.setRootOrgId(req.getRootOrgId());
 
 		studentInfo.setOrgId(req.getOrgId());
@@ -104,43 +102,14 @@ public class StudentCloudServiceProvider extends ControllerSupport implements St
 		String studentCode = req.getStudentCode();
 		String securityPhone = req.getSecurityPhone();
 
-		StudentEntity student = null;
-		if (null != studentId) {
-			student = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
-		} else {
-
-			if (null == rootOrgId) {
-				throw new StatusException("150000", "rootOrgId is null");
-			}
-
-			OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
-			if (null == rootOrg) {
-				throw new StatusException("150001", "机构不存在");
-			}
-			if (null != rootOrg.getParentId()) {
-				throw new StatusException("150002", "机构错误");
-			}
-
-			if (StringUtils.isNotBlank(identityNumber)) {
-				student = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
-			} else if (StringUtils.isNotBlank(studentCode)) {
-				student = studentRepo.findByStudentCodeAndRootOrgId(studentCode, rootOrgId);
-			} else if (StringUtils.isNotBlank(securityPhone)) {
-				student = studentRepo.findBySecurityPhoneAndRootOrgId(securityPhone, rootOrgId);
-			} else {
-				throw new StatusException("150010", "参数不足");
-			}
-		}
-
-		if (null == student) {
-			throw new StatusException("150005", "学生不存在");
-		}
+		StudentInfo student = studentService.getStudentInfo(rootOrgId, studentId, identityNumber,
+				studentCode, securityPhone);
 
 		StudentBean studentBean = new StudentBean();
 		studentBean.setId(student.getId());
 		studentBean.setName(student.getName());
 		studentBean.setIdentityNumber(student.getIdentityNumber());
-		studentBean.setStudentCode(student.getStudentCode());
+		studentBean.setStudentCodeList(student.getStudentCodeList());
 		studentBean.setRootOrgId(student.getRootOrgId());
 		if (null != student.getOrgId()) {
 			OrgEntity org = GlobalHelper.getEntity(orgRepo, student.getOrgId(), OrgEntity.class);
@@ -148,16 +117,11 @@ public class StudentCloudServiceProvider extends ControllerSupport implements St
 			studentBean.setOrgCode(org.getCode());
 			studentBean.setOrgName(org.getName());
 		}
+		studentBean.setOrgId(student.getOrgId());
+		studentBean.setOrgCode(student.getOrgCode());
+		studentBean.setOrgName(student.getOrgName());
 		studentBean.setPhoneNumber(student.getPhoneNumber());
-		if (null != student.getPhotoPath()) {
-			String urlPrefix = PropertyHolder.getString(PropKeys.STUDENT_PHOTO_URL_PREFIX);
-			if (StringUtils.isBlank(urlPrefix)) {
-				throw new StatusException("560111",
-						"property[$studentPhoto.url.prefix] is not configured");
-			}
-			studentBean.setPhotoPath(urlPrefix + student.getPhotoPath());
-		}
-
+		studentBean.setPhotoPath(student.getPhotoPath());
 		studentBean.setRemark(student.getRemark());
 		studentBean.setSecurityPhone(student.getSecurityPhone());
 

+ 24 - 0
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/StudentCodeRepo.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.examcloud.core.basic.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+import cn.com.qmth.examcloud.core.basic.dao.entity.StudentCodeEntity;
+
+/**
+ * Created by songyue on 17/1/13.
+ */
+public interface StudentCodeRepo
+		extends
+			JpaRepository<StudentCodeEntity, Long>,
+			QueryByExampleExecutor<StudentCodeEntity>,
+			JpaSpecificationExecutor<StudentCodeEntity> {
+
+	StudentCodeEntity findByStudentCodeAndRootOrgId(String studentCode, Long rootOrgId);
+
+	List<StudentCodeEntity> findByStudentId(Long studentId);
+
+}

+ 0 - 5
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/StudentRepo.java

@@ -17,13 +17,8 @@ public interface StudentRepo
 
 	StudentEntity findByIdentityNumber(String identityNumber);
 
-	StudentEntity findByIdentityNumberAndStudentCodeAndRootOrgId(String identityNumber,
-			String studentCode, Long rootOrgId);
-
 	StudentEntity findByIdentityNumberAndRootOrgId(String identityNumber, Long rootOrgId);
 
-	StudentEntity findByStudentCodeAndRootOrgId(String studentCode, Long rootOrgId);
-
 	StudentEntity findBySecurityPhoneAndRootOrgId(String securityPhone, Long rootOrgId);
 
 	StudentEntity findBySecurityPhone(String securityPhone);

+ 86 - 0
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/entity/StudentCodeEntity.java

@@ -0,0 +1,86 @@
+package cn.com.qmth.examcloud.core.basic.dao.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+import cn.com.qmth.examcloud.web.jpa.JpaEntity;
+
+/**
+ * 学生学号
+ *
+ * @author WANGWEI
+ * @date 2018年8月22日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Entity
+@Table(name = "EC_B_STUDENT_CODE", indexes = {
+		@Index(name = "IDX_B_SC_005001", columnList = "rootOrgId,studentCode", unique = true),
+		@Index(name = "IDX_B_SC_005002", columnList = "studentId", unique = false),
+		@Index(name = "IDX_B_SC_005003", columnList = "studentCode", unique = false),
+		@Index(name = "IDX_B_SC_005004", columnList = "identityNumber", unique = false)})
+public class StudentCodeEntity extends JpaEntity {
+
+	private static final long serialVersionUID = 757531976286006550L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	private Long id;
+
+	@Column(nullable = false)
+	private Long rootOrgId;
+
+	@Column(nullable = false)
+	private Long studentId;
+
+	@Column(nullable = false)
+	private String identityNumber;
+
+	@Column(nullable = false)
+	private String studentCode;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+}

+ 1 - 12
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/entity/StudentEntity.java

@@ -19,8 +19,7 @@ import cn.com.qmth.examcloud.web.jpa.JpaEntity;
  */
 @Entity
 @Table(name = "EC_B_STUDENT", indexes = {
-		@Index(name = "IDX_B_S_002001", columnList = "rootOrgId,identityNumber", unique = true),
-		@Index(name = "IDX_B_S_002002", columnList = "rootOrgId,studentCode", unique = true) })
+		@Index(name = "IDX_B_S_002001", columnList = "rootOrgId,identityNumber", unique = true)})
 public class StudentEntity extends JpaEntity {
 
 	private static final long serialVersionUID = 757531976286006550L;
@@ -35,8 +34,6 @@ public class StudentEntity extends JpaEntity {
 	@Column(nullable = false)
 	private String password;
 
-	private String studentCode;
-
 	@Column(nullable = false)
 	private String identityNumber;
 
@@ -94,14 +91,6 @@ public class StudentEntity extends JpaEntity {
 		this.password = password;
 	}
 
-	public String getStudentCode() {
-		return studentCode;
-	}
-
-	public void setStudentCode(String studentCode) {
-		this.studentCode = studentCode;
-	}
-
 	public String getIdentityNumber() {
 		return identityNumber;
 	}

+ 67 - 58
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/StudentService.java

@@ -1,58 +1,67 @@
-package cn.com.qmth.examcloud.core.basic.service;
-
-import java.util.List;
-
-import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
-import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
-
-/**
- * 类注释
- *
- * @author WANGWEI
- * @date 2018年6月29日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public interface StudentService {
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param studentInfo
-	 * @return
-	 */
-	StudentEntity saveStudent(StudentInfo studentInfo);
-
-	/**
-	 * 查询
-	 *
-	 * @author WANGWEI
-	 * @param rootOrgId
-	 * @param studentId
-	 * @param identityNumber
-	 * @param studentCode
-	 * @param securityPhone
-	 * @return
-	 */
-	StudentInfo getStudentInfo(Long rootOrgId, Long studentId, String identityNumber,
-			String studentCode, String securityPhone);
-
-	/**
-	 * 解绑学号
-	 *
-	 * @author WANGWEI
-	 * @param studentCode
-	 * @param identityNumber
-	 */
-	List<Long> unbindStudentCode(Long rootOrgId, String studentCode, String identityNumber);
-
-	/**
-	 * 手机号码是否被绑定
-	 *
-	 * @author WANGWEI
-	 * @param securityPhone
-	 * @return
-	 */
-	Boolean hasBeBound(String securityPhone);
-
-}
+package cn.com.qmth.examcloud.core.basic.service;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
+import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface StudentService {
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param studentInfo
+	 * @return
+	 */
+	StudentEntity saveStudent(StudentInfo studentInfo);
+
+	/**
+	 * 查询
+	 *
+	 * @author WANGWEI
+	 * @param rootOrgId
+	 * @param studentId
+	 * @param identityNumber
+	 * @param studentCode
+	 * @param securityPhone
+	 * @return
+	 */
+	StudentInfo getStudentInfo(Long rootOrgId, Long studentId, String identityNumber,
+			String studentCode, String securityPhone);
+
+	/**
+	 * 解绑学号
+	 *
+	 * @author WANGWEI
+	 * @param studentCode
+	 * @param identityNumber
+	 */
+	List<Long> unbindStudentCode(Long rootOrgId, String studentCode, String identityNumber);
+
+	/**
+	 * 解绑安全手机
+	 *
+	 * @author WANGWEI
+	 * @param studentId
+	 * @return
+	 */
+	public void unbindSecurityPhone(Long studentId);
+
+	/**
+	 * 手机号码是否被绑定
+	 *
+	 * @author WANGWEI
+	 * @param securityPhone
+	 * @return
+	 */
+	Boolean hasBeBound(String securityPhone);
+
+}

+ 8 - 6
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/StudentInfo.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.examcloud.core.basic.service.bean;
 
+import java.util.List;
+
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 
 /**
@@ -49,9 +51,9 @@ public class StudentInfo implements JsonSerializable {
 	private String orgName;
 
 	/**
-	 * 学生code
+	 * 学生code集合
 	 */
-	private String studentCode;
+	private List<String> studentCodeList;
 
 	/**
 	 * 身份证号码
@@ -139,12 +141,12 @@ public class StudentInfo implements JsonSerializable {
 		this.orgName = orgName;
 	}
 
-	public String getStudentCode() {
-		return studentCode;
+	public List<String> getStudentCodeList() {
+		return studentCodeList;
 	}
 
-	public void setStudentCode(String studentCode) {
-		this.studentCode = studentCode;
+	public void setStudentCodeList(List<String> studentCodeList) {
+		this.studentCodeList = studentCodeList;
 	}
 
 	public String getIdentityNumber() {

+ 10 - 1
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/AuthServiceImpl.java

@@ -28,6 +28,7 @@ import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
 import cn.com.qmth.examcloud.core.basic.dao.PrivilegeRepo;
 import cn.com.qmth.examcloud.core.basic.dao.RolePrivilegeRelationRepo;
 import cn.com.qmth.examcloud.core.basic.dao.RoleRepo;
+import cn.com.qmth.examcloud.core.basic.dao.StudentCodeRepo;
 import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
 import cn.com.qmth.examcloud.core.basic.dao.ThirdPartyAccessRepo;
 import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
@@ -36,6 +37,7 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.PrivilegeEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.RoleEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.RolePrivilegeRelationEntity;
+import cn.com.qmth.examcloud.core.basic.dao.entity.StudentCodeEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.ThirdPartyAccessEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.ThirdPartyAccessPK;
@@ -78,6 +80,9 @@ public class AuthServiceImpl implements AuthService {
 	@Autowired
 	StudentRepo studentRepo;
 
+	@Autowired
+	StudentCodeRepo studentCodeRepo;
+
 	@Autowired
 	ThirdPartyAccessRepo thirdPartyAccessRepo;
 
@@ -230,7 +235,11 @@ public class AuthServiceImpl implements AuthService {
 		} else {
 			// 学生学号登录
 			if (AccountType.STUDENT_CODE.equals(accountTypeEnum)) {
-				student = studentRepo.findByStudentCodeAndRootOrgId(accountValue, rootOrg.getId());
+				StudentCodeEntity scEntity = studentCodeRepo
+						.findByStudentCodeAndRootOrgId(accountValue, rootOrg.getId());
+
+				student = GlobalHelper.getEntity(studentRepo, scEntity.getStudentId(),
+						StudentEntity.class);
 			}
 			// 学生身份证号登录
 			else if (AccountType.STUDENT_IDENTITY_NUMBER.equals(accountTypeEnum)) {

+ 156 - 39
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/StudentServiceImpl.java

@@ -1,23 +1,28 @@
 package cn.com.qmth.examcloud.core.basic.service.impl;
 
 import java.util.List;
+import java.util.Map;
 
 import javax.transaction.Transactional;
 
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.UrlUtil;
 import cn.com.qmth.examcloud.core.basic.base.constants.BasicConsts;
 import cn.com.qmth.examcloud.core.basic.base.constants.PropKeys;
 import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
+import cn.com.qmth.examcloud.core.basic.dao.StudentCodeRepo;
 import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
 import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
 import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
+import cn.com.qmth.examcloud.core.basic.dao.entity.StudentCodeEntity;
 import cn.com.qmth.examcloud.core.basic.dao.entity.StudentEntity;
 import cn.com.qmth.examcloud.core.basic.service.StudentService;
 import cn.com.qmth.examcloud.core.basic.service.UserService;
@@ -39,6 +44,9 @@ public class StudentServiceImpl implements StudentService {
 	@Autowired
 	UserRepo userRepo;
 
+	@Autowired
+	StudentCodeRepo studentCodeRepo;
+
 	@Autowired
 	UserService userService;
 
@@ -112,20 +120,6 @@ public class StudentServiceImpl implements StudentService {
 		StudentEntity student = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber,
 				rootOrgId);
 
-		String studentCode = studentInfo.getStudentCode();
-		if (StringUtils.isNotBlank(studentCode)) {
-			StudentEntity studentByCode = studentRepo.findByStudentCodeAndRootOrgId(studentCode,
-					rootOrgId);
-			if (null != studentByCode
-					&& (!studentByCode.getIdentityNumber().equalsIgnoreCase(identityNumber))) {
-				throw new StatusException("160008", "学号被占用. 学号: " + studentCode);
-			}
-
-			if (null != student && null != student.getStudentCode()
-					&& (!studentCode.equalsIgnoreCase(student.getStudentCode()))) {
-				throw new StatusException("160005", "身份证号已关联学号");
-			}
-		}
 		long updateTime = 0L;
 		if (null != student) {
 			if (null != student.getUpdateTime()) {
@@ -143,17 +137,15 @@ public class StudentServiceImpl implements StudentService {
 			} else {
 				student.setPassword(BasicConsts.DEFAULT_PASSWORD);
 			}
+
+			student.setRootOrgId(rootOrgId);
+			student.setIdentityNumber(identityNumber);
 		}
 
-		student.setRootOrgId(rootOrgId);
-		student.setIdentityNumber(identityNumber);
 		student.setOrgId(org.getId());
-		if (StringUtils.isNotBlank(studentCode)) {
-			student.setStudentCode(studentCode);
-		}
 		if (null != studentInfo.getName()) {
 			if (StringUtils.isBlank(studentInfo.getName())) {
-				throw new StatusException("160006", "姓名不能为空");
+				throw new StatusException("160006", "姓名不能为空串");
 			}
 			student.setName(studentInfo.getName());
 		}
@@ -171,6 +163,46 @@ public class StudentServiceImpl implements StudentService {
 		}
 		StudentEntity saved = studentRepo.saveAndFlush(student);
 
+		List<String> studentCodeList = studentInfo.getStudentCodeList();
+		if (CollectionUtils.isNotEmpty(studentCodeList)) {
+
+			if (5 < studentCodeList.size()) {
+				throw new StatusException("160019", "身份证绑定的学号数量不能超过5个");
+			}
+
+			for (String studentCode : studentCodeList) {
+				StudentCodeEntity studentCodeEntity = studentCodeRepo
+						.findByStudentCodeAndRootOrgId(studentCode, rootOrgId);
+
+				if (null != studentCodeEntity) {
+					if (!studentCodeEntity.getIdentityNumber().equalsIgnoreCase(identityNumber)) {
+						throw new StatusException("160008", "学号被占用. 学号: " + studentCode);
+					}
+				} else {
+					studentCodeEntity = new StudentCodeEntity();
+					studentCodeEntity.setIdentityNumber(identityNumber);
+					studentCodeEntity.setRootOrgId(rootOrgId);
+					studentCodeEntity.setStudentCode(studentCode);
+					studentCodeEntity.setStudentId(saved.getId());
+
+					studentCodeRepo.save(studentCodeEntity);
+				}
+
+			}
+		}
+
+		List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo
+				.findByStudentId(saved.getId());
+
+		if (5 < studentCodeEntityList.size()) {
+			throw new StatusException("160018", "身份证绑定的学号数量不能超过5个");
+		}
+
+		List<String> lastStudentCodeList = Lists.newArrayList();
+		for (StudentCodeEntity cur : studentCodeEntityList) {
+			lastStudentCodeList.add(cur.getStudentCode());
+		}
+
 		// 同步操作
 		if (updateTime != saved.getUpdateTime().getTime()) {
 			SyncStudentReq req = new SyncStudentReq();
@@ -185,7 +217,7 @@ public class StudentServiceImpl implements StudentService {
 			req.setPhotoPath(saved.getPhotoPath());
 			req.setRootOrgId(saved.getRootOrgId());
 			req.setSecurityPhone(saved.getSecurityPhone());
-			req.setStudentCode(saved.getStudentCode());
+			req.setStudentCodeList(lastStudentCodeList);
 
 			req.setSyncType("update");
 
@@ -218,13 +250,20 @@ public class StudentServiceImpl implements StudentService {
 			count++;
 			s = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
 		}
+
 		if (StringUtils.isNotBlank(identityNumber)) {
 			count++;
 			s = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
 		}
 		if (StringUtils.isNotBlank(studentCode)) {
 			count++;
-			s = studentRepo.findByStudentCodeAndRootOrgId(studentCode, rootOrgId);
+
+			StudentCodeEntity studentCodeEntity = studentCodeRepo
+					.findByStudentCodeAndRootOrgId(studentCode, rootOrgId);
+			if (null != studentCodeEntity) {
+				s = GlobalHelper.getEntity(studentRepo, studentCodeEntity.getStudentId(),
+						StudentEntity.class);
+			}
 		}
 		if (StringUtils.isNotBlank(securityPhone)) {
 			count++;
@@ -269,7 +308,14 @@ public class StudentServiceImpl implements StudentService {
 		OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, s.getRootOrgId(), OrgEntity.class);
 		info.setRootOrgName(rootOrg.getName());
 		info.setSecurityPhone(s.getSecurityPhone());
-		info.setStudentCode(s.getStudentCode());
+
+		List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo.findByStudentId(s.getId());
+
+		List<String> studentCodeList = Lists.newArrayList();
+		for (StudentCodeEntity cur : studentCodeEntityList) {
+			studentCodeList.add(cur.getStudentCode());
+		}
+		info.setStudentCodeList(studentCodeList);
 
 		return info;
 	}
@@ -281,48 +327,80 @@ public class StudentServiceImpl implements StudentService {
 			throw new StatusException("120001", "rootOrgId is null");
 		}
 
+		// 更新的学生集合
 		List<StudentEntity> studentList = Lists.newArrayList();
+		// 解绑的学号集合
+		Map<Long, List<String>> unboundStudentCodeMap = Maps.newHashMap();
 
 		StudentEntity s1 = null;
 		StudentEntity s2 = null;
 		if (null != studentCode) {
-			s1 = studentRepo.findByStudentCodeAndRootOrgId(studentCode, rootOrgId);
-			if (null != s1) {
+			StudentCodeEntity sc = studentCodeRepo.findByStudentCodeAndRootOrgId(studentCode,
+					rootOrgId);
+			if (null != sc) {
+				studentCodeRepo.delete(sc);
+				s1 = GlobalHelper.getEntity(studentRepo, sc.getStudentId(), StudentEntity.class);
 				studentList.add(s1);
+				List<String> unboundStudentCodeList = Lists.newArrayList();
+				unboundStudentCodeList.add(sc.getStudentCode());
+				unboundStudentCodeMap.put(s1.getId(), unboundStudentCodeList);
 			}
 		}
+
 		if (null != identityNumber) {
 			s2 = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
 			if (null != s2) {
 				if (null == s1 || !s1.getId().equals(s2.getId())) {
 					studentList.add(s2);
 				}
+
+				List<StudentCodeEntity> scList = studentCodeRepo.findByStudentId(s2.getId());
+				studentCodeRepo.deleteAll(scList);
+
+				List<String> unboundStudentCodeList = unboundStudentCodeMap.get(s2.getId());
+				if (null == unboundStudentCodeList) {
+					unboundStudentCodeList = Lists.newArrayList();
+					unboundStudentCodeMap.put(s2.getId(), unboundStudentCodeList);
+				}
+				for (StudentCodeEntity cur : scList) {
+					unboundStudentCodeList.add(cur.getStudentCode());
+				}
 			}
 		}
 
 		List<Long> studentIdList = Lists.newArrayList();
 
 		for (StudentEntity cur : studentList) {
-			cur.setStudentCode(null);
-			StudentEntity saved = studentRepo.saveAndFlush(cur);
-			studentIdList.add(saved.getId());
+			studentIdList.add(cur.getId());
 
 			SyncStudentReq req = new SyncStudentReq();
-			req.setEnable(saved.getEnable());
-			req.setId(saved.getId());
-			req.setIdentityNumber(saved.getIdentityNumber());
-			req.setName(saved.getName());
+			req.setEnable(cur.getEnable());
+			req.setId(cur.getId());
+			req.setIdentityNumber(cur.getIdentityNumber());
+			req.setName(cur.getName());
 
-			req.setOrgId(saved.getOrgId());
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, saved.getOrgId(), OrgEntity.class);
+			req.setOrgId(cur.getOrgId());
+			OrgEntity org = GlobalHelper.getEntity(orgRepo, cur.getOrgId(), OrgEntity.class);
 			req.setOrgCode(org.getCode());
 			req.setOrgName(org.getName());
 
-			req.setPhoneNumber(saved.getPhoneNumber());
-			req.setPhotoPath(saved.getPhotoPath());
-			req.setRootOrgId(saved.getRootOrgId());
-			req.setSecurityPhone(saved.getSecurityPhone());
-			req.setStudentCode(saved.getStudentCode());
+			req.setPhoneNumber(cur.getPhoneNumber());
+			req.setPhotoPath(cur.getPhotoPath());
+			req.setRootOrgId(cur.getRootOrgId());
+			req.setSecurityPhone(cur.getSecurityPhone());
+
+			List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo
+					.findByStudentId(cur.getId());
+
+			List<String> lastStudentCodeList = Lists.newArrayList();
+			for (StudentCodeEntity sc : studentCodeEntityList) {
+				lastStudentCodeList.add(sc.getStudentCode());
+			}
+
+			req.setStudentCodeList(lastStudentCodeList);
+
+			List<String> unboundStudentCodeList = unboundStudentCodeMap.get(cur.getId());
+			req.setUnboundStudentCodeList(unboundStudentCodeList);
 
 			req.setSyncType("update");
 
@@ -332,6 +410,45 @@ public class StudentServiceImpl implements StudentService {
 		return studentIdList;
 	}
 
+	@Override
+	public void unbindSecurityPhone(Long studentId) {
+
+		StudentEntity s = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
+		if (null == s) {
+			throw new StatusException("450110", "学生不存在");
+		}
+		s.setSecurityPhone(null);
+		StudentEntity saved = studentRepo.save(s);
+
+		SyncStudentReq req = new SyncStudentReq();
+		req.setEnable(saved.getEnable());
+		req.setId(saved.getId());
+		req.setIdentityNumber(saved.getIdentityNumber());
+		req.setName(saved.getName());
+
+		req.setOrgId(saved.getOrgId());
+		OrgEntity org = GlobalHelper.getEntity(orgRepo, saved.getOrgId(), OrgEntity.class);
+		req.setOrgCode(org.getCode());
+		req.setOrgName(org.getName());
+
+		req.setPhoneNumber(saved.getPhoneNumber());
+		req.setPhotoPath(saved.getPhotoPath());
+		req.setRootOrgId(saved.getRootOrgId());
+		req.setSecurityPhone(saved.getSecurityPhone());
+
+		List<StudentCodeEntity> studentCodeEntityList = studentCodeRepo
+				.findByStudentId(saved.getId());
+		List<String> lastStudentCodeList = Lists.newArrayList();
+		for (StudentCodeEntity sc : studentCodeEntityList) {
+			lastStudentCodeList.add(sc.getStudentCode());
+		}
+		req.setStudentCodeList(lastStudentCodeList);
+
+		req.setSyncType("update");
+
+		dataSyncCloudService.syncStudent(req);
+	}
+
 	@Override
 	public Boolean hasBeBound(String securityPhone) {