wangwei hace 7 años
padre
commit
7f15d59fee
Se han modificado 70 ficheros con 6284 adiciones y 0 borrados
  1. 0 0
      examcloud-exchange-base/pom.xml
  2. 31 0
      examcloud-outlet-api/pom.xml
  3. 157 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/CommonGainScoreController.java
  4. 57 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ExamController.java
  5. 49 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ExamVerifyPhotoController.java
  6. 225 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/FaceppController.java
  7. 54 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ScorePushController.java
  8. 57 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/StudentInfoController.java
  9. 107 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/sydx/ScoreController.java
  10. 81 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/sydx/StudentExamInfoController.java
  11. 25 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/CourseClient.java
  12. 28 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/ExamClient.java
  13. 33 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/ExamStudentClient.java
  14. 29 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/OeClient.java
  15. 19 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/OrgClient.java
  16. 25 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/StudentClient.java
  17. 25 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/StudentFaceInfoClient.java
  18. 7 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/DetectNoFaceException.java
  19. 26 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/ExamStudentNotExistException.java
  20. 15 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/FaceppException.java
  21. 15 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/InvalidJpgException.java
  22. 7 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchCourseLevelException.java
  23. 7 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchExamException.java
  24. 15 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchExamStudentException.java
  25. 30 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/SaveExamException.java
  26. 27 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/SaveExamStudentException.java
  27. 26 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/UpYunException.java
  28. 78 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/BaseResponse.java
  29. 39 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/FailureBaseResponse.java
  30. 9 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/IBaseResponse.java
  31. 36 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/SuccessBaseResponse.java
  32. 17 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ExamService.java
  33. 272 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ExamStudentImportService.java
  34. 338 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/FaceppService.java
  35. 62 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/OutletScoreService.java
  36. 16 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ScorePushService.java
  37. 19 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/StudentInfoService.java
  38. 111 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/UpyunService.java
  39. 78 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/ExamServiceImpl.java
  40. 239 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/OutletScoreServiceImpl.java
  41. 295 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/StudentInfoServiceImpl.java
  42. 159 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/scorePush/SydxScorePushServiceImpl.java
  43. 117 0
      examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/scorePush/XncdScorePushServiceImpl.java
  44. 26 0
      examcloud-outlet-domain/pom.xml
  45. 20 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/ExamRecordDao.java
  46. 18 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/ExamScoreDao.java
  47. 76 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/OutletScoreDao.java
  48. 88 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/ExamRecordDaoImpl.java
  49. 53 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/ExamScoreDaoImpl.java
  50. 425 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/OutletScoreDaoImpl.java
  51. 88 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamReq.java
  52. 70 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamScore.java
  53. 33 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamStudentImportDTO.java
  54. 230 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/OutletScore.java
  55. 251 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/StudentInfoReq.java
  56. 52 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/CreateFacesetResponse.java
  57. 26 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/Face.java
  58. 46 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/FaceDetectResponse.java
  59. 43 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/FaceRectangle.java
  60. 115 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletCourse.java
  61. 527 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletExam.java
  62. 412 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletExamStudent.java
  63. 251 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletOrg.java
  64. 151 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletStudent.java
  65. 63 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/enums/OrgIdServiceEnum.java
  66. 17 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/enums/OutletOrgType.java
  67. 39 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/repo/ExamScoreRepo.java
  68. 40 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/utils/OutletUtils.java
  69. 59 0
      examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/utils/SpringContextUtils.java
  70. 3 0
      pom.xml

+ 0 - 0
examcloud-exchange-commons/pom.xml → examcloud-exchange-base/pom.xml


+ 31 - 0
examcloud-outlet-api/pom.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2.0-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-outlet-api</artifactId>
+	<packaging>jar</packaging>
+
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.exchange</groupId>
+			<artifactId>examcloud-outlet-domain</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.upyun</groupId>
+			<artifactId>java-sdk</artifactId>
+			<version>3.14</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+		</dependency>
+	</dependencies>
+
+
+</project>

+ 157 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/CommonGainScoreController.java

@@ -0,0 +1,157 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import cn.com.qmth.examcloud.outlet.repo.ExamScoreRepo;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.OutletScoreService;
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+
+
+
+
+
+import javax.servlet.http.HttpServletRequest;
+
+import java.util.List;
+
+/**
+ * 公共-获取成绩接口
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:57:26
+ * @company 	QMTH
+ * @description ScoreController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/score")
+public class CommonGainScoreController  extends ControllerSupport{
+
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
+    
+    @Autowired
+    private OutletScoreService outletScoreService;
+
+    @ApiOperation(value = "查询成绩:根据考试名称、机构ID和学生考试方式查询")
+    @GetMapping
+    public ResponseEntity<?> query(@RequestParam(name = "examName") String examName,
+                                   @RequestParam(name = "examStuRemark",required=false) String examStuRemark,
+                                   HttpServletRequest request) {
+    	try{
+    		User accessUser = getAccessUser();
+    		if(accessUser == null){
+    			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+    		}
+    		if (StringUtils.isEmpty(examName)) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("考试名称不能为空"),HttpStatus.BAD_REQUEST);
+            }
+            Long orgId = accessUser.getRootOrgId();
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScore(examName, examStuRemark, orgId);
+            return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功",outletScoreList), HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+        
+    }
+    
+    @ApiOperation(value = "查询成绩:按考试名称、考生身份证号、机构ID查询成绩")
+    @GetMapping("/examNameAndIdentityNumberList")
+    public ResponseEntity<?> queryByIdentityNumber(@RequestParam(name = "examName") String examName,
+    											   @RequestParam(name = "identityNumberList") List<String> identityNumberList,
+    											   HttpServletRequest request) {
+        try{
+        	User accessUser = getAccessUser();
+    		if(accessUser == null){
+    			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+    		}
+    		if (StringUtils.isEmpty(examName)) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("考试名称不能为空"),HttpStatus.BAD_REQUEST);
+            }
+    		if (identityNumberList==null||identityNumberList.size()==0) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("身份证号不能为空"),HttpStatus.BAD_REQUEST);
+            }
+    		if(identityNumberList.size()>1000){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("单次查询,身份证号数量不能大于1000"),HttpStatus.BAD_REQUEST);
+	    	}
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScoreByExamNameAndIdentityNumbers(examName,identityNumberList,accessUser.getRootOrgId());
+            return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功",outletScoreList), HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+    }
+    
+    @ApiOperation(value = "查询成绩:按考试名称、机构ID、学号、课程code查询成绩")
+    @GetMapping("/batchNameAndCourseCodeAndStudentCodes")
+    public ResponseEntity<?> queryExamScores(
+    		@RequestParam(name = "batchName") String batchName,
+    		@RequestParam(name = "courseCode") String courseCode,
+    		@RequestParam(name = "studentCodes") List<String> studentCodes,
+    		HttpServletRequest request){
+    	try{
+    		User accessUser = getAccessUser();
+    		if(accessUser == null){
+    			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+    		}
+	    	if(StringUtils.isEmpty(batchName)){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("考试名称不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(StringUtils.isEmpty(courseCode)){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("课程不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(studentCodes == null || studentCodes.size()==0){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("学号不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(studentCodes.size()>1000){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("单次查询,学号数量不能大于1000"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	List<OutletScore> outletScoreList = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(),batchName,courseCode,studentCodes);
+	    	return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功",outletScoreList), HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+    }
+    
+    @ApiOperation(value = "查询成绩明细:按考试名称、机构ID、学号、课程code查询成绩")
+    @GetMapping("/batchQueryScoreDetail")
+    public ResponseEntity<?> batchQueryScoreDetail(@RequestParam(name = "examName")String examName,
+						    		 @RequestParam(name = "studentCode")String studentCode,
+						    		 @RequestParam(name = "courseCode")String courseCode,
+						    		 HttpServletRequest request){
+    	User accessUser = getAccessUser();
+    	if(accessUser == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+		if(examName == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("examName is not null"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+		if(studentCode == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("studentCode is not null"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+		if(courseCode == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("courseCode is not null"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+    	try {
+			List<OutletScore> outletScores = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(), examName, studentCode, courseCode);
+			return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功",outletScores), HttpStatus.OK);
+    	} catch (Exception e) {
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("查询失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+    }
+    
+}

+ 57 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ExamController.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.dto.ExamReq;
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamException;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.ExamService;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午3:20:33
+ * @company 	QMTH
+ * @description ExamController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/exam")
+public class ExamController  extends ControllerSupport{
+	
+    @Autowired
+    private ExamService examService;
+	
+	@ApiOperation(value = "创建考试")
+	@PostMapping
+	public ResponseEntity<?> createExam(@RequestBody ExamReq examReq,HttpServletRequest request){
+		User accessUser = getAccessUser();
+		if(accessUser == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+		try {
+			OutletExam exam = examService.createExam(examReq, accessUser.getUserToken(), accessUser.getRootOrgId());
+			return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("执行成功",exam), HttpStatus.OK);
+		}catch(SaveExamException e){
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("创建失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+	}
+	
+}
+

+ 49 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ExamVerifyPhotoController.java

@@ -0,0 +1,49 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamPhotoVerifyData;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.client.OeClient;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 上午11:49:40
+ * @company 	QMTH
+ * @description ExamVerifyPhotoController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/examVerifyPhotos")
+public class ExamVerifyPhotoController  extends ControllerSupport{
+	
+	@Autowired
+	private OeClient oeClient;
+	
+	@GetMapping
+	public ResponseEntity<?> getExamVerifyPhotos(HttpServletRequest request,@RequestParam Long scoreId){
+		User accessUser = getAccessUser();
+		if(accessUser == null){
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+		try{
+			ExamPhotoVerifyData examPhotoVerifyData = oeClient.getExamPhotoVerifyData(accessUser.getUserToken(),scoreId);
+			return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功",examPhotoVerifyData), HttpStatus.OK);
+		}catch(Exception e){
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("查询失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+	}
+	
+}
+

+ 225 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/FaceppController.java

@@ -0,0 +1,225 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import cn.com.qmth.examcloud.commons.base.util.GsonUtil;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.client.ExamStudentClient;
+import cn.com.qmth.examcloud.outlet.client.StudentFaceInfoClient;
+import cn.com.qmth.examcloud.outlet.exception.DetectNoFaceException;
+import cn.com.qmth.examcloud.outlet.exception.ExamStudentNotExistException;
+import cn.com.qmth.examcloud.outlet.exception.InvalidJpgException;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.IBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.FaceppService;
+import cn.com.qmth.examcloud.outlet.service.UpyunService;
+import cn.com.qmth.examcloud.common.dto.core.StudentFaceInfo;
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * 学生照片接口
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:58:31
+ * @company 	QMTH
+ * @description FaceppController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/facepp")
+public class FaceppController  extends ControllerSupport{
+
+    private static final Logger LOG = LoggerFactory.getLogger(FaceppController.class);
+    
+    /**
+     * ZIP最大50M
+     */
+    private static final int ZIP_MAX_SIZE = 50;
+    /**
+     * 最大张数500张
+     */
+    private static final int MAX_COUNT = 500;
+    /**
+     * 每张照片最大尺寸 500KB
+     */
+    private static final int MAX_SIZE = 500;
+
+    @Autowired
+    private ExamStudentClient examStudentClient;
+
+    @Autowired
+    private UpyunService upyunService;
+
+    @Autowired
+    private FaceppService faceppService;
+
+    @Autowired
+    private StudentFaceInfoClient studentFaceInfoClient;
+
+    /**
+     * 单个上传
+     * @param file
+     * @param request
+     * @return
+     */
+    @PostMapping("/add")
+    public ResponseEntity<IBaseResponse> add(@RequestParam MultipartFile file, HttpServletRequest request) {
+    	User accessUser = getAccessUser();
+        if (accessUser == null) {
+            return new ResponseEntity<>(new FailureBaseResponse("请先登录", null), HttpStatus.BAD_REQUEST);
+        }
+        try {
+            LOG.info("fileName = {}", file.getOriginalFilename());
+            faceppService.processOne(accessUser,file.getOriginalFilename(), file.getBytes(), accessUser.getRootOrgId());
+            return new ResponseEntity<>(new SuccessBaseResponse("上传成功", null),HttpStatus.OK);
+        } catch (InvalidJpgException e) {
+            e.printStackTrace();
+            return new ResponseEntity<>(new FailureBaseResponse("不是一个图片文件",null), HttpStatus.NOT_ACCEPTABLE);
+        } catch (ExamStudentNotExistException e) {
+            e.printStackTrace();
+            return new ResponseEntity<>(new FailureBaseResponse("考生不存在",null), HttpStatus.NOT_ACCEPTABLE);
+        } catch (DetectNoFaceException e) {
+            e.printStackTrace();
+            return new ResponseEntity<>(new FailureBaseResponse("检测不到人脸",null), HttpStatus.NOT_ACCEPTABLE);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new ResponseEntity<>(new FailureBaseResponse("上传失败",null), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    /**
+     * 学生照片打包成ZIP文件批量上传
+     * @param file
+     * @param request
+     * @return
+     * @throws Exception
+     */
+    @PostMapping("/import")
+    public ResponseEntity<IBaseResponse> batchAllFace(@RequestParam MultipartFile file, HttpServletRequest request) throws Exception {
+    	User accessUser = getAccessUser();
+        if (accessUser == null) {
+            return new ResponseEntity<>(new FailureBaseResponse("请先登录", null), HttpStatus.BAD_REQUEST);
+        }
+        String userToken = accessUser.getToken();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        if (!file.getOriginalFilename().endsWith(".zip")) {
+            return new ResponseEntity<>(new FailureBaseResponse("文件格式不正确,必须是zip格式的压缩包", null), HttpStatus.BAD_REQUEST);
+        }
+        //文件大小限制
+        if (file.getSize() > ZIP_MAX_SIZE * 1024 * 1024) {
+            return new ResponseEntity<>(new FailureBaseResponse("文件大小超过50M,请分批导入", null), HttpStatus.BAD_REQUEST);
+        }
+        ZipInputStream zin = new ZipInputStream(file.getInputStream());
+        ZipEntry ze;
+        //一次最多处理10个照片
+        int count = 0;
+        String identityNumber = "";
+        String suffix = "";
+        try {
+            while ((ze = zin.getNextEntry()) != null && count < MAX_COUNT) {
+                if (!ze.isDirectory()) {
+                    count++;
+                    if (ze.getSize() > MAX_SIZE * 1024) {
+                        throw new InvalidJpgException(ze.getName() + "超过了" + MAX_SIZE + "KB,请压缩后上传");
+                    }
+                    //计算出身份证号
+                    String[] nameAndSuffix = ze.getName().split("\\.");
+                    if (nameAndSuffix.length < 2) {
+                        throw new InvalidJpgException(ze.getName() + "不是一个照片文件");
+                    }
+                    identityNumber = (nameAndSuffix[0].startsWith("/") || nameAndSuffix[0].startsWith("\\")) ? nameAndSuffix[0].substring(1) : nameAndSuffix[0];
+                    suffix = nameAndSuffix[1];
+                    LOG.info("文件名为 :" + identityNumber + ",后缀名为:" + suffix);
+                    //根据身份证号码,查询考生是否存在
+                    LOG.info("查询身份证号码为 :" + identityNumber + "的学生");
+                    String json = examStudentClient.getExamStudentByIdentityNumber(userToken, identityNumber);
+                    if (StringUtils.isEmpty(json)) {
+                        LOG.error("身份证号为:" + identityNumber + "的考生不存在");
+                        continue;
+                    } else {
+                        List<ExamStudent> examStudentList = GsonUtil.jsonToArrayList(json, ExamStudent.class);
+                        if (examStudentList.size() < 1) {
+                            LOG.error("身份证号为:" + identityNumber + "的考生不存在");
+                            //如果找不到学生信息,则跳过
+                            continue;
+                        }
+                        ExamStudent examStudent = examStudentList.get(0);
+                        ByteArrayOutputStream output = new ByteArrayOutputStream();
+                        //保存学生照片到又拍云
+                        int len = -1;
+                        byte[] bytes = new byte[4096];
+                        while ((len = zin.read(bytes)) != -1) {
+                            output.write(bytes, 0, len);
+                        }
+                        output.close();
+                        byte[] dataBytes = output.toByteArray();
+                        String fileName = upyunService.getMd5(dataBytes);
+                        if (upyunService.saveStudentPhoto(identityNumber,dataBytes,fileName,"." + suffix)) {
+                            LOG.info("保存" + identityNumber + "的照片到又拍云成功");
+                            //调用人脸识别接口
+                            String faceToken = null;
+                            try {
+                                faceToken = faceppService.detectSingleFace(upyunService.getDownloadUrl(identityNumber, fileName, "." + suffix));
+                            } catch (DetectNoFaceException e) {
+                                LOG.error(identityNumber + "检测人脸失败");
+                                continue;
+                            }
+                            ResponseEntity<StudentFaceInfo> studentFaceInfoResponseEntity = studentFaceInfoClient.getByIdentityNumber(userToken, identityNumber, rootOrgId);
+                            StudentFaceInfo studentFaceInfo = studentFaceInfoResponseEntity.getBody();
+                            //获取faceSet,并将faceToken添加进facesetToken
+                            String facesetToken = studentFaceInfoClient.getFaceSet();
+                            if (faceppService.addFace(faceToken, facesetToken)){
+                            	String photoMD5 = fileName+"."+suffix;
+                            	faceppService.saveStudentFaceInfo(studentFaceInfo,
+			                            					      photoMD5,
+			        			                    			  faceToken,
+			        			                    			  facesetToken,
+			        			                    			  examStudent.getStudentId(),
+			        			                    			  accessUser.getDisplayName(),
+			        			                    			  "INTERFACE_IMPORT",
+			        			                    			  userToken);
+                            } else {
+                                LOG.error(identityNumber + "添加照片到人脸集合失败");
+                                continue;
+                            }
+                        } else {
+                            LOG.error("身份证号为:" + identityNumber + "的考生照片保存到又拍云失败");
+                            continue;
+                        }
+                    }
+                }
+            }
+        } catch (InvalidJpgException e) {
+            LOG.error("导入照片出现格式错误:", e);
+            return new ResponseEntity<>(new FailureBaseResponse(e.getMessage(), identityNumber), HttpStatus.BAD_REQUEST);
+        }
+        catch (IOException e) {
+            LOG.error("导入照片出现IO错误:", e);
+            return new ResponseEntity<>(new FailureBaseResponse(e.getMessage(), identityNumber), HttpStatus.INTERNAL_SERVER_ERROR);
+        } finally {
+            zin.closeEntry();
+        }
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+    
+    
+}

+ 54 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/ScorePushController.java

@@ -0,0 +1,54 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import io.swagger.annotations.ApiOperation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamRecordDto;
+import cn.com.qmth.examcloud.outlet.enums.OrgIdServiceEnum;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.ScorePushService;
+import cn.com.qmth.examcloud.outlet.utils.SpringContextUtils;
+
+/**
+ * 推送成绩公共接口
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:57:34
+ * @company 	QMTH
+ * @description ScorePushController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/score-push")
+@ConditionalOnProperty("app.pushscore.enable")
+public class ScorePushController {
+	
+	private static final Logger log = LoggerFactory.getLogger(ScorePushController.class);
+	
+    @ApiOperation(value = "推送成绩")
+    @PostMapping
+    public ResponseEntity<Object> push(@RequestBody ExamRecordDto examRecordDto) throws Exception {
+    	log.info("推送成绩orgId:"+examRecordDto.getOrgId()+"scoreId:"+examRecordDto.getScoreId());
+    	OrgIdServiceEnum orgIdServiceEnum = OrgIdServiceEnum.getServiceNameByOrgId(examRecordDto.getOrgId());
+    	if(orgIdServiceEnum !=null){
+    		try{
+    			ScorePushService scorePushService = (ScorePushService) SpringContextUtils.getBeanById(orgIdServiceEnum.getServiceName());
+        		scorePushService.scorePush(examRecordDto);
+        		return new ResponseEntity<>(new SuccessBaseResponse("分数ID:"+examRecordDto.getScoreId()+":推送成绩成功",null),HttpStatus.OK);
+    		}catch(Exception e){
+    			e.printStackTrace();
+    			return new ResponseEntity<>(new FailureBaseResponse("分数ID:"+examRecordDto.getScoreId()+":推送成绩失败"),HttpStatus.INTERNAL_SERVER_ERROR);
+    		}
+    	}else{
+    		return new ResponseEntity<>(new SuccessBaseResponse("没有机构ID为"+examRecordDto.getOrgId()+"的配置",null),HttpStatus.OK);
+    	}
+    }
+}

+ 57 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/StudentInfoController.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.outlet.api;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.dto.StudentInfoReq;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamStudentException;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.StudentInfoService;
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午4:30:29
+ * @company 	QMTH
+ * @description StudentInfoController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/studentInfo")
+public class StudentInfoController extends ControllerSupport{
+	
+	@Autowired
+	private StudentInfoService studentInfoService;
+	
+	@ApiOperation(value = "保存学生信息")
+	@PostMapping
+	public ResponseEntity<?> saveStudentInfo(@RequestBody List<StudentInfoReq> studentInfoReqs,HttpServletRequest request){
+		User accessUser = getAccessUser();
+        if(accessUser == null){
+        	return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("检测到用户为空,请先登录"), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        try {
+			studentInfoService.saveStudentInfo(studentInfoReqs, accessUser.getUserToken(), accessUser.getRootOrgId());
+			return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("创建成功",null),HttpStatus.OK);
+		} catch (SaveExamStudentException e) {
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("调用失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+	}
+	
+}
+

+ 107 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/sydx/ScoreController.java

@@ -0,0 +1,107 @@
+package cn.com.qmth.examcloud.outlet.api.sydx;
+
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import cn.com.qmth.examcloud.outlet.repo.ExamScoreRepo;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.OutletScoreService;
+import io.swagger.annotations.ApiOperation;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+import java.util.List;
+
+/**
+ * 石油大学专用-获取成绩接口
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:57:26
+ * @company 	QMTH
+ * @description ScoreController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/sydx/score")
+public class ScoreController  extends ControllerSupport{
+
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
+    
+    @Autowired
+    private OutletScoreService outletScoreService;
+
+    @ApiOperation(value = "查询成绩:根据考试名称、机构ID和学生考试方式查询")
+    @GetMapping
+    public ResponseEntity<?> query(@RequestParam(name = "examRemark") String examRemark,
+                                @RequestParam(name = "examStuRemark") String examStuRemark,
+                                HttpServletRequest request) {
+    	try{
+    		if (StringUtils.isEmpty(examRemark)) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("examRemark不能为空"),HttpStatus.BAD_REQUEST);
+            }
+    		User accessUser = getAccessUser();
+            Long orgId = accessUser.getRootOrgId();
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScore(examRemark, examStuRemark, orgId);
+
+            return new ResponseEntity<List<OutletScore>>(outletScoreList, HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+        
+    }
+    
+    @ApiOperation(value = "查询成绩:按考生身份证号、机构ID查询成绩")
+    @GetMapping("/identityNumber")
+    public ResponseEntity<?> queryByIdentityNumber(@RequestParam(name = "identityNumberList") List<String> identityNumberList,HttpServletRequest request) {
+        try{
+        	if (identityNumberList==null||identityNumberList.size()==0) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("身份证号不能为空"),HttpStatus.BAD_REQUEST);
+            }
+        	User accessUser = getAccessUser();
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScoreByIdentityNumbers(identityNumberList, accessUser.getRootOrgId());
+            return new ResponseEntity<List<OutletScore>>(outletScoreList, HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+    }
+    
+    @ApiOperation(value = "查询成绩:按考试名称、机构ID、学号、课程code查询成绩")
+    @GetMapping("/batchNameAndCourseCodeAndStudentCodes")
+    public ResponseEntity<?> queryExamScores(
+    		@RequestParam(name = "batchName") String batchName,
+    		@RequestParam(name = "courseCode") String courseCode,
+    		@RequestParam(name = "studentCodes") List<String> studentCodes,
+    		HttpServletRequest request){
+    	try{
+	    	if(StringUtils.isEmpty(batchName)){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("考试批次名称不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(StringUtils.isEmpty(courseCode)){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("课程不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(studentCodes == null || studentCodes.size()==0){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("学号不能为空"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	if(studentCodes.size()>1000){
+	    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("单次查询,学号数量不能大于1000"),HttpStatus.BAD_REQUEST);
+	    	}
+	    	User accessUser = getAccessUser();
+	    	List<OutletScore> outletScoreList = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(),batchName,courseCode,studentCodes);
+	    	return new ResponseEntity<List<OutletScore>>(outletScoreList, HttpStatus.OK);
+    	}catch(Exception e){
+    		e.printStackTrace();
+    		return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+    	}
+    }
+    
+}

+ 81 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/api/sydx/StudentExamInfoController.java

@@ -0,0 +1,81 @@
+package cn.com.qmth.examcloud.outlet.api.sydx;
+
+
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.outlet.dto.ExamStudentImportDTO;
+import cn.com.qmth.examcloud.outlet.exception.NoSuchCourseLevelException;
+import cn.com.qmth.examcloud.outlet.exception.NoSuchExamException;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamException;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamStudentException;
+import cn.com.qmth.examcloud.outlet.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.outlet.response.IBaseResponse;
+import cn.com.qmth.examcloud.outlet.service.ExamStudentImportService;
+
+import com.alibaba.fastjson.JSON;
+
+import io.swagger.annotations.ApiOperation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 石油大学专用-接收考生数据接口
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:57:42
+ * @company 	QMTH
+ * @description StudentExamInfoController.java
+ */
+@RestController
+@RequestMapping("${app.api.root}/sydx/import_exam_student_info")
+public class StudentExamInfoController  extends ControllerSupport{
+
+    private static final Logger LOG = LoggerFactory.getLogger(StudentExamInfoController.class);
+
+    @Autowired
+    private ExamStudentImportService examStudentImportService;
+
+    @ApiOperation(value = "石油大学使用:创建考试和导入学生")
+    @PostMapping
+    public ResponseEntity<IBaseResponse> post(@RequestBody ExamStudentImportDTO examStudentImportDTO,
+                                              HttpServletRequest request) {
+    	User accessUser = getAccessUser();
+        if(accessUser == null){
+        	return new ResponseEntity<>(new FailureBaseResponse("检测到用户为空,请先登录", null), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        try {
+            LOG.info("请求参数是:" + JSON.toJSONString(examStudentImportDTO));
+        } catch (Exception e) {
+        }
+        Long rootOrgId = accessUser.getRootOrgId();
+        if (rootOrgId == null) {
+            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
+        }
+        try {
+            Long examId = examStudentImportService.save(accessUser.getUserToken(), rootOrgId, examStudentImportDTO);
+            return new ResponseEntity<>(new SuccessBaseResponse("", examId), HttpStatus.OK);
+        } catch (NoSuchCourseLevelException e) {
+            LOG.error("课程级别不存在", e);
+            return new ResponseEntity<>(new FailureBaseResponse("课程级别不存在", null), HttpStatus.INTERNAL_SERVER_ERROR);
+        } catch (NoSuchExamException e) {
+            LOG.error("考试不存在", e);
+            return new ResponseEntity<>(new FailureBaseResponse("考试不存在", null), HttpStatus.INTERNAL_SERVER_ERROR);
+        } catch (SaveExamException e) {
+            LOG.error("创建考试失败", e);
+            return new ResponseEntity<>(new FailureBaseResponse("创建考试失败,可能该考试名称已经存在", null), HttpStatus.INTERNAL_SERVER_ERROR);
+        } catch (SaveExamStudentException e) {
+            LOG.error("创建考生失败", e);
+            return new ResponseEntity<>(new FailureBaseResponse("创建考生失败,可能该考生信息已经存在", null), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+}

+ 25 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/CourseClient.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletCourse;
+
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+@FeignClient(value = "ExamCloud-service-core")
+public interface CourseClient {
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.core}/course")
+    ResponseEntity<OutletCourse> getCourseByCode(@RequestHeader("user_token") String token, @RequestParam(value = "orgId") Long orgId, @RequestParam(value = "code") String code);
+
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.core}/course")
+    ResponseEntity<OutletCourse> save(@RequestHeader("user_token") String token, @RequestBody OutletCourse course);
+}

+ 28 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/ExamClient.java

@@ -0,0 +1,28 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+@FeignClient(value = "ExamCloud-service-exam-work")
+public interface ExamClient {
+
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.exam}/exam")
+    ResponseEntity<OutletExam> save(@RequestHeader("user_token") String token, @RequestBody OutletExam exam);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.exam}/exam/{id}")
+    ResponseEntity<OutletExam> getOne(@RequestHeader("user_token") String token, @PathVariable(value = "id") Long id);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.exam}/exam/all")
+    ResponseEntity<List<OutletExam>> queryByRemark(@RequestHeader("user_token") String token, @RequestParam(value = "remark") String remark);
+    
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.exam}/exam/name")
+    ResponseEntity<List<OutletExam>> queryByName(@RequestHeader("user_token") String token, @RequestParam(value = "name") String name);
+}

+ 33 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/ExamStudentClient.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletExamStudent;
+
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+@FeignClient(value = "ExamCloud-service-exam-work")
+public interface ExamStudentClient {
+
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.exam}/exam_student")
+    ResponseEntity<OutletExamStudent> save(@RequestHeader("user_token") String token, @RequestBody OutletExamStudent examStudent);
+
+
+    @RequestMapping(method = RequestMethod.PUT, value = "${app.api.exam}/exam_student")
+    ResponseEntity<OutletExamStudent> updateExamStudent(@RequestHeader("user_token") String token, @RequestBody OutletExamStudent examStudent);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.exam}/exam_student/all")
+    String getExamStudentByIdentityNumber(@RequestHeader("user_token") String token, @RequestParam("identityNumber") String identityNumber);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.exam}/exam_student/all")
+    ResponseEntity<List<OutletExamStudent>> queryExamStudent(@RequestHeader("user_token") String token, @RequestParam("identityNumber") String identityNumber, @RequestParam("examId") Long examId, @RequestParam("courseCode") String courseCode);
+}

+ 29 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/OeClient.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamPhotoVerifyData;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午3:11:55
+ * @company 	QMTH
+ * @description OeClient.java
+ */
+@FeignClient(value = "ExamCloud-SERVICE-OE")
+public interface OeClient {
+
+	/**
+	 * 查询考试拍照相关数据
+	 * @param scoreId
+	 * @return
+	 */
+	@RequestMapping(method = RequestMethod.GET, value = "/api/exam_record/examPhotoVerifyCount")
+	public ExamPhotoVerifyData getExamPhotoVerifyData(@RequestHeader("user_token") String token,@RequestParam("scoreId") Long scoreId);
+	
+}
+

+ 19 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/OrgClient.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletOrg;
+
+
+@FeignClient(value = "ExamCloud-service-core")
+public interface OrgClient {
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.core}/org")
+    ResponseEntity<OutletOrg> findByParentIdAndCode(@RequestHeader("user_token") String token, @RequestParam("parentId") Long parentId, @RequestParam("code") String code);
+
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.core}/org")
+    ResponseEntity<OutletOrg> save(@RequestHeader("user_token") String token, @RequestBody OutletOrg org);
+
+}

+ 25 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/StudentClient.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletStudent;
+
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+@FeignClient(value = "ExamCloud-service-core")
+public interface StudentClient {
+
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.core}/student")
+    ResponseEntity<OutletStudent> save(@RequestHeader("user_token") String token, @RequestBody OutletStudent student);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.core}/student")
+    ResponseEntity<List<OutletStudent>> getStudentByIdentityNumber(@RequestHeader("user_token") String token, @RequestParam("identityNumber") String identityNumber);
+
+    @RequestMapping(method = RequestMethod.PUT, value = "${app.api.core}/student")
+    ResponseEntity<OutletStudent> updateStudent(@RequestHeader("user_token") String token, @RequestBody OutletStudent student);
+}

+ 25 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/client/StudentFaceInfoClient.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.outlet.client;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.examcloud.common.dto.core.StudentFaceInfo;
+
+/**
+ * Created by yuanpan on 2017/5/14.
+ */
+@FeignClient(value = "ExamCloud-service-core")
+public interface StudentFaceInfoClient {
+    @RequestMapping(method = RequestMethod.POST, value = "${app.api.core}/studentFaceInfo")
+    ResponseEntity<StudentFaceInfo> save(@RequestHeader("user_token") String token, @RequestBody StudentFaceInfo studentFaceInfo);
+
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.core}/studentFaceInfo/identityNumber")
+    ResponseEntity<StudentFaceInfo> getByIdentityNumber(@RequestHeader("user_token") String token, @RequestParam("identityNumber") String identityNumber, @RequestParam("orgId") Long orgId);
+    /**
+     * 获取faceSetToken(人脸集合)
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET, value = "${app.api.core}/faceSet/enableFaceSet")
+    String getFaceSet();
+}

+ 7 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/DetectNoFaceException.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class DetectNoFaceException extends Exception {
+}

+ 26 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/ExamStudentNotExistException.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/8/2.
+ */
+public class ExamStudentNotExistException extends Exception {
+
+    public ExamStudentNotExistException() {
+    }
+
+    public ExamStudentNotExistException(String message) {
+        super(message);
+    }
+
+    public ExamStudentNotExistException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ExamStudentNotExistException(Throwable cause) {
+        super(cause);
+    }
+
+    public ExamStudentNotExistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 15 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/FaceppException.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class FaceppException extends Exception {
+
+    public FaceppException() {
+        super();
+    }
+
+    public FaceppException(String message) {
+        super(message);
+    }
+}

+ 15 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/InvalidJpgException.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/5/11.
+ */
+public class InvalidJpgException extends Exception {
+
+    public InvalidJpgException() {
+        super();
+    }
+
+    public InvalidJpgException(String message) {
+        super(message);
+    }
+}

+ 7 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchCourseLevelException.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+public class NoSuchCourseLevelException extends Exception {
+}

+ 7 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchExamException.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+public class NoSuchExamException extends Exception {
+}

+ 15 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/NoSuchExamStudentException.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/5/11.
+ */
+public class NoSuchExamStudentException extends Exception {
+
+    public NoSuchExamStudentException() {
+        super();
+    }
+
+    public NoSuchExamStudentException(String message) {
+        super(message);
+    }
+}

+ 30 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/SaveExamException.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+public class SaveExamException extends RuntimeException {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -8244262438827548422L;
+
+	public SaveExamException() {
+        super();
+    }
+
+    public SaveExamException(String message) {
+        super(message);
+    }
+
+    public SaveExamException(Throwable cause) {
+        super(cause);
+    }
+
+    public SaveExamException(String message, Throwable cause) {
+        super(message, cause);
+    }
+	
+	
+}

+ 27 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/SaveExamStudentException.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/5/8.
+ */
+public class SaveExamStudentException extends RuntimeException {
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -300824565660602644L;
+
+	public SaveExamStudentException() {
+        super();
+    }
+
+    public SaveExamStudentException(String message) {
+        super(message);
+    }
+
+    public SaveExamStudentException(Throwable cause) {
+        super(cause);
+    }
+
+    public SaveExamStudentException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

+ 26 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/exception/UpYunException.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.outlet.exception;
+
+/**
+ * Created by yuanpan on 2017/8/2.
+ */
+public class UpYunException extends Exception {
+
+    public UpYunException() {
+    }
+
+    public UpYunException(String message) {
+        super(message);
+    }
+
+    public UpYunException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UpYunException(Throwable cause) {
+        super(cause);
+    }
+
+    public UpYunException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 78 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/BaseResponse.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.outlet.response;
+
+public class BaseResponse implements IBaseResponse {
+    /**
+     * 是否成功
+     */
+    protected boolean success;
+
+
+    /**
+     * 返回消息
+     */
+    protected String message;
+
+    /**
+     * 返回数据
+     */
+    protected Object data;
+
+
+    public BaseResponse(boolean success) {
+        this.success = success;
+    }
+
+    public BaseResponse(boolean success, String message) {
+        this.success = success;
+        this.message = message;
+    }
+
+    public BaseResponse(boolean success, Object data) {
+        this.success = success;
+        this.data = data;
+    }
+
+    public BaseResponse(boolean success, String message, Object data) {
+        this.success = success;
+        this.message = message;
+        this.data = data;
+    }
+
+
+//    public BaseResponse(boolean success, ResponseMsgEnum responseMsgEnum, Object data) {
+//        this.success = success;
+//        this.status = responseMsgEnum.getStatus();
+//        this.message = responseMsgEnum.getMessage();
+//        this.data = data;
+//    }
+//
+//    public BaseResponse(boolean success, ResponseMsgEnum responseMsgEnum) {
+//        this.success = success;
+//        this.status = responseMsgEnum.getStatus();
+//        this.message = responseMsgEnum.getMessage();
+//    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+}

+ 39 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/FailureBaseResponse.java

@@ -0,0 +1,39 @@
+package cn.com.qmth.examcloud.outlet.response;
+
+public class FailureBaseResponse implements IBaseResponse {
+
+	public FailureBaseResponse(String message){
+		 this.message = message;
+	}
+	
+    public FailureBaseResponse(String message, Object data) {
+        this.message = message;
+        this.data = data;
+    }
+
+    /**
+     * 返回消息
+     */
+    protected String message;
+
+    /**
+     * 返回数据
+     */
+    protected Object data;
+
+
+    @Override
+    public boolean isSuccess() {
+        return false;
+    }
+
+    @Override
+    public String getMessage() {
+        return this.message;
+    }
+
+    @Override
+    public Object getData() {
+        return this.data;
+    }
+}

+ 9 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/IBaseResponse.java

@@ -0,0 +1,9 @@
+package cn.com.qmth.examcloud.outlet.response;
+
+public interface IBaseResponse {
+    boolean isSuccess();
+
+    String getMessage();
+
+    Object getData();
+}

+ 36 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/response/SuccessBaseResponse.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.outlet.response;
+
+public class SuccessBaseResponse implements IBaseResponse {
+
+
+    public SuccessBaseResponse(String message, Object data) {
+        this.message = message;
+        this.data = data;
+    }
+
+    /**
+     * 返回消息
+     */
+    protected String message;
+
+    /**
+     * 返回数据
+     */
+    protected Object data;
+
+
+    @Override
+    public boolean isSuccess() {
+        return true;
+    }
+
+    @Override
+    public String getMessage() {
+        return this.message;
+    }
+
+    @Override
+    public Object getData() {
+        return this.data;
+    }
+}

+ 17 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ExamService.java

@@ -0,0 +1,17 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import cn.com.qmth.examcloud.outlet.dto.ExamReq;
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午3:28:34
+ * @company 	QMTH
+ * @description ExamController.java
+ */
+public interface ExamService{
+
+	public OutletExam createExam(ExamReq examReq,String userToken,Long rootOrgId)  throws Exception;
+	
+}
+

+ 272 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ExamStudentImportService.java

@@ -0,0 +1,272 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.core.User;
+import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
+import cn.com.qmth.examcloud.outlet.client.CourseClient;
+import cn.com.qmth.examcloud.outlet.client.ExamClient;
+import cn.com.qmth.examcloud.outlet.client.ExamStudentClient;
+import cn.com.qmth.examcloud.outlet.client.OrgClient;
+import cn.com.qmth.examcloud.outlet.client.StudentClient;
+import cn.com.qmth.examcloud.outlet.dto.ExamStudentImportDTO;
+import cn.com.qmth.examcloud.outlet.entity.OutletCourse;
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+import cn.com.qmth.examcloud.outlet.entity.OutletExamStudent;
+import cn.com.qmth.examcloud.outlet.entity.OutletOrg;
+import cn.com.qmth.examcloud.outlet.entity.OutletStudent;
+import cn.com.qmth.examcloud.outlet.enums.OutletOrgType;
+import cn.com.qmth.examcloud.outlet.exception.NoSuchCourseLevelException;
+import cn.com.qmth.examcloud.outlet.exception.NoSuchExamException;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamException;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamStudentException;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+@Service
+public class ExamStudentImportService {
+	
+	private static final Logger log = LoggerFactory.getLogger(ExamStudentImportService.class);
+
+    @Autowired
+    private OrgClient orgClient;
+
+    @Autowired
+    private ExamClient examClient;
+
+    @Autowired
+    private CourseClient courseClient;
+
+    @Autowired
+    private StudentClient studentClient;
+
+    @Autowired
+    private ExamStudentClient examStudentClient;
+
+
+    /**
+     * 石油大学
+	 * 1.保存考试信息
+	 * 2.保存学习中心
+	 * 3.保存课程
+	 * 4.保存学生信息
+	 * 5.保存考生信息
+     * @param rootOrgId
+     * @param examStudentImportDTO
+     * @throws NoSuchExamException
+     * @throws NoSuchCourseLevelException
+     */
+    public Long save(String userToken, Long rootOrgId, ExamStudentImportDTO examStudentImportDTO) throws NoSuchCourseLevelException, NoSuchExamException, SaveExamException, SaveExamStudentException {
+    	log.info("创建考试和导入学生开始");
+    	OutletExam exam = saveExam(examStudentImportDTO,userToken,rootOrgId);
+        List<OutletExamStudent> examStudentList = examStudentImportDTO.getExamStudentList();
+        for (OutletExamStudent examStudent : examStudentList) {
+        	OutletOrg org = saveOrg(examStudent,userToken,rootOrgId);
+            
+        	saveCourse(examStudent,userToken,rootOrgId);
+        	
+        	OutletStudent student = saveStudent(examStudent,org,userToken,rootOrgId);
+        	
+        	saveExamStudent(examStudent,student,org,exam,userToken,rootOrgId);
+        }
+        log.info("创建考试和导入学生完成");
+        return exam.getId();
+    }
+    
+    /**
+     * 保存考试信息
+     * @param examStudentImportDTO
+     * @param userToken
+     * @param rootOrgId
+     * @return
+     * @throws SaveExamException
+     */
+	private OutletExam saveExam(ExamStudentImportDTO examStudentImportDTO,String userToken,Long rootOrgId) throws SaveExamException {
+		OutletExam exam = examStudentImportDTO.getExam();
+		log.info("1.保存考试信息,考试批次:"+exam.getRemark());
+        ResponseEntity<List<OutletExam>> examListResp = examClient.queryByRemark(userToken, exam.getRemark());
+        //判断考试是否存在
+        if (examListResp != null && examListResp.getBody() != null && examListResp.getBody().size() > 0) {
+            exam = examListResp.getBody().get(0);
+        } else {
+        	exam.setEnable(true);//默认开启考试
+            exam.setOrgId(rootOrgId);
+            ResponseEntity<OutletExam> saveExamResp = null;
+            try {
+                saveExamResp = examClient.save(userToken, exam);
+            } catch (Exception e) {
+                throw new SaveExamException();
+            }
+            exam = saveExamResp.getBody();
+        }
+        return exam;
+	}
+
+	/**
+     * 保存学习中心
+     * @param examStudent
+     * @param userToken
+     * @param rootOrgId
+     * @return
+     */
+    private OutletOrg saveOrg(OutletExamStudent examStudent,String userToken,Long rootOrgId){
+    	log.info("2.保存学习中心,学习中心code:"+examStudent.getOrgCode());
+    	//判断学习中心是否存在,不存在则创建
+        String orgCode = examStudent.getOrgCode();
+        //根据orgCode,查询学习中心
+        ResponseEntity<OutletOrg> orgResponseEntity = orgClient.findByParentIdAndCode(userToken, rootOrgId, orgCode);
+        OutletOrg org = orgResponseEntity.getBody();
+        if (org == null) {
+            org = new OutletOrg();
+            org.setName(examStudent.getOrgName());
+            org.setCode(examStudent.getOrgCode());
+            org.setParentId(rootOrgId);
+            org.setRootId(rootOrgId);
+            org.setEnable(true);
+            org.setType(OutletOrgType.SCHOOL);
+            org.setApps("ecs_oe");
+            ResponseEntity<OutletOrg> saveOrgResp = orgClient.save(userToken, org);
+            org = saveOrgResp.getBody();
+        }
+        return org;
+    }
+    
+    /**
+     * 保存课程
+     * @param examStudent
+     * @param userToken
+     * @param rootOrgId
+     * @throws NoSuchCourseLevelException
+     */
+    private void saveCourse(OutletExamStudent examStudent,String userToken,Long rootOrgId) throws NoSuchCourseLevelException{
+    	//判断课程是否存在,不存在则新增
+    	CourseLevel courseLevel = getCourseLevelByCName(examStudent.getCourseLevel());
+    	String courseCode = examStudent.getCourseCode();
+    	if(courseLevel != null){
+    		courseCode = courseLevel.getAbbreviate()+examStudent.getCourseCode();
+    	}
+        log.info("3.保存课程,课程code:"+courseCode);
+        examStudent.setCourseCode(courseCode);
+        ResponseEntity<OutletCourse> getCourseResp = courseClient.getCourseByCode(userToken, rootOrgId, examStudent.getCourseCode());
+        OutletCourse course = getCourseResp.getBody();
+        if (course == null) {
+            course = new OutletCourse();
+            course.setOrgId(rootOrgId);
+            course.setEnable(true);
+            course.setCode(examStudent.getCourseCode());
+            course.setCreateTime(new Date());
+            course.setLevel(getCourseLevelByCName(examStudent.getCourseLevel()));
+            course.setName(examStudent.getCourseName());
+            ResponseEntity<OutletCourse> saveCourseResp = courseClient.save(userToken, course);
+            course = saveCourseResp.getBody();
+        }
+    }
+    
+    /**
+     * 保存学生信息
+     * @param examStudent
+     * @param org
+     * @param userToken
+     * @param rootOrgId
+     * @return
+     */
+    private OutletStudent saveStudent(OutletExamStudent examStudent,OutletOrg org,String userToken,Long rootOrgId) {
+    	//保存学生信息,在保存学生信息的接口中会自动保存用户信息,所以不需要单独调用UserApi去保存用户信息
+    	log.info("4.保存学生信息,学生身份证号:"+examStudent.getIdentityNumber());
+    	OutletStudent student = new OutletStudent();
+        student.setIdentityNumber(examStudent.getIdentityNumber());
+        student.setName(examStudent.getName());
+        student.setStudentCode(examStudent.getStudentCode());
+        User user = new User();
+        user.setOrgId(org.getId());
+        user.setRootOrgId(rootOrgId);
+        user.setEnable(true);
+        student.setUser(user);
+        //查询学生信息是否存在
+        List<OutletStudent> studentList = studentClient.getStudentByIdentityNumber(userToken, examStudent.getIdentityNumber()).getBody();
+        if (studentList == null || studentList.size() < 1) {
+            ResponseEntity<OutletStudent> saveStudentResp = studentClient.save(userToken, student);
+            student = saveStudentResp.getBody();
+        } else {
+        	OutletStudent stu = studentList.get(0);
+            student.setOrgId(org.getId());
+            student.setRootOrgId(rootOrgId);
+            student.setId(stu.getId());
+            student.setUser(stu.getUser());
+            ResponseEntity<OutletStudent> updateStudentResp = studentClient.updateStudent(userToken,student);
+            student = updateStudentResp.getBody();
+        }
+        return student;
+	}
+    
+    /**
+     * 保存考生信息
+     * @param examStudent
+     * @param student
+     * @param org
+     * @param exam
+     * @param userToken
+     * @param rootOrgId
+     * @throws NoSuchCourseLevelException
+     * @throws SaveExamStudentException
+     */
+	private void saveExamStudent(OutletExamStudent examStudent,OutletStudent student,OutletOrg org,OutletExam exam,String userToken,Long rootOrgId) throws NoSuchCourseLevelException, SaveExamStudentException {
+		log.info("5.保存考生信息,考试ID:"+exam.getId()
+							  +"课程code:"+examStudent.getCourseCode()
+							  +",考生身份证号:"+examStudent.getIdentityNumber());
+		//判断考生信息是否存在
+        ResponseEntity<List<OutletExamStudent>> examStudentListResp = examStudentClient.queryExamStudent(userToken, examStudent.getIdentityNumber(), exam.getId(), examStudent.getCourseCode());
+        if (examStudentListResp != null && examStudentListResp.getBody() != null && examStudentListResp.getBody().size() > 0) {
+        	//学生该门课程考试已经存在
+        	List<OutletExamStudent> examStudents = examStudentListResp.getBody();
+        	OutletExamStudent examStudentOld = examStudents.get(0);
+        	//更新相关的姓名、学习中心、专业
+        	examStudentOld.setName(student.getName());
+        	examStudentOld.setOrgId(org.getId());
+        	examStudentOld.setOrgCode(org.getCode());
+        	examStudentOld.setOrgName(org.getName());
+        	examStudentOld.setRootOrgId(rootOrgId);
+        	examStudentOld.setSpecialtyName(examStudent.getSpecialtyName());
+        	 try {
+                 examStudentClient.save(userToken, examStudentOld);
+             } catch (Exception e) {
+                 throw new SaveExamStudentException("保存考生时候出现异常", e);
+             }
+        } else {
+            //学生的该门课程考试不存在
+            examStudent.setStudentId(student.getId());
+            examStudent.setOrgId(org.getId());
+            examStudent.setRootOrgId(rootOrgId);
+            examStudent.setExam(exam);
+            examStudent.setFinished(false);
+            examStudent.setCourseLevel(getCourseLevelByCName(examStudent.getCourseLevel())+"");
+            try {
+                examStudentClient.save(userToken, examStudent);
+            } catch (Exception e) {
+                throw new SaveExamStudentException("保存考生时候出现异常", e);
+            }
+        }
+	}
+    
+    private CourseLevel getCourseLevelByCName(String cname){
+    	if(StringUtils.isBlank(cname)){
+    		return null;
+    	}
+        for(CourseLevel level:CourseLevel.values()){
+        	if(cname.equals(level.getName())){
+        		return level;
+        	}
+        }
+        return null;
+    }
+
+}

+ 338 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/FaceppService.java

@@ -0,0 +1,338 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import cn.com.qmth.examcloud.common.dto.core.Student;
+import cn.com.qmth.examcloud.common.dto.core.StudentFaceInfo;
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.security.entity.AccessUser;
+import cn.com.qmth.examcloud.commons.base.util.GsonUtil;
+import cn.com.qmth.examcloud.outlet.client.ExamStudentClient;
+import cn.com.qmth.examcloud.outlet.client.StudentFaceInfoClient;
+import cn.com.qmth.examcloud.outlet.entity.FaceDetectResponse;
+import cn.com.qmth.examcloud.outlet.exception.*;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+
+
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+@Service
+public class FaceppService {
+	private static final Logger LOG = LoggerFactory.getLogger(FaceppService.class);
+
+    @Value("${app.facepp.api_key}")
+    private String apiKey;
+
+    @Value("${app.facepp.api_secret}")
+    private String apiSecret;
+    
+    @Autowired
+    ExamStudentClient examStudentClient;
+
+    @Autowired
+    UpyunService upyunService;
+
+    @Autowired
+    StudentFaceInfoClient studentFaceInfoClient;
+
+    private void closeResponse(CloseableHttpResponse httpResponse) {
+        if (httpResponse != null) {
+            try {
+                httpResponse.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                httpResponse = null;
+            }
+        }
+    }
+
+    /**
+     * 检测人脸
+     *
+     * @param imageUrl
+     * @return 检测到的人脸的face_token
+     * @throws URISyntaxException
+     * @throws DetectNoFaceException
+     */
+    public String detectSingleFace(String imageUrl) throws URISyntaxException, DetectNoFaceException {
+        int time = 3;//重新检测次数为3次
+        String faceToken = "";
+        while (time > 0) {
+            //调用人脸识别接口
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            URI uri = new URIBuilder()
+                    .setScheme("https")
+                    .setHost("api-cn.faceplusplus.com")
+                    .setPath("/facepp/v3/detect")
+                    .setParameter("api_key", apiKey)
+                    .setParameter("api_secret", apiSecret)
+                    .setParameter("image_url", imageUrl)
+                    .build();
+
+            HttpPost httpPost = new HttpPost(uri);
+            CloseableHttpResponse httpResponse = null;
+            try {
+            	httpResponse = httpClient.execute(httpPost);
+                HttpEntity responseEntity = httpResponse.getEntity();
+                int statusCode = httpResponse.getStatusLine().getStatusCode();
+                BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent()));
+                if (statusCode == 200) {
+                	Gson gson = new GsonBuilder().create();
+                    FaceDetectResponse faceDetectResponse = gson.fromJson(reader, FaceDetectResponse.class);
+                    if (faceDetectResponse.getFaces() != null && faceDetectResponse.getFaces().size() > 0) {
+                        faceToken = faceDetectResponse.getFaces().get(0).getFace_token();
+                        break;
+                    } else {
+                        throw new DetectNoFaceException();
+                    }
+                } else {
+                     StringBuffer buffer = new StringBuffer();
+                     String str = "";
+                     while(StringUtils.isNoneBlank((str = reader.readLine()))) {
+                         buffer.append(str);
+                     }
+                     String result = buffer.toString();
+                     LOG.info("获取token失败:"+result);
+                     time--;
+                }
+                httpClient.close();
+            } catch (IOException e) {
+                //重试
+                LOG.error("检测人脸失败,剩余次数:" + (time - 1), e);
+                time--;
+                if (time < 1) {
+                    throw new DetectNoFaceException();
+                }
+            }finally{
+            	closeResponse(httpResponse);
+            }
+        }
+        LOG.info("检测到人脸token:" + faceToken);
+        return faceToken;
+    }
+
+    /**
+     * 将人脸加入到人脸集合
+     *
+     * @param faceToken
+     * @param facesetToken
+     * @throws URISyntaxException
+     */
+    public boolean addFace(String faceToken, String facesetToken) throws URISyntaxException {
+        boolean success = false;
+        int time = 3;//重新检测次数为3次
+        while (time > 0) {
+            //调用人脸识别接口
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            URI uri = new URIBuilder()
+                    .setScheme("https")
+                    .setHost("api-cn.faceplusplus.com")
+                    .setPath("/facepp/v3/faceset/addface")
+                    .setParameter("api_key", apiKey)
+                    .setParameter("api_secret", apiSecret)
+                    .setParameter("faceset_token", facesetToken)
+                    .setParameter("face_tokens", faceToken)
+                    .build();
+
+            HttpPost httpPost = new HttpPost(uri);
+            CloseableHttpResponse httpResponse = null;
+            try {
+                httpResponse = httpClient.execute(httpPost);
+                StatusLine statusLine = httpResponse.getStatusLine();
+                //不能这么打印,会导致流关闭,从而造成异常。除非下面到代码不需要从流读取响应内容,则这里可以打印
+                LOG.info("添加人脸到集合响应:" + EntityUtils.toString(httpResponse.getEntity()));
+                if (statusLine.getStatusCode() == 200) {
+                    success = true;
+                    //加入成功
+                    break;
+                } else {
+                    time--;
+                }
+            } catch (IOException e) {
+                LOG.error("添加人脸失败,剩余次数:" + (time - 1), e);
+                time--;
+            } finally {
+                closeResponse(httpResponse);
+            }
+        }
+        return success;
+    }
+    
+    
+    /**
+     * 添加人脸到人脸集合
+     * @param faceToken
+     * @return 添加成功则返回faceset_token,否则返回null
+     * @throws URISyntaxException
+     */
+/*    public String createFaceset(String faceToken) throws URISyntaxException {
+        int time = 3;//重新检测次数为3次
+        while (time > 0) {
+
+
+            //调用人脸识别接口
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            URI uri = new URIBuilder()
+                    .setScheme("https")
+                    .setHost("api-cn.faceplusplus.com")
+                    .setPath("/facepp/v3/faceset/create")
+                    .setParameter("api_key", apiKey)
+                    .setParameter("api_secret", apiSecret)
+                    .setParameter("face_tokens", faceToken)
+                    .build();
+
+            HttpPost httpPost = new HttpPost(uri);
+            CloseableHttpResponse httpResponse = null;
+            try {
+                httpResponse = httpClient.execute(httpPost);
+                StatusLine statusLine = httpResponse.getStatusLine();
+                if (statusLine.getStatusCode() == 200) {
+                    HttpEntity httpEntity = httpResponse.getEntity();
+                    Gson gson = new GsonBuilder().create();
+                    Reader reader = new InputStreamReader(httpEntity.getContent());
+                    CreateFacesetResponse faceDetectResponse = gson.fromJson(reader, CreateFacesetResponse.class);
+                    if (!StringUtils.isEmpty(faceDetectResponse.getFaceset_token())) {
+                        return faceDetectResponse.getFaceset_token();
+                    }
+                }
+                //准备重试
+                time--;
+            } catch (IOException e) {
+                //重试
+                LOG.error("保存人脸失败,剩余次数:" + (time - 1), e);
+                time--;
+            } finally {
+                closeResponse(httpResponse);
+            }
+        }
+        return null;
+    }*/
+
+    public void processOne(User accessUser, String fileName, byte[] dataBytes, Long rootOrgId) throws
+            InvalidJpgException, ExamStudentNotExistException, NoSuchAlgorithmException,
+            DetectNoFaceException, URISyntaxException, FaceppException, UpYunException {
+    	String userToken = accessUser.getUserToken();
+        String[] nameAndSuffix = fileName.split("\\.");
+        if (nameAndSuffix.length < 2) {
+            throw new InvalidJpgException(fileName + "不是一个照片文件");
+        }
+        String identityNumber = (nameAndSuffix[0].startsWith("/") || nameAndSuffix[0].startsWith("\\")) ? nameAndSuffix[0].substring(1) : nameAndSuffix[0];
+        String suffix = nameAndSuffix[1];
+        LOG.info("文件名为 :" + identityNumber + ",后缀名为:" + suffix);
+        //根据身份证号码,查询考生是否存在
+        LOG.info("查询身份证号码为 :" + identityNumber + "的学生");
+        String json = examStudentClient.getExamStudentByIdentityNumber(userToken, identityNumber);
+        //LOG.info("查询结果为 :" + json);
+        if (StringUtils.isEmpty(json)) {
+            LOG.error("身份证号为:" + identityNumber + "的考生不存在");
+            throw new ExamStudentNotExistException();
+        } else {
+            List<ExamStudent> examStudentList = GsonUtil.jsonToArrayList(json, ExamStudent.class);
+
+            if (examStudentList.size() < 1) {
+                LOG.error("身份证号为:" + identityNumber + "的考生不存在");
+                throw new ExamStudentNotExistException();
+            }
+            ExamStudent examStudent = examStudentList.get(0);
+            //保存学生照片到又拍云
+            String upyunFileName = upyunService.getMd5(dataBytes);
+            try {
+                if (upyunService.saveStudentPhoto(identityNumber, dataBytes, upyunFileName, "." + suffix)) {
+                    //调用人脸识别接口
+                    String faceToken = detectSingleFace(upyunService.getDownloadUrl(identityNumber, upyunFileName, "." + suffix));
+                    if(StringUtils.isBlank(faceToken)){
+                    	 throw new FaceppException(identityNumber+"获取token失败");
+                    }
+                    String facesetToken = studentFaceInfoClient.getFaceSet();
+                    ResponseEntity<StudentFaceInfo> studentFaceInfoResponseEntity = studentFaceInfoClient.getByIdentityNumber(userToken, identityNumber, rootOrgId);
+                    StudentFaceInfo studentFaceInfo = studentFaceInfoResponseEntity.getBody();
+                    if (addFace(faceToken,facesetToken)){
+                    	String photoMD5 = upyunFileName+"."+suffix;
+                    	saveStudentFaceInfo(studentFaceInfo,
+                    					    photoMD5,	
+			                    			faceToken,
+			                    			facesetToken,
+			                    			examStudent.getStudentId(),
+			                    			accessUser.getDisplayName(),
+			                    			"INTERFACE_ADD",
+			                    			userToken);
+                    } else {
+                        throw new FaceppException(identityNumber + "保存当前faceToken到人脸集合(faceSet)失败");
+                    }
+                } else {
+                    throw new UpYunException("身份证号为:" + identityNumber + "的考生照片保存到又拍云失败");
+                }
+            } catch (IOException e) {
+                throw new RuntimeException("身份证号为:" + identityNumber + "的考生照片保存失败", e);
+            }
+        }
+    }
+    
+    /**
+     * 保存studentFaceInfo
+     * @param studentFaceInfo
+     * @param photoMD5
+     * @param faceToken
+     * @param facesetToken
+     * @param studentId
+     * @param accessUserName
+     * @param createType
+     * @param userToken
+     */
+    public void saveStudentFaceInfo(StudentFaceInfo studentFaceInfo,
+						    		String photoMD5,
+						    		String faceToken,
+						    		String facesetToken,
+						    		Long studentId,
+						    		String accessUserName,
+						    		String createType,
+						    		String userToken){
+    	if (studentFaceInfo == null) {
+            studentFaceInfo = new StudentFaceInfo();
+            Student student = new Student();
+            student.setId(studentId);
+            studentFaceInfo.setStudent(student);
+            studentFaceInfo.setCreateUser(accessUserName);
+            studentFaceInfo.setCreateTime(new Date());
+        } else {
+            studentFaceInfo.setUpdateUser(accessUserName);
+            studentFaceInfo.setUpdateTime(new Date());
+        }
+        studentFaceInfo.setFaceToken(faceToken);
+        studentFaceInfo.setFaceSetToken(facesetToken);
+        studentFaceInfo.setPhotoMD5(photoMD5);
+        studentFaceInfo.setCreateType(createType);
+    	studentFaceInfoClient.save(userToken, studentFaceInfo);
+    }
+}

+ 62 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/OutletScoreService.java

@@ -0,0 +1,62 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+
+/**
+ * @author  	chenken
+ * @date    	2018年1月3日 下午3:37:36
+ * @company 	QMTH
+ * @description OutletScoreService.java
+ */
+public interface OutletScoreService {
+	/**
+	 * 根据oe_exam_score 的ID查询
+	 * 供推送成绩使用
+	 * @param scoreId
+	 * @return
+	 */
+	List<OutletScore> getExamScoreById(Long scoreId)  throws Exception;
+	/**
+	 * 
+	 * @param rootOrgId
+	 * @param examName
+	 * @param studentCode
+	 * @param courseCode
+	 * @return
+	 * @throws Exception
+	 */
+	List<OutletScore> queryExamScoreBy(Long rootOrgId,String examName,String studentCode,String courseCode) throws Exception;
+	/**
+	 * 
+	 * @param examRemark
+	 * @param examStuRemark
+	 * @param examOrgId
+	 * @return
+	 * @throws Exception
+	 */
+	List<OutletScore> queryExamScore(String examName, String examStuRemark, Long examOrgId)  throws Exception ;
+    /**
+     * 按身份证号查询成绩
+     * @param identityNumber 身份证号
+     * @return
+     */
+    List<OutletScore> queryExamScoreByIdentityNumbers(List<String> identityNumbers, Long examOrgId)  throws Exception;
+    /**
+     * 按考试名称和身份证号查询成绩
+     * @param identityNumber 身份证号
+     * @return
+     */
+    List<OutletScore> queryExamScoreByExamNameAndIdentityNumbers(String examName,List<String> identityNumbers, Long examOrgId) throws Exception;
+    /**
+     * 根据机构ID,批次名称,课程code,学号List查询考生成绩
+     * @param orgId
+     * @param batchName
+     * @param courseCode
+     * @param studentCodes
+     * @return
+     */
+    List<OutletScore> queryExamScoreBy(Long orgId,String batchName, String courseCode,List<String> studentCodes) throws Exception;
+}
+

+ 16 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/ScorePushService.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamRecordDto;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月17日 上午11:00:13
+ * @company 	QMTH
+ * @description 分数推送接口
+ */
+public interface ScorePushService {
+
+	public void scorePush(ExamRecordDto examRecordDto) throws Exception;
+	
+}
+

+ 19 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/StudentInfoService.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.outlet.dto.StudentInfoReq;
+
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午4:33:13
+ * @company 	QMTH
+ * @description StudentInfoService.java
+ */
+public interface StudentInfoService {
+
+	public void saveStudentInfo(List<StudentInfoReq> studentInfoReqs,String userToken,Long rootOrgId) throws Exception ;
+	
+}
+

+ 111 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/UpyunService.java

@@ -0,0 +1,111 @@
+package cn.com.qmth.examcloud.outlet.service;
+
+import main.java.com.UpYun;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Created by yuanpan on 2017/5/11.
+ */
+@Service
+public class UpyunService {
+
+    private UpYun upyun;
+
+    @Value("${app.upyun.path}")
+    private String path;
+
+    @Value("${app.upyun.bucket}")
+    private String bucket;
+
+    @Value("${app.upyun.operator}")
+    private String operator;
+
+    @Value("${app.upyun.password}")
+    private String password;
+
+    public String getDownloadUrl(String identityNumber, String fileName, String fileSuffix) {
+//        http://exam-cloud-test.b0.upaiyun.com/student_base_photo/420678442922121/11b1841125259151f0347415d1740595.jpg
+
+        if (fileSuffix.startsWith(".")) {
+            return "http://" + bucket + ".b0.upaiyun.com/student_base_photo/" + identityNumber + "/" + fileName + "" + fileSuffix;
+        } else {
+            return "http://" + bucket + ".b0.upaiyun.com/student_base_photo/" + identityNumber + "/" + fileName + "." + fileSuffix;
+        }
+
+    }
+
+    public String getMd5(byte[] bytes) throws NoSuchAlgorithmException {
+        //用来计算md5摘要的
+        char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+        MessageDigest md5 = MessageDigest.getInstance("MD5");
+        md5.update(bytes);
+
+        byte[] md5DigestBytes = md5.digest();
+        int dlen = md5DigestBytes.length;
+
+        char[] md5val = new char[dlen * 2];
+        int k = 0;
+        for (byte encoded : md5DigestBytes) {
+            md5val[k++] = hexDigits[encoded >> 4 & 15];
+            md5val[k++] = hexDigits[encoded & 5];
+        }
+
+        return new String(md5val);
+    }
+
+    public boolean saveStudentPhoto(String identityNumber, byte[] bytes, String fileName, String fileSuffix) throws IOException {
+
+        if (fileSuffix.startsWith(".")) {
+            return getUpyun().writeFile(path + "/" + identityNumber + "/" + fileName + fileSuffix, bytes, true);
+        } else {
+            return getUpyun().writeFile(path + "/" + identityNumber + "/" + fileName + "." + fileSuffix, bytes, true);
+        }
+
+    }
+
+    /**
+     * 保存照片到又拍云
+     *
+     * @param identityNumber
+     * @param bytes
+     * @param fileSuffix
+     * @return
+     * @throws IOException
+     */
+    public boolean saveStudentPhoto(String identityNumber, byte[] bytes, String fileSuffix) throws IOException, NoSuchAlgorithmException {
+
+        //用来计算md5摘要的
+        char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+        MessageDigest md5 = MessageDigest.getInstance("MD5");
+        md5.update(bytes);
+
+        byte[] md5DigestBytes = md5.digest();
+        int dlen = md5DigestBytes.length;
+
+        char[] md5val = new char[dlen * 2];
+        int k = 0;
+        for (byte encoded : md5DigestBytes) {
+            md5val[k++] = hexDigits[encoded >> 4 & 15];
+            md5val[k++] = hexDigits[encoded & 5];
+        }
+
+        String fileName = new String(md5val);
+
+        return saveStudentPhoto(identityNumber, bytes, fileName, fileSuffix);
+
+    }
+
+    private UpYun getUpyun() {
+        if (upyun == null) {
+            upyun = new UpYun(bucket, operator, password);
+        }
+        return upyun;
+    }
+}

+ 78 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/ExamServiceImpl.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.outlet.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.em.enums.ExamType;
+import cn.com.qmth.examcloud.outlet.client.ExamClient;
+import cn.com.qmth.examcloud.outlet.dto.ExamReq;
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamException;
+import cn.com.qmth.examcloud.outlet.service.ExamService;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午3:29:39
+ * @company 	QMTH
+ * @description ExamServiceImpl.java
+ */
+@Service("examService")
+public class ExamServiceImpl implements ExamService {
+
+	@Autowired
+	private ExamClient examClient;
+	
+	@Override
+	public OutletExam createExam(ExamReq examReq,String userToken,Long rootOrgId) throws Exception {
+		checkExamReq(examReq);
+		OutletExam exam = new OutletExam();
+        ResponseEntity<List<OutletExam>> examListResp = examClient.queryByName(userToken,examReq.getName());
+        //判断考试是否存在
+        if (examListResp != null && examListResp.getBody() != null && examListResp.getBody().size() > 0) {
+            exam = examListResp.getBody().get(0);
+        } else {
+        	exam.setName(examReq.getName());
+        	exam.setBeginTime(examReq.getBeginTime());
+        	exam.setEndTime(examReq.getEndTime());
+        	exam.setRemark(examReq.getName());//备注填考试名称
+        	exam.setExamType(strToEnum(examReq.getExamType()));
+        	exam.setDuration(examReq.getDuration());
+        	exam.setEnable(true);		//默认开启考试
+            exam.setOrgId(rootOrgId);	//设置 机构
+            ResponseEntity<OutletExam> saveExamResp = examClient.save(userToken, exam);
+            exam = saveExamResp.getBody();
+        }
+        exam.setAfterExamRemark(null);//考后说明置空
+        exam.setBeforeExamRemark(null);////靠前说明置空
+        return exam;
+	}
+
+	private void checkExamReq(ExamReq examReq) {
+		if(examReq == null){
+			throw new SaveExamException("考试信息不能为空");
+		}
+		if(examReq.getName() == null){
+			throw new SaveExamException("考试名称不能为空");
+		}
+		if(examReq.getBeginTime() == null){
+			throw new SaveExamException("考试开始时间不能为空");
+		}
+		if(examReq.getEndTime() == null){
+			throw new SaveExamException("考试结束时间不能为空");
+		}
+	}
+	
+	public ExamType strToEnum(String str){
+    	for(ExamType examType:ExamType.values()){
+    		if(examType.name().equals(str)){
+    			return examType;
+    		}
+    	}
+    	return null;
+    }
+
+}
+

+ 239 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/OutletScoreServiceImpl.java

@@ -0,0 +1,239 @@
+package cn.com.qmth.examcloud.outlet.service.impl;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamRecord;
+import cn.com.qmth.examcloud.common.dto.em.ExamScore;
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+import cn.com.qmth.examcloud.common.dto.em.enums.ExamRecordStatus;
+import cn.com.qmth.examcloud.common.dto.em.enums.MarkingType;
+import cn.com.qmth.examcloud.outlet.dao.ExamRecordDao;
+import cn.com.qmth.examcloud.outlet.dao.ExamScoreDao;
+import cn.com.qmth.examcloud.outlet.dao.OutletScoreDao;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import cn.com.qmth.examcloud.outlet.service.OutletScoreService;
+
+/**
+ * @author  	chenken
+ * @date    	2018年1月3日 下午3:39:23
+ * @company 	QMTH
+ * @description OutletScoreServiceImpl.java
+ */
+@Service("outletScoreService")
+public class OutletScoreServiceImpl implements OutletScoreService{
+
+	@Autowired
+	private OutletScoreDao outletScoreDao;
+	
+	@Autowired
+	private ExamRecordDao examRecordDao;
+	
+	@Autowired
+	private ExamScoreDao examScoreDao;
+	
+	@Override
+	public List<OutletScore> getExamScoreById(Long scoreId)  throws Exception{
+		if(scoreId == null){
+			return null;
+		}
+		return outletScoreDao.getExamScoreById(scoreId);
+	}
+	
+	@Override
+	public List<OutletScore> queryExamScore(String examName, String examStuRemark,Long examOrgId) throws Exception {
+		if(StringUtils.isBlank(examName) || examOrgId == null){
+			return null;
+		}
+		List<ExamStudent> examStudents = outletScoreDao.findExamStudents(examName, examStuRemark, examOrgId);
+		return getExamStudentsScore(examStudents);
+	}
+
+	@Override
+	public List<OutletScore> queryExamScoreByIdentityNumbers(List<String> identityNumbers, Long examOrgId) throws Exception {
+		if(identityNumbers==null||identityNumbers.size()==0||examOrgId == null){
+			return null;
+		}
+		List<ExamStudent> examStudents = outletScoreDao.findExamStudents(identityNumbers,examOrgId);
+		return getExamStudentsScore(examStudents);
+	}
+	
+	@Override
+	public List<OutletScore> queryExamScoreBy(Long orgId,String batchName,String courseCode, List<String> studentCodes) throws Exception {
+		List<ExamStudent> examStudents = outletScoreDao.findExamStudents(orgId,batchName,courseCode,studentCodes);
+		return getExamStudentsScore(examStudents);
+	}
+	
+	private List<OutletScore> getExamStudentsScore(List<ExamStudent> examStudents) throws Exception{
+		List<OutletScore> outletScoreList = new ArrayList<OutletScore>();
+		
+		for(ExamStudent examStudent:examStudents){
+			OutletScore outletScore = new OutletScore(examStudent);
+			outletScore = findExamData(outletScore,examStudent);
+			outletScoreList.add(outletScore);
+		}
+		return outletScoreList;
+	}
+	
+	private OutletScore findExamData(OutletScore outletScore,ExamStudent examStudent) throws Exception{
+        List<ExamRecord> examRecordList = examRecordDao.findByExamStudentId(examStudent.getId());
+        Boolean isFinished = examStudent.getFinished();
+        if(isFinished==null){
+        	isFinished = false;
+        }
+        //是否缺考
+        outletScore.setIsMissExam(!isFinished);
+        //是否违纪
+        outletScore.setIsBreachThePrinciple(isBreachThePrinciple(isFinished,examRecordList));
+        //最终成绩
+        setFinalExamScoreAndEndTime(isFinished,outletScore,examRecordList,examStudent);
+        return outletScore;
+    }
+	
+	/**
+	 * 1.设置最终成绩
+	 * 2.设置考试结束时间
+	 */
+	public void setFinalExamScoreAndEndTime(Boolean isFinished,OutletScore outletScore,List<ExamRecord> examRecordList,ExamStudent examStudent){
+		if(!isFinished){
+			return;
+		}
+		ExamScore examScore = finalExamScore(examRecordList,examStudent.getExam().getMarkingType());
+    	if(examScore != null){
+    		outletScore.setScoreId(examScore.getId());
+            outletScore.setTotalScore(examScore.getTotalScore());
+            outletScore.setObjectiveScore(examScore.getObjectiveScore());
+            outletScore.setSubjectiveScore(examScore.getSubjectiveScore());
+            //设置考试结束时间和人脸识别成功率
+            ExamRecord examRecord = examRecordDao.findByScoreId(examScore.getId());
+            if(examRecord != null){
+            	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            	Date endTime =  examRecord.getEndTime();
+                if(endTime == null){
+                	endTime = examRecord.getCleanTime();
+                }
+                outletScore.setEndTime(endTime == null?null:sdf.format(endTime));
+            }
+    	}
+	}
+
+	/**
+	 * 查询并计算最终成绩
+	 * @param isFinished
+	 * @param examRecordList
+	 * @param markingType
+	 */
+	private ExamScore finalExamScore(List<ExamRecord> examRecordAllList, MarkingType markingType) {
+    	//第一次过滤考试记录:正常结束或者被系统处理的
+    	List<ExamRecord> firstFilterExamRecordList = examRecordAllList.stream().filter(examRecord->{
+    		return  examRecord.getStatus() == ExamRecordStatus.EXAM_END || 
+    				examRecord.getStatus() == ExamRecordStatus.EXAM_OVERDUE;
+    	}).collect(Collectors.toList());
+    	
+        if (firstFilterExamRecordList != null && firstFilterExamRecordList.size()>0) {
+        	/**
+        	 * 第二次过滤考试记录:过滤出有效的考试记录 
+        	 * 1.没有警告的也没有违纪的
+        	 * 2.有警告已审核通过的且没有违纪的
+        	 */
+            Stream<ExamRecord> secondFilterExamRecordStream = firstFilterExamRecordList.stream().filter(examRecord -> {
+                return (!examRecord.getIsWarn() && examRecord.getInvigilatorOperation() != 1) 
+                	|| (examRecord.getIsWarn() && examRecord.getIsAudit() && examRecord.getInvigilatorOperation() != 1);
+            });
+            
+            List<ExamRecord> secondFilterExamRecords = secondFilterExamRecordStream.collect(Collectors.toList());
+            if(secondFilterExamRecords == null|| secondFilterExamRecords.size() == 0){
+            	return null;
+            }
+            //取出有效记录的成绩
+            List<Long> examRecordIds = new ArrayList<Long>();
+            for(int i = 0;i<secondFilterExamRecords.size();i++){
+            	examRecordIds.add(secondFilterExamRecords.get(i).getId());
+            }
+            List<ExamScore> effectiveExamScoreList = examScoreDao.findByExamRecordIdIn(examRecordIds);
+            
+            //全部评阅规则或客观分最高规则:取总分最高
+            if(markingType == MarkingType.ALL||markingType == MarkingType.OBJECT_SCORE_MAX){
+				List<ExamScore> examScores = effectiveExamScoreList
+											.stream()
+											.sorted((o1,o2)->o2.getTotalScore().compareTo(o1.getTotalScore()))
+											.collect(Collectors.toList());
+				return examScores.get(0);
+            }else if(markingType == MarkingType.LAST_SUBMIT){
+            	//最后一次提交规则:取最后一次的成绩
+            	List<ExamScore> examScores = effectiveExamScoreList
+											.stream()
+											.sorted((o1,o2)->o2.getId().compareTo(o1.getId()))
+											.collect(Collectors.toList());
+				return examScores.get(0);
+			}else if(markingType == null){
+				//离线考试
+				if(effectiveExamScoreList != null&& effectiveExamScoreList.size()>0){
+					return effectiveExamScoreList.get(0);
+				}
+			}
+        }
+        return null;
+	}
+
+	/**
+	 * 是否违纪
+	 * @param isFinished
+	 * @param examRecordList
+	 * @return
+	 */
+	private Boolean isBreachThePrinciple(Boolean isFinished,List<ExamRecord> examRecordList) {
+		if(!isFinished){
+    		return null;
+    	}
+		if(examRecordList==null || examRecordList.size()==0){
+			return false;
+		}
+    	List<ExamRecord> examRecordFilterList = examRecordList.stream().filter(examRecord -> {
+    		return  examRecord.getInvigilatorOperation() == 1;
+    	}).collect(Collectors.toList());
+        return (examRecordFilterList == null || examRecordFilterList.size()==0)?false:true;
+	}
+
+	@Override
+	public List<OutletScore> queryExamScoreByExamNameAndIdentityNumbers(
+			String examName, List<String> identityNumbers, Long examOrgId)
+			throws Exception {
+		if(StringUtils.isBlank(examName)){
+			return null;
+		}
+		if(identityNumbers==null||identityNumbers.size()==0||examOrgId == null){
+			return null;
+		}
+		List<ExamStudent> examStudents = outletScoreDao.findExamStudents(examName,identityNumbers,examOrgId);
+		return getExamStudentsScore(examStudents);
+	}
+
+	@Override
+	public List<OutletScore> queryExamScoreBy(Long rootOrgId, String examName,
+			String studentCode, String courseCode) throws Exception {
+		if(rootOrgId == null){
+			return null;
+		}
+		if(examName == null){
+			return null;
+		}
+		if(studentCode == null){
+			return null;
+		}
+		if(courseCode == null){
+			return null;
+		}
+		return outletScoreDao.queryExamScoreBy(rootOrgId, examName, studentCode, courseCode);
+	}
+
+}
+

+ 295 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/StudentInfoServiceImpl.java

@@ -0,0 +1,295 @@
+package cn.com.qmth.examcloud.outlet.service.impl;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.core.User;
+import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
+import cn.com.qmth.examcloud.outlet.client.CourseClient;
+import cn.com.qmth.examcloud.outlet.client.ExamClient;
+import cn.com.qmth.examcloud.outlet.client.ExamStudentClient;
+import cn.com.qmth.examcloud.outlet.client.OrgClient;
+import cn.com.qmth.examcloud.outlet.client.StudentClient;
+import cn.com.qmth.examcloud.outlet.dto.StudentInfoReq;
+import cn.com.qmth.examcloud.outlet.entity.OutletCourse;
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+import cn.com.qmth.examcloud.outlet.entity.OutletExamStudent;
+import cn.com.qmth.examcloud.outlet.entity.OutletOrg;
+import cn.com.qmth.examcloud.outlet.entity.OutletStudent;
+import cn.com.qmth.examcloud.outlet.enums.OutletOrgType;
+import cn.com.qmth.examcloud.outlet.exception.NoSuchCourseLevelException;
+import cn.com.qmth.examcloud.outlet.exception.SaveExamStudentException;
+import cn.com.qmth.examcloud.outlet.service.StudentInfoService;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月7日 下午4:33:27
+ * @company 	QMTH
+ * @description StudentInfoServiceImpl.java
+ */
+@Service("studentInfoService")
+public class StudentInfoServiceImpl implements StudentInfoService {
+
+	private static final Logger log = LoggerFactory.getLogger(StudentInfoServiceImpl.class);
+	
+    @Autowired
+    private OrgClient orgClient;
+
+    @Autowired
+    private ExamClient examClient;
+
+    @Autowired
+    private CourseClient courseClient;
+
+    @Autowired
+    private StudentClient studentClient;
+
+    @Autowired
+    private ExamStudentClient examStudentClient;
+	
+	@Override
+	public void saveStudentInfo(List<StudentInfoReq> studentInfoReqs,String userToken,Long rootOrgId) throws Exception {
+		log.info("创建考试和导入学生开始");
+		OutletExam exam = chechExamStudentInfo(studentInfoReqs,rootOrgId,userToken);
+        for (StudentInfoReq studentInfoReq : studentInfoReqs) {
+        	OutletOrg org = saveOrg(studentInfoReq,userToken,rootOrgId);
+            
+        	OutletCourse course = saveCourse(studentInfoReq,userToken,rootOrgId);
+        	
+        	OutletStudent student = saveStudent(studentInfoReq,org,userToken,rootOrgId);
+        	
+        	saveExamStudent(studentInfoReq,student,course,org,exam,userToken,rootOrgId);
+        }
+        log.info("创建考试和导入学生完成");
+	}
+
+	/**
+     * 保存学习中心
+     * @param studentInfoReq
+     * @param userToken
+     * @param rootOrgId
+     * @return
+     */
+    private OutletOrg saveOrg(StudentInfoReq studentInfoReq,String userToken,Long rootOrgId){
+    	log.info("2.保存学习中心,学习中心code:"+studentInfoReq.getOrgCode());
+    	//判断学习中心是否存在,不存在则创建
+        String orgCode = studentInfoReq.getOrgCode();
+        //根据orgCode,查询学习中心
+        ResponseEntity<OutletOrg> orgResponseEntity = orgClient.findByParentIdAndCode(userToken, rootOrgId, orgCode);
+        OutletOrg org = orgResponseEntity.getBody();
+        if (org == null) {
+            org = new OutletOrg();
+            org.setName(studentInfoReq.getOrgName());
+            org.setCode(studentInfoReq.getOrgCode());
+            org.setParentId(rootOrgId);
+            org.setRootId(rootOrgId);
+            org.setEnable(true);
+            org.setType(OutletOrgType.SCHOOL);
+            ResponseEntity<OutletOrg> saveOrgResp = orgClient.save(userToken, org);
+            org = saveOrgResp.getBody();
+        }
+        return org;
+    }
+    
+    /**
+     * 保存课程
+     * @param studentInfoReq
+     * @param userToken
+     * @param rootOrgId
+     * @throws NoSuchCourseLevelException
+     */
+    private OutletCourse saveCourse(StudentInfoReq studentInfoReq,String userToken,Long rootOrgId) throws NoSuchCourseLevelException{
+    	//判断课程是否存在,不存在则新增
+    	String courseCode = studentInfoReq.getCourseCode();
+    	if(StringUtils.isNotBlank(studentInfoReq.getCourseLevel())){
+    		CourseLevel courseLevel = getCourseLevelByCName(studentInfoReq.getCourseLevel());
+    		if(courseLevel!=null){
+    			courseCode = courseLevel.getAbbreviate()+studentInfoReq.getCourseCode();
+    		}
+    	}
+    	
+        log.info("3.保存课程,课程code:"+courseCode);
+        studentInfoReq.setCourseCode(courseCode);
+        ResponseEntity<OutletCourse> getCourseResp = courseClient.getCourseByCode(userToken, rootOrgId, studentInfoReq.getCourseCode());
+        OutletCourse course = getCourseResp.getBody();
+        if (course == null) {
+            course = new OutletCourse();
+            course.setOrgId(rootOrgId);
+            course.setEnable(true);
+            course.setCode(studentInfoReq.getCourseCode());
+            course.setCreateTime(new Date());
+            if(StringUtils.isNotBlank(studentInfoReq.getCourseLevel())){
+            	course.setLevel(getCourseLevelByCName(studentInfoReq.getCourseLevel()));
+            }
+            course.setName(studentInfoReq.getCourseName());
+            ResponseEntity<OutletCourse> saveCourseResp = courseClient.save(userToken, course);
+            course = saveCourseResp.getBody();
+        }
+        return course;
+    }
+    
+    /**
+     * 保存学生信息
+     * @param studentInfoReq
+     * @param org
+     * @param userToken
+     * @param rootOrgId
+     * @return
+     */
+    private OutletStudent saveStudent(StudentInfoReq studentInfoReq,OutletOrg org,String userToken,Long rootOrgId) {
+    	//保存学生信息,在保存学生信息的接口中会自动保存用户信息,所以不需要单独调用UserApi去保存用户信息
+    	log.info("4.保存学生信息,学生身份证号:"+studentInfoReq.getIdentityNumber());
+    	OutletStudent student = new OutletStudent();
+        student.setIdentityNumber(studentInfoReq.getIdentityNumber());
+        student.setName(studentInfoReq.getStudentName());
+        student.setStudentCode(studentInfoReq.getStudentCode());
+        User user = new User();
+        user.setOrgId(org.getId());
+        user.setRootOrgId(rootOrgId);
+        user.setEnable(true);
+        student.setUser(user);
+        //查询学生信息是否存在
+        List<OutletStudent> studentList = studentClient.getStudentByIdentityNumber(userToken, studentInfoReq.getIdentityNumber()).getBody();
+        if (studentList == null || studentList.size() < 1) {
+        	student.setCreateTime(new Date());
+            ResponseEntity<OutletStudent> saveStudentResp = studentClient.save(userToken, student);
+            student = saveStudentResp.getBody();
+        } else {
+        	OutletStudent stu = studentList.get(0);
+            student.setOrgId(org.getId());
+            student.setRootOrgId(rootOrgId);
+            student.setId(stu.getId());
+            student.setUser(stu.getUser());
+            ResponseEntity<OutletStudent> updateStudentResp = studentClient.updateStudent(userToken,student);
+            student = updateStudentResp.getBody();
+        }
+        return student;
+	}
+    
+    /**
+     * 保存考生信息
+     * @param studentInfoReq
+     * @param student
+     * @param org
+     * @param exam
+     * @param userToken
+     * @param rootOrgId
+     * @throws NoSuchCourseLevelException
+     * @throws SaveExamStudentException
+     */
+	private void saveExamStudent(StudentInfoReq studentInfoReq,OutletStudent student,OutletCourse course,OutletOrg org,OutletExam exam,String userToken,Long rootOrgId) throws NoSuchCourseLevelException, SaveExamStudentException {
+		log.info("5.保存考生信息,考试ID:"+exam.getId()
+							  +"课程code:"+studentInfoReq.getCourseCode()
+							  +",考生身份证号:"+studentInfoReq.getIdentityNumber());
+		//判断考生信息是否存在
+        ResponseEntity<List<OutletExamStudent>> examStudentListResp = examStudentClient.queryExamStudent(userToken, studentInfoReq.getIdentityNumber(), exam.getId(), studentInfoReq.getCourseCode());
+        if (examStudentListResp != null && examStudentListResp.getBody() != null && examStudentListResp.getBody().size() > 0) {
+        	//学生该门课程考试已经存在
+        	List<OutletExamStudent> examStudents = examStudentListResp.getBody();
+        	OutletExamStudent examStudentOld = examStudents.get(0);
+        	//更新相关的姓名、学习中心、专业
+        	examStudentOld.setName(student.getName());
+        	examStudentOld.setOrgId(org.getId());
+        	examStudentOld.setOrgCode(org.getCode());
+        	examStudentOld.setOrgName(org.getName());
+        	examStudentOld.setRootOrgId(rootOrgId);
+        	examStudentOld.setSpecialtyName(studentInfoReq.getSpecialtyName());
+        	 try {
+                 examStudentClient.save(userToken, examStudentOld);
+             } catch (Exception e) {
+                 throw new SaveExamStudentException("保存考生失败");
+             }
+        } else {
+        	//考生不存在
+        	OutletExamStudent examStudent =  initExamStudent(studentInfoReq,student,org,exam,course,rootOrgId);
+            try {
+                examStudentClient.save(userToken, examStudent);
+            } catch (Exception e) {
+                throw new SaveExamStudentException("保存考生失败");
+            }
+        }
+	}
+    
+    private OutletExamStudent initExamStudent(StudentInfoReq studentInfoReq,OutletStudent student, OutletOrg org, OutletExam exam,OutletCourse course,Long rootOrgId){
+    	OutletExamStudent examStudent = new OutletExamStudent();
+    	examStudent.setName(studentInfoReq.getStudentName());
+    	examStudent.setStudentCode(studentInfoReq.getStudentCode());
+    	examStudent.setIdentityNumber(studentInfoReq.getIdentityNumber());
+    	examStudent.setSpecialtyName(studentInfoReq.getSpecialtyName());
+    	examStudent.setPaperType(studentInfoReq.getPaperType());
+    	examStudent.setInfoCollector(studentInfoReq.getInfoCollector());
+    	examStudent.setRemark(studentInfoReq.getRemark());
+    	examStudent.setGrade(studentInfoReq.getGrade());
+    	examStudent.setGraduated(studentInfoReq.getGraduated());
+    	
+    	examStudent.setStudentId(student.getId());
+    	
+    	examStudent.setOrgId(org.getId());
+    	examStudent.setOrgCode(org.getCode());
+    	examStudent.setOrgName(org.getName());
+    	examStudent.setRootOrgId(rootOrgId);
+    	examStudent.setExam(exam);
+    	
+    	examStudent.setCourseCode(course.getCode());
+    	examStudent.setCourseName(course.getName());
+    	if(StringUtils.isNotBlank(studentInfoReq.getCourseLevel())){
+    		examStudent.setCourseLevel(getCourseLevelByCName(studentInfoReq.getCourseLevel())+"");
+    	}
+    	examStudent.setFinished(false);
+		return examStudent;
+	}
+
+    private CourseLevel getCourseLevelByCName(String cname){
+    	if(StringUtils.isBlank(cname)){
+    		return null;
+    	}
+        for(CourseLevel level:CourseLevel.values()){
+        	if(cname.equals(level.getName())){
+        		return level;
+        	}
+        }
+        return null;
+    }
+
+	/**
+	 * 检查数据
+	 * @param examStudentReqList
+	 */
+	private OutletExam chechExamStudentInfo(List<StudentInfoReq> examStudentReqList, Long rootOrgId,String userToken){
+		if(examStudentReqList==null||examStudentReqList.size()==0){
+			throw new SaveExamStudentException("集合不能为空");
+		}
+		if(examStudentReqList.size()>1000){
+			throw new SaveExamStudentException("单次推送集合长度不能大于1000");
+		}
+		HashSet<String> examNameSet = new HashSet<String>();
+		for(StudentInfoReq examStudentAllInfoReq:examStudentReqList){
+			examNameSet.add(examStudentAllInfoReq.getExamName());
+		}
+		if(examNameSet.size()>1){
+			throw new SaveExamStudentException("集合中不允许存在多个考试");
+		}
+		String examName = examStudentReqList.get(0).getExamName();
+		ResponseEntity<List<OutletExam>> examListResp = examClient.queryByName(userToken, examName);
+		
+		if (examListResp == null || examListResp.getBody() == null || examListResp.getBody().size() == 0) {
+			throw new SaveExamStudentException("考试不存在,请先创建考试");
+		}
+		
+		if(examListResp.getBody().size()>1){
+			throw new SaveExamStudentException("当前机构中存在多个名称为"+examName+"的考试,请重新创建考试");
+		}
+		
+		return examListResp.getBody().get(0);
+	}
+	
+}
+

+ 159 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/scorePush/SydxScorePushServiceImpl.java

@@ -0,0 +1,159 @@
+package cn.com.qmth.examcloud.outlet.service.impl.scorePush;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamRecordDto;
+import cn.com.qmth.examcloud.commons.base.util.GsonUtil;
+import cn.com.qmth.examcloud.outlet.dao.OutletScoreDao;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import cn.com.qmth.examcloud.outlet.repo.ExamScoreRepo;
+import cn.com.qmth.examcloud.outlet.service.OutletScoreService;
+import cn.com.qmth.examcloud.outlet.service.ScorePushService;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月17日 上午11:01:45
+ * @company 	QMTH
+ * @description 石油大学推送成绩接口
+ */
+@Service("sydxScorePushService")
+public class SydxScorePushServiceImpl implements ScorePushService{
+
+    private static final Logger LOG = LoggerFactory.getLogger(SydxScorePushServiceImpl.class);
+
+    @Value("${sydx.pushscore.url.schema}")
+    private String pushUrlSchema;
+
+    @Value("${sydx.pushscore.url.host}")
+    private String pushUrlHost;
+
+    @Value("${sydx.pushscore.url.port}")
+    private String pushUrlPort;
+
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
+    
+    @Autowired
+    private OutletScoreService outletScoreService;
+    
+	@Autowired
+	private OutletScoreDao outletScoreDao;
+    
+	@Override
+	public void scorePush(ExamRecordDto examRecordDto) throws Exception {
+		//有警告未审核
+        if (examRecordDto.isWarn() && !examRecordDto.isAudit()) {
+            return;
+        }
+        //违纪
+  		if(examRecordDto.getInvigilatorOperation() == 1){
+  			return;
+  		}
+        //考试记录是作废状态
+  		if(StringUtils.isNotBlank(examRecordDto.getExamRecordStatus()) &&
+  				"EXAM_INVALID".equals(examRecordDto.getExamRecordStatus())){
+  			return;
+  		}
+		
+  		Long scoreId = examRecordDto.getScoreId();
+  		
+		LOG.info("准备推送成绩:{}", scoreId);
+
+        List<OutletScore> outletScores = outletScoreDao.sydxGetExamScoreById(scoreId);
+
+        if (outletScores == null || outletScores.size() == 0) {
+            LOG.info("{}成绩数据不存在", scoreId);
+        }
+        
+        for(OutletScore outletScore:outletScores){
+        	String courseCode = outletScore.getCourseCode();
+        	//将Z000001变成000001
+        	if(courseCode.startsWith("Z")||courseCode.startsWith("Q")||courseCode.startsWith("S")){
+        		outletScore.setCourseCode(courseCode.substring(1, courseCode.length()));
+        	}else{
+        		outletScore.setCourseCode(courseCode);
+        	}
+        }
+
+        CloseableHttpResponse httpResponse = null;
+        CloseableHttpClient httpClient = null;
+        try {
+            String scoreStr = GsonUtil.toJson(outletScores);
+            LOG.info("成绩数据:{}", scoreStr);
+            RequestConfig config = RequestConfig.custom()
+                    .setConnectTimeout(5000)
+                    .setConnectionRequestTimeout(5000)
+                    .setSocketTimeout(5000)
+                    .build();
+
+            httpClient = HttpClientBuilder
+                    .create()
+                    .setDefaultRequestConfig(config)
+                    .build();
+
+            URI uri = new URIBuilder()
+                    .setScheme(pushUrlSchema)
+                    .setHost(pushUrlHost)
+                    .setPort(Integer.parseInt(pushUrlPort))
+                    .setPath("/entity/learning/interface/stuHomeworkScore_syncFinalExamScore.action")
+                    .setParameter("loginId", "bjsy")
+                    .setParameter("password", "1111")
+                    .setParameter("examRemark", outletScores.get(0).getExamRemark())
+                    .setParameter("examStuRemark", outletScores.get(0).getStudentRemark())
+                    .setParameter("scoreJsonStr", scoreStr)//通过查询参数的方式传递
+                    .build();
+
+            HttpPost httpPost = new HttpPost(uri);
+//	            StringEntity data = new StringEntity(scoreStr);
+//	            httpPost.setEntity(data);
+
+            httpResponse = httpClient.execute(httpPost);
+            HttpEntity entity = httpResponse.getEntity();
+            String entityStr = EntityUtils.toString(entity);
+            LOG.info("推送结果:{}", entityStr);
+        } catch (Exception e) {
+            LOG.error(scoreId + "成绩推送失败", e);
+            e.printStackTrace();
+        } finally {
+
+            if (httpResponse != null) {
+                try {
+                    httpResponse.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                } finally {
+                    httpResponse = null;
+                }
+            }
+
+            if (httpClient != null) {
+                try {
+                    httpClient.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                } finally {
+                    httpClient = null;
+                }
+            }
+        }
+	}
+
+}
+

+ 117 - 0
examcloud-outlet-api/src/main/java/cn/com/qmth/examcloud/outlet/service/impl/scorePush/XncdScorePushServiceImpl.java

@@ -0,0 +1,117 @@
+package cn.com.qmth.examcloud.outlet.service.impl.scorePush;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.examcloud.common.dto.oe.marking.ExamRecordDto;
+import cn.com.qmth.examcloud.common.dto.oe.marking.PushScoreActionEnum;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import cn.com.qmth.examcloud.outlet.repo.ExamScoreRepo;
+import cn.com.qmth.examcloud.outlet.service.OutletScoreService;
+import cn.com.qmth.examcloud.outlet.service.ScorePushService;
+import cn.com.qmth.examcloud.outlet.utils.OutletUtils;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月17日 下午2:22:43
+ * @company 	QMTH
+ * @description 西南财大推送成绩接口
+ */
+@Service("xncdScorePushService")
+public class XncdScorePushServiceImpl  implements ScorePushService{
+
+	private static final Logger log = LoggerFactory.getLogger(XncdScorePushServiceImpl.class);
+	
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
+    
+    @Autowired
+    private OutletScoreService outletScoreService;
+    
+    private static final String pushScoreUrl = "http://www.swufe-online.com/netedu/qmth.do";
+	
+	@Override
+	public void scorePush(ExamRecordDto examRecordDto) throws Exception {
+		//西南财大只有考试结束后或自动清理才推送分数
+		if(examRecordDto.getPushScoreActionEnum() == PushScoreActionEnum.END_EXAM 
+				|| examRecordDto.getPushScoreActionEnum() == PushScoreActionEnum.CLEAN){
+			log.info("开始推送西南财大考生成绩 scoreId:"+examRecordDto.getScoreId());
+			Long scoreId = examRecordDto.getScoreId();
+	        List<OutletScore> outletScores = outletScoreService.getExamScoreById(scoreId);
+	        if (outletScores != null && outletScores.size() > 0) {
+	        	OutletScore outletScore = outletScores.get(0);
+	        	
+	        	CloseableHttpResponse httpResponse = null;
+	            CloseableHttpClient httpClient = HttpClients.createDefault();;
+	            HttpPost httpPost = new HttpPost(pushScoreUrl);
+	            
+	            List<NameValuePair> params = buildParamsData(outletScore);
+	            
+	            httpPost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));
+	            
+	            httpResponse = httpClient.execute(httpPost);
+	            
+	            String result = "";
+	            HttpEntity responseEntity = httpResponse.getEntity();
+	            int statusCode= httpResponse.getStatusLine().getStatusCode();
+	            if(statusCode == 200){
+	                BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent()));
+	                StringBuffer buffer = new StringBuffer();
+	                String str = "";
+	                while(StringUtils.isNoneBlank((str = reader.readLine()))) {
+	                    buffer.append(str);
+	                }
+	                result = buffer.toString();
+	            }
+	                 
+	            httpClient.close();
+	            if(httpResponse!=null){
+	                httpResponse.close();
+	            }
+	            log.info(result);
+	        }
+		}
+	}
+	
+	private List<NameValuePair> buildParamsData(OutletScore outletScore){
+		Map<String,Object> map = OutletUtils.getKeyAndValue(outletScore);
+        map.remove("examRemark");//西南财大接口不需要
+        map.remove("studentRemark");
+        map.remove("isMissExam");
+        
+        map.put("op","pushScore");
+        map.put("x","xczx_white_list");
+        map.put("LoginName","qmth");
+        map.put("PassWord","qmth123!");
+        
+        //是否违纪
+        boolean isBreachThePrinciple = (boolean) map.get("isBreachThePrinciple");
+        map.put("isBreachThePrinciple", isBreachThePrinciple?1:0);
+        
+        List<NameValuePair> params = new ArrayList<NameValuePair>();
+        for(String key:map.keySet()){
+        	params.add(new BasicNameValuePair(key,map.get(key)+""));
+        }
+        
+        return params;
+	}
+
+}
+

+ 26 - 0
examcloud-outlet-domain/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2.0-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-outlet-domain</artifactId>
+	<packaging>jar</packaging>
+
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.commons</groupId>
+			<artifactId>examcloud-commons-web</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.commons</groupId>
+			<artifactId>examcloud-commons-dto</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+	</dependencies>
+
+</project>

+ 20 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/ExamRecordDao.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.outlet.dao;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamRecord;
+
+/**
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:53:42
+ * @company 	QMTH
+ * @description ExamRecordDao.java
+ */
+public interface ExamRecordDao {
+
+	List<ExamRecord> findByExamStudentId(Long examStudentId);
+	
+	public ExamRecord findByScoreId(Long scoreId);
+
+}
+

+ 18 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/ExamScoreDao.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.examcloud.outlet.dao;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamScore;
+
+/**
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:54:16
+ * @company 	QMTH
+ * @description ExamScoreDao.java
+ */
+public interface ExamScoreDao {
+
+	List<ExamScore> findByExamRecordIdIn(List<Long> examRecordIds);
+
+}
+

+ 76 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/OutletScoreDao.java

@@ -0,0 +1,76 @@
+package cn.com.qmth.examcloud.outlet.dao;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+
+/**
+ * @author  	chenken
+ * @date    	2018年1月3日 下午4:02:01
+ * @company 	QMTH
+ * @description OutletScoreRepo.java
+ */
+public interface OutletScoreDao {
+	
+	List<OutletScore> sydxQuery(String examRemark, String examStuRemark, Long examOrgId);
+	/**
+	 * 按考试,学号,课程查询成绩明细
+	 * @param rootOrgId
+	 * @param examName
+	 * @param studentCode
+	 * @param courseCode
+	 * @return
+	 */
+	List<OutletScore> queryExamScoreBy(Long rootOrgId,String examName,String studentCode,String courseCode);
+	/**
+	 * 石油大学:按scoreId查询成绩
+	 * @param scoreId
+	 * @return
+	 */
+	List<OutletScore> sydxGetExamScoreById(Long scoreId);
+    /**
+     * 按身份证号查询成绩
+     * @param identityNumber 身份证号
+     * @return
+     */
+    List<OutletScore> sydxQueryScoreByIdentityNumber(List<String> identityNumbers, Long examOrgId);
+    /**
+	 * 按scoreId查询成绩
+	 * @param scoreId
+	 * @return
+	 */
+	List<OutletScore> getExamScoreById(Long scoreId);
+    /**
+     * 按照examRemark,examStuRemark,examOrgId查询考生
+     * @param examRemark
+     * @param examStuRemark
+     * @param examOrgId
+     * @return
+     */
+    public List<ExamStudent> findExamStudents(String examRemark, String examStuRemark, Long examOrgId);
+    /**
+     * 根据身份证号查询查询考生
+     * @param identityNumbers
+     * @param examOrgId
+     * @return
+     */
+    public List<ExamStudent> findExamStudents(List<String> identityNumbers, Long examOrgId);
+    /**
+     * 根据考试名称身份证号查询查询考生
+     * @param identityNumbers
+     * @param examOrgId
+     * @return
+     */
+    public List<ExamStudent> findExamStudents(String examName,List<String> identityNumbers, Long examOrgId);
+    /**
+     * 根据机构ID,批次名称,课程code,学号List查询考生
+     * @param batchName
+     * @param courseCode
+     * @param studentCodes
+     * @return
+     */
+	List<ExamStudent> findExamStudents(Long orgId,String batchName, String courseCode,List<String> studentCodes);
+    
+}
+

+ 88 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/ExamRecordDaoImpl.java

@@ -0,0 +1,88 @@
+package cn.com.qmth.examcloud.outlet.dao.impl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamRecord;
+import cn.com.qmth.examcloud.common.dto.em.enums.ExamRecordStatus;
+import cn.com.qmth.examcloud.outlet.dao.ExamRecordDao;
+
+/**
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:54:00
+ * @company 	QMTH
+ * @description ExamRecordDaoImpl.java
+ */
+@Component("examRecordDao")
+public class ExamRecordDaoImpl implements ExamRecordDao {
+	
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	@Override
+	public List<ExamRecord> findByExamStudentId(Long examStudentId) {
+		String sql = "select id,"
+						+ " id,"
+						+ " exam_student_id,"
+						+ " invigilator_operation,"
+						+ " is_audit,"
+						+ " is_warn,"
+						+ " org_id,"
+						+ " status "
+				 + " from oe_exam_record t "
+				 + " where t.exam_student_id = "+examStudentId;
+		return jdbcTemplate.query(sql.toString(), new RowMapper<ExamRecord>() {
+			@Override
+			public ExamRecord mapRow(ResultSet rs, int arg1) throws SQLException {
+				ExamRecord examRecord = new ExamRecord();
+				examRecord.setId(rs.getLong("id"));
+				examRecord.setExamStudentId(rs.getLong("exam_student_id"));
+				examRecord.setInvigilatorOperation(rs.getInt("invigilator_operation"));
+				examRecord.setIsAudit(rs.getBoolean("is_audit"));
+				examRecord.setIsWarn(rs.getBoolean("is_warn"));
+				examRecord.setStatus(ExamRecordStatus.valueOf(rs.getString("status")));
+				examRecord.setOrgId(rs.getLong("org_id"));
+				return examRecord;
+			}
+		});
+	}
+
+	@Override
+	public ExamRecord findByScoreId(Long scoreId) {
+		String sql = "select"
+						+ " t1.id,"
+						+ " t1.exam_student_id,"
+						+ " t1.invigilator_operation,"
+						+ " t1.is_audit,"
+						+ " t1.is_warn,"
+						+ " t1.org_id,"
+						+ " t1.status,"
+						+ " t1.end_time,"
+						+ " t1.clean_time"
+				 + " from oe_exam_record t1 left join oe_exam_score t2 on t1.id = t2.exam_record_id"
+				 + " where t2.id = "+scoreId;
+		return jdbcTemplate.queryForObject(sql.toString(), new RowMapper<ExamRecord>() {
+			@Override
+			public ExamRecord mapRow(ResultSet rs, int arg1) throws SQLException {
+				ExamRecord examRecord = new ExamRecord();
+				examRecord.setId(rs.getLong("id"));
+				examRecord.setExamStudentId(rs.getLong("exam_student_id"));
+				examRecord.setInvigilatorOperation(rs.getInt("invigilator_operation"));
+				examRecord.setIsAudit(rs.getBoolean("is_audit"));
+				examRecord.setIsWarn(rs.getBoolean("is_warn"));
+				examRecord.setStatus(ExamRecordStatus.valueOf(rs.getString("status")));
+				examRecord.setOrgId(rs.getLong("org_id"));
+				examRecord.setEndTime(rs.getTimestamp("end_time"));
+				examRecord.setCleanTime(rs.getTimestamp("clean_time"));
+				return examRecord;
+			}
+		});
+	}
+}
+

+ 53 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/ExamScoreDaoImpl.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.examcloud.outlet.dao.impl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamScore;
+import cn.com.qmth.examcloud.outlet.dao.ExamScoreDao;
+
+/**
+ * @author  	chenken
+ * @date    	2018年4月3日 下午3:54:23
+ * @company 	QMTH
+ * @description ExamScoreDaoImpl.java
+ */
+@Component("examScoreDao")
+public class ExamScoreDaoImpl implements ExamScoreDao{
+	
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	@Override
+	public List<ExamScore> findByExamRecordIdIn(List<Long> examRecordIds) {
+		StringBuffer examRecordIdsString = new StringBuffer();
+		for(Long number:examRecordIds){
+			examRecordIdsString.append(number+",");
+		}
+		String numbers = examRecordIdsString.toString();
+		numbers = numbers.substring(0, numbers.lastIndexOf(","));
+		String sql = "select id,objective_score,subjective_score,total_score "
+				  + " from oe_exam_score t "
+				  + " where t.exam_record_id IN ("+numbers+")";
+		
+		return this.jdbcTemplate.query(sql,new RowMapper<ExamScore>() {
+			@Override
+			public ExamScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				ExamScore examScore = new ExamScore();
+				examScore.setId(rs.getLong("id"));
+				examScore.setObjectiveScore(rs.getDouble("objective_score"));
+				examScore.setSubjectiveScore(rs.getDouble("subjective_score"));
+				examScore.setTotalScore(rs.getDouble("total_score"));
+				return examScore;
+			}
+		});
+	}
+
+}
+

+ 425 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dao/impl/OutletScoreDaoImpl.java

@@ -0,0 +1,425 @@
+package cn.com.qmth.examcloud.outlet.dao.impl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Repository;
+
+import cn.com.qmth.examcloud.common.dto.em.Exam;
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+import cn.com.qmth.examcloud.common.dto.em.enums.MarkingType;
+import cn.com.qmth.examcloud.outlet.dao.OutletScoreDao;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+
+/**
+ * @author  	chenken
+ * @date    	2018年1月3日 下午4:02:31
+ * @company 	QMTH
+ * @description OutletScoreRepoImpl.java
+ */
+@Repository("outletScoreDao")
+public class OutletScoreDaoImpl implements OutletScoreDao{
+
+	private static final Logger log = LoggerFactory.getLogger(OutletScoreDaoImpl.class);
+	
+	@Autowired
+	public JdbcTemplate jdbcTemplate;
+	
+	@Override
+	public List<OutletScore> sydxQuery(String examRemark, String examStuRemark,Long examOrgId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select " +
+	                " s.id 					score_id,"+ 
+	                " stu.`name` 			student_name,"+ 
+	                " stu.student_code 		student_code,"+ 
+	                " stu.identity_number 	identity_number," +
+	                " s.total_score 		total_score,"+ 
+	                " s.objective_score 	objective_score,"+ 
+	                " s.subjective_score 	subjective_score," +
+	                " stu.course_name 		course_name,"+
+	                " stu.course_code 		course_code,"+ 
+	                " e.remark 				exam_remark,"+ 
+	                " stu.remark 			student_remark," +
+	                " r.end_time 			end_time" +
+	                " from oe_exam_score s " +
+	                " left join oe_exam_record r on s.exam_record_id = r.id" +
+	                " left join ecs_exam_student stu on stu.id = r.exam_student_id" +
+	                " left join ecs_exam e on e.id = r.batch_id" +
+	                " where 1=1 ");
+		if(StringUtils.isNotBlank(examRemark)){
+			sql.append(" and e.remark = '"+examRemark+"'");
+		}
+		if(StringUtils.isNotBlank(examStuRemark)){
+			sql.append(" and stu.remark = '"+examStuRemark+"'");
+		}
+		if(examOrgId != null){
+			sql.append(" and e.org_id = "+examOrgId);
+		}
+		
+		sql.append(" and (r.is_warn = 0 OR (r.is_warn = 1 and r.is_audit = 1))");
+		sql.append(" and r.invigilator_operation <> 1 and r.status <> 'EXAM_INVALID' and r.status <> 'EXAM_ING'");
+		sql.append(" order by s.id");
+		
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<OutletScore>() {
+			@Override
+			public OutletScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getOutletScoreByResultSet(rs);
+			}
+		});
+	}
+	
+	
+	@Override
+	public List<OutletScore> sydxGetExamScoreById(Long scoreId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "
+                +" s.id 				score_id,"
+                +" stu.`name` 			student_name,"
+                +" stu.student_code 	student_code,"
+                +" stu.identity_number 	identity_number," 
+                +" s.total_score 		total_score,"
+                +" s.objective_score 	objective_score,"
+                +" s.subjective_score 	subjective_score," 
+                +" stu.course_name 		course_name,"
+                +" stu.course_code 		course_code,"
+                +" e.remark 			exam_remark,"
+                +" stu.remark 			student_remark," 
+                +" r.end_time 			end_time " 
+                +" from oe_exam_score s " 
+                +" left join oe_exam_record r on s.exam_record_id = r.id" 
+                +" left join ecs_exam_student stu on stu.id = r.exam_student_id" 
+                +" left join ecs_exam e on e.id = r.batch_id" 
+                +" where s.id = "+scoreId);
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<OutletScore>() {
+			@Override
+			public OutletScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getOutletScoreByResultSet(rs);
+			}
+		});
+	}
+	
+	@Override
+	public List<OutletScore> sydxQueryScoreByIdentityNumber(List<String> identityNumbers, Long examOrgId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select" 
+	                +" s.id 				score_id,"
+	                +" stu.`name` 			student_name,"
+	                +" stu.student_code		student_code,"
+	                +" stu.identity_number 	identity_number,"
+	                +" s.total_score 		total_score,"
+	                +" s.objective_score 	objective_score,"
+	                +" s.subjective_score 	subjective_score," 
+	                +" stu.course_name 		course_name,"
+	                +" stu.course_code 		course_code,"
+	                +" e.remark 			exam_remark,"
+	                +" stu.remark 			student_remark," 
+	                +" r.end_time 			end_time"
+	                +" from oe_exam_score s "
+	                +" left join oe_exam_record r on s.exam_record_id = r.id" 
+	                +" left join ecs_exam_student stu on stu.id = r.exam_student_id" 
+	                +" left join ecs_exam e on e.id = r.batch_id" 
+	                +" where 1=1 ");
+		StringBuffer numberString = new StringBuffer();
+		for(String number:identityNumbers){
+			numberString.append("'"+number+"',");
+		}
+		String numbers = numberString.toString();
+		numbers = numbers.substring(0, numbers.lastIndexOf(","));
+		sql.append(" and r.identity_number in ("+numbers+") and e.org_id = "+examOrgId );
+		
+		sql.append(" and (r.is_warn = 0 OR (r.is_warn = 1 and r.is_audit = 1))");
+		sql.append(" and r.invigilator_operation <> 1 and r.status <> 'EXAM_INVALID' and r.status <> 'EXAM_ING' ");
+		sql.append(" order by s.id");
+		
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<OutletScore>() {
+			@Override
+			public OutletScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getOutletScoreByResultSet(rs);
+			}
+		});
+	}
+
+	@Override
+	public List<OutletScore> getExamScoreById(Long scoreId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "
+	                +" s.id 				score_id,"
+	                +" stu.`name` 			student_name,"
+	                +" stu.student_code 	student_code,"
+	                +" stu.identity_number 	identity_number," 
+	                +" s.total_score 		total_score,"
+	                +" s.objective_score 	objective_score,"
+	                +" s.subjective_score 	subjective_score," 
+	                +" stu.course_name 		course_name,"
+	                +" stu.course_code 		course_code,"
+	                +" e.id 			    exam_id,"
+	                +" e.name 			    exam_name,"
+	                +" e.remark 			exam_remark,"
+	                +" stu.remark 			student_remark," 
+	                +" r.start_time			start_time,"
+	                +" r.end_time 			end_time," 
+	                +" r.succ_percent 		succ_percent,"
+	                +" r.invigilator_operation invigilatorOperation "
+	                +" from oe_exam_score s " 
+	                +" left join oe_exam_record r on s.exam_record_id = r.id" 
+	                +" left join ecs_exam_student stu on stu.id = r.exam_student_id" 
+	                +" left join ecs_exam e on e.id = r.batch_id" 
+	                +" where s.id = "+scoreId);
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<OutletScore>() {
+			@Override
+			public OutletScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamScoreByIdResult(rs);
+			}
+		});
+	}
+
+	private OutletScore getExamScoreByIdResult(ResultSet rs) throws SQLException{
+		OutletScore outletScore = new OutletScore();
+		outletScore.setScoreId(rs.getLong("score_id"));
+		outletScore.setStudentName(rs.getString("student_name"));
+		outletScore.setStudentCode(rs.getString("student_code"));
+		outletScore.setIdentityNumber(rs.getString("identity_number"));
+		outletScore.setTotalScore(rs.getDouble("total_score"));
+		outletScore.setObjectiveScore(rs.getDouble("objective_score"));
+		outletScore.setSubjectiveScore(rs.getDouble("subjective_score"));
+		outletScore.setCourseName(rs.getString("course_name"));
+		outletScore.setCourseCode(rs.getString("course_code"));
+		outletScore.setExamRemark(rs.getString("exam_remark"));
+		outletScore.setStudentRemark(rs.getString("student_remark"));
+		outletScore.setEndTime(rs.getString("end_time"));
+		//新增 20180517
+		outletScore.setStartTime(rs.getString("start_time"));
+		outletScore.setExamId(rs.getLong("exam_id"));
+		outletScore.setExamName(rs.getString("exam_name"));
+		outletScore.setSuccessRate(rs.getDouble("succ_percent"));
+		Integer invigilatorOperation = rs.getInt("invigilatorOperation");
+		outletScore.setIsBreachThePrinciple(invigilatorOperation == 1?true:false);
+		return outletScore;
+	}
+
+	private OutletScore getOutletScoreByResultSet(ResultSet rs) throws SQLException{
+		OutletScore outletScore = new OutletScore();
+		outletScore.setScoreId(rs.getLong("score_id"));
+		outletScore.setStudentName(rs.getString("student_name"));
+		outletScore.setStudentCode(rs.getString("student_code"));
+		outletScore.setIdentityNumber(rs.getString("identity_number"));
+		outletScore.setTotalScore(rs.getDouble("total_score"));
+		outletScore.setObjectiveScore(rs.getDouble("objective_score"));
+		outletScore.setSubjectiveScore(rs.getDouble("subjective_score"));
+		outletScore.setCourseName(rs.getString("course_name"));
+		outletScore.setCourseCode(rs.getString("course_code"));
+		outletScore.setExamRemark(rs.getString("exam_remark"));
+		outletScore.setStudentRemark(rs.getString("student_remark"));
+		outletScore.setEndTime(rs.getString("end_time"));
+		return outletScore;
+	}
+
+	@Override
+	public List<ExamStudent> findExamStudents(String examRemark,String examStuRemark, Long examOrgId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "+
+						 " stu.id 				id,"+
+						 " stu.`name` 			student_name,"+
+						 " stu.student_code 	student_code,"+
+						 " stu.identity_number 	identity_number,"+
+						 " stu.course_name 		course_name,"+
+						 " stu.course_code 		course_code,"+
+						 " stu.remark 			student_remark,"+
+						 " stu.finished			finished,"+
+						 " exam.remark 			exam_remark,"+
+						 " exam.marking_type	marking_type"+
+					" from ecs_exam_student stu "+
+					" left join ecs_exam exam  on stu.exam_id = exam.id"+
+					" where 1=1 ");
+		if(StringUtils.isNotBlank(examRemark)){
+			sql.append(" and exam.remark = '"+examRemark+"'");
+		}
+		if(examOrgId != null){
+			sql.append(" and exam.root_org_id = "+examOrgId);
+		}
+		if(StringUtils.isNotBlank(examStuRemark)){
+			sql.append(" and stu.remark = '"+examStuRemark+"'");
+		}
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudent>() {
+			@Override
+			public ExamStudent mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamStudentByResultSet(rs);
+			}
+		});
+	}
+	
+	private ExamStudent getExamStudentByResultSet(ResultSet rs) throws SQLException{
+		ExamStudent examStudent = new ExamStudent();
+		examStudent.setId(rs.getLong("id"));
+		examStudent.setName(rs.getString("student_name"));
+		examStudent.setStudentCode(rs.getString("student_code"));
+		examStudent.setIdentityNumber(rs.getString("identity_number"));
+		examStudent.setCourseCode(rs.getString("course_code"));
+		examStudent.setCourseName(rs.getString("course_name"));
+		examStudent.setRemark(rs.getString("student_remark"));
+		examStudent.setFinished(rs.getBoolean("finished"));
+		Exam exam = new Exam();
+		exam.setRemark(rs.getString("exam_remark"));
+		exam.setMarkingType(MarkingType.toMarkingType(rs.getString("marking_type")));
+		examStudent.setExam(exam);
+		return examStudent;
+	}
+
+	@Override
+	public List<ExamStudent> findExamStudents(List<String> identityNumbers,Long examOrgId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "+
+						 " stu.id 				id,"+
+						 " stu.`name` 			student_name,"+
+						 " stu.student_code 		student_code,"+
+						 " stu.identity_number 	identity_number,"+
+						 " stu.course_name 		course_name,"+
+						 " stu.course_code 		course_code,"+
+						 " stu.remark 			student_remark,"+
+						 " stu.finished			finished,"+
+						 " exam.remark 			exam_remark,"+
+						 " exam.marking_type		marking_type"+
+					" from ecs_exam_student stu "+
+					" left join ecs_exam exam  on stu.exam_id = exam.id"+
+					" where 1=1 ");
+		StringBuffer numberString = new StringBuffer();
+		for(String number:identityNumbers){
+			numberString.append("'"+number+"',");
+		}
+		String numbers = numberString.toString();
+		numbers = numbers.substring(0, numbers.lastIndexOf(","));
+		sql.append(" and stu.identity_number in ("+numbers+") and exam.root_org_id = "+examOrgId );
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudent>() {
+			@Override
+			public ExamStudent mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamStudentByResultSet(rs);
+			}
+		});
+	}
+
+	@Override
+	public List<ExamStudent> findExamStudents(Long orgId, String batchName,String courseCode, List<String> studentCodes) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "+
+					     " stu.id 				id,"+
+						 " stu.`name` 			student_name,"+
+						 " stu.student_code 		student_code,"+
+						 " stu.identity_number 	identity_number,"+
+						 " stu.course_name 		course_name,"+
+						 " stu.course_code 		course_code,"+
+						 " stu.remark 			student_remark,"+
+						 " stu.finished			finished,"+
+						 " exam.remark 			exam_remark,"+
+						 " exam.marking_type		marking_type"+
+					" from ecs_exam_student stu "+
+					" left join ecs_exam exam  on stu.exam_id = exam.id"+
+					" where 1=1 ");
+		sql.append(" and exam.name='"+batchName+"' and exam.root_org_id = "+orgId);
+		sql.append(" and stu.course_code LIKE '%"+courseCode+"'");
+		StringBuffer studentCodesStringBuffer = new StringBuffer();
+		for(String studentCode:studentCodes){
+			studentCodesStringBuffer.append("'"+studentCode+"',");
+		}
+		String studentCodesString = studentCodesStringBuffer.toString();
+		studentCodesString = studentCodesString.substring(0, studentCodesString.lastIndexOf(","));
+		
+		sql.append(" and student_code IN ("+studentCodesString+")");
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudent>() {
+			@Override
+			public ExamStudent mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamStudentByResultSet(rs);
+			}
+		});
+	}
+
+	@Override
+	public List<ExamStudent> findExamStudents(String examName,List<String> identityNumbers, Long examOrgId) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "+
+						 " stu.id 				id,"+
+						 " stu.`name` 			student_name,"+
+						 " stu.student_code 		student_code,"+
+						 " stu.identity_number 	identity_number,"+
+						 " stu.course_name 		course_name,"+
+						 " stu.course_code 		course_code,"+
+						 " stu.remark 			student_remark,"+
+						 " stu.finished			finished,"+
+						 " exam.remark 			exam_remark,"+
+						 " exam.marking_type		marking_type"+
+					" from ecs_exam_student stu "+
+					" left join ecs_exam exam  on stu.exam_id = exam.id"+
+					" where 1=1 ");
+		StringBuffer numberString = new StringBuffer();
+		for(String number:identityNumbers){
+			numberString.append("'"+number+"',");
+		}
+		String numbers = numberString.toString();
+		numbers = numbers.substring(0, numbers.lastIndexOf(","));
+		sql.append(" and exam.root_org_id = "+examOrgId );
+		sql.append(" and exam.name = '"+examName+"'");
+		sql.append(" and stu.identity_number in ("+numbers+")");
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudent>() {
+			@Override
+			public ExamStudent mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamStudentByResultSet(rs);
+			}
+		});
+	}
+
+
+	@Override
+	public List<OutletScore> queryExamScoreBy(Long rootOrgId, String examName,
+			String studentCode, String courseCode) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("select "
+	                +" s.id 				score_id,"
+	                +" stu.`name` 			student_name,"
+	                +" stu.student_code 	student_code,"
+	                +" stu.identity_number 	identity_number," 
+	                +" s.total_score 		total_score,"
+	                +" s.objective_score 	objective_score,"
+	                +" s.subjective_score 	subjective_score," 
+	                +" stu.course_name 		course_name,"
+	                +" stu.course_code 		course_code,"
+	                +" e.id 			    exam_id,"
+	                +" e.name 			    exam_name,"
+	                +" e.remark 			exam_remark,"
+	                +" stu.remark 			student_remark," 
+	                +" r.start_time			start_time,"
+	                +" r.end_time 			end_time," 
+	                +" r.succ_percent 		succ_percent,"
+	                +" r.invigilator_operation invigilatorOperation "
+	                +" from oe_exam_score s " 
+	                +" left join oe_exam_record r on s.exam_record_id = r.id" 
+	                +" left join ecs_exam_student stu on stu.id = r.exam_student_id" 
+	                +" left join ecs_exam e on e.id = r.batch_id" 
+	                +" where e.name = '"+examName+"'"
+	                +" 	and	 e.root_org_id="+rootOrgId
+	                +"	and	 r.student_code='"+studentCode+"'"
+	                +"	and	 r.course_code LIKE '%"+courseCode+"'");
+		log.info(sql.toString());
+		return  jdbcTemplate.query(sql.toString(), new RowMapper<OutletScore>() {
+			@Override
+			public OutletScore mapRow(ResultSet rs, int arg1) throws SQLException {
+				return getExamScoreByIdResult(rs);
+			}
+		});
+	}
+	
+}
+

+ 88 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamReq.java

@@ -0,0 +1,88 @@
+package cn.com.qmth.examcloud.outlet.dto;
+
+import java.util.Date;
+
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月2日 下午3:44:54
+ * @company 	QMTH
+ * @description ExamReq.java
+ */
+public class ExamReq{
+
+	/**
+	 * 机构ID
+	 */
+	private Long rootOrgId;
+	/**
+	 * 考试名称
+	 */
+	private String name;
+	/**
+	 * 考试类型
+	 */
+	private String examType;
+	/**
+	 * 考试开始时间
+	 */
+	private Date beginTime;
+	/**
+	 * 考试结束时间
+	 */
+	private Date endTime;
+	/**
+	 * 考试时长(分钟)
+	 */
+	private Integer duration;
+	
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getExamType() {
+		return examType;
+	}
+
+	public void setExamType(String examType) {
+		this.examType = examType;
+	}
+
+	public Date getBeginTime() {
+		return beginTime;
+	}
+
+	public void setBeginTime(Date beginTime) {
+		this.beginTime = beginTime;
+	}
+
+	public Date getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(Date endTime) {
+		this.endTime = endTime;
+	}
+
+	public Integer getDuration() {
+		return duration;
+	}
+
+	public void setDuration(Integer duration) {
+		this.duration = duration;
+	}
+	
+}
+

+ 70 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamScore.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.examcloud.outlet.dto;
+
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+
+import javax.persistence.*;
+
+/**
+ * Created by yuanpan on 2017/4/27.
+ */
+@Entity
+@SqlResultSetMapping(
+        name = "OutletScoreMapping",
+        classes = {
+                @ConstructorResult(
+                        targetClass = OutletScore.class,
+                        columns = {
+                                @ColumnResult(name = "score_id", type = Long.class),
+                                @ColumnResult(name = "student_name", type = String.class),
+                                @ColumnResult(name = "student_code", type = String.class),
+                                @ColumnResult(name = "identity_number", type = String.class),
+                                @ColumnResult(name = "total_score", type = Double.class),
+                                @ColumnResult(name = "objective_score", type = Double.class),
+                                @ColumnResult(name = "subjective_score", type = Double.class),
+                                @ColumnResult(name = "course_name", type = String.class),
+                                @ColumnResult(name = "course_code", type = String.class),
+                                @ColumnResult(name = "exam_remark", type = String.class),
+                                @ColumnResult(name = "student_remark", type = String.class),
+                                @ColumnResult(name = "end_time", type = String.class)
+                        }
+                )
+        }
+)
+@NamedNativeQueries({
+        @NamedNativeQuery(name = "ExamScore.sydxQuery", query = "select \n" +
+                "s.id `score_id`, stu.`name` `student_name`, stu.student_code,stu.identity_number,\n" +
+                "s.total_score,s.objective_score,s.subjective_score,\n" +
+                "stu.course_name,stu.course_code,e.remark `exam_remark`,stu.remark `student_remark`,\n" +
+                "r.end_time\n" +
+                "from oe_exam_score s \n" +
+                "left join oe_exam_record r on s.exam_record_id = r.id\n" +
+                "left join ecs_exam_student stu on stu.id = r.exam_student_id\n" +
+                "left join ecs_exam e on e.id = r.batch_id\n" +
+                "where e.remark = ?1 and stu.remark = ?2 and e.org_id = ?3", resultSetMapping = "OutletScoreMapping"),
+        @NamedNativeQuery(name = "ExamScore.sydxGet", query = "select \n" +
+                "s.id `score_id`, stu.`name` `student_name`, stu.student_code,stu.identity_number,\n" +
+                "s.total_score,s.objective_score,s.subjective_score,\n" +
+                "stu.course_name,stu.course_code,e.remark `exam_remark`,stu.remark `student_remark`,\n" +
+                "r.end_time\n" +
+                "from oe_exam_score s \n" +
+                "left join oe_exam_record r on s.exam_record_id = r.id\n" +
+                "left join ecs_exam_student stu on stu.id = r.exam_student_id\n" +
+                "left join ecs_exam e on e.id = r.batch_id\n" +
+                "where s.id = ?1 ", resultSetMapping = "OutletScoreMapping"),
+        @NamedNativeQuery(name = "ExamScore.sydxQueryScoreByIdentityNumber", query = "select \n" +
+                "s.id `score_id`, stu.`name` `student_name`, stu.student_code,stu.identity_number,\n" +
+                "s.total_score,s.objective_score,s.subjective_score,\n" +
+                "stu.course_name,stu.course_code,e.remark `exam_remark`,stu.remark `student_remark`,\n" +
+                "r.end_time\n" +
+                "from oe_exam_score s \n" +
+                "left join oe_exam_record r on s.exam_record_id = r.id\n" +
+                "left join ecs_exam_student stu on stu.id = r.exam_student_id\n" +
+                "left join ecs_exam e on e.id = r.batch_id\n" +
+                "where r.identity_number in (?1) and e.org_id = ?2", resultSetMapping = "OutletScoreMapping")
+})
+@Table(name = "oe_exam_score")
+public class ExamScore {
+
+    @Id
+    private Long id;
+}

+ 33 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/ExamStudentImportDTO.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.examcloud.outlet.dto;
+
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.outlet.entity.OutletExam;
+import cn.com.qmth.examcloud.outlet.entity.OutletExamStudent;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+public class ExamStudentImportDTO {
+    private OutletExam exam;
+
+    private List<OutletExamStudent> examStudentList;
+
+
+    public OutletExam getExam() {
+        return exam;
+    }
+
+    public void setExam(OutletExam exam) {
+        this.exam = exam;
+    }
+
+    public List<OutletExamStudent> getExamStudentList() {
+        return examStudentList;
+    }
+
+    public void setExamStudentList(List<OutletExamStudent> examStudentList) {
+        this.examStudentList = examStudentList;
+    }
+}

+ 230 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/OutletScore.java

@@ -0,0 +1,230 @@
+package cn.com.qmth.examcloud.outlet.dto;
+
+import cn.com.qmth.examcloud.common.dto.em.ExamStudent;
+
+/**
+ * Created by yuanpan on 2017/2/15.
+ */
+public class OutletScore {
+
+    private Long scoreId;//分数id
+    
+    private Long examId;
+    
+    private String examName;
+    
+    private String studentName;//考生名称
+
+    private String studentCode;//考生学号
+
+    private String identityNumber;//考生身份证号码
+
+    private Double totalScore;//总得分
+
+    private Double objectiveScore;//客观题得分
+
+    private Double subjectiveScore;//主观题得分
+
+    private String courseName;//课程名称
+
+    private String courseCode;//课程代码
+
+    private String examRemark;//接口外部系统考试标识
+    
+    private String startTime;//开始考试时间
+
+    private String endTime;//交卷时间
+
+    private String studentRemark;//ecs_exam_student考生标的备注字段,这里用来标识:毕业/非毕业/入学考试
+    /**
+     * 是否缺考
+     */
+    private Boolean isMissExam;
+    /**
+     * 是否违纪
+     */
+    private Boolean isBreachThePrinciple;
+    /**
+     * 人脸识别成功率
+     */
+    private Double successRate;
+    
+    public OutletScore() {}
+
+    public OutletScore(Long scoreId, String studentName, String studentCode, String identityNumber, Double totalScore, Double objectiveScore, Double subjectiveScore, String courseName, String courseCode, String examRemark, String studentRemark, String endTime) {
+        this.scoreId = scoreId;
+        this.studentName = studentName;
+        this.studentCode = studentCode;
+        this.identityNumber = identityNumber;
+        this.totalScore = totalScore;
+        this.objectiveScore = objectiveScore;
+        this.subjectiveScore = subjectiveScore;
+        this.courseName = courseName;
+        this.courseCode = courseCode;
+        this.examRemark = examRemark;
+        this.studentRemark = studentRemark;
+        this.endTime = endTime;
+    }
+
+    public OutletScore(ExamStudent examStudent) {
+    	this.studentName = examStudent.getName();
+        this.studentCode = examStudent.getStudentCode();
+        this.courseCode = examStudent.getCourseCode();
+        this.identityNumber = examStudent.getIdentityNumber();
+        this.examRemark = examStudent.getExam().getRemark();
+        this.studentRemark = examStudent.getRemark();
+        String courseCode = examStudent.getCourseCode();
+        if(courseCode.startsWith("Z")
+        		||courseCode.startsWith("Q")
+        			||courseCode.startsWith("S")){
+        	this.courseCode = courseCode.substring(1,courseCode.length());
+    	}else{
+    		this.courseCode = courseCode;
+    	}
+	}
+
+	public Long getScoreId() {
+        return scoreId;
+    }
+
+    public void setScoreId(Long scoreId) {
+        this.scoreId = scoreId;
+    }
+
+    public String getStudentName() {
+        return studentName;
+    }
+
+    public void setStudentName(String studentName) {
+        this.studentName = studentName;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getIdentityNumber() {
+        return identityNumber;
+    }
+
+    public void setIdentityNumber(String identityNumber) {
+        this.identityNumber = identityNumber;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getExamRemark() {
+        return examRemark;
+    }
+
+    public void setExamRemark(String examRemark) {
+        this.examRemark = examRemark;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public String getStudentRemark() {
+        return studentRemark;
+    }
+
+    public void setStudentRemark(String studentRemark) {
+        this.studentRemark = studentRemark;
+    }
+
+	public Boolean getIsMissExam() {
+		return isMissExam;
+	}
+
+	public void setIsMissExam(Boolean isMissExam) {
+		this.isMissExam = isMissExam;
+	}
+
+	public Boolean getIsBreachThePrinciple() {
+		return isBreachThePrinciple;
+	}
+
+	public void setIsBreachThePrinciple(Boolean isBreachThePrinciple) {
+		this.isBreachThePrinciple = isBreachThePrinciple;
+	}
+
+	public Double getSuccessRate() {
+		return successRate;
+	}
+
+	public void setSuccessRate(Double successRate) {
+		this.successRate = successRate;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public String getStartTime() {
+		return startTime;
+	}
+
+	public void setStartTime(String startTime) {
+		this.startTime = startTime;
+	}
+    
+}

+ 251 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/dto/StudentInfoReq.java

@@ -0,0 +1,251 @@
+package cn.com.qmth.examcloud.outlet.dto;
+
+import java.io.Serializable;
+
+
+public class StudentInfoReq implements Serializable{
+	
+	private static final long serialVersionUID = -6575958224230885795L;
+	/**
+	 * 考试ID
+	 */
+	private Long examId;
+	/**
+	 * 考试名称
+	 */
+	private String examName;
+	/**
+	 * 学生姓名
+	 */
+	private String studentName;
+	/**
+	 * 学生学号
+	 */
+	private String studentCode;
+	/**
+	 * 学生身份证号
+	 */
+	private String identityNumber;
+	/**
+	 * 考试课程名称
+	 */
+	private String courseName;
+	/**
+	 * 考试课程code
+	 */
+	private String courseCode;
+	/**
+	 * 考试课程level
+	 */
+	private String courseLevel;
+	/**
+	 * 试卷类型
+	 */
+	private String paperType;
+	/**
+	 * 采集人
+	 */
+	private String infoCollector;
+	/**
+	 * 专业名称
+	 */
+	private String specialtyName;
+	/**
+	 * 所属机构code
+	 */
+	private String orgCode;
+	/**
+	 * 所属机构名称
+	 */
+	private String orgName;
+	/**
+	 * 性别
+	 */
+	private String gender;
+	/**
+	 * 年级
+	 */
+	private String grade;
+	/**
+	 * 是否为重修
+	 */
+	private Boolean repair;
+	/**
+	 * 是否毕业
+	 */
+	private Boolean graduated;
+	/**
+	 * 备注
+	 */
+	private String remark;
+	
+	/**
+	 * 机构ID
+	 */
+	private Long orgId;
+	/**
+	 * 顶级机构id 
+	 */
+	private Long rootOrgId;
+	
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public String getStudentName() {
+		return studentName;
+	}
+
+	public void setStudentName(String studentName) {
+		this.studentName = studentName;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+
+	public String getCourseName() {
+		return courseName;
+	}
+
+	public void setCourseName(String courseName) {
+		this.courseName = courseName;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public String getCourseLevel() {
+		return courseLevel;
+	}
+
+	public void setCourseLevel(String courseLevel) {
+		this.courseLevel = courseLevel;
+	}
+
+	public String getPaperType() {
+		return paperType;
+	}
+
+	public void setPaperType(String paperType) {
+		this.paperType = paperType;
+	}
+
+	public String getInfoCollector() {
+		return infoCollector;
+	}
+
+	public void setInfoCollector(String infoCollector) {
+		this.infoCollector = infoCollector;
+	}
+
+	public String getSpecialtyName() {
+		return specialtyName;
+	}
+
+	public void setSpecialtyName(String specialtyName) {
+		this.specialtyName = specialtyName;
+	}
+
+	public String getOrgCode() {
+		return orgCode;
+	}
+
+	public void setOrgCode(String orgCode) {
+		this.orgCode = orgCode;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	public String getGender() {
+		return gender;
+	}
+
+	public void setGender(String gender) {
+		this.gender = gender;
+	}
+
+	public String getGrade() {
+		return grade;
+	}
+
+	public void setGrade(String grade) {
+		this.grade = grade;
+	}
+
+	public Boolean getRepair() {
+		return repair;
+	}
+
+	public void setRepair(Boolean repair) {
+		this.repair = repair;
+	}
+
+	public Boolean getGraduated() {
+		return graduated;
+	}
+
+	public void setGraduated(Boolean graduated) {
+		this.graduated = graduated;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+	
+}

+ 52 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/CreateFacesetResponse.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class CreateFacesetResponse {
+    private String request_id;
+    private String faceset_token;
+    private String outer_id;
+    private int face_added;
+    private int face_count;
+
+    public String getRequest_id() {
+        return request_id;
+    }
+
+    public void setRequest_id(String request_id) {
+        this.request_id = request_id;
+    }
+
+    public String getFaceset_token() {
+        return faceset_token;
+    }
+
+    public void setFaceset_token(String faceset_token) {
+        this.faceset_token = faceset_token;
+    }
+
+    public String getOuter_id() {
+        return outer_id;
+    }
+
+    public void setOuter_id(String outer_id) {
+        this.outer_id = outer_id;
+    }
+
+    public int getFace_added() {
+        return face_added;
+    }
+
+    public void setFace_added(int face_added) {
+        this.face_added = face_added;
+    }
+
+    public int getFace_count() {
+        return face_count;
+    }
+
+    public void setFace_count(int face_count) {
+        this.face_count = face_count;
+    }
+}

+ 26 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/Face.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class Face {
+    private String face_token;
+
+    private FaceRectangle face_rectangle;
+
+    public String getFace_token() {
+        return face_token;
+    }
+
+    public void setFace_token(String face_token) {
+        this.face_token = face_token;
+    }
+
+    public FaceRectangle getFace_rectangle() {
+        return face_rectangle;
+    }
+
+    public void setFace_rectangle(FaceRectangle face_rectangle) {
+        this.face_rectangle = face_rectangle;
+    }
+}

+ 46 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/FaceDetectResponse.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class FaceDetectResponse {
+    private String image_id;
+    private String request_id;
+    private int time_used;
+    private List<Face> faces;
+
+
+    public String getImage_id() {
+        return image_id;
+    }
+
+    public void setImage_id(String image_id) {
+        this.image_id = image_id;
+    }
+
+    public String getRequest_id() {
+        return request_id;
+    }
+
+    public void setRequest_id(String request_id) {
+        this.request_id = request_id;
+    }
+
+    public int getTime_used() {
+        return time_used;
+    }
+
+    public void setTime_used(int time_used) {
+        this.time_used = time_used;
+    }
+
+    public List<Face> getFaces() {
+        return faces;
+    }
+
+    public void setFaces(List<Face> faces) {
+        this.faces = faces;
+    }
+}

+ 43 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/FaceRectangle.java

@@ -0,0 +1,43 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+/**
+ * Created by yuanpan on 2017/5/15.
+ */
+public class FaceRectangle {
+    private int width;
+    private int top;
+    private int left;
+    private int height;
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getTop() {
+        return top;
+    }
+
+    public void setTop(int top) {
+        this.top = top;
+    }
+
+    public int getLeft() {
+        return left;
+    }
+
+    public void setLeft(int left) {
+        this.left = left;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public void setHeight(int height) {
+        this.height = height;
+    }
+}

+ 115 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletCourse.java

@@ -0,0 +1,115 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
+
+/**
+ * 
+ * @Description: 课程
+ * @author ting.yin
+ * @date 2017年1月5日
+ */
+public class OutletCourse implements Serializable{
+
+	
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = 3402653478406795762L;
+
+	private Long id;
+
+	private String code;
+
+    private String name;
+
+	private Long orgId;
+	
+	private CourseLevel level;
+
+	private Date createTime;
+
+	private Date updateTime;
+
+	private Boolean enable;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+    public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public static long getSerialversionuid() {
+		return serialVersionUID;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public CourseLevel getLevel() {
+		return level;
+	}
+
+	public void setLevel(CourseLevel level) {
+		this.level = level;
+	}
+
+	public OutletCourse() {
+	}
+
+	public OutletCourse(String name, String code) {
+		this.name = name;
+		this.code = code;
+		this.createTime = new Date();
+		this.enable = true;
+	}
+}

+ 527 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletExam.java

@@ -0,0 +1,527 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+
+import cn.com.qmth.examcloud.common.dto.em.enums.ExamType;
+import cn.com.qmth.examcloud.common.dto.em.enums.MarkingType;
+import cn.com.qmth.examcloud.common.dto.em.enums.PracticeType;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.validation.constraints.NotNull;
+
+public class OutletExam implements Serializable {
+
+	private static final long serialVersionUID = -1674026406657304645L;
+
+	private Long id;
+
+	/**
+	 * 机构Id
+	 */
+	private Long orgId;
+
+	/**
+	 * 顶级机构Id
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 考试批次开始时间
+     */
+	private Date beginTime;
+
+	/**
+	 * 考试批次结束时间
+     */
+	private Date endTime;
+
+	/**
+	 * 考试名称
+     */
+	private String name;
+
+	/**
+	 * 考试类型
+     */
+	private ExamType examType;
+
+	/**
+	 * 是否入学考试
+     */
+	private Boolean isEntranceExam;
+
+	/**
+	 * 考试时长
+	 */
+	private Integer duration;
+	/**
+	 * 冻结时间
+	 */
+	private Integer freezeTime;
+
+	/**
+	 * 考试状态
+     */
+	private String status;
+
+
+	private Boolean enable;
+
+	/**
+	 * 考试备注
+     */
+	private String remark;
+
+	/**
+	 * 创建时间
+     */
+	private Date createTime;
+
+	/**
+	 * 考试次数
+     */
+	private Long examTimes;
+
+	/**
+	 * 断点续考时间(秒)
+     */
+	private Long examReconnectTime;
+
+	/**
+	 * 考前说明
+     */
+	private String beforeExamRemark;
+
+	/**
+	 * 考后说明
+     */
+	private String afterExamRemark;
+
+	/**
+	 * 是否显示成绩
+     */
+	private String isObjScoreView;
+
+	/**
+	 * 练习模式
+     */
+	private PracticeType practiceType;
+
+	/**
+	 * 单选题补充说明是否可填
+	 */
+	private Boolean singleEdit;
+
+	/**
+	 * 多选题补充说明是否可填
+	 */
+	private Boolean mutipleEdit;
+
+	/**
+	 * 判断题补充说明是否可填
+	 */
+	private Boolean boolEdit;
+
+	/**
+	 * 填空题补充说明是否可填
+	 */
+	private Boolean fillBlankEdit;
+
+	/**
+	 * 单选题补充说明
+     */
+	private String singleAnswerRemark;
+
+	/**
+	 * 多选题补充说明
+     */
+	private String mutipleAnswerRemark;
+
+	/**
+	 * 判断题补充说明
+     */
+	private String boolAnswerRemark;
+
+	/**
+	 * 填空题补充说明
+     */
+	private String fillBlankRemark;
+
+	/**
+	 * 问答题补充说明
+     */
+	private String textAnswerRemark;
+
+	/**
+	 * 套题补充说明
+	 */
+	private String nestedAnswerRemark;
+
+	/**
+	 * 是否启用人脸识别
+     */
+	private String isFaceEnable;
+
+	/**
+	 * 进入考试是否验证人脸识别(强制、非强制)
+     */
+	private String isFaceCheck;
+
+	/**
+	 * 抓拍间隔
+     */
+	private Double snapshotInterval;
+
+	/**
+	 * 预警阈值
+     */
+	private Double warnThreshold;
+
+	/**
+	 * 阅卷方式
+     */
+	private MarkingType markingType;
+
+	/**
+	 * 学生是否可以删除
+     */
+	@NotNull
+	private Boolean canStuDel;
+	
+	/**
+	 * 是否开启人脸活体检测
+	 */
+	private Boolean isFaceVerify;
+	/**
+	 * 活体检测开始分钟数
+	 */
+	private Integer faceVerifyStartMinute;
+	/**
+	 * 活体检测结束分钟数
+	 */
+	private Integer faceVerifyEndMinute;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Date getBeginTime() {
+		return beginTime;
+	}
+
+	public void setBeginTime(Date beginTime) {
+		this.beginTime = beginTime;
+	}
+
+	public Date getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(Date endTime) {
+		this.endTime = endTime;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public ExamType getExamType() {
+		return examType;
+	}
+
+	public void setExamType(ExamType examType) {
+		this.examType = examType;
+	}
+
+	public Integer getDuration() {
+		return duration;
+	}
+
+	public void setDuration(Integer duration) {
+		this.duration = duration;
+	}
+
+	public Integer getFreezeTime() {
+		return freezeTime;
+	}
+
+	public void setFreezeTime(Integer freezeTime) {
+		this.freezeTime = freezeTime;
+	}
+
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Long getExamTimes() {
+		return examTimes;
+	}
+
+	public void setExamTimes(Long examTimes) {
+		this.examTimes = examTimes;
+	}
+
+	public Long getExamReconnectTime() {
+		return examReconnectTime;
+	}
+
+	public void setExamReconnectTime(Long examReconnectTime) {
+		this.examReconnectTime = examReconnectTime;
+	}
+
+	public String getBeforeExamRemark() {
+		return beforeExamRemark;
+	}
+
+	public void setBeforeExamRemark(String beforeExamRemark) {
+		this.beforeExamRemark = beforeExamRemark;
+	}
+
+	public String getAfterExamRemark() {
+		return afterExamRemark;
+	}
+
+	public void setAfterExamRemark(String afterExamRemark) {
+		this.afterExamRemark = afterExamRemark;
+	}
+
+	public String getIsObjScoreView() {
+		return isObjScoreView;
+	}
+
+	public void setIsObjScoreView(String isObjScoreView) {
+		this.isObjScoreView = isObjScoreView;
+	}
+
+	public PracticeType getPracticeType() {
+		return practiceType;
+	}
+
+	public void setPracticeType(PracticeType practiceType) {
+		this.practiceType = practiceType;
+	}
+
+	public String getSingleAnswerRemark() {
+		return singleAnswerRemark;
+	}
+
+	public void setSingleAnswerRemark(String singleAnswerRemark) {
+		this.singleAnswerRemark = singleAnswerRemark;
+	}
+
+	public String getMutipleAnswerRemark() {
+		return mutipleAnswerRemark;
+	}
+
+	public void setMutipleAnswerRemark(String mutipleAnswerRemark) {
+		this.mutipleAnswerRemark = mutipleAnswerRemark;
+	}
+
+	public String getBoolAnswerRemark() {
+		return boolAnswerRemark;
+	}
+
+	public void setBoolAnswerRemark(String boolAnswerRemark) {
+		this.boolAnswerRemark = boolAnswerRemark;
+	}
+
+	public String getFillBlankRemark() {
+		return fillBlankRemark;
+	}
+
+	public void setFillBlankRemark(String fillBlankRemark) {
+		this.fillBlankRemark = fillBlankRemark;
+	}
+
+	public String getTextAnswerRemark() {
+		return textAnswerRemark;
+	}
+
+	public void setTextAnswerRemark(String textAnswerRemark) {
+		this.textAnswerRemark = textAnswerRemark;
+	}
+
+	public String getNestedAnswerRemark() {
+		return nestedAnswerRemark;
+	}
+
+	public void setNestedAnswerRemark(String nestedAnswerRemark) {
+		this.nestedAnswerRemark = nestedAnswerRemark;
+	}
+
+	public String getIsFaceEnable() {
+		return isFaceEnable;
+	}
+
+	public void setIsFaceEnable(String isFaceEnable) {
+		this.isFaceEnable = isFaceEnable;
+	}
+
+	public String getIsFaceCheck() {
+		return isFaceCheck;
+	}
+
+	public void setIsFaceCheck(String isFaceCheck) {
+		this.isFaceCheck = isFaceCheck;
+	}
+
+	public Double getSnapshotInterval() {
+		return snapshotInterval;
+	}
+
+	public void setSnapshotInterval(Double snapshotInterval) {
+		this.snapshotInterval = snapshotInterval;
+	}
+
+	public Double getWarnThreshold() {
+		return warnThreshold;
+	}
+
+	public void setWarnThreshold(Double warnThreshold) {
+		this.warnThreshold = warnThreshold;
+	}
+
+	public MarkingType getMarkingType() {
+		return markingType;
+	}
+
+	public void setMarkingType(MarkingType markingType) {
+		this.markingType = markingType;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public Boolean getSingleEdit() {
+		return singleEdit;
+	}
+
+	public void setSingleEdit(Boolean singleEdit) {
+		this.singleEdit = singleEdit;
+	}
+
+	public Boolean getMutipleEdit() {
+		return mutipleEdit;
+	}
+
+	public void setMutipleEdit(Boolean mutipleEdit) {
+		this.mutipleEdit = mutipleEdit;
+	}
+
+	public Boolean getBoolEdit() {
+		return boolEdit;
+	}
+
+	public void setBoolEdit(Boolean boolEdit) {
+		this.boolEdit = boolEdit;
+	}
+
+	public Boolean getFillBlankEdit() {
+		return fillBlankEdit;
+	}
+
+	public void setFillBlankEdit(Boolean fillBlankEdit) {
+		this.fillBlankEdit = fillBlankEdit;
+	}
+
+	public Boolean getCanStuDel() {
+		return canStuDel;
+	}
+
+	public void setCanStuDel(Boolean canStuDel) {
+		this.canStuDel = canStuDel;
+	}
+
+	public Boolean getEntranceExam() {
+		return isEntranceExam;
+	}
+
+	public void setEntranceExam(Boolean entranceExam) {
+		isEntranceExam = entranceExam;
+	}
+	
+	public Boolean getIsEntranceExam() {
+		return isEntranceExam;
+	}
+
+	public void setIsEntranceExam(Boolean isEntranceExam) {
+		this.isEntranceExam = isEntranceExam;
+	}
+
+	public Boolean getIsFaceVerify() {
+		return isFaceVerify;
+	}
+
+	public void setIsFaceVerify(Boolean isFaceVerify) {
+		this.isFaceVerify = isFaceVerify;
+	}
+
+	public Integer getFaceVerifyStartMinute() {
+		return faceVerifyStartMinute;
+	}
+
+	public void setFaceVerifyStartMinute(Integer faceVerifyStartMinute) {
+		this.faceVerifyStartMinute = faceVerifyStartMinute;
+	}
+
+	public Integer getFaceVerifyEndMinute() {
+		return faceVerifyEndMinute;
+	}
+
+	public void setFaceVerifyEndMinute(Integer faceVerifyEndMinute) {
+		this.faceVerifyEndMinute = faceVerifyEndMinute;
+	}
+
+	public OutletExam() {
+	}
+}

+ 412 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletExamStudent.java

@@ -0,0 +1,412 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+import java.io.Serializable;
+
+public class OutletExamStudent implements Serializable {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = 4647883873040374983L;
+
+	private long id;
+
+    private String name;
+
+    private OutletExam exam;
+    /**
+     * 学校id
+     */
+    private Long rootOrgId;
+    /**
+     * 学习中心id
+     */
+    private Long orgId;
+    /**
+     * 学习中心code
+     */
+    private String orgCode;
+    private String orgName;
+
+    private String studentCode;
+
+    private String identityNumber;
+
+    private String examNumber;
+
+    private String courseCode;
+
+    private String courseName;
+
+    private String courseLevel;
+
+    /**
+     * 试卷类型
+     */
+    private String paperType;
+    /**
+     * 学位
+     */
+    private Boolean degree;
+
+    private String specialtyName;
+    /**
+	 * 专业code
+	 */
+	private String specialtyCode;
+
+    /**
+     * 是否重修
+     */
+    private Boolean repair;
+
+    /**
+     * 年级
+     */
+    private String grade;
+    /**
+     * 是否毕业
+     */
+    private Boolean graduated;
+    
+    /**
+     * 入学考试:recruit
+     * 毕业:graduated
+     * 非毕业:studying
+     */
+    private String remark;
+
+    /**
+     * 是否缺考
+     * 1:不缺考
+     * 0:缺考
+     */
+    private Boolean finished;
+
+    /**
+     * 学生id
+     */
+    private Long studentId;
+
+    private String phone;
+    private String infoCollector;
+    
+    /**
+	 * 正常考试次数  不含重考
+	 */
+	private Integer normalExamTimes;
+	/**
+	 * 是否为重考
+	 */
+	private Boolean isReexamine;
+	
+	/**
+	 * 重考原因类型
+	 */
+	private String reexamineType;
+	/**
+	 * 重考原因详情
+	 */
+	private String reexamineDetail;
+	/**
+	 * 重考已完成  true:是 false:否
+	 */
+	private Boolean reexamineCompleted;
+
+    /**
+     * 考试开始时间(针对学生,网考使用)
+     */
+    private String examBeginTime;
+
+    /**
+     * 考试结束时间(针对学生,网考使用)
+     */
+    private String examEndTime;
+
+    /**
+     * 是否可上传
+     */
+    private Boolean canUpload;
+
+	public OutletExamStudent() {}
+	
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public OutletExam getExam() {
+        return exam;
+    }
+
+    public void setExam(OutletExam exam) {
+        this.exam = exam;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getIdentityNumber() {
+        return identityNumber;
+    }
+
+    public void setIdentityNumber(String identityNumber) {
+        this.identityNumber = identityNumber;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getSpecialtyName() {
+        return specialtyName;
+    }
+
+    public void setSpecialtyName(String specialtyName) {
+        this.specialtyName = specialtyName;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getGrade() {
+        return grade;
+    }
+
+    public void setGrade(String grade) {
+        this.grade = grade;
+    }
+
+    public static long getSerialversionuid() {
+        return serialVersionUID;
+    }
+
+    public Long getRootOrgId() {
+        return rootOrgId;
+    }
+
+    public void setRootOrgId(Long rootOrgId) {
+        this.rootOrgId = rootOrgId;
+    }
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public String getOrgCode() {
+        return orgCode;
+    }
+
+    public void setOrgCode(String orgCode) {
+        this.orgCode = orgCode;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public String getCourseLevel() {
+        return courseLevel;
+    }
+
+    public void setCourseLevel(String courseLevel) {
+        this.courseLevel = courseLevel;
+    }
+
+    public Boolean getDegree() {
+        return degree;
+    }
+
+    public void setDegree(Boolean degree) {
+        this.degree = degree;
+    }
+
+    public Boolean getRepair() {
+        return repair;
+    }
+
+    public void setRepair(Boolean repair) {
+        this.repair = repair;
+    }
+
+    public Boolean getGraduated() {
+        return graduated;
+    }
+
+    public void setGraduated(Boolean graduated) {
+        this.graduated = graduated;
+    }
+
+    public Boolean getFinished() {
+        return finished;
+    }
+
+    public void setFinished(Boolean finished) {
+        this.finished = finished;
+    }
+
+    public Long getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Long studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getInfoCollector() {
+        return infoCollector;
+    }
+
+    public void setInfoCollector(String infoCollector) {
+        this.infoCollector = infoCollector;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public String getSpecialtyCode() {
+		return specialtyCode;
+	}
+
+	public void setSpecialtyCode(String specialtyCode) {
+		this.specialtyCode = specialtyCode;
+	}
+	
+	public Integer getNormalExamTimes() {
+		return normalExamTimes;
+	}
+
+	public void setNormalExamTimes(Integer normalExamTimes) {
+		this.normalExamTimes = normalExamTimes;
+	}
+
+	public Boolean getIsReexamine() {
+		return isReexamine;
+	}
+
+	public void setIsReexamine(Boolean isReexamine) {
+		this.isReexamine = isReexamine;
+	}
+
+	public String getReexamineType() {
+		return reexamineType;
+	}
+
+	public void setReexamineType(String reexamineType) {
+		this.reexamineType = reexamineType;
+	}
+
+	public String getReexamineDetail() {
+		return reexamineDetail;
+	}
+
+	public void setReexamineDetail(String reexamineDetail) {
+		this.reexamineDetail = reexamineDetail;
+	}
+
+	public Boolean getReexamineCompleted() {
+		return reexamineCompleted;
+	}
+
+	public void setReexamineCompleted(Boolean reexamineCompleted) {
+		this.reexamineCompleted = reexamineCompleted;
+	}
+
+    public Boolean getReexamine() {
+        return isReexamine;
+    }
+
+    public void setReexamine(Boolean reexamine) {
+        isReexamine = reexamine;
+    }
+
+    public String getExamBeginTime() {
+        return examBeginTime;
+    }
+
+    public void setExamBeginTime(String examBeginTime) {
+        this.examBeginTime = examBeginTime;
+    }
+
+    public String getExamEndTime() {
+        return examEndTime;
+    }
+
+    public void setExamEndTime(String examEndTime) {
+        this.examEndTime = examEndTime;
+    }
+
+    public Boolean getCanUpload() {
+        return canUpload;
+    }
+
+    public void setCanUpload(Boolean canUpload) {
+        this.canUpload = canUpload;
+    }
+}

+ 251 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletOrg.java

@@ -0,0 +1,251 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+import javax.validation.constraints.NotNull;
+
+import cn.com.qmth.examcloud.outlet.enums.OutletOrgType;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class OutletOrg implements Serializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 8250086189391122785L;
+	private Long id;
+    /**
+     * 顶级机构id,无上级时为0;eg.学校即是顶级
+     */
+    private Long rootId;
+    /**
+     * 父级机构id,无上级时为0;eg.学习中心的父级为学校
+     */
+    private Long parentId;
+
+    private Integer level;
+    
+    private String name;
+    
+    /**
+     * 学习中心代码
+     */
+    private String code;
+
+    private String logo;
+
+    private String address;
+
+    /**
+     * 可使用的应用模块
+     */
+    private String apps;
+
+    @NotNull
+    private Boolean enable;
+    
+    /**
+     * 联系电话
+     */
+    private String telphone;
+    /**
+     * 联系人
+     */
+    private String contacts;
+
+    private Date createTime;
+
+    private Date updateTime;
+    
+    /**
+     * 机构类型:学校,启明,印刷
+     */
+    private OutletOrgType type;
+    
+    /**
+     * 机器数量
+     */
+    private Integer macNumber;
+    
+    /**
+     * 是否提供人员
+     */
+    private Boolean isProvide;
+    
+    /**
+     * 备注
+     */
+    private String remark;
+    
+    /**
+     * 网考端系统名称
+     */
+    private String examSysName;
+    
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getRootId() {
+        return rootId;
+    }
+
+    public void setRootId(Long rootId) {
+        this.rootId = rootId;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public Integer getLevel() {
+        return level;
+    }
+
+    public void setLevel(Integer level) {
+        this.level = level;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getLogo() {
+        return logo;
+    }
+
+    public void setLogo(String logo) {
+        this.logo = logo;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getApps() {
+        return apps;
+    }
+
+    public void setApps(String apps) {
+        this.apps = apps;
+    }
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getTelphone() {
+		return telphone;
+	}
+
+	public void setTelphone(String telphone) {
+		this.telphone = telphone;
+	}
+
+	public String getContacts() {
+		return contacts;
+	}
+
+	public void setContacts(String contacts) {
+		this.contacts = contacts;
+	}
+
+
+	public OutletOrgType getType() {
+		return type;
+	}
+
+	public void setType(OutletOrgType type) {
+		this.type = type;
+	}
+	
+	public Integer getMacNumber() {
+		return macNumber;
+	}
+
+	public void setMacNumber(Integer macNumber) {
+		this.macNumber = macNumber;
+	}
+
+	public Boolean getIsProvide() {
+		return isProvide;
+	}
+
+	public void setIsProvide(Boolean isProvide) {
+		this.isProvide = isProvide;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	
+	public String getExamSysName() {
+		return examSysName;
+	}
+
+	public void setExamSysName(String examSysName) {
+		this.examSysName = examSysName;
+	}
+
+	public OutletOrg(String name, String code, String contacts,String telphone) {
+        this.name = name;
+        this.code = code;
+        this.telphone = telphone;
+        this.contacts = contacts;
+    }
+
+    public OutletOrg() {
+    }
+}

+ 151 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/entity/OutletStudent.java

@@ -0,0 +1,151 @@
+package cn.com.qmth.examcloud.outlet.entity;
+
+import cn.com.qmth.examcloud.common.dto.core.User;
+
+import javax.validation.constraints.NotNull;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Created by songyue on 17/1/13.
+ */
+public class OutletStudent implements Serializable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -3879026866880289468L;
+
+	private Long id;
+
+	private User user;
+
+	@NotNull
+	private String name;
+
+	private String studentCode;
+
+	private String identityNumber;
+
+	private String photoPath;
+
+	private String remark;
+
+	private Boolean enable;
+
+	private Date createTime;
+
+	private Date updateTime;
+
+	private Long orgId;
+
+	private Long rootOrgId;
+
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
+	}
+	
+	public OutletStudent() {
+	}
+
+	public OutletStudent(Long studentId) {
+		this.id = studentId;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+
+	public String getPhotoPath() {
+		return photoPath;
+	}
+
+	public void setPhotoPath(String photoPath) {
+		this.photoPath = photoPath;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+}

+ 63 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/enums/OrgIdServiceEnum.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.outlet.enums;
+/**
+ * @author  	chenken
+ * @date    	2018年5月17日 下午2:56:03
+ * @company 	QMTH
+ * @description 机构ID与service名称枚举类
+ */
+public enum OrgIdServiceEnum {
+	
+	SYDX(1L,"sydxScorePushService","石油大学推送成绩service"),
+	
+	XNCD(1384L,"xncdScorePushService","西南财大推送成绩service");
+	
+	private OrgIdServiceEnum(Long orgId, String serviceName, String desc) {
+		this.orgId = orgId;
+		this.serviceName = serviceName;
+		this.desc = desc;
+	}
+	
+	public static OrgIdServiceEnum getServiceNameByOrgId(Long orgId){
+		if(orgId == null){
+			return null;
+		}
+		for(OrgIdServiceEnum orgIdServiceEnum:OrgIdServiceEnum.values()){
+			if(orgId.longValue() == orgIdServiceEnum.getOrgId().longValue()){
+				return orgIdServiceEnum;
+			}
+		}
+		return null;
+	}
+
+	private Long orgId;
+	
+	private String serviceName;
+	
+	private String desc;
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getServiceName() {
+		return serviceName;
+	}
+
+	public void setServiceName(String serviceName) {
+		this.serviceName = serviceName;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+	
+}
+

+ 17 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/enums/OutletOrgType.java

@@ -0,0 +1,17 @@
+package cn.com.qmth.examcloud.outlet.enums;
+
+public enum OutletOrgType {
+	SCHOOL("学校"),
+	PRINT_QMTH("启明"),
+	PRINT_SUPPLIER("印刷");
+	
+	private String name;
+	
+	private OutletOrgType(String name){
+		this.name = name;
+	}
+	
+	public String getName(){
+		return this.name;
+	}
+}

+ 39 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/repo/ExamScoreRepo.java

@@ -0,0 +1,39 @@
+package cn.com.qmth.examcloud.outlet.repo;
+
+import cn.com.qmth.examcloud.outlet.dto.ExamScore;
+import cn.com.qmth.examcloud.outlet.dto.OutletScore;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by yuanpan on 2017/4/26.
+ */
+@Repository
+public interface ExamScoreRepo extends JpaRepository<ExamScore, Long> {
+
+    //    @Query(nativeQuery = true, value = "select \n" +
+//            "s.id `score_id`, stu.`name` `student_name`, stu.student_code,stu.identity_number,\n" +
+//            "s.total_score,s.objective_score,s.subjective_score,\n" +
+//            "stu.course_name,stu.course_code,stu.remark `student_remark`,\n" +
+//            "r.end_time\n" +
+//            "from oe_exam_score s \n" +
+//            "left join oe_exam_record r on s.exam_record_id = r.id\n" +
+//            "left join ecs_exam_student stu on stu.id = r.exam_student_id\n" +
+//            "left join ecs_exam e on e.id = r.batch_id\n" +
+//            "where e.remark = ?1 and stu.remark = ?2 and e.org_id = ?3")
+//    List<Object> findOutletScoreByRemark(String examRemark, String examStuRemark, Long examOrgId);
+
+    List<OutletScore> sydxQuery(String examRemark, String examStuRemark, Long examOrgId);
+
+    List<OutletScore> sydxGet(Long scoreId);
+    
+    /**
+     * 按身份证号查询成绩
+     * @param identityNumber 身份证号
+     * @return
+     */
+    List<OutletScore> sydxQueryScoreByIdentityNumber(List<String> identityNumbers, Long examOrgId);
+    
+}

+ 40 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/utils/OutletUtils.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.examcloud.outlet.utils;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author  	chenken
+ * @date    	2018年5月17日 下午3:56:42
+ * @company 	QMTH
+ * @description OutletUtils.java
+ */
+public class OutletUtils {
+
+    public static Map<String, Object> getKeyAndValue(Object obj) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        // 得到类对象
+        Class<?> userCla = (Class<?>) obj.getClass();
+        /* 得到类中的所有属性集合 */
+        Field[] fs = userCla.getDeclaredFields();
+        for (int i = 0; i < fs.length; i++) {
+            Field f = fs[i];
+            f.setAccessible(true); // 设置些属性是可以访问的
+            Object val = new Object();
+            try {
+                val = f.get(obj);
+                // 得到此属性的值
+                map.put(f.getName(), val);// 设置键值
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        System.out.println("单个对象的所有键值==反射==" + map.toString());
+        return map;
+    }
+	
+}
+

+ 59 - 0
examcloud-outlet-domain/src/main/java/cn/com/qmth/examcloud/outlet/utils/SpringContextUtils.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.examcloud.outlet.utils;
+
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * 获取ApplicationContext和Object的工具类
+ */
+@Component
+public class SpringContextUtils implements ApplicationContextAware {
+    private static ApplicationContext applicationContext;
+ 
+    public void setApplicationContext(ApplicationContext arg0)
+            throws BeansException {
+        applicationContext = arg0;
+    }
+ 
+    /**
+     * 获取applicationContext对象
+     * @return
+     */
+    public static ApplicationContext getApplicationContext(){
+        return applicationContext;
+    }
+     
+    /**
+     * 根据bean的id来查找对象
+     * @param id
+     * @return
+     */
+    public static Object getBeanById(String id){
+        return applicationContext.getBean(id);
+    }
+     
+    /**
+     * 根据bean的class来查找对象
+     * @param c
+     * @return
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static Object getBeanByClass(Class c){
+        return applicationContext.getBean(c);
+    }
+     
+    /**
+     * 根据bean的class来查找所有的对象(包括子类)
+     * @param c
+     * @return
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static Map getBeansByClass(Class c){
+        return applicationContext.getBeansOfType(c);
+    }
+}
+

+ 3 - 0
pom.xml

@@ -21,5 +21,8 @@
 		<module>examcloud-exchange-outer-api-provider</module>
 		<module>examcloud-exchange-outer-service</module>
 		<module>examcloud-exchange-outer-dao</module>
+
+		<module>examcloud-outlet-api</module>
+		<module>examcloud-outlet-domain</module>
 	</modules>
 </project>