deason 5 年之前
父节点
当前提交
a7f4626fae
共有 100 个文件被更改,包括 9358 次插入2 次删除
  1. 12 0
      .gitignore
  2. 0 2
      README.md
  3. 38 0
      examcloud-exchange-base/pom.xml
  4. 57 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/CourseLevel.java
  5. 29 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/ExamRecordStatus.java
  6. 19 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/GenerateStudentPaperStatus.java
  7. 46 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/IsSuccess.java
  8. 41 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/MarkingType.java
  9. 63 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/OrgIdServiceEnum.java
  10. 17 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/OutletOrgType.java
  11. 24 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/PracticeType.java
  12. 78 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/BaseResponse.java
  13. 39 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/FailureBaseResponse.java
  14. 9 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/IBaseResponse.java
  15. 36 0
      examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/SuccessBaseResponse.java
  16. 23 0
      examcloud-exchange-inner-api-provider/pom.xml
  17. 144 0
      examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/controller/UpyunController.java
  18. 72 0
      examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/SmsCloudServiceProvider.java
  19. 102 0
      examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/UpyunCloudServiceProvider.java
  20. 19 0
      examcloud-exchange-inner-service/pom.xml
  21. 40 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/SmsService.java
  22. 62 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/CaptureFailedAlarmInfo.java
  23. 81 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/SendSmsInfo.java
  24. 78 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/ShortMessageInfo.java
  25. 31 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/SmsCodeRedisInfo.java
  26. 207 0
      examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/impl/SmsServiceImpl.java
  27. 23 0
      examcloud-exchange-outer-api-provider/pom.xml
  28. 177 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/CommonGainScoreController.java
  29. 181 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/FaceController.java
  30. 99 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeExamController.java
  31. 50 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeExamVerifyPhotoController.java
  32. 122 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeStudentInfoController.java
  33. 107 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/bean/SwufeCreateExamDomain.java
  34. 265 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/bean/SwufeSaveExamStudentDomain.java
  35. 116 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/SydxScoreController.java
  36. 242 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/SydxStudentExamInfoController.java
  37. 539 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamDomain.java
  38. 66 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamScoreDomain.java
  39. 409 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamStudentDomain.java
  40. 95 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxFailureRecordDomain.java
  41. 33 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxImportDomain.java
  42. 78 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/CourseGroupOuterServiceProvider.java
  43. 138 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamOuterServiceProvider.java
  44. 481 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamQuestionOuterServiceProvider.java
  45. 380 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamStudentOuterServiceProvider.java
  46. 216 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/FaceOuterServiceProvider.java
  47. 64 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/GetExamRecordAuditInfoServiceProvider.java
  48. 148 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/GetScoreDataServiceProvider.java
  49. 73 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/QueryCapturePhotoServiceProvider.java
  50. 114 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ScoreQueueServiceProvider.java
  51. 269 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/StudentOuterServiceProvider.java
  52. 204 0
      examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/cug/CugOuterServiceProvider.java
  53. 19 0
      examcloud-exchange-outer-api/pom.xml
  54. 25 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/CourseGroupOuterService.java
  55. 26 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/CugOuterService.java
  56. 36 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamOuterService.java
  57. 57 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamQuestionOuterService.java
  58. 36 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamStudentOuterService.java
  59. 29 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/FaceOuterService.java
  60. 18 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/GetExamRecordAuditInfoService.java
  61. 22 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/GetScoreDataService.java
  62. 18 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/QueryCapturePhotoService.java
  63. 32 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ScoreQueueService.java
  64. 57 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/StudentOuterService.java
  65. 46 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/CourseBean.java
  66. 56 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultPaperBean.java
  67. 56 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionGroupBean.java
  68. 109 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionStructureWrapperBean.java
  69. 67 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionUnitWrapperBean.java
  70. 206 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/ExamStudent4BatchBean.java
  71. 136 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/ExamStudentStatus4BatchBean.java
  72. 63 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterBlockBean.java
  73. 128 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamRecordBean.java
  74. 173 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudent4ResetReqBean.java
  75. 285 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudent4ResetRespBean.java
  76. 160 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudentBean.java
  77. 60 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterGetCapturePhotoBean.java
  78. 135 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterScoreDataBean.java
  79. 25 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSectionBean.java
  80. 25 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSectionCollectionBean.java
  81. 63 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectivePaperStructBean.java
  82. 61 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectiveQuestionBean.java
  83. 93 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectiveQuestionRecordBean.java
  84. 183 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/Student4BatchBean.java
  85. 52 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/StudentStatus4BatchBean.java
  86. 76 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterBatchSaveExamStudentReq.java
  87. 35 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterBatchSaveStudentReq.java
  88. 43 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterDeleteScoreQueueTopReq.java
  89. 32 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetCourseListReq.java
  90. 35 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetExamRecordAuditInfoReq.java
  91. 62 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetExamReq.java
  92. 59 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetPaperStructReq.java
  93. 26 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetQuestionAnswerReq.java
  94. 42 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetScoreDataReq.java
  95. 24 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetScoreQueueTopReq.java
  96. 26 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetSubjectivePaperStructReq.java
  97. 59 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetSubjectiveQuestionReq.java
  98. 42 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterQueryCapturePhotoReq.java
  99. 82 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterQueryScoreDataReq.java
  100. 102 0
      examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterResetExamStudentReq.java

+ 12 - 0
.gitignore

@@ -0,0 +1,12 @@
+.project
+.classpath
+.settings
+target/
+.idea/
+*.iml
+*test/
+# Package Files #
+*.jar
+logs/
+
+

+ 0 - 2
README.md

@@ -1,2 +0,0 @@
-# examcloud-exchange
-

+ 38 - 0
examcloud-exchange-base/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<project
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+        xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>cn.com.qmth.examcloud.exchange</groupId>
+        <artifactId>examcloud-exchange</artifactId>
+        <version>2019-SNAPSHOT</version>
+    </parent>
+    <artifactId>examcloud-exchange-base</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-web</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-support</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.0.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.6</version>
+        </dependency>
+    </dependencies>
+</project>

+ 57 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/CourseLevel.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+public enum CourseLevel {
+
+	ZSB("专升本", "Z"),
+
+	GQZ("高起专", "Q"),
+
+	GQB("高起本", "S"),
+
+	ALL("不限", "");
+
+	/**
+	 * 名称
+	 */
+	private String name;
+
+	/**
+	 * 简写
+	 */
+	private String abbreviate;
+
+	private CourseLevel(String name, String abbreviate) {
+		this.name = name;
+		this.abbreviate = abbreviate;
+	}
+
+	public String getName() {
+		return this.name;
+	}
+
+	public String getAbbreviate() {
+		return abbreviate;
+	}
+
+	/**
+	 * 混合查询
+	 *
+	 * @author WANGWEI
+	 * @param name
+	 * @return
+	 */
+	public static CourseLevel getCourseLevel(String name) {
+		if (null == name) {
+			return CourseLevel.ALL;
+		}
+		for (CourseLevel cur : CourseLevel.values()) {
+			if (name.equals(cur.getName())) {
+				return cur;
+			}
+			if (name.equals(cur.name())) {
+				return cur;
+			}
+		}
+		return CourseLevel.ALL;
+	}
+}

+ 29 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/ExamRecordStatus.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+/**
+ * 考试记录状态
+ * @author xudengqi
+ * 2016年8月23日
+ */
+public enum ExamRecordStatus {
+	/**
+	 * 考试中
+	 */
+	EXAM_ING,
+	
+	/**
+	 * 考试结束
+	 */
+	EXAM_END,
+	
+	/**
+	 * 考试过期
+	 */
+	EXAM_OVERDUE,
+	
+	/**
+	 * 考试无效/作废
+	 */
+	EXAM_INVALID;
+
+}

+ 19 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/GenerateStudentPaperStatus.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+/**
+ * Created by yuanpan on 2017/8/8.
+ */
+public enum GenerateStudentPaperStatus {
+	/**
+	 * 成功
+	 */
+    SUCCEEDED,
+    /**
+     * 失败
+     */
+    FAILED,
+    /**
+     * 不需要
+     */
+    NONEED
+}

+ 46 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/IsSuccess.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+/**
+ * @author  	chenken
+ * @date    	2018年2月26日 下午3:13:05
+ * @company 	QMTH
+ * @description 成功或失败
+ */
+public enum IsSuccess {
+	/**
+	 * 成功
+	 */
+	SUCCESS("成功"),
+	/**
+	 * 失败
+	 */
+	FAILED("失败");
+	
+	private String desc;
+	
+	public static IsSuccess strToEnum(String name){
+		if(name==null || "".equals(name)){
+			return null;
+		}
+		for(IsSuccess isSuccess:IsSuccess.values()){
+			if(name.equals(isSuccess.name())){
+				return isSuccess;
+			}
+		}
+		
+		return null;
+	}
+	
+	private IsSuccess(String desc){
+		this.desc = desc;
+	}
+	
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+}
+

+ 41 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/MarkingType.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+/**
+ * Created by songyue on 17/6/22.
+ */
+public enum MarkingType {
+
+    ALL("全部评阅"),
+    OBJECT_SCORE_MAX("客观分最高"),
+    LAST_SUBMIT("最后一次提交");
+    
+    public static void main(String[] args) {
+		System.out.println(MarkingType.toMarkingType("XXX"));
+	}
+    
+    public static MarkingType toMarkingType(String str){
+    	if(str==null || "".equals(str)){
+    		return null;
+    	}
+    	for(MarkingType type:MarkingType.values()){
+    		if(str.equals(type.name())){
+    			return type;
+    		}
+    	}
+    	return null;
+    }
+
+    private String name;
+
+    private MarkingType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 63 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/OrgIdServiceEnum.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.exchange.base.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-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/OutletOrgType.java

@@ -0,0 +1,17 @@
+package cn.com.qmth.examcloud.exchange.base.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;
+	}
+}

+ 24 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/enums/PracticeType.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.examcloud.exchange.base.enums;
+
+/**
+ * Created by songyue on 17/6/22.
+ */
+public enum PracticeType {
+
+    AFTER_PRACTICE("结束统一显示答案"),
+    IN_PRACTICE("边答边显示答案");
+
+    private String name;
+
+    private PracticeType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 78 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/BaseResponse.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.exchange.base.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-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/FailureBaseResponse.java

@@ -0,0 +1,39 @@
+package cn.com.qmth.examcloud.exchange.base.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-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/IBaseResponse.java

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

+ 36 - 0
examcloud-exchange-base/src/main/java/cn/com/qmth/examcloud/exchange/base/response/SuccessBaseResponse.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.exchange.base.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;
+    }
+}

+ 23 - 0
examcloud-exchange-inner-api-provider/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2019-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-exchange-inner-api-provider</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.rpc</groupId>
+			<artifactId>examcloud-exchange-inner-api</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.exchange</groupId>
+			<artifactId>examcloud-exchange-inner-service</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+	</dependencies>
+</project>

+ 144 - 0
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/controller/UpyunController.java

@@ -0,0 +1,144 @@
+package cn.com.qmth.examcloud.exchange.inner.api.controller;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.util.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+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.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.AES;
+import cn.com.qmth.examcloud.commons.util.MD5;
+import cn.com.qmth.examcloud.commons.util.UUID;
+import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.filestorage.FileStoragePathEnvInfo;
+import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.upyun.UpyunService;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * Upyun服务
+ *
+ * @author WANGWEI
+ * @date 2018年11月21日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@RestController
+@RequestMapping("${$rmp.ctr.exchange.inner}/upyun")
+public class UpyunController extends ControllerSupport {
+
+    @Autowired
+    SystemProperties systemConfig;
+
+    @Autowired
+    UpyunService upyunService;
+
+    @ApiOperation(value = "保存照片")
+    @PutMapping("put/{siteId}/{fileSuffix}")
+    public String putFile(@PathVariable String siteId, @PathVariable String fileSuffix,
+                          @RequestParam(required = false) String md5, HttpServletRequest req) {
+
+        String contentLength = req.getHeader("Content-Length");
+        if (StringUtils.isNotBlank(contentLength)) {
+            long contentLengthLong = Long.parseLong(contentLength);
+            if (contentLengthLong < 10) {
+                throw new StatusException("600108", "empty IO stream");
+            }
+        }
+
+        if (StringUtils.isNotBlank(md5)) {
+            if (MD5.encrypt16("").equalsIgnoreCase(md5)) {
+                throw new StatusException("600109", "empty IO stream");
+            }
+        }
+
+        User accessUser = getAccessUser();
+
+        if (!fileSuffix.matches("\\w+")) {
+            throw new StatusException("600100", "fileSuffix is wrong");
+        }
+
+        fileSuffix = "." + fileSuffix;
+
+        ServletInputStream in = null;
+
+        if (StringUtils.isNotBlank(md5)) {
+
+            try {
+                in = req.getInputStream();
+
+                //通用存储
+                FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+                env.setRootOrgId(String.valueOf(accessUser.getRootOrgId()));
+                env.setUserId(String.valueOf(accessUser.getUserId()));
+                env.setFileSuffix(fileSuffix);
+                YunPathInfo pi = FileStorageUtil.saveFile(siteId, env, in, md5);
+                String url = pi.getUrl();
+
+                url = new AES().encrypt(url);
+                return url;
+            } catch (IOException e) {
+                throw new ExamCloudRuntimeException(e);
+            } finally {
+                IOUtils.closeQuietly(in);
+            }
+
+        } else {
+
+            try {
+                FileUtils.forceMkdir(new File(systemConfig.getTempDataDir()));
+            } catch (IOException e1) {
+                log.error("fail to make dir. path=" + systemConfig.getTempDataDir());
+            }
+
+            String filePath = systemConfig.getTempDataDir() + File.separator + UUID.randomUUID()
+                    + fileSuffix;
+            File file = new File(filePath);
+
+            FileOutputStream out = null;
+            try {
+                in = req.getInputStream();
+                out = new FileOutputStream(file);
+                IOUtils.copy(in, out);
+
+                //通用存储
+                FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+                env.setRootOrgId(String.valueOf(accessUser.getRootOrgId()));
+                env.setUserId(String.valueOf(accessUser.getUserId()));
+                env.setFileSuffix(fileSuffix);
+                YunPathInfo pi = FileStorageUtil.saveFile(siteId, env, file, true);
+                String url = pi.getUrl();
+                url = new AES().encrypt(url);
+                return url;
+            } catch (IOException e) {
+                throw new ExamCloudRuntimeException(e);
+            } finally {
+                IOUtils.closeQuietly(in);
+                IOUtils.closeQuietly(out);
+                try {
+                    FileUtils.forceDelete(file);
+                } catch (IOException e) {
+                    log.error("fail to delete file. path=" + filePath);
+                }
+            }
+
+        }
+
+    }
+
+}

+ 72 - 0
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/SmsCloudServiceProvider.java

@@ -0,0 +1,72 @@
+package cn.com.qmth.examcloud.exchange.inner.api.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.validation.Valid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.exchange.inner.api.SmsCloudService;
+import cn.com.qmth.examcloud.exchange.inner.api.request.CheckSmsCodeReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsCodeReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsReq;
+import cn.com.qmth.examcloud.exchange.inner.api.response.CheckSmsCodeResp;
+import cn.com.qmth.examcloud.exchange.inner.api.response.SendSmsCodeResp;
+import cn.com.qmth.examcloud.exchange.inner.api.response.SendSmsResp;
+import cn.com.qmth.examcloud.exchange.inner.service.SmsService;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.WithoutStackTrace;
+import io.swagger.annotations.ApiParam;
+
+/**
+ * 短信发送
+ */
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.inner}" + "/sms")
+public class SmsCloudServiceProvider extends ControllerSupport implements SmsCloudService {
+
+	private static final long serialVersionUID = -1497756895732370672L;
+
+	@Autowired
+	private SmsService smsService;
+
+	@Override
+	@RequestMapping(method = RequestMethod.POST, value = "sendSms")
+	public SendSmsResp sendSms(@RequestBody @Valid @ApiParam(required = true) SendSmsReq req) {
+
+		String smsAssemblyCode = req.getSmsAssemblyCode();
+		List<String> phoneList = req.getPhoneList();
+		Map<String, String> params = req.getParams();
+
+		smsService.sendSms(smsAssemblyCode, phoneList, params);
+
+		SendSmsResp resp = new SendSmsResp();
+		return resp;
+	}
+
+	@Override
+	@WithoutStackTrace
+	@RequestMapping(method = RequestMethod.POST, value = "sendSmsCode")
+	public SendSmsCodeResp sendSmsCode(
+			@RequestBody @Valid @ApiParam(required = true) SendSmsCodeReq req) {
+		smsService.sendSmsCode(req.getPhone(), req.getCode());
+		SendSmsCodeResp sendSmsResp = new SendSmsCodeResp();
+		return sendSmsResp;
+	}
+
+	@Override
+	@WithoutStackTrace
+	@RequestMapping(method = RequestMethod.POST, value = "checkSmsCode")
+	public CheckSmsCodeResp checkSmsCode(
+			@RequestBody @Valid @ApiParam(required = true) CheckSmsCodeReq req) {
+		smsService.validateSmsCode(req.getPhone(), req.getCode());
+		CheckSmsCodeResp resp = new CheckSmsCodeResp();
+		return resp;
+	}
+
+}

+ 102 - 0
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/UpyunCloudServiceProvider.java

@@ -0,0 +1,102 @@
+package cn.com.qmth.examcloud.exchange.inner.api.provider;
+
+import java.io.IOException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.ModelAttribute;
+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 org.springframework.web.multipart.MultipartFile;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.AES;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.exchange.inner.api.UpyunCloudService;
+import cn.com.qmth.examcloud.exchange.inner.api.request.DeleteFileReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.PutFileReq;
+import cn.com.qmth.examcloud.exchange.inner.api.response.DeleteFileResp;
+import cn.com.qmth.examcloud.exchange.inner.api.response.PutFileResp;
+import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.filestorage.FileStoragePathEnvInfo;
+import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.upyun.UpyunService;
+
+/**
+ * Upyun服务
+ *
+ * @author WANGWEI
+ * @date 2018年11月21日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.inner}/upyun")
+public class UpyunCloudServiceProvider extends ControllerSupport implements UpyunCloudService {
+
+    private static final long serialVersionUID = -6911335293165224994L;
+
+    @Autowired
+    UpyunService upyunService;
+
+    @Autowired
+    SystemProperties systemConfig;
+
+    AES aes = new AES();
+
+    @PostMapping("putFile")
+    @Override
+    public PutFileResp putFile(@ModelAttribute PutFileReq req) {
+        String fileSuffix = req.getFileSuffix();
+        String relativePath = req.getRelativePath();
+        if (StringUtils.isNotBlank(relativePath)) {
+            relativePath = PathUtil.startsWithoutSeparator(relativePath);
+        }
+        Long rootOrgId = req.getRootOrgId();
+        String rootOrgDomain = req.getRootOrgDomain();
+        Long userId = req.getUserId();
+        String siteId = req.getSiteId();
+        MultipartFile mf = req.getFile();
+
+        FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+        env.setRootOrgId(String.valueOf(rootOrgId));
+        env.setRootOrgDomain(rootOrgDomain);
+        env.setUserId(String.valueOf(userId));
+        env.setFileSuffix(fileSuffix);
+        env.setRelativePath(relativePath);
+
+        env.setExt1(req.getExt1());
+        env.setExt2(req.getExt2());
+        env.setExt3(req.getExt3());
+        env.setExt4(req.getExt4());
+        env.setExt5(req.getExt5());
+
+        YunPathInfo pi = null;
+        try {
+            pi = FileStorageUtil.saveFile(siteId, env, mf.getInputStream(), null);
+        } catch (IOException e) {
+            throw new StatusException("005001", "fail to write to upyun", e);
+        }
+
+        PutFileResp resp = new PutFileResp();
+        resp.setUrl(pi.getUrl());
+        resp.setRelativePath(pi.getRelativePath());
+        return resp;
+    }
+
+    @PostMapping("deleteFile")
+    @Override
+    public DeleteFileResp deleteFile(@RequestBody DeleteFileReq req) {
+        String siteId = req.getSiteId();
+        String filePath = req.getFilePath();
+
+        upyunService.delete(siteId, filePath);
+
+        DeleteFileResp resp = new DeleteFileResp();
+        return resp;
+    }
+
+}

+ 19 - 0
examcloud-exchange-inner-service/pom.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2019-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-exchange-inner-service</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.exchange</groupId>
+			<artifactId>examcloud-exchange-base</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+	</dependencies>
+</project>

+ 40 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/SmsService.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.examcloud.exchange.inner.service;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SmsService {
+	/**
+	 * 验证码配置代码
+	 */
+	String YZM_SMS_ASSEMBLY_CODE = "YZM";
+
+	/**
+	 * 发送短信
+	 *
+	 * @param smsAssemblyCode
+	 * @param phoneList
+	 * @param params
+	 */
+	void sendSms(String smsAssemblyCode, List<String> phoneList, Map<String, String> params);
+
+	/**
+	 * 发送短信验证码
+	 *
+	 * @param phone
+	 *            手机号
+	 * @param code
+	 *            验证码
+	 */
+	void sendSmsCode(String phone, String code);
+
+	/**
+	 * 校验短信验证码
+	 *
+	 * @param phone
+	 *            手机号
+	 * @param code
+	 *            验证码
+	 */
+	void validateSmsCode(String phone, String code);
+}

+ 62 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/CaptureFailedAlarmInfo.java

@@ -0,0 +1,62 @@
+package cn.com.qmth.examcloud.exchange.inner.service.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.BaseRequest;
+
+public class CaptureFailedAlarmInfo extends BaseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 825615697674106990L;
+	/**
+	 * 签名
+	 */
+	private String sign;
+	/**
+	 * 模板code
+	 */
+	private String templateCode;
+	
+	/**
+	 * 手机号码 
+	 */
+	private String phone;
+	
+	/**
+	 * 模板变量
+	 */
+	private String templateParam;
+
+	public String getSign() {
+		return sign;
+	}
+
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+
+	public String getTemplateCode() {
+		return templateCode;
+	}
+
+	public void setTemplateCode(String templateCode) {
+		this.templateCode = templateCode;
+	}
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public String getTemplateParam() {
+		return templateParam;
+	}
+
+	public void setTemplateParam(String templateParam) {
+		this.templateParam = templateParam;
+	}
+
+}

+ 81 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/SendSmsInfo.java

@@ -0,0 +1,81 @@
+package cn.com.qmth.examcloud.exchange.inner.service.bean;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年7月4日 上午11:04:00
+ * @company 	QMTH
+ * @description SendSmsInfo.java
+ */
+public class SendSmsInfo implements Serializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 6836677240744430606L;
+	/**
+	 * 手机号码 
+	 */
+	private String phone;
+	/**
+	 * 验证码
+	 */
+	private String code;
+	/**
+	 * 签名
+	 */
+	private String sign;
+	/**
+	 * 模板code
+	 */
+	private String templateCode;
+	/**
+	 * 允许请求的间隔时间/秒
+	 */
+	private Integer intervalSeconds;
+	/**
+	 * 有效时间 / 秒
+	 */
+	private Integer effectiveTime;
+	
+	
+	public String getPhone() {
+		return phone;
+	}
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+	public String getCode() {
+		return code;
+	}
+	public void setCode(String code) {
+		this.code = code;
+	}
+	public String getSign() {
+		return sign;
+	}
+	public void setSign(String sign) {
+		this.sign = sign;
+	}
+	public String getTemplateCode() {
+		return templateCode;
+	}
+	public void setTemplateCode(String templateCode) {
+		this.templateCode = templateCode;
+	}
+	public Integer getEffectiveTime() {
+		return effectiveTime;
+	}
+	public void setEffectiveTime(Integer effectiveTime) {
+		this.effectiveTime = effectiveTime;
+	}
+	public Integer getIntervalSeconds() {
+		return intervalSeconds;
+	}
+	public void setIntervalSeconds(Integer intervalSeconds) {
+		this.intervalSeconds = intervalSeconds;
+	}
+	
+}

+ 78 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/ShortMessageInfo.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.exchange.inner.service.bean;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class ShortMessageInfo implements Serializable {
+
+	private static final long serialVersionUID = 6234229280391013286L;
+
+	/**
+	 * 接受短信的手机号
+	 */
+	private String phone;
+
+	/**
+	 * 发送次数
+	 */
+	private Integer times;
+
+	/**
+	 * 最后一次消息
+	 */
+	private String lastMessage;
+
+	/**
+	 * 发送时间
+	 */
+	private List<Date> sendTimeList = new ArrayList<Date>();
+
+	/**
+	 * 创建时间
+	 */
+	private Date creationTime;
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public Integer getTimes() {
+		return times;
+	}
+
+	public void setTimes(Integer times) {
+		this.times = times;
+	}
+
+	public String getLastMessage() {
+		return lastMessage;
+	}
+
+	public void setLastMessage(String lastMessage) {
+		this.lastMessage = lastMessage;
+	}
+
+	public List<Date> getSendTimeList() {
+		return sendTimeList;
+	}
+
+	public void setSendTimeList(List<Date> sendTimeList) {
+		this.sendTimeList = sendTimeList;
+	}
+
+	public Date getCreationTime() {
+		return creationTime;
+	}
+
+	public void setCreationTime(Date creationTime) {
+		this.creationTime = creationTime;
+	}
+
+}

+ 31 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/SmsCodeRedisInfo.java

@@ -0,0 +1,31 @@
+package cn.com.qmth.examcloud.exchange.inner.service.bean;
+
+import java.io.Serializable;
+
+public class SmsCodeRedisInfo implements Serializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 2874230996452650628L;
+
+	private String code;
+	
+	private long createTime;
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public long getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(long createTime) {
+		this.createTime = createTime;
+	}
+}

+ 207 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/impl/SmsServiceImpl.java

@@ -0,0 +1,207 @@
+package cn.com.qmth.examcloud.exchange.inner.service.impl;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tomcat.util.buf.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.http.ProtocolType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.google.common.collect.Maps;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
+import cn.com.qmth.examcloud.commons.util.UUID;
+import cn.com.qmth.examcloud.exchange.inner.service.SmsService;
+import cn.com.qmth.examcloud.exchange.inner.service.bean.ShortMessageInfo;
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.SmsAssemblyCacheBean;
+import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
+import cn.com.qmth.examcloud.web.redis.RedisClient;
+
+/**
+ * {@link StatusException} 状态码范围:101XXX<br>
+ * <p>
+ * 阿里云短信服务
+ *
+ * @author WANGWEI
+ * @date 2019年3月27日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Service
+public class SmsServiceImpl implements SmsService {
+
+	@Autowired
+	RedisClient redisClient;
+
+	protected ExamCloudLog log = ExamCloudLogFactory.getLog(this.getClass());
+
+	@Override
+	public void sendSms(String smsAssemblyCode, List<String> phoneList,
+			Map<String, String> params) {
+		SmsAssemblyCacheBean smsAssembly = CacheHelper.getSmsAssembly(smsAssemblyCode);
+		if (null == smsAssembly) {
+			throw new StatusException("101040", "smsAssemblyCode is wrong");
+		}
+		boolean virtualEnable = PropertyHolder.getBoolean("sms.virtual.enable", false);
+		if (!virtualEnable) {
+			execute(smsAssembly, "SendSms", phoneList, params);
+		}
+	}
+
+	@Override
+	public void sendSmsCode(String phone, String code) {
+
+		boolean virtualEnable = PropertyHolder.getBoolean("sms.smsCode.virtual.enable", false);
+
+		if (virtualEnable) {
+			return;
+		}
+
+		String key = "$_SMS:" + phone;
+		ShortMessageInfo sm = redisClient.get(key, ShortMessageInfo.class);
+		if (null != sm) {
+			Date creationTime = sm.getCreationTime();
+			boolean sameDay = DateUtil.isSameDay(creationTime, new Date());
+			if (!sameDay) {
+				sm = null;
+			}
+		}
+
+		Date now = new Date();
+
+		if (null == sm) {
+			sm = new ShortMessageInfo();
+			sm.setCreationTime(now);
+			sm.setPhone(phone);
+			sm.setTimes(0);
+		} else {
+			List<Date> sendTimeList = sm.getSendTimeList();
+
+			if (10 <= sendTimeList.size()) {
+				throw new StatusException("101000", "一天内发送次数超过10次");
+			} else if (5 <= sendTimeList.size()) {
+				Date d = sendTimeList.get(sendTimeList.size() - 5);
+				if (now.getTime() - d.getTime() < 1000 * 60 * 60) {
+					throw new StatusException("101000", "一小时内发送次数超过5次");
+				}
+			} else {
+				Date d = sendTimeList.get(sendTimeList.size() - 1);
+				if (now.getTime() - d.getTime() < 1000 * 60) {
+					throw new StatusException("101000", "一分钟内发送次数超过1次");
+				}
+			}
+		}
+		Map<String, String> params = Maps.newHashMap();
+		params.put("code", code);
+		this.sendSms(YZM_SMS_ASSEMBLY_CODE, Arrays.asList(new String[]{phone}), params);
+
+		sm.getSendTimeList().add(now);
+		sm.setTimes(sm.getSendTimeList().size());
+		sm.setLastMessage(code);
+
+		redisClient.set(key, sm, 60 * 60 * 24);
+	}
+
+	@Override
+	public void validateSmsCode(String phone, String code) {
+
+		boolean virtualEnable = PropertyHolder.getBoolean("sms.smsCode.virtual.enable", false);
+
+		if (virtualEnable) {
+			String virtualCode = PropertyHolder.getString("sms.smsCode.virtual.code", "5220");
+			if (!virtualCode.equals(code)) {
+				throw new StatusException("102008", "验证码错误");
+			} else {
+				return;
+			}
+		}
+
+		String key = "$_SMS:" + phone;
+		ShortMessageInfo sm = redisClient.get(key, ShortMessageInfo.class);
+
+		if (null == sm) {
+			throw new StatusException("101001", "未发送验证码");
+		}
+		List<Date> sendTimeList = sm.getSendTimeList();
+		Date date = sendTimeList.get(sendTimeList.size() - 1);
+		Date now = new Date();
+
+		if (now.getTime() - date.getTime() > 1000 * 60 * 5) {
+			throw new StatusException("101002", "验证码过期");
+		}
+
+		if (!sm.getLastMessage().equals(code)) {
+			throw new StatusException("101003", "验证码错误");
+		} else {
+			sm.setLastMessage(UUID.randomUUID());
+			redisClient.set(key, sm);
+		}
+
+	}
+
+	/**
+	 * 执行
+	 *
+	 * @param smsAssembly
+	 * @param action
+	 * @param phoneList
+	 * @param templateParams
+	 *            短信模板参数
+	 * @author WANGWEI
+	 */
+	private void execute(SmsAssemblyCacheBean smsAssembly, String action, List<String> phoneList,
+			Map<String, String> templateParams) {
+		String accessKeyId = PropertyHolder.getString("aliyun.sms.accessKeyId");
+		String accessSecret = PropertyHolder.getString("aliyun.sms.accessKeySecret");
+		String signName = smsAssembly.getExt1();
+		String templateCode = smsAssembly.getExt2();
+
+		DefaultProfile profile = DefaultProfile.getProfile("default", accessKeyId, accessSecret);
+		IAcsClient client = new DefaultAcsClient(profile);
+
+		CommonRequest request = new CommonRequest();
+		request.setProtocol(ProtocolType.HTTPS);
+		request.setMethod(MethodType.POST);
+		request.setDomain("dysmsapi.aliyuncs.com");
+		request.setVersion("2017-05-25");
+		request.setAction(action);
+		String phoneNumbers = StringUtils.join(phoneList, ',');
+		request.putQueryParameter("PhoneNumbers", phoneNumbers);
+		request.putQueryParameter("SignName", signName);
+		request.putQueryParameter("TemplateCode", templateCode);
+		request.putQueryParameter("TemplateParam", JsonUtil.toJson(templateParams));
+		try {
+			CommonResponse response = client.getCommonResponse(request);
+			String data = response.getData();
+			JsonParser jp = new JsonParser();
+			JsonObject jsonObj = jp.parse(data).getAsJsonObject();
+			String code = jsonObj.get("Code").getAsString();
+
+			if (!code.equals("OK")) {
+				log.error("aliyun sms response: " + JsonUtil.toJson(response));
+				throw new StatusException("101001", "短信发送失败");
+			}
+
+		} catch (StatusException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new StatusException("101002", "短信发送失败", e);
+		}
+	}
+
+}

+ 23 - 0
examcloud-exchange-outer-api-provider/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2019-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-exchange-outer-api-provider</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.exchange</groupId>
+			<artifactId>examcloud-exchange-outer-service</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.exchange</groupId>
+			<artifactId>examcloud-exchange-outer-api</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+	</dependencies>
+</project>

+ 177 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/CommonGainScoreController.java

@@ -0,0 +1,177 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.exchange.base.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.exchange.base.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.exchange.outer.service.OutletScoreService;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.OutletScore;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+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("/api/ecs_outlet/score")
+public class CommonGainScoreController extends ControllerSupport {
+
+    @Autowired
+    private OutletScoreService outletScoreService;
+
+    @ApiOperation(value = "查询成绩:根据考试名称(不推荐)/考试代码(推荐)、机构ID和学生考试方式查询")
+    @Deprecated
+    @GetMapping
+    public ResponseEntity<?> query(@RequestParam(name = "examCode", required = false) String examCode,
+                                   @RequestParam(name = "examName") @Deprecated 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();
+            //如果examCode为空,则将examName作为examCode
+            final String finalExamCode;
+            if (StringUtils.isEmpty(examCode)) {
+                finalExamCode = examName;
+            } else {
+                finalExamCode = examCode;
+            }
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScore(finalExamCode, examStuRemark, orgId);
+            return new ResponseEntity<>(new SuccessBaseResponse("查询成功", outletScoreList), HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("查询失败", e);
+            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();
+            log.error("查询失败", e);
+            return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "查询成绩:按考试名称/考试代码、机构ID、学号、课程code查询成绩")
+    @GetMapping("/batchNameAndCourseCodeAndStudentCodes")
+    public ResponseEntity<?> queryExamScores(
+            @RequestParam(name = "examCode",required = false) @ApiParam("考试代码") String examCode,
+            @RequestParam(name = "batchName") @Deprecated @ApiParam("考试名称,已废弃,推荐使用examCode") 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);
+            }
+            //如果考试代码为空,则将考试名称作为考试代码
+            final String finalExamCode;
+            if (StringUtils.isEmpty(courseCode)) {
+                finalExamCode = batchName;
+            } else {
+                finalExamCode = examCode;
+            }
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(),
+                    finalExamCode, courseCode, studentCodes);
+            return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功", outletScoreList), HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("查询失败", e);
+            return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "查询成绩明细:按考试名称/考试代码、机构ID、学号、课程code查询成绩")
+    @GetMapping("/batchQueryScoreDetail")
+    public ResponseEntity<?> batchQueryScoreDetail(@RequestParam(name = "examCode",required = false) @ApiParam("考试代码") String examCode,
+                                                   @RequestParam(name = "examName") @Deprecated @ApiParam("考试名称,已弃用,推荐使用examCode") 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 {
+            final String finalExamCode;
+            if (StringUtils.isEmpty(examCode)){
+                finalExamCode=examName;
+            }else {
+                finalExamCode=examCode;
+            }
+            List<OutletScore> outletScores = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(), finalExamCode, studentCode, courseCode);
+            return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功", outletScores), HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("查询失败", e);
+            return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("查询失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+}

+ 181 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/FaceController.java

@@ -0,0 +1,181 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.tomcat.util.http.fileupload.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.ZipUtil;
+import cn.com.qmth.examcloud.exchange.outer.service.FaceService;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 人脸 处理
+ * 
+ * @author chenken
+ * @date 2018年4月3日 下午3:58:31
+ * @company QMTH
+ * @description FaceppController.java
+ */
+@RestController
+@RequestMapping("/api/ecs_outlet/facepp")
+public class FaceController extends ControllerSupport {
+
+	@Autowired
+	SystemProperties systemConfig;
+
+	/**
+	 * ZIP最大50M
+	 */
+	private static final int ZIP_MAX_SIZE = 50;
+
+	/**
+	 * 每张照片最大尺寸 500KB
+	 */
+	private static final int MAX_SIZE = 500;
+
+	@Autowired
+	private FaceService faceService;
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param file
+	 */
+	@ApiOperation(value = "保存学生照片")
+	@PostMapping("add")
+	public void addPhoto(@RequestParam CommonsMultipartFile file,
+			@RequestParam(required = false) String operator) {
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		log.debug("fileName =" + file.getOriginalFilename());
+		DiskFileItem item = (DiskFileItem) file.getFileItem();
+		File storeLocation = item.getStoreLocation();
+		String fileName = file.getOriginalFilename();
+
+		if (StringUtils.containsWhitespace(fileName)) {
+			throw new StatusException("600100", "文件名不能含有空白字符");
+		}
+
+		if (!fileName.matches("[^\\.\\s]+\\.[^\\.\\s]+")) {
+			throw new StatusException("600101", "文件名不合法");
+		}
+		String identityNumber = fileName.substring(0, fileName.lastIndexOf("."));
+		String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
+
+		if (StringUtils.isBlank(operator)) {
+			operator = accessUser.getDisplayName();
+		}
+		faceService.processFace(rootOrgId, identityNumber, fileSuffix, storeLocation, operator);
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param file
+	 * @return
+	 */
+	@ApiOperation(value = "导入学生照片")
+	@PostMapping("import")
+	public List<Map<String, String>> importPhotos(@RequestParam CommonsMultipartFile file) {
+
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		DiskFileItem item = (DiskFileItem) file.getFileItem();
+		File storeLocation = item.getStoreLocation();
+		String filename = file.getOriginalFilename();
+
+		if (!filename.endsWith(".zip")) {
+			throw new StatusException("620001", "文件格式不正确,必须是zip格式的压缩包");
+		}
+		// 文件大小限制
+		if (file.getSize() > ZIP_MAX_SIZE * 1024 * 1024) {
+			throw new StatusException("620002", "文件大小超过50M,请分批导入");
+		}
+
+		List<Map<String, String>> ret = Lists.newArrayList();
+
+		String tempDirPath = systemConfig.getTempDataDir() + File.separator + "photo_import"
+				+ File.separator + System.currentTimeMillis();
+		File tempDir = new File(tempDirPath);
+		try {
+			ZipUtil.unzip(storeLocation, new File(tempDirPath));
+		} catch (Exception e) {
+			throw new StatusException("620003", "zip文件损坏");
+		}
+
+		File[] files = tempDir.listFiles();
+
+		if (null == files) {
+			throw new StatusException("620004", "zip文件为空");
+		}
+
+		for (File f : files) {
+			Map<String, String> map = Maps.newHashMap();
+			String fileName = f.getName();
+			map.put("file", fileName);
+
+			if (f.length() > MAX_SIZE * 1024) {
+				map.put("statusCode", "EX-620005");
+				map.put("statusDesc", "文件大小超过500KB");
+				ret.add(map);
+				continue;
+			}
+			try {
+				if (StringUtils.containsWhitespace(fileName)) {
+					throw new StatusException("600100", "文件名不能含有空白字符");
+				}
+
+				if (!fileName.matches("[^\\.\\s]+\\.[^\\.\\s]+")) {
+					throw new StatusException("600101", "文件名不合法");
+				}
+				String identityNumber = fileName.substring(0, fileName.lastIndexOf("."));
+				String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
+
+				faceService.processFace(rootOrgId, identityNumber, fileSuffix, f,
+						accessUser.getDisplayName());
+
+				map.put("statusCode", "200");
+				map.put("statusDesc", "成功");
+
+			} catch (StatusException e) {
+				map.put("statusCode", e.getCode());
+				map.put("statusDesc", e.getDesc());
+			} catch (Exception e) {
+				map.put("statusCode", "系统异常");
+				map.put("statusDesc", e.getCause().getMessage());
+			}
+			ret.add(map);
+		}
+
+		try {
+			FileUtils.deleteDirectory(tempDir);
+		} catch (IOException e) {
+			log.error("fail to clean temp dir.", e);
+		}
+
+		return ret;
+	}
+
+}

+ 99 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeExamController.java

@@ -0,0 +1,99 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.swufe;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.swufe.bean.SwufeCreateExamDomain;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+import java.util.Map;
+
+/**
+ * @author chenken
+ * @date 2018年5月7日 下午3:20:33
+ * @company QMTH
+ * @description 创建考试
+ */
+@RestController
+@RequestMapping("/api/ecs_outlet/exam")
+public class SwufeExamController extends ControllerSupport {
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@ApiOperation(value = "创建考试")
+	@PostMapping
+	public Map<String, Object> createExam(@RequestBody SwufeCreateExamDomain examReq,
+			HttpServletRequest request) {
+		tranTimes(examReq);
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		SaveExamReq saveExamReq = new SaveExamReq();
+		saveExamReq
+				.setBeginTime(DateUtil.parse(examReq.getBeginTime(), DatePatterns.CHINA_DEFAULT));
+		saveExamReq.setDuration(examReq.getDuration());
+		saveExamReq.setEndTime(DateUtil.parse(examReq.getEndTime(), DatePatterns.CHINA_DEFAULT));
+		saveExamReq.setExamType(examReq.getExamType());
+		// code不传时取name当code
+		if (StringUtils.isNotBlank(examReq.getCode())) {
+			saveExamReq.setCode(examReq.getCode());
+		} else {
+			saveExamReq.setCode(examReq.getName());
+		}
+		saveExamReq.setName(examReq.getName());
+		saveExamReq.setRootOrgId(rootOrgId);
+		examCloudService.saveExam(saveExamReq);
+
+		GetExamReq req = new GetExamReq();
+		//如果考试code为空,则将name作为code
+		if (StringUtils.isEmpty(examReq.getCode())){
+			req.setCode(examReq.getName());
+		}else {
+			req.setCode(examReq.getCode());
+		}
+		req.setRootOrgId(rootOrgId);
+		GetExamResp resp = examCloudService.getExam(req);
+
+		Map<String, Object> map = Maps.newHashMap();
+		map.put("examId", resp.getId());
+		return map;
+
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param exam
+	 */
+	private void tranTimes(SwufeCreateExamDomain exam) {
+		String beginTime = exam.getBeginTime();
+		if (StringUtils.isNotBlank(beginTime)) {
+			beginTime = StringUtils.replace(beginTime, ".000Z", "");
+			beginTime = StringUtils.replace(beginTime, "T", " ");
+			exam.setBeginTime(beginTime);
+		}
+
+		String endTime = exam.getEndTime();
+		if (StringUtils.isNotBlank(endTime)) {
+			endTime = StringUtils.replace(endTime, ".000Z", "");
+			endTime = StringUtils.replace(endTime, "T", " ");
+			exam.setEndTime(endTime);
+		}
+	}
+
+}

+ 50 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeExamVerifyPhotoController.java

@@ -0,0 +1,50 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.swufe;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamRecordCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetExamPhotoVerifyDataReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetExamPhotoVerifyDataResp;
+import cn.com.qmth.examcloud.exchange.base.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.exchange.base.response.SuccessBaseResponse;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+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 javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author chenken
+ * @date 2018年5月7日 上午11:49:40
+ * @company QMTH
+ * @description 抓拍照片数据获取接口
+ */
+@RestController
+@RequestMapping("/api/ecs_outlet/examVerifyPhotos")
+public class SwufeExamVerifyPhotoController extends ControllerSupport {
+
+	@Autowired
+	private ExamRecordCloudService examRecordCloudService;
+
+	@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 {
+			GetExamPhotoVerifyDataReq req = new GetExamPhotoVerifyDataReq();
+			req.setScoreId(scoreId);
+			GetExamPhotoVerifyDataResp examPhotoVerifyData = examRecordCloudService.getExamPhotoVerifyData(req);
+			return new ResponseEntity<SuccessBaseResponse>(new SuccessBaseResponse("查询成功", examPhotoVerifyData), HttpStatus.OK);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("查询失败"),HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+	}
+
+}

+ 122 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/SwufeStudentInfoController.java

@@ -0,0 +1,122 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.swufe;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.SaveStudentReq;
+import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStudentBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamStudentReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.base.enums.CourseLevel;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.swufe.bean.SwufeSaveExamStudentDomain;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author chenken
+ * @date 2018年5月7日 下午4:30:29
+ * @company QMTH
+ * @description 保存学生信息
+ */
+@RestController
+@RequestMapping("/api/ecs_outlet/studentInfo")
+public class SwufeStudentInfoController extends ControllerSupport {
+
+	@Autowired
+	StudentCloudService studentCloudService;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	@PostMapping
+	public Map<String, Object> saveStudentInfo(
+			@RequestBody List<SwufeSaveExamStudentDomain> studentInfoReqs) {
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		List<Long> examStudentIdList = Lists.newArrayList();
+		for (SwufeSaveExamStudentDomain cur : studentInfoReqs) {
+			GetExamReq req = new GetExamReq();
+			//如果没有传examCode,则以examName当作examCode
+			if (StringUtils.isEmpty(cur.getExamCode())){
+				req.setCode(cur.getExamName());
+			}else {
+				req.setCode(cur.getExamCode());
+			}
+			req.setRootOrgId(rootOrgId);
+			GetExamResp resp = examCloudService.getExam(req);
+
+			Long examId = resp.getId();
+			ExamBean examBean = resp.getExamBean();
+			String examName = examBean.getName();
+
+			SaveStudentReq saveStudentReq = new SaveStudentReq();
+			saveStudentReq.setIdentityNumber(cur.getIdentityNumber());
+			saveStudentReq.setName(cur.getStudentName());
+			saveStudentReq.setOrgCode(cur.getOrgCode());
+			saveStudentReq.setOrgId(cur.getOrgId());
+			saveStudentReq.setOrgName(cur.getOrgName());
+			saveStudentReq.setRootOrgId(rootOrgId);
+			if (StringUtils.isNotBlank(cur.getStudentCode())) {
+				List<String> studentCodeList = Lists.newArrayList();
+				studentCodeList.add(cur.getStudentCode());
+				saveStudentReq.setStudentCodeList(studentCodeList);
+			}
+
+			SaveStudentResp insertOrUpdateStudentResp = studentCloudService
+					.saveStudent(saveStudentReq);
+
+			Long studentId = insertOrUpdateStudentResp.getStudentId();
+
+			SaveExamStudentReq sReq = new SaveExamStudentReq();
+			sReq.setCourseLevel(cur.getCourseLevel());
+
+			CourseLevel courseLevel = CourseLevel.getCourseLevel(cur.getCourseLevel());
+			String courseCode = courseLevel.getAbbreviate() + cur.getCourseCode();
+			sReq.setCourseCode(courseCode);
+
+			sReq.setCourseName(cur.getCourseName());
+			sReq.setExamId(examId);
+			sReq.setStudentId(studentId);
+			sReq.setExamName(examName);
+			sReq.setIdentityNumber(cur.getIdentityNumber());
+			if (StringUtils.isNotBlank(cur.getPaperType())) {
+				sReq.setPaperType(cur.getPaperType());
+			} else {
+				sReq.setPaperType("O");
+			}
+			sReq.setRootOrgId(rootOrgId);
+			sReq.setStudentCode(cur.getStudentCode());
+			sReq.setStudentName(cur.getStudentName());
+			sReq.setRemark(cur.getRemark());
+			SaveExamStudentResp savedExamStudent = examStudentCloudService.saveExamStudent(sReq);
+			ExamStudentBean examStudentBean = savedExamStudent.getExamStudentBean();
+			examStudentIdList.add(examStudentBean.getId());
+		}
+
+		Map<String, Object> map = Maps.newHashMap();
+		map.put("success", true);
+		map.put("examStudentIdList", examStudentIdList);
+		return map;
+	}
+
+}

+ 107 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/bean/SwufeCreateExamDomain.java

@@ -0,0 +1,107 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.swufe.bean;
+
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * @author chenken
+ * @date 2018年5月2日 下午3:44:54
+ * @company QMTH
+ * @description ExamReq.java
+ */
+public class SwufeCreateExamDomain implements JsonSerializable {
+
+	private static final long serialVersionUID = -4675668482972680269L;
+
+	/**
+	 * 机构ID
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 考试编码
+	 */
+	private String code;
+
+	/**
+	 * 考试名称
+	 */
+	private String name;
+
+	/**
+	 * 考试类型
+	 */
+	private ExamType examType;
+
+	/**
+	 * 考试开始时间
+	 */
+	private String beginTime;
+
+	/**
+	 * 考试结束时间
+	 */
+	private String endTime;
+
+	/**
+	 * 考试时长(分钟)
+	 */
+	private Integer duration;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	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 ExamType getExamType() {
+		return examType;
+	}
+
+	public void setExamType(ExamType examType) {
+		this.examType = examType;
+	}
+
+	public String getBeginTime() {
+		return beginTime;
+	}
+
+	public void setBeginTime(String beginTime) {
+		this.beginTime = beginTime;
+	}
+
+	public String getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(String endTime) {
+		this.endTime = endTime;
+	}
+
+	public Integer getDuration() {
+		return duration;
+	}
+
+	public void setDuration(Integer duration) {
+		this.duration = duration;
+	}
+
+}

+ 265 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/swufe/bean/SwufeSaveExamStudentDomain.java

@@ -0,0 +1,265 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.swufe.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+
+public class SwufeSaveExamStudentDomain implements JsonSerializable{
+	
+	private static final long serialVersionUID = -6575958224230885795L;
+	/**
+	 * 考试ID
+	 */
+	private Long examId;
+	/**
+	 * 考试代码
+	 */
+	private String examCode;
+	/**
+	 * 考试名称
+	 * @deprecated replaced by examCode
+	 */
+	@Deprecated
+	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 getExamCode() {
+		return examCode;
+	}
+
+	public void setExamCode(String examCode) {
+		this.examCode = examCode;
+	}
+
+	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;
+	}
+	
+}

+ 116 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/SydxScoreController.java

@@ -0,0 +1,116 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.util.StringUtil;
+import cn.com.qmth.examcloud.exchange.base.response.FailureBaseResponse;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean.SydxExamScoreDomain;
+import cn.com.qmth.examcloud.exchange.outer.service.OutletScoreService;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.OutletScore;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+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("/api/ecs_outlet/sydx/score")
+public class SydxScoreController extends ControllerSupport {
+
+    @Autowired
+    private OutletScoreService outletScoreService;
+
+    @ApiOperation(value = "查询成绩:根据考试名称、机构ID和学生考试方式查询")
+    @GetMapping
+    public ResponseEntity<?> query(
+            @RequestParam(name = "examCode", required = false) @ApiParam(value = "考试代码,推荐使用") String examCode,
+            @RequestParam(name = "examRemark") @Deprecated @ApiParam(value = "考试名称,已弃用,推荐使用examCode") String examRemark,
+            @RequestParam(name = "examStuRemark", required = false) 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();
+            //如果考试代码为空,则将考试名称作为考试代码
+            final String finalExamCode;
+            if (StringUtils.isEmpty(examCode)) {
+                finalExamCode = examRemark;
+            } else {
+                finalExamCode = examCode;
+            }
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScore(finalExamCode, 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查询成绩")
+    @PostMapping("/getExamScores")
+    public ResponseEntity<?> queryExamScores(@RequestBody SydxExamScoreDomain sydxExamScoreDomain) {
+        try {
+            if (StringUtils.isEmpty(sydxExamScoreDomain.getBatchName())) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("考试批次名称不能为空"), HttpStatus.BAD_REQUEST);
+            }
+            if (StringUtils.isEmpty(sydxExamScoreDomain.getCourseCode())) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("课程不能为空"), HttpStatus.BAD_REQUEST);
+            }
+            if (sydxExamScoreDomain.getStudentCodes() == null || sydxExamScoreDomain.getStudentCodes().size() == 0) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("学号不能为空"), HttpStatus.BAD_REQUEST);
+            }
+            if (sydxExamScoreDomain.getStudentCodes().size() > 1000) {
+                return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("单次查询,学号数量不能大于1000"), HttpStatus.BAD_REQUEST);
+            }
+            User accessUser = getAccessUser();
+            //如果考试代码为空,则将考试名称作为考试代码
+            String finalExamCode = sydxExamScoreDomain.getExamCode();
+            if (StringUtils.isNotEmpty(sydxExamScoreDomain.getBatchName())) {
+                finalExamCode = sydxExamScoreDomain.getBatchName();
+            }
+
+            List<OutletScore> outletScoreList = outletScoreService.queryExamScoreBy(accessUser.getRootOrgId(),
+                    finalExamCode, sydxExamScoreDomain.getCourseCode(), sydxExamScoreDomain.getStudentCodes());
+            return new ResponseEntity<List<OutletScore>>(outletScoreList, HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new ResponseEntity<FailureBaseResponse>(new FailureBaseResponse("请求失败"), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+}

+ 242 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/SydxStudentExamInfoController.java

@@ -0,0 +1,242 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx;
+
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+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 com.google.common.collect.Lists;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.SaveStudentReq;
+import cn.com.qmth.examcloud.core.basic.api.request.UnbindStudentCodeReq;
+import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStudentBean;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamStudentReq;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamResp;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.base.enums.CourseLevel;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean.SydxExamDomain;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean.SydxExamStudentDomain;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean.SydxFailureRecordDomain;
+import cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean.SydxImportDomain;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+
+/**
+ * 石油大学专用-接收考生数据接口
+ * 
+ * @author chenken
+ * @date 2018年4月3日 下午3:57:42
+ * @company QMTH
+ * @description StudentExamInfoController.java
+ */
+@RestController
+@RequestMapping("/api/ecs_outlet/sydx/import_exam_student_info")
+public class SydxStudentExamInfoController extends ControllerSupport {
+
+	@Autowired
+	StudentCloudService studentCloudService;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	/**
+	 * 石油大学使用:创建考试和导入学生
+	 *
+	 * @author WANGWEI
+	 * @param outerReq
+	 * @return
+	 */
+	@PostMapping
+	public ResponseEntity<?> post(@RequestBody SydxImportDomain outerReq) {
+
+		tranTimes(outerReq);
+
+		SydxExamDomain exam = outerReq.getExam();
+
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		SaveExamReq saveExamReq = new SaveExamReq();
+		saveExamReq.setBeginTime(DateUtil.parse(exam.getBeginTime(), DatePatterns.CHINA_DEFAULT));
+		saveExamReq.setDuration(exam.getDuration());
+		saveExamReq.setEndTime(DateUtil.parse(exam.getEndTime(), DatePatterns.CHINA_DEFAULT));
+		saveExamReq.setExamType(exam.getExamType());
+		// code不传时取name当code
+		if (StringUtils.isNotBlank(exam.getCode())) {
+			saveExamReq.setCode(exam.getCode());
+		} else {
+			saveExamReq.setCode(exam.getName());
+		}
+		saveExamReq.setName(exam.getName());
+		saveExamReq.setRemark(exam.getRemark());
+		saveExamReq.setRootOrgId(rootOrgId);
+		SaveExamResp resp = examCloudService.saveExam(saveExamReq);
+
+		Long examId = resp.getExamId();
+		ExamBean examBean = resp.getExamBean();
+		String examName = examBean.getName();
+		List<SydxExamStudentDomain> examStudentList = outerReq.getExamStudentList();
+
+		List<Long> examStudentIdList = Lists.newArrayList();
+		List<SydxFailureRecordDomain> failureRecordList = Lists.newArrayList();
+
+		for (SydxExamStudentDomain cur : examStudentList) {
+
+			SaveStudentReq saveStudentReq = new SaveStudentReq();
+			saveStudentReq.setIdentityNumber(cur.getIdentityNumber());
+			saveStudentReq.setName(cur.getName());
+			saveStudentReq.setPhoneNumber(cur.getPhone());
+			saveStudentReq.setOrgCode(cur.getOrgCode());
+			saveStudentReq.setOrgId(cur.getOrgId());
+			saveStudentReq.setOrgName(cur.getOrgName());
+			saveStudentReq.setRootOrgId(rootOrgId);
+			if (StringUtils.isNotBlank(cur.getStudentCode())) {
+				List<String> studentCodeList = Lists.newArrayList();
+				studentCodeList.add(cur.getStudentCode());
+				saveStudentReq.setStudentCodeList(studentCodeList);
+			}
+
+			SaveStudentResp saveStudentResp = null;
+			try {
+				saveStudentResp = studentCloudService.saveStudent(saveStudentReq);
+			} catch (StatusException e) {
+				String code = e.getCode();
+				if (code.equals("B-160005") || code.equals("B-160008")) {
+					UnbindStudentCodeReq unbindStudentCodeReq = new UnbindStudentCodeReq();
+					unbindStudentCodeReq.setRootOrgId(rootOrgId);
+					unbindStudentCodeReq.setStudentCode(cur.getStudentCode());
+					unbindStudentCodeReq.setIdentityNumber(cur.getIdentityNumber());
+					studentCloudService.unbindStudentCode(unbindStudentCodeReq);
+					saveStudentResp = studentCloudService.saveStudent(saveStudentReq);
+				} else {
+					throw e;
+				}
+			}
+
+			Long studentId = saveStudentResp.getStudentId();
+
+			SaveExamStudentReq sReq = new SaveExamStudentReq();
+			sReq.setCourseLevel(cur.getCourseLevel());
+
+			CourseLevel courseLevel = CourseLevel.getCourseLevel(cur.getCourseLevel());
+			String courseCode = courseLevel.getAbbreviate() + cur.getCourseCode();
+			sReq.setCourseCode(courseCode);
+
+			sReq.setCourseName(cur.getCourseName());
+			sReq.setExamId(examId);
+			sReq.setStudentId(studentId);
+			sReq.setExamName(examName);
+			sReq.setIdentityNumber(cur.getIdentityNumber());
+			sReq.setPaperType(cur.getPaperType());
+			sReq.setRootOrgId(rootOrgId);
+			sReq.setStudentCode(cur.getStudentCode());
+			sReq.setStudentName(cur.getName());
+			sReq.setPaperType(cur.getPaperType());
+			sReq.setRemark(cur.getRemark());
+			sReq.setGrade(cur.getGrade());
+			sReq.setInfoCollector(cur.getInfoCollector());
+			sReq.setSpecialtyName(cur.getSpecialtyName());
+
+			try {
+				SaveExamStudentResp savedExamStudent = examStudentCloudService
+						.saveExamStudent(sReq);
+				ExamStudentBean examStudentBean = savedExamStudent.getExamStudentBean();
+				examStudentIdList.add(examStudentBean.getId());
+			} catch (StatusException e) {
+				SydxFailureRecordDomain fr = new SydxFailureRecordDomain();
+				fr.setCode(e.getCode());
+				fr.setDesc(e.getDesc());
+				fr.setCourseCode(cur.getCourseCode());
+				fr.setCourseLevel(cur.getCourseLevel());
+				fr.setCourseName(cur.getCourseName());
+				fr.setIdentityNumber(cur.getIdentityNumber());
+				fr.setStudentCode(cur.getStudentCode());
+				failureRecordList.add(fr);
+			} catch (Exception e) {
+				SydxFailureRecordDomain fr = new SydxFailureRecordDomain();
+				fr.setCode("EX-210001");
+				fr.setDesc(e.getMessage());
+				fr.setCourseCode(cur.getCourseCode());
+				fr.setCourseLevel(cur.getCourseLevel());
+				fr.setCourseName(cur.getCourseName());
+				fr.setIdentityNumber(cur.getIdentityNumber());
+				fr.setStudentCode(cur.getStudentCode());
+				failureRecordList.add(fr);
+			}
+		}
+
+		if (CollectionUtils.isNotEmpty(failureRecordList)) {
+			return new ResponseEntity<Object>(failureRecordList, HttpStatus.INTERNAL_SERVER_ERROR);
+		} else {
+			return new ResponseEntity<Object>(examStudentIdList, HttpStatus.OK);
+		}
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param examStudentImportDTO
+	 */
+	private void tranTimes(SydxImportDomain examStudentImportDTO) {
+		SydxExamDomain exam = examStudentImportDTO.getExam();
+
+		String beginTime = exam.getBeginTime();
+		if (StringUtils.isNotBlank(beginTime)) {
+			beginTime = StringUtils.replace(beginTime, ".000Z", "");
+			beginTime = StringUtils.replace(beginTime, "T", " ");
+			exam.setBeginTime(beginTime);
+		}
+
+		String endTime = exam.getEndTime();
+		if (StringUtils.isNotBlank(endTime)) {
+			endTime = StringUtils.replace(endTime, ".000Z", "");
+			endTime = StringUtils.replace(endTime, "T", " ");
+			exam.setEndTime(endTime);
+		}
+
+		List<SydxExamStudentDomain> examStudentList = examStudentImportDTO.getExamStudentList();
+		if (CollectionUtils.isNotEmpty(examStudentList)) {
+
+			for (SydxExamStudentDomain cur : examStudentList) {
+				SydxExamDomain curExam = cur.getExam();
+				if (null == curExam) {
+					continue;
+				}
+				String b = curExam.getBeginTime();
+				if (StringUtils.isNotBlank(b)) {
+					b = StringUtils.replace(b, ".000Z", "");
+					b = StringUtils.replace(b, "T", " ");
+					curExam.setBeginTime(b);
+				}
+
+				String e = curExam.getEndTime();
+				if (StringUtils.isNotBlank(e)) {
+					e = StringUtils.replace(e, ".000Z", "");
+					e = StringUtils.replace(e, "T", " ");
+					curExam.setEndTime(e);
+				}
+			}
+		}
+	}
+
+}

+ 539 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamDomain.java

@@ -0,0 +1,539 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.validation.constraints.NotNull;
+
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.exchange.base.enums.MarkingType;
+import cn.com.qmth.examcloud.exchange.base.enums.PracticeType;
+
+public class SydxExamDomain implements Serializable {
+
+	private static final long serialVersionUID = -1674026406657304645L;
+
+	private Long id;
+
+	/**
+	 * 考试编码
+	 */
+	private String code;
+
+	/**
+	 * 机构Id
+	 */
+	private Long orgId;
+
+	/**
+	 * 顶级机构Id
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 考试批次开始时间
+	 */
+	private String beginTime;
+
+	/**
+	 * 考试批次结束时间
+	 */
+	private String 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 String getBeginTime() {
+		return beginTime;
+	}
+
+	public void setBeginTime(String beginTime) {
+		this.beginTime = beginTime;
+	}
+
+	public String getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(String 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 String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+}

+ 66 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamScoreDomain.java

@@ -0,0 +1,66 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+public class SydxExamScoreDomain implements JsonSerializable {
+
+	private static final long serialVersionUID = -1674026406657304645L;
+
+	/**
+	 * 考试批次名称
+	 */
+	@Deprecated
+	@ApiModelProperty(value = "考试批次名称,已废弃,推荐使用examCode")
+	private String batchName;
+
+	/**
+	 * 考试代码
+	 */
+	@ApiModelProperty(value = "考试代码,推荐使用")
+	private String examCode;
+
+	/**
+	 * 机构Id
+	 */
+	private String courseCode;
+
+	public String getExamCode() {
+		return examCode;
+	}
+
+	public void setExamCode(String examCode) {
+		this.examCode = examCode;
+	}
+
+	/**
+	 * 学生代码
+	 */
+	private List<String> studentCodes;
+
+	public String getBatchName() {
+		return batchName;
+	}
+
+	public void setBatchName(String batchName) {
+		this.batchName = batchName;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public List<String> getStudentCodes() {
+		return studentCodes;
+	}
+
+	public void setStudentCodes(List<String> studentCodes) {
+		this.studentCodes = studentCodes;
+	}
+}

+ 409 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxExamStudentDomain.java

@@ -0,0 +1,409 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean;
+
+import java.io.Serializable;
+
+public class SydxExamStudentDomain implements Serializable {
+
+	private static final long serialVersionUID = 4647883873040374983L;
+
+	private long id;
+
+    private String name;
+
+    private SydxExamDomain 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 SydxExamStudentDomain() {}
+	
+    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 SydxExamDomain getExam() {
+        return exam;
+    }
+
+    public void setExam(SydxExamDomain 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;
+    }
+}

+ 95 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxFailureRecordDomain.java

@@ -0,0 +1,95 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean;
+
+import java.io.Serializable;
+
+public class SydxFailureRecordDomain implements Serializable {
+
+	private static final long serialVersionUID = -6794614626330803366L;
+
+	/**
+	 * 状态码
+	 */
+	private String code;
+
+	/**
+	 * 状态描述
+	 */
+	private String desc;
+
+	private String name;
+
+	private String studentCode;
+
+	private String identityNumber;
+
+	private String courseCode;
+
+	private String courseName;
+
+	private String courseLevel;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+	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 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 getCourseLevel() {
+		return courseLevel;
+	}
+
+	public void setCourseLevel(String courseLevel) {
+		this.courseLevel = courseLevel;
+	}
+
+}

+ 33 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/controller/sydx/bean/SydxImportDomain.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.examcloud.exchange.outer.api.controller.sydx.bean;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * Created by yuanpan on 2017/4/25.
+ */
+public class SydxImportDomain implements JsonSerializable {
+
+	private static final long serialVersionUID = 7067803176577343830L;
+
+	private SydxExamDomain exam;
+
+	private List<SydxExamStudentDomain> examStudentList;
+
+	public SydxExamDomain getExam() {
+		return exam;
+	}
+
+	public void setExam(SydxExamDomain exam) {
+		this.exam = exam;
+	}
+
+	public List<SydxExamStudentDomain> getExamStudentList() {
+		return examStudentList;
+	}
+
+	public void setExamStudentList(List<SydxExamStudentDomain> examStudentList) {
+		this.examStudentList = examStudentList;
+	}
+}

+ 78 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/CourseGroupOuterServiceProvider.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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 com.google.common.collect.Lists;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.exchange.outer.api.CourseGroupOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.CourseBean;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetCourseListReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetCourseListResp;
+import cn.com.qmth.examcloud.exchange.outer.service.CourseGroupService;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.Course;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 课程组服务
+ *
+ * @author WANGWEI
+ * @date 2019年1月7日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api(value = "课程组服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/courseGroup")
+public class CourseGroupOuterServiceProvider extends ControllerSupport
+		implements
+			CourseGroupOuterService {
+
+	private static final long serialVersionUID = -1645240245909412821L;
+
+	@Autowired
+	CourseGroupService courseGroupService;
+
+	@ApiOperation(value = "查询课程组课程集合", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterGetCourseListResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("getCourseList")
+	@Override
+	public OuterGetCourseListResp getCourseList(
+			@RequestBody @ApiParam(required = true) OuterGetCourseListReq req) {
+		Long rootOrgId = req.getRootOrgId();
+		String courseGroupName = req.getCourseGroupName();
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		List<Course> courseList = courseGroupService.getCourseList(rootOrgId, courseGroupName);
+
+		List<CourseBean> list = Lists.newArrayList();
+		for (Course cur : courseList) {
+			CourseBean bean = new CourseBean();
+			bean.setCode(cur.getCode());
+			bean.setLevel(cur.getLevel());
+			bean.setName(cur.getName());
+			list.add(bean);
+		}
+
+		OuterGetCourseListResp resp = new OuterGetCourseListResp();
+		resp.setCourseList(list);
+		return resp;
+	}
+
+}

+ 138 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamOuterServiceProvider.java

@@ -0,0 +1,138 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamResp;
+import cn.com.qmth.examcloud.exchange.outer.api.ExamOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetExamReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveExamReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetExamResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveExamResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 考试服务
+ *
+ * @author WANGWEI
+ * @date 2018年7月2日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api(value = "考试服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/exam")
+public class ExamOuterServiceProvider extends ControllerSupport implements ExamOuterService {
+
+	private static final long serialVersionUID = 4007321110021402052L;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@ApiOperation(value = "保存考试信息", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterSaveExamResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("saveExam")
+	@Override
+	public OuterSaveExamResp saveExam(
+			@RequestBody @ApiParam(required = true) OuterSaveExamReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		Date beginTime = req.getBeginTime();
+		Integer duration = req.getDuration();
+		Date endTime = req.getEndTime();
+		ExamType examType = req.getExamType();
+		String code = req.getCode();
+		String name = req.getName();
+		String remark = req.getRemark();
+		Long rootOrgId = req.getRootOrgId();
+		Long examTimes = req.getExamTimes();
+		Map<String, String> properties = req.getProperties();
+
+		SaveExamReq saveExamReq = new SaveExamReq();
+		saveExamReq.setBeginTime(beginTime);
+		saveExamReq.setDuration(duration);
+		saveExamReq.setEndTime(endTime);
+		saveExamReq.setExamType(examType);
+		// code不传时取name当code
+		if (StringUtils.isNotBlank(code)) {
+			saveExamReq.setCode(code);
+		} else {
+			saveExamReq.setCode(name);
+		}
+		saveExamReq.setName(name);
+		saveExamReq.setRemark(remark);
+		saveExamReq.setRootOrgId(rootOrgId);
+		saveExamReq.setExamTimes(examTimes);
+
+		saveExamReq.setProperties(properties);
+
+		SaveExamResp r = examCloudService.saveExam(saveExamReq);
+
+		OuterSaveExamResp resp = new OuterSaveExamResp();
+		resp.setExamId(r.getExamId());
+		return resp;
+	}
+
+	@ApiOperation(value = "查询考试信息", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetExamResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("getExam")
+	@Override
+	public OuterGetExamResp getExam(@RequestBody @ApiParam(required = true) OuterGetExamReq req) {
+		Long id = req.getId();
+		String name = req.getName();
+		String code = req.getCode();
+		// name有值时,当code使用
+		if (StringUtils.isNotBlank(name)) {
+			code = name;
+		}
+		Long rootOrgId = req.getRootOrgId();
+
+		GetExamReq getExamReq = new GetExamReq();
+		getExamReq.setId(id);
+		getExamReq.setName(name);
+		getExamReq.setCode(code);
+		getExamReq.setRootOrgId(rootOrgId);
+		GetExamResp r = examCloudService.getExam(getExamReq);
+		ExamBean e = r.getExamBean();
+
+		OuterGetExamResp resp = new OuterGetExamResp();
+		resp.setBeginTime(e.getBeginTime());
+		resp.setDuration(e.getDuration());
+		resp.setEnable(e.getEnable());
+		resp.setEndTime(e.getEndTime());
+		resp.setExamTimes(e.getExamTimes());
+		resp.setExamType(e.getExamType());
+		resp.setId(e.getId());
+		// code当name
+		resp.setName(e.getCode());
+		resp.setRemark(e.getRemark());
+		resp.setRootOrgId(e.getRootOrgId());
+
+		return resp;
+	}
+
+}

+ 481 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamQuestionOuterServiceProvider.java

@@ -0,0 +1,481 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.RegExpUtil;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamRecordCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.PagedToBeMarkExamRecordBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.PagedToBeMarkSubjectiveAnswerBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetPagedToBeMarkExamRecordReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetPagedToBeMarkExamRecordResp;
+import cn.com.qmth.examcloud.exchange.outer.api.ExamQuestionOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.*;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetPaperStructReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetQuestionAnswerReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectivePaperStructReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectiveQuestionReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetPaperStructResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetQuestionAnswerResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectivePaperStructResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectiveQuestionResp;
+import cn.com.qmth.examcloud.exchange.outer.service.OutletPaperStructService;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.OuterCourseBean;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.OuterQuestionBean;
+import cn.com.qmth.examcloud.question.commons.core.paper.DefaultPaper;
+import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionGroup;
+import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionStructureWrapper;
+import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionUnitWrapper;
+import cn.com.qmth.examcloud.question.commons.core.question.AnswerType;
+import cn.com.qmth.examcloud.question.commons.core.question.QuestionType;
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
+import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigPaperCacheBean;
+import cn.com.qmth.examcloud.support.cache.bean.QuestionAnswerCacheBean;
+import cn.com.qmth.examcloud.support.enums.BlockType;
+import cn.com.qmth.examcloud.support.handler.richText.RichTextHandler;
+import cn.com.qmth.examcloud.support.handler.richText.RichTextHandlerFactory;
+import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
+import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
+import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import com.mysql.cj.util.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Description 考试作答服务
+ * @Author lideyin
+ * @Date 2020/3/30 14:48
+ * @Version 1.0
+ */
+@Api("考试作答服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/question")
+public class ExamQuestionOuterServiceProvider extends ControllerSupport implements ExamQuestionOuterService {
+
+    private static final long serialVersionUID = 7607495598308348018L;
+
+    @Autowired
+    private ExamRecordCloudService examRecordCloudService;
+
+    @Autowired
+    private OutletPaperStructService outletPaperStructService;
+
+
+    @Override
+    @ApiOperation(value = "获取主观题试卷结构", httpMethod = "POST")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetSubjectivePaperStructResp.class),
+            @ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+    @PostMapping("/getSubjectivePaperStruct")
+    public OuterGetSubjectivePaperStructResp getSubjectivePaperStruct(@RequestBody OuterGetSubjectivePaperStructReq req) {
+        if (req.getExamId() == null) {
+            throw new StatusException("101201", "考试ID不能为空");
+        }
+
+        // 获取考试相关联的课程列表
+        List<OuterCourseBean> courses = outletPaperStructService.getExamCourses(req.getExamId());
+        if (CollectionUtils.isEmpty(courses)) {
+            log.warn(String.format("getExamCourses is empty, examId = %s", req.getExamId()));
+            throw new StatusException("101202", "考试相关的课程列表为空");
+        }
+
+        List<OuterSubjectivePaperStructBean> paperStructList = new ArrayList<>();
+        for (OuterCourseBean course : courses) {
+            OuterSubjectivePaperStructBean paperStruct = new OuterSubjectivePaperStructBean();
+            paperStruct.setExamId(req.getExamId());
+            paperStruct.setSubjectCode(course.getCode());
+            paperStruct.setSubjectName(course.getName());
+            paperStructList.add(paperStruct);
+
+            // 根据考试和课程获取调卷规则下试卷的试题列表
+            List<OuterQuestionBean> questions = outletPaperStructService.getPaperStructQuestions(req.getExamId(), course.getCode());
+            if (CollectionUtils.isEmpty(questions)) {
+                // 当前考试和课程对应的调卷规则不存在时,则获取不到试卷试题
+                log.warn(String.format("getPaperStructQuestions is empty, examId = %s, courseCode = %s", req.getExamId(), course.getCode()));
+                paperStruct.setQuestions(new ArrayList<>());
+                continue;
+            }
+
+            List<OuterSubjectiveQuestionBean> newQuestions = new ArrayList<>();
+            for (OuterQuestionBean question : questions) {
+                OuterSubjectiveQuestionBean newQuestion = new OuterSubjectiveQuestionBean();
+                newQuestion.setMainNumber(question.getMainNumber());
+                newQuestion.setMainTitle(question.getMainTitle());
+                newQuestion.setSubNumber(question.getSubNumber());
+                newQuestion.setTotalScore(question.getTotalScore());
+                newQuestions.add(newQuestion);
+            }
+
+            paperStruct.setQuestions(newQuestions);
+        }
+
+        OuterGetSubjectivePaperStructResp resp = new OuterGetSubjectivePaperStructResp();
+        resp.setPaperStructList(paperStructList);
+        return resp;
+    }
+
+    @ApiOperation(value = "获取主观题作答结果", httpMethod = "POST")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetSubjectiveQuestionResp.class),
+            @ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+    @PostMapping("/getSubjectiveQuestion")
+    @Override
+    public OuterGetSubjectiveQuestionResp getSubjectiveQuestion(@RequestBody OuterGetSubjectiveQuestionReq req) {
+        Long st = System.currentTimeMillis();
+
+        Long examId = req.getExamId();
+        if (null == examId) {
+            throw new StatusException("101001", "考试id不允许为空");
+        }
+
+        String subjectCode = req.getSubjectCode();
+        if (StringUtils.isNullOrEmpty(subjectCode)) {
+            throw new StatusException("101002", "科目代码不允许为空");
+        }
+
+        Long startId = req.getStartId();
+        if (null == startId) {
+            throw new StatusException("101003", "考生id不允许为空");
+        }
+
+        Integer size = req.getSize();
+        if (null == size) {
+            throw new StatusException("101004", "数据量大小不允许为空");
+        }
+
+        if (size.intValue() > 500) {
+            throw new StatusException("101005", "数据量最大不得超过500");
+        }
+
+        long startTime = System.currentTimeMillis();
+        if (log.isDebugEnabled()) {
+            log.debug("0 [GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "] start...");
+        }
+
+        GetPagedToBeMarkExamRecordReq pagedReq = new GetPagedToBeMarkExamRecordReq();
+        pagedReq.setExamId(examId);
+        pagedReq.setSubjectCode(subjectCode);
+        pagedReq.setStartId(startId);
+        pagedReq.setSize(size);
+        GetPagedToBeMarkExamRecordResp pagedResp = examRecordCloudService.getPagedToBeMarkExamRecord(pagedReq);
+
+        if (log.isDebugEnabled()) {
+            log.debug("1.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "]" +
+                    "通过rpc获取待阅卷列表耗时:" + (System.currentTimeMillis() - startTime) + " ms");
+        }
+
+        startTime = System.currentTimeMillis();
+
+        OuterGetSubjectiveQuestionResp resp = new OuterGetSubjectiveQuestionResp();
+        resp.setNextId(pagedResp.getNextId());
+        resp.setDataList(getOuterExamRecordBean(pagedResp.getToBeMarkExamRecordBeanList()));
+
+        if (log.isDebugEnabled()) {
+            log.debug("2.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "]" +
+                    "构造满足条件的考试记录集合耗时:" + (System.currentTimeMillis() - startTime) + " ms");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("999.[GET_SUBJECTIVE_QUESTION-" + examId + "-" + subjectCode + "-" + startId + "] end..." +
+                    "合计耗时:" + (System.currentTimeMillis() - st) + " ms");
+        }
+
+        return resp;
+    }
+
+    @ApiOperation(value = "获取题目答案", httpMethod = "POST")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetQuestionAnswerResp.class),
+            @ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+    @PostMapping("/getQuestionAnswer")
+    @Override
+    public OuterGetQuestionAnswerResp getQuestionAnswer(@RequestBody OuterGetQuestionAnswerReq req) {
+        if (StringUtils.isNullOrEmpty(req.getQuestionId())) {
+            throw new StatusException("102001", "题目id不允许为空");
+        }
+
+        QuestionAnswerCacheBean questionAnswer = CacheHelper.getQuestionAnswer(req.getQuestionId());
+
+        OuterGetQuestionAnswerResp resp = new OuterGetQuestionAnswerResp();
+        resp.setAnswerList(questionAnswer.getRightAnswers());
+
+        return resp;
+    }
+
+    @ApiOperation(value = "获取试卷结构(题库中的原始试卷结构)", httpMethod = "POST")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetQuestionAnswerResp.class),
+            @ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+    @PostMapping("/getPaperStruct")
+    @Override
+    public OuterGetPaperStructResp getPaperStruct(@RequestBody OuterGetPaperStructReq req) {
+        if (null == req.getExamId()) {
+            throw new StatusException("103001", "考试记录id不允许为空");
+        }
+
+        if (null == req.getCourseId()) {
+            throw new StatusException("103002", "课程id不允许为空");
+        }
+
+        if (StringUtils.isNullOrEmpty(req.getPaperType())) {
+            throw new StatusException("103003", "试卷类型不允许为空");
+        }
+
+        if (StringUtils.isNullOrEmpty(req.getBasePaperId())) {
+            throw new StatusException("103004", "原始试卷id不允许为空");
+        }
+
+        CourseCacheBean course = CacheHelper.getCourse(req.getCourseId());
+        if (null == course) {
+            throw new StatusException("103005", "课程id不正确");
+        }
+
+        ExtractConfigPaperCacheBean extractConfigPaper = CacheHelper.getExtractConfigPaper(req.getExamId(),
+                course.getCode(), req.getPaperType(), req.getBasePaperId());
+
+        OuterGetPaperStructResp resp = new OuterGetPaperStructResp();
+        if (null != extractConfigPaper.getDefaultPaper()) {
+            resp.setDefaultPaper(transferPaperFrom(extractConfigPaper.getDefaultPaper()));
+        }
+
+        return resp;
+    }
+
+    private DefaultPaperBean transferPaperFrom(DefaultPaper defaultPaper) {
+        DefaultPaperBean defaultPaperBean = new DefaultPaperBean();
+        defaultPaperBean.setFullyObjective(defaultPaper.getFullyObjective());
+        defaultPaperBean.setName(defaultPaper.getName());
+
+        List<DefaultQuestionGroup> qgList = defaultPaper.getQuestionGroupList();
+        List<DefaultQuestionGroupBean> qgBeanList = new ArrayList<>();
+        for (DefaultQuestionGroup dqg : qgList) {
+            DefaultQuestionGroupBean dqgBean = new DefaultQuestionGroupBean();
+            dqgBean.setGroupName(dqg.getGroupName());
+            dqgBean.setGroupScore(dqg.getGroupScore());
+
+            List<DefaultQuestionStructureWrapper> qwList = dqg.getQuestionWrapperList();
+            List<DefaultQuestionStructureWrapperBean> qwBeanList = new ArrayList<>();
+            for (DefaultQuestionStructureWrapper qw : qwList) {
+                DefaultQuestionStructureWrapperBean qwBean = new DefaultQuestionStructureWrapperBean();
+                qwBean.setQuestionId(qw.getQuestionId());
+                qwBean.setVersion(qw.getVersion());
+                qwBean.setQuestionScore(qw.getQuestionScore());
+                qwBean.setLimitedPlayTimes(qw.getLimitedPlayTimes());
+                qwBean.setPlayedTimes(qw.getPlayedTimes());
+                qwBean.setTimeLimit(qw.getTimeLimit());
+
+                List<DefaultQuestionUnitWrapper> quwList = qw.getQuestionUnitWrapperList();
+                List<DefaultQuestionUnitWrapperBean> quwBeanList = new ArrayList<>();
+                for (DefaultQuestionUnitWrapper quw : quwList) {
+                    DefaultQuestionUnitWrapperBean quwBean = new DefaultQuestionUnitWrapperBean();
+                    quwBean.setOptionPermutation(quw.getOptionPermutation());
+                    quwBean.setQuestionScore(quw.getQuestionScore());
+                    quwBean.setQuestionType(quw.getQuestionType() == null ? null : quw.getQuestionType().name());
+                    quwBean.setAnswerType(quw.getAnswerType() == null ? null : quw.getAnswerType().name());
+
+                    quwBeanList.add(quwBean);
+                }
+
+                qwBean.setQuestionUnitWrapperList(quwBeanList);
+
+                qwBeanList.add(qwBean);
+            }
+
+            dqgBean.setQuestionWrapperList(qwBeanList);
+
+            qgBeanList.add(dqgBean);
+        }
+
+        defaultPaperBean.setQuestionGroupList(qgBeanList);
+
+        return defaultPaperBean;
+    }
+
+
+    /**
+     * 构造满足条件的考试记录集合
+     *
+     * @param toBeMarkExamRecordBeanList
+     * @return
+     */
+    private List<OuterExamRecordBean> getOuterExamRecordBean(List<PagedToBeMarkExamRecordBean> toBeMarkExamRecordBeanList) {
+        if (null == toBeMarkExamRecordBeanList || toBeMarkExamRecordBeanList.isEmpty()) {
+            return null;
+        }
+
+        List<OuterExamRecordBean> resultList = new ArrayList<>();
+        for (PagedToBeMarkExamRecordBean pb : toBeMarkExamRecordBeanList) {
+            OuterExamRecordBean resultBean = new OuterExamRecordBean();
+            resultBean.setExamId(pb.getExamId());
+            resultBean.setStudentCode(pb.getIdentityNumber());//因为外部接口定义的名字虽然叫studentCode,实际是身份证号
+            resultBean.setName(pb.getStudentName());
+            resultBean.setCollege(pb.getGrade());
+            resultBean.setClassName(null);
+            resultBean.setTeacher(null);
+            resultBean.setSubjectCode(pb.getCourseCode());
+            resultBean.setSubjectName(pb.getCourseName());
+            resultBean.setExamNumber(String.valueOf(pb.getExamRecordDataId()));
+
+            resultBean.setSubjectives(getSubjectives(pb.getExamId(), pb.getSubjectiveAnswerList()));
+
+            resultList.add(resultBean);
+        }
+
+        return resultList;
+    }
+
+    /**
+     * 构造满足条件的主观题集合
+     *
+     * @param subjectiveAnswerList
+     * @return
+     */
+    private List<OuterSubjectiveQuestionRecordBean> getSubjectives(Long examId,
+                                                                   List<PagedToBeMarkSubjectiveAnswerBean> subjectiveAnswerList) {
+        List<OuterSubjectiveQuestionRecordBean> resultList = new ArrayList<>();
+        RichTextHandler complexRichTextHandler = RichTextHandlerFactory.getHandler("complex");
+
+        for (PagedToBeMarkSubjectiveAnswerBean pb : subjectiveAnswerList) {
+            OuterSubjectiveQuestionRecordBean resultBean = new OuterSubjectiveQuestionRecordBean();
+            resultBean.setMainNumber(pb.getMainNumber());
+            resultBean.setSubNumber(pb.getOrder());
+            resultBean.setQuestionId(pb.getQuestionId());
+
+            resultBean.setAnswer(transferFrom(complexRichTextHandler.handle(pb.getAnswer())));
+
+            //格式化学生答案
+            String transformedAnswerType = getTransformedAnswerType(pb.getAnswerType(), pb.getQuestionType(), examId);
+
+            RichTextHandler richTextHandler = null;
+            String stuAnswer = pb.getStudentAnswer();
+            SectionCollectionBean formattedStudentAnswer = new SectionCollectionBean();
+
+            //图片作答特殊处理:将图片作答中的文字部分和图片部分拆开
+            if (BlockType.image.name().equals(transformedAnswerType)) {
+                if (!StringUtils.isNullOrEmpty(stuAnswer)) {
+                    //图片作答的标识
+                    String firstMatch = RegExpUtil.find(stuAnswer, "<div \\S*photo-answers-block\\S*>");
+
+                    int index;
+                    if (StringUtils.isNullOrEmpty(firstMatch)) {
+                        index = -1;
+                    } else {
+                        index = stuAnswer.indexOf(firstMatch);
+                    }
+
+                    //只有文字作答,处理文字
+                    if (index == -1) {
+                        richTextHandler = RichTextHandlerFactory.getHandler(BlockType.text.name());
+                        formattedStudentAnswer = richTextHandler.handle(stuAnswer);
+                    } else {
+                        //只有图片作答,处理图片
+                        if (index == 0) {
+                            richTextHandler = RichTextHandlerFactory.getHandler(BlockType.image.name());
+                            formattedStudentAnswer = richTextHandler.handle(stuAnswer);
+                        }
+                        //既有图片又有文字
+                        else {
+                            //文字部分
+                            String stuAnswer_text = stuAnswer.substring(0, index);
+                            SectionCollectionBean formattedStudentAnswer_text =
+                                    RichTextHandlerFactory.getHandler(BlockType.text.name()).handle(stuAnswer_text);
+
+                            //图片部分
+                            String stuAnswer_image = stuAnswer.substring(index);
+                            SectionCollectionBean formattedStudentAnswer_image =
+                                    RichTextHandlerFactory.getHandler(BlockType.image.name()).handle(stuAnswer_image);
+
+                            formattedStudentAnswer = new SectionCollectionBean();
+                            List<SectionBean> sections = new ArrayList<>();
+                            sections.addAll(formattedStudentAnswer_text.getSections());
+                            sections.addAll(formattedStudentAnswer_image.getSections());
+                            formattedStudentAnswer.setSections(sections);
+                        }
+                    }
+
+                }
+            }
+            //非图片作答,则直接根据作答类型进行处理
+            else {
+                richTextHandler = RichTextHandlerFactory.getHandler(transformedAnswerType);
+                formattedStudentAnswer = richTextHandler.handle(stuAnswer);
+            }
+
+            OuterSectionCollectionBean stuAnswerResult = transferFrom(formattedStudentAnswer);
+
+            resultBean.setStudentAnswer(stuAnswerResult);
+
+            resultBean.setBody(transferFrom(complexRichTextHandler.handle(pb.getBody())));
+            resultBean.setParentBody(transferFrom(complexRichTextHandler.handle(pb.getParentBody())));
+
+            resultList.add(resultBean);
+        }
+
+        return resultList;
+    }
+
+    private static OuterSectionCollectionBean transferFrom(SectionCollectionBean sectionCollection) {
+        List<SectionBean> sections = sectionCollection.getSections();
+        if (null == sections || sections.isEmpty()) {
+            return new OuterSectionCollectionBean();
+        }
+
+        OuterSectionCollectionBean result = new OuterSectionCollectionBean();
+
+        List<OuterSectionBean> outerSections = new ArrayList<>();
+        sections.stream().forEach(sec -> {
+            OuterSectionBean outerSection = new OuterSectionBean();
+            List<OuterBlockBean> outerBlocks = new ArrayList<>();
+
+            if (null != sec.getBlocks() && !sec.getBlocks().isEmpty()) {
+                sec.getBlocks().stream().forEach(bl -> {
+                    OuterBlockBean outerBlock = new OuterBlockBean();
+                    outerBlock.setType(bl.getType());
+                    outerBlock.setValue(bl.getValue());
+                    outerBlock.setParam(bl.getParam());
+                    outerBlock.setPlayTime(bl.getPlayTime());
+
+                    outerBlocks.add(outerBlock);
+                });
+            }
+
+            outerSection.setBlocks(outerBlocks);
+            outerSections.add(outerSection);
+        });
+
+        result.setSections(outerSections);
+        return result;
+    }
+
+    /**
+     * 根据原始作答类型和学生实际作答推断出真实的作答类型
+     *
+     * @param answerType   原始作答类型
+     * @param questionType 题型
+     * @param examId       考试id
+     * @return
+     */
+    private String getTransformedAnswerType(AnswerType answerType, QuestionType questionType, Long examId) {
+        //如果题型为问答题,且作答类型不为音频作答,且开启微信作答,则此题为图片作答题
+        if (questionType == QuestionType.ESSAY &&
+                (null == answerType || (null != answerType && answerType != AnswerType.SINGLE_AUDIO))) {
+            if (ExamCacheTransferHelper.weixinAnswerEnabled(examId)) {
+                return "image";
+            }
+        }
+
+        if (null != answerType && answerType == AnswerType.SINGLE_AUDIO) {
+            return "audio";
+        }
+
+        return "text";
+    }
+}

+ 380 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ExamStudentOuterServiceProvider.java

@@ -0,0 +1,380 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 com.google.common.collect.Lists;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStudentBean;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStudentBean4Reset;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.ResetExamStudentReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamStudentReq;
+import cn.com.qmth.examcloud.examwork.api.request.UpdateExamStudentStatusReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.examwork.api.response.ResetExamStudentResp;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.ExamStudentOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.ExamStudent4BatchBean;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.ExamStudentStatus4BatchBean;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterExamStudent4ResetReqBean;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterExamStudent4ResetRespBean;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterExamStudentBean;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterBatchSaveExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterResetExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdateExamStudentStatusReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterBatchSaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterResetExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdateExamStudentStatusResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 考生服务
+ *
+ * @author WANGWEI
+ * @date 2018年7月2日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api(value = "考生服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/examStudent")
+public class ExamStudentOuterServiceProvider extends ControllerSupport
+		implements
+			ExamStudentOuterService {
+
+	private static final long serialVersionUID = -8252740695302763716L;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@ApiOperation(value = "保存考生信息", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterSaveExamStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("saveExamStudent")
+	@Override
+	public OuterSaveExamStudentResp saveExamStudent(
+			@RequestBody @ApiParam(required = true) OuterSaveExamStudentReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		Long examId = req.getExamId();
+		String examCode = req.getExamCode();
+		String examName = req.getExamName();
+		if (StringUtils.isNotBlank(examName)) {
+			examCode = examName;
+		}
+
+		GetExamReq getExamReq = new GetExamReq();
+		getExamReq.setId(examId);
+		getExamReq.setCode(examCode);
+		getExamReq.setRootOrgId(req.getRootOrgId());
+		GetExamResp r = examCloudService.getExam(getExamReq);
+		ExamBean examBean = r.getExamBean();
+
+		SaveExamStudentReq request = new SaveExamStudentReq();
+
+		request.setCourseCode(req.getCourseCode());
+		request.setCourseLevel(req.getCourseLevel());
+		request.setCourseName(req.getCourseName());
+		request.setExamId(req.getExamId());
+		request.setExamName(examBean.getName());
+		request.setIdentityNumber(req.getIdentityNumber());
+		request.setPaperType(req.getPaperType());
+		request.setRootOrgId(req.getRootOrgId());
+		request.setStudentCode(req.getStudentCode());
+		request.setStudentName(req.getStudentName());
+		request.setInfoCollector(req.getInfoCollector());
+		request.setSpecialtyName(req.getSpecialtyName());
+		request.setExamSite(req.getExamSite());
+		request.setGrade(req.getGrade());
+		request.setRemark(req.getRemark());
+
+		request.setExt1(req.getExt1());
+		request.setExt2(req.getExt2());
+		request.setExt3(req.getExt3());
+		request.setExt4(req.getExt4());
+		request.setExt5(req.getExt5());
+
+		SaveExamStudentResp response = examStudentCloudService.saveExamStudent(request);
+
+		ExamStudentBean sb = response.getExamStudentBean();
+
+		OuterSaveExamStudentResp resp = new OuterSaveExamStudentResp();
+		OuterExamStudentBean bean = new OuterExamStudentBean();
+		bean.setCourseCode(sb.getCourseCode());
+		bean.setCourseLevel(sb.getCourseLevel());
+		bean.setCourseName(sb.getCourseName());
+		bean.setExamId(sb.getExamId());
+		bean.setExamName(sb.getExamName());
+		bean.setIdentityNumber(sb.getIdentityNumber());
+		bean.setPaperType(sb.getPaperType());
+		bean.setRootOrgId(sb.getRootOrgId());
+		bean.setStudentCode(sb.getStudentCode());
+		bean.setStudentName(sb.getStudentName());
+
+		resp.setExamStudentBean(bean);
+
+		return resp;
+	}
+
+	@ApiOperation(value = "批量保存考生信息", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterBatchSaveExamStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("batchSaveExamStudent")
+	@Override
+	public OuterBatchSaveExamStudentResp batchSaveExamStudent(
+			@RequestBody @ApiParam(required = true) OuterBatchSaveExamStudentReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		Long examId = req.getExamId();
+		String examCode = req.getExamCode();
+		String examName = req.getExamName();
+		if (StringUtils.isNotBlank(examName)) {
+			examCode = examName;
+		}
+
+		GetExamReq getExamReq = new GetExamReq();
+		getExamReq.setId(examId);
+		getExamReq.setCode(examCode);
+		getExamReq.setRootOrgId(req.getRootOrgId());
+		GetExamResp r = examCloudService.getExam(getExamReq);
+		ExamBean examBean = r.getExamBean();
+
+		List<ExamStudent4BatchBean> examStudentList = req.getExamStudentList();
+
+		List<ExamStudentStatus4BatchBean> successList = Lists.newArrayList();
+		List<ExamStudentStatus4BatchBean> failureList = Lists.newArrayList();
+
+		for (ExamStudent4BatchBean cur : examStudentList) {
+			SaveExamStudentReq request = new SaveExamStudentReq();
+
+			request.setCourseCode(cur.getCourseCode());
+			request.setCourseLevel(cur.getCourseLevel());
+			request.setCourseName(cur.getCourseName());
+			request.setExamId(req.getExamId());
+			request.setExamName(examBean.getName());
+			request.setIdentityNumber(cur.getIdentityNumber());
+			request.setPaperType(cur.getPaperType());
+			request.setRootOrgId(req.getRootOrgId());
+			request.setStudentCode(cur.getStudentCode());
+			request.setStudentName(cur.getStudentName());
+			request.setInfoCollector(cur.getInfoCollector());
+			request.setSpecialtyName(cur.getSpecialtyName());
+			request.setExamSite(cur.getExamSite());
+			request.setGrade(cur.getGrade());
+			request.setRemark(cur.getRemark());
+
+			request.setExt1(cur.getExt1());
+			request.setExt2(cur.getExt2());
+			request.setExt3(cur.getExt3());
+			request.setExt4(cur.getExt4());
+			request.setExt5(cur.getExt5());
+
+			ExamStudentStatus4BatchBean bean = new ExamStudentStatus4BatchBean();
+			try {
+				SaveExamStudentResp response = examStudentCloudService.saveExamStudent(request);
+				ExamStudentBean sb = response.getExamStudentBean();
+
+				bean.setCourseCode(sb.getCourseCode());
+				bean.setCourseLevel(sb.getCourseLevel());
+				bean.setCourseName(sb.getCourseName());
+				bean.setExamId(sb.getExamId());
+				bean.setExamName(sb.getExamName());
+				bean.setIdentityNumber(sb.getIdentityNumber());
+				bean.setStudentCode(sb.getStudentCode());
+				bean.setName(sb.getStudentName());
+				successList.add(bean);
+
+			} catch (Exception e) {
+
+				bean.setCourseCode(cur.getCourseCode());
+				bean.setCourseLevel(cur.getCourseLevel());
+				bean.setCourseName(cur.getCourseName());
+				bean.setExamId(req.getExamId());
+				bean.setExamName(req.getExamName());
+				bean.setIdentityNumber(cur.getIdentityNumber());
+				bean.setStudentCode(cur.getStudentCode());
+				bean.setName(cur.getStudentName());
+				failureList.add(bean);
+
+			}
+
+		}
+
+		OuterBatchSaveExamStudentResp resp = new OuterBatchSaveExamStudentResp();
+		resp.setSuccessList(successList);
+		resp.setFailureList(failureList);
+		return resp;
+	}
+
+	@ApiOperation(value = "更新考生状态", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterBatchSaveExamStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("updateExamStudentStatus")
+	@Override
+	public OuterUpdateExamStudentStatusResp updateExamStudentStatus(
+			@RequestBody @ApiParam(required = true) OuterUpdateExamStudentStatusReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		Long examId = req.getExamId();
+		String examCode = req.getExamCode();
+		String examName = req.getExamName();
+		if (StringUtils.isNotBlank(examName)) {
+			examCode = examName;
+		}
+
+		GetExamReq getExamReq = new GetExamReq();
+		getExamReq.setId(examId);
+		getExamReq.setCode(examCode);
+		getExamReq.setRootOrgId(req.getRootOrgId());
+		GetExamResp r = examCloudService.getExam(getExamReq);
+		ExamBean examBean = r.getExamBean();
+
+		UpdateExamStudentStatusReq uessReq = new UpdateExamStudentStatusReq();
+		uessReq.setCourseCode(req.getCourseCode());
+		uessReq.setCourseId(req.getCourseId());
+		uessReq.setEnable(req.getEnable());
+		uessReq.setExamName(examBean.getName());
+		uessReq.setExamCode(req.getExamCode());
+		uessReq.setExamId(req.getExamId());
+		uessReq.setIdentityNumber(req.getIdentityNumber());
+		uessReq.setRootOrgId(req.getRootOrgId());
+		uessReq.setStudentId(req.getStudentId());
+
+		examStudentCloudService.updateExamStudentStatus(uessReq);
+
+		OuterUpdateExamStudentStatusResp resp = new OuterUpdateExamStudentStatusResp();
+		return resp;
+	}
+
+	@ApiOperation(value = "重置考生", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterResetExamStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("resetExamStudent")
+	@Override
+	public OuterResetExamStudentResp resetExamStudent(
+			@RequestBody @ApiParam(required = true) OuterResetExamStudentReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		Long examId = req.getExamId();
+		String examCode = req.getExamCode();
+		String examName = req.getExamName();
+		if (StringUtils.isNotBlank(examName)) {
+			examCode = examName;
+		}
+
+		GetExamReq getExamReq = new GetExamReq();
+		getExamReq.setId(examId);
+		getExamReq.setCode(examCode);
+		getExamReq.setRootOrgId(req.getRootOrgId());
+		GetExamResp r = examCloudService.getExam(getExamReq);
+		ExamBean examBean = r.getExamBean();
+
+		ResetExamStudentReq resReq = new ResetExamStudentReq();
+		resReq.setExamName(examBean.getName());
+		resReq.setExamCode(req.getExamCode());
+		resReq.setExamId(req.getExamId());
+		resReq.setIdentityNumber(req.getIdentityNumber());
+		resReq.setRootOrgId(req.getRootOrgId());
+		resReq.setStudentCode(req.getStudentCode());
+		resReq.setStudentName(req.getStudentName());
+
+		List<ExamStudentBean4Reset> examStudentList = Lists.newArrayList();
+		resReq.setExamStudentList(examStudentList);
+
+		List<OuterExamStudent4ResetReqBean> outerExamStudentList = req.getExamStudentList();
+		for (OuterExamStudent4ResetReqBean cur : outerExamStudentList) {
+			ExamStudentBean4Reset b = new ExamStudentBean4Reset();
+			examStudentList.add(b);
+
+			b.setCourseCode(cur.getCourseCode());
+			b.setCourseLevel(cur.getCourseLevel());
+			b.setCourseName(cur.getCourseName());
+			b.setExamSite(cur.getExamSite());
+			b.setExt1(cur.getExt1());
+			b.setExt2(cur.getExt2());
+			b.setExt3(cur.getExt3());
+			b.setExt4(cur.getExt4());
+			b.setExt5(cur.getExt5());
+			b.setGrade(cur.getGrade());
+			b.setInfoCollector(cur.getInfoCollector());
+			b.setPaperType(cur.getPaperType());
+			b.setRemark(cur.getRemark());
+			b.setSpecialtyName(cur.getSpecialtyName());
+		}
+
+		ResetExamStudentResp resResp = examStudentCloudService.resetExamStudent(resReq);
+
+		List<ExamStudentBean> savedExamStudentList = resResp.getExamStudentList();
+
+		List<OuterExamStudent4ResetRespBean> outerList = Lists.newArrayList();
+
+		for (ExamStudentBean cur : savedExamStudentList) {
+			OuterExamStudent4ResetRespBean b = new OuterExamStudent4ResetRespBean();
+			outerList.add(b);
+
+			b.setCourseCode(cur.getCourseCode());
+			b.setCourseId(cur.getCourseId());
+			b.setCourseLevel(cur.getCourseLevel());
+			b.setCourseName(cur.getCourseName());
+			b.setExamId(cur.getExamId());
+			b.setExamName(cur.getExamName());
+			b.setExamSite(cur.getExamSite());
+			b.setGrade(cur.getGrade());
+			b.setId(cur.getId());
+			b.setIdentityNumber(cur.getIdentityNumber());
+			b.setInfoCollector(cur.getInfoCollector());
+			b.setOrgCode(cur.getOrgCode());
+			b.setOrgId(cur.getOrgId());
+			b.setOrgName(cur.getOrgName());
+			b.setPaperType(cur.getPaperType());
+			b.setRemark(cur.getRemark());
+			b.setRootOrgId(cur.getRootOrgId());
+			b.setSpecialtyName(cur.getSpecialtyName());
+			b.setStudentCode(cur.getStudentCode());
+			b.setStudentId(cur.getStudentId());
+			b.setStudentName(cur.getStudentName());
+
+		}
+		OuterResetExamStudentResp resp = new OuterResetExamStudentResp();
+		resp.setExamStudentList(outerList);
+		return resp;
+	}
+
+}

+ 216 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/FaceOuterServiceProvider.java

@@ -0,0 +1,216 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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.commons.CommonsMultipartFile;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.HttpClientUtil;
+import cn.com.qmth.examcloud.commons.util.ZipUtil;
+import cn.com.qmth.examcloud.exchange.outer.api.FaceOuterService;
+import cn.com.qmth.examcloud.exchange.outer.service.FaceService;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+/**
+ * 人脸服务
+ *
+ * @author WANGWEI
+ * @date 2018年11月14日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api("人脸服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/face")
+public class FaceOuterServiceProvider extends ControllerSupport implements FaceOuterService {
+
+	private static final long serialVersionUID = -6268268043341270752L;
+
+	@Autowired
+	SystemProperties systemConfig;
+
+	/**
+	 * ZIP最大50M
+	 */
+	private static final int ZIP_MAX_SIZE = 50;
+
+	/**
+	 * 每张照片最大尺寸 500KB
+	 */
+	private static final int MAX_SIZE = 500;
+
+	@Autowired
+	private FaceService faceService;
+
+	@ApiOperation(value = "保存学生照片", httpMethod = "POST")
+	@PostMapping("addPhotoByUrl")
+	@Override
+	public void addPhotoByUrl(
+			@RequestParam @ApiParam(value = "顶级机构ID", example = "1", required = true) Long rootOrgId,
+			@RequestParam @ApiParam(value = "身份证", required = true) String identityNumber,
+			@RequestParam @ApiParam(value = "照片地址", required = true) String photoUrl,
+			@RequestParam @ApiParam(value = "操作者", required = true) String operator) {
+
+		if (!getEnterpriseRootOrgId().equals(rootOrgId)) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		if (photoUrl.startsWith("http")) {
+			byte[] bs = HttpClientUtil.get(photoUrl);
+
+			int lastIndexOf = photoUrl.lastIndexOf(".");
+			if (0 > lastIndexOf) {
+				throw new StatusException("100002",
+						"photoPath is not end with photo file suffix.");
+			}
+			String fileSuffix = photoUrl.substring(lastIndexOf);
+
+			String fileName = System.currentTimeMillis() + fileSuffix;
+			File temp = new File(systemConfig.getTempDataDir() + File.separator + "student_photo"
+					+ File.separator + fileName);
+
+			try {
+				FileUtils.writeByteArrayToFile(temp, bs);
+			} catch (IOException e) {
+				throw new StatusException("100003", "文件读写失败");
+			}
+
+			faceService.processFace(rootOrgId, identityNumber, fileSuffix, temp, operator);
+		}
+
+	}
+
+	@ApiOperation(value = "保存学生照片", httpMethod = "POST")
+	@PostMapping("addPhoto")
+	@Override
+	public void addPhoto(
+			@RequestParam @ApiParam(value = "顶级机构ID", example = "1", required = true) Long rootOrgId,
+			@RequestParam @ApiParam(value = "身份证", required = true) String identityNumber,
+			@RequestParam @ApiParam(value = "操作者", required = true) String operator,
+			@RequestParam @ApiParam(value = "学生照片文件(文件名称=身份证号码+文件后缀) 如:xxxxxxxxxx.jpg", required = true) CommonsMultipartFile file) {
+
+		if (!getEnterpriseRootOrgId().equals(rootOrgId)) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		DiskFileItem item = (DiskFileItem) file.getFileItem();
+		File storeLocation = item.getStoreLocation();
+		String fileName = file.getOriginalFilename();
+
+		if (StringUtils.containsWhitespace(fileName)) {
+			throw new StatusException("600100", "文件名不能含有空白字符");
+		}
+
+		if (!fileName.matches("[^\\.\\s]+\\.[^\\.\\s]+")) {
+			throw new StatusException("600101", "文件名不合法");
+		}
+		String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
+
+		faceService.processFace(rootOrgId, identityNumber, fileSuffix, storeLocation, operator);
+	}
+
+	@ApiOperation(value = "导入学生照片", httpMethod = "POST")
+	@PostMapping("importPhotos")
+	@Override
+	public List<Map<String, String>> importPhotos(
+			@RequestParam @ApiParam(value = "顶级机构ID", example = "1", required = true) Long rootOrgId,
+			@RequestParam @ApiParam(value = "操作者", required = true) String operator,
+			@RequestParam @ApiParam(value = "学生照片文件(身份证号码+文件后缀)压缩包(ZIP文件,压缩包内不含目录)", required = true) CommonsMultipartFile file) {
+
+		if (!getEnterpriseRootOrgId().equals(rootOrgId)) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		DiskFileItem item = (DiskFileItem) file.getFileItem();
+		File storeLocation = item.getStoreLocation();
+		String filename = file.getOriginalFilename();
+
+		if (!filename.endsWith(".zip")) {
+			throw new StatusException("620001", "文件格式不正确,必须是zip格式的压缩包");
+		}
+		// 文件大小限制
+		if (file.getSize() > ZIP_MAX_SIZE * 1024 * 1024) {
+			throw new StatusException("620002", "文件大小超过50M,请分批导入");
+		}
+
+		List<Map<String, String>> ret = Lists.newArrayList();
+
+		String tempDirPath = systemConfig.getTempDataDir() + File.separator + "photo_import"
+				+ File.separator + System.currentTimeMillis();
+		File tempDir = new File(tempDirPath);
+		try {
+			ZipUtil.unzip(storeLocation, new File(tempDirPath));
+		} catch (Exception e) {
+			throw new StatusException("620003", "zip文件损坏");
+		}
+
+		File[] files = tempDir.listFiles();
+
+		if (null == files) {
+			throw new StatusException("620004", "zip文件为空");
+		}
+
+		for (File f : files) {
+			Map<String, String> map = Maps.newHashMap();
+			String fileName = f.getName();
+			map.put("file", fileName);
+
+			if (f.length() > MAX_SIZE * 1024) {
+				map.put("statusCode", "EX-620005");
+				map.put("statusDesc", "文件大小超过500KB");
+				ret.add(map);
+				continue;
+			}
+			try {
+				if (StringUtils.containsWhitespace(fileName)) {
+					throw new StatusException("600100", "文件名不能含有空白字符");
+				}
+
+				if (!fileName.matches("[^\\.\\s]+\\.[^\\.\\s]+")) {
+					throw new StatusException("600101", "文件名不合法");
+				}
+				String identityNumber = fileName.substring(0, fileName.lastIndexOf("."));
+				String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
+
+				faceService.processFace(rootOrgId, identityNumber, fileSuffix, f, operator);
+
+				map.put("statusCode", "200");
+				map.put("statusDesc", "成功");
+
+			} catch (StatusException e) {
+				map.put("statusCode", e.getCode());
+				map.put("statusDesc", e.getDesc());
+			} catch (Exception e) {
+				map.put("statusCode", "系统异常");
+				map.put("statusDesc", e.getCause().getMessage());
+			}
+			ret.add(map);
+		}
+
+		try {
+			FileUtils.deleteDirectory(tempDir);
+		} catch (IOException e) {
+			log.error("fail to clean temp dir.", e);
+		}
+
+		return ret;
+	}
+
+}

+ 64 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/GetExamRecordAuditInfoServiceProvider.java

@@ -0,0 +1,64 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamScoreDataCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetAuditDataReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetAuditDataResp;
+import cn.com.qmth.examcloud.exchange.outer.api.GetExamRecordAuditInfoService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetExamRecordAuditInfoReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetExamRecordAuditInfoResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+
+@Api("获取考试记录审核信息服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/examRecordAuditInfo")
+public class GetExamRecordAuditInfoServiceProvider  extends ControllerSupport implements GetExamRecordAuditInfoService{
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -4020820717853946467L;
+	
+	@Autowired
+	private ExamScoreDataCloudService examScoreDataCloudService;
+	
+	@ApiOperation(value = "获取考试记录审核信息", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetExamRecordAuditInfoResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/getExamRecordAuditInfo")
+	@Override
+	public OuterGetExamRecordAuditInfoResp getExamRecordAuditInfo(@RequestBody OuterGetExamRecordAuditInfoReq req) {
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+		if (req.getExamRecordDataId()==null) {
+			throw new StatusException("1000002", "examRecordDataId is null");
+		}
+		GetAuditDataReq getAuditDataReq = new GetAuditDataReq();
+		getAuditDataReq.setExamRecordDataId(req.getExamRecordDataId());
+		GetAuditDataResp auditDataResp = examScoreDataCloudService.getAuditData(getAuditDataReq);
+		OuterGetExamRecordAuditInfoResp resp = new OuterGetExamRecordAuditInfoResp();
+		resp.setExamRecordDataId(req.getExamRecordDataId());
+		if(auditDataResp!=null){
+			resp.setDisciplineType(auditDataResp.getDisciplineType());
+			resp.setDisciplineDetail(auditDataResp.getDisciplineDetail());
+			resp.setCreationTime(auditDataResp.getCreationTime());
+			resp.setAuditUserName(auditDataResp.getAuditUserName());
+			resp.setIsDiscipline(auditDataResp.getIsDiscipline());
+		}
+		return resp;
+	}
+
+}

+ 148 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/GetScoreDataServiceProvider.java

@@ -0,0 +1,148 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cn.com.qmth.examcloud.commons.util.StringUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamScoreDataCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.ScoreDataBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetScoreDataReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.QueryScoreDataReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetScoreDataResp;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.QueryScoreDataResp;
+import cn.com.qmth.examcloud.exchange.outer.api.GetScoreDataService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterScoreDataBean;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetScoreDataReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterQueryScoreDataReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetScoreDataResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterQueryScoreDataResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+
+@Api("获取成绩服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/score")
+public class GetScoreDataServiceProvider extends ControllerSupport implements GetScoreDataService {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1857049574734356057L;
+
+	@Autowired
+	private ExamScoreDataCloudService examScoreDataCloudService;
+
+	@ApiOperation(value = "获取成绩数据", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetScoreDataResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/getScoreData")
+	@Override
+	public OuterGetScoreDataResp getScoreData(@RequestBody OuterGetScoreDataReq req) {
+		if(req.getRootOrgId() == null){
+			throw new StatusException("1000001", "rootOrgId不能为空");
+		}
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000002", "rootOrgId错误");
+		}
+		if (req.getExamRecordDataId()==null) {
+			throw new StatusException("1000003", "examRecordDataId不能为空");
+		}
+		GetScoreDataReq getScoreDataReq = new GetScoreDataReq();
+		getScoreDataReq.setExamRecordDataId(req.getExamRecordDataId());
+		GetScoreDataResp scoreDataResp = examScoreDataCloudService.getScoreData(getScoreDataReq);
+
+		OuterGetScoreDataResp outerGetScoreDataResp = new OuterGetScoreDataResp();
+		OuterScoreDataBean outerScoreDataBean = new OuterScoreDataBean();
+		outerScoreDataBean.setExamRecordDataId(scoreDataResp.getExamRecordDataId());
+		outerScoreDataBean.setStudentCode(scoreDataResp.getStudentCode());
+		outerScoreDataBean.setStudentName(scoreDataResp.getStudentName());
+		outerScoreDataBean.setIdentityNumber(scoreDataResp.getIdentityNumber());
+		outerScoreDataBean.setCourseCode(scoreDataResp.getCourseCode());
+		outerScoreDataBean.setCourseName(scoreDataResp.getCourseName());
+		outerScoreDataBean.setStartTime(scoreDataResp.getStartTime());
+		outerScoreDataBean.setEndTime(scoreDataResp.getEndTime());
+		outerScoreDataBean.setTotalScore(scoreDataResp.getTotalScore());
+		outerScoreDataBean.setIsWarn(scoreDataResp.getIsWarn());
+		outerScoreDataBean.setIsAudit(scoreDataResp.getIsAudit());
+		outerScoreDataBean.setIsIllegality(scoreDataResp.getIsIllegality());
+		outerGetScoreDataResp.setOuterScoreDataBean(outerScoreDataBean);
+		return outerGetScoreDataResp;
+	}
+
+	@ApiOperation(value = "按考试名称,rootOrgId,courseCode,身份证号或学号获取成绩数据", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterQueryScoreDataResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/queryScoreData")
+	@Override
+	public OuterQueryScoreDataResp queryScoreData(@RequestBody OuterQueryScoreDataReq req) {
+		if(req.getRootOrgId() == null){
+			throw new StatusException("1000001", "rootOrgId不能为空");
+		}
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000002", "rootOrgId错误");
+		}
+
+		if(StringUtils.isBlank(req.getCourseCode())){
+			throw new StatusException("1000004", "课程code不能为空");
+		}
+		if(req.getRootOrgId() == null){
+			throw new StatusException("1000005", "rootOrgId不能为空");
+		}
+		if(StringUtils.isBlank(req.getIdentityNumber()) && StringUtils.isBlank(req.getStudentCode())){
+			throw new StatusException("1000006", "身份证号和学号不能都为空");
+		}
+		QueryScoreDataReq queryScoreDataReq = new QueryScoreDataReq();
+		queryScoreDataReq.setCourseCode(req.getCourseCode());
+
+		//如果考试名称不为空,则把考试名称作为考试编码
+		if (StringUtils.isNoneBlank(req.getExamName())) {
+			queryScoreDataReq.setExamCode(req.getExamName());
+		} else {
+			queryScoreDataReq.setExamCode(req.getExamCode());
+		}
+		if(StringUtils.isBlank(queryScoreDataReq.getExamCode())){
+			throw new StatusException("1000003", "考试代码不能为空");
+		}
+
+		queryScoreDataReq.setExamName(req.getExamName());
+		queryScoreDataReq.setIdentityNumber(req.getIdentityNumber());
+		queryScoreDataReq.setRootOrgId(req.getRootOrgId());
+		queryScoreDataReq.setStudentCode(req.getStudentCode());
+		QueryScoreDataResp queryScoreDataResp = examScoreDataCloudService.queryScoreData(queryScoreDataReq);
+		List<ScoreDataBean> scoreDataBeanList = queryScoreDataResp.getScoreDataBeanList();
+		List<OuterScoreDataBean> outerScoreDataBeanList = new ArrayList<OuterScoreDataBean>();
+		for(ScoreDataBean scoreDataBean:scoreDataBeanList){
+			OuterScoreDataBean outerScoreDataBean = new OuterScoreDataBean();
+			outerScoreDataBean.setCourseCode(scoreDataBean.getCourseCode());
+			outerScoreDataBean.setCourseName(scoreDataBean.getCourseName());
+			outerScoreDataBean.setEndTime(scoreDataBean.getEndTime());
+			outerScoreDataBean.setExamRecordDataId(scoreDataBean.getExamRecordDataId());
+			outerScoreDataBean.setIdentityNumber(scoreDataBean.getIdentityNumber());
+			outerScoreDataBean.setIsAudit(scoreDataBean.getIsAudit());
+			outerScoreDataBean.setIsWarn(scoreDataBean.getIsWarn());
+			outerScoreDataBean.setIsIllegality(scoreDataBean.getIsIllegality());
+			outerScoreDataBean.setStartTime(scoreDataBean.getStartTime());
+			outerScoreDataBean.setStudentCode(scoreDataBean.getStudentCode());
+			outerScoreDataBean.setStudentName(scoreDataBean.getStudentName());
+			outerScoreDataBean.setTotalScore(scoreDataBean.getTotalScore());
+			outerScoreDataBeanList.add(outerScoreDataBean);
+		}
+		OuterQueryScoreDataResp outerQueryScoreDataResp = new OuterQueryScoreDataResp();
+		outerQueryScoreDataResp.setOuterScoreDataBeanList(outerScoreDataBeanList);
+		return outerQueryScoreDataResp;
+	}
+
+}

+ 73 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/QueryCapturePhotoServiceProvider.java

@@ -0,0 +1,73 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamScoreDataCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.QueryCapturePhotoBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.QueryCapturePhotoReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.QueryCapturePhotoResp;
+import cn.com.qmth.examcloud.exchange.outer.api.QueryCapturePhotoService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterGetCapturePhotoBean;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterQueryCapturePhotoReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterQueryCapturePhotoResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+
+@Api("获取抓拍照片信息服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/capturePhoto")
+public class QueryCapturePhotoServiceProvider extends ControllerSupport implements QueryCapturePhotoService {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 3051021630006959568L;
+	
+	@Autowired
+	private ExamScoreDataCloudService examScoreDataCloudService;
+
+	@ApiOperation(value = "获取抓拍照片信息数据", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterQueryCapturePhotoResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/queryCapturePhoto")
+	@Override
+	public OuterQueryCapturePhotoResp queryCapturePhotoList(@RequestBody OuterQueryCapturePhotoReq req) {
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+		if (req.getExamRecordDataId()==null) {
+			throw new StatusException("1000002", "examRecordDataId is null");
+		}
+		QueryCapturePhotoReq queryCapturePhotoReq = new QueryCapturePhotoReq();
+		queryCapturePhotoReq.setExamRecordDataId(req.getExamRecordDataId());
+		QueryCapturePhotoResp capturePhotoResp = examScoreDataCloudService.queryCapturePhoto(queryCapturePhotoReq);
+		OuterQueryCapturePhotoResp resp = new OuterQueryCapturePhotoResp();
+		resp.setExamRecordDataId(capturePhotoResp.getExamRecordDataId());
+		
+		List<OuterGetCapturePhotoBean> capturePhotoList = new ArrayList<OuterGetCapturePhotoBean>();
+		for(QueryCapturePhotoBean queryCapturePhotoBean:capturePhotoResp.getCapturePhotoList()){
+			OuterGetCapturePhotoBean outerGetCapturePhotoBean = new OuterGetCapturePhotoBean();
+			outerGetCapturePhotoBean.setFileUrl(queryCapturePhotoBean.getFileUrl());
+			outerGetCapturePhotoBean.setIsPass(queryCapturePhotoBean.getIsPass());
+			outerGetCapturePhotoBean.setIsStranger(queryCapturePhotoBean.getIsStranger());
+			outerGetCapturePhotoBean.setIsLivenessPass(queryCapturePhotoBean.getIsLivenessPass());
+			capturePhotoList.add(outerGetCapturePhotoBean);
+		}
+		resp.setCapturePhotoList(capturePhotoList);
+		return resp;
+	}
+
+}

+ 114 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/ScoreQueueServiceProvider.java

@@ -0,0 +1,114 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamScoreObtainQueueCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.DeleteExamScoreQueueReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetTopExamScoreQueueReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetTopExamScoreQueueResp;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.exchange.outer.api.ScoreQueueService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterDeleteScoreQueueTopReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetScoreQueueTopReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterDeleteScoreQueueTopResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetScoreQueueTopResp;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+
+@Api("成绩队列服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/scoreQueue")
+public class ScoreQueueServiceProvider extends ControllerSupport implements ScoreQueueService {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = -7975687672489564748L;
+
+	@Autowired
+	private ExamScoreObtainQueueCloudService examScoreObtainQueueCloudService;
+	@Autowired
+	private ExamCloudService examCloudService;
+
+
+
+	@ApiOperation(value = "取队列最顶层记录", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterGetScoreQueueTopResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/getScoreQueueTop")
+	@Override
+	public OuterGetScoreQueueTopResp getScoreQueueTop(@RequestBody OuterGetScoreQueueTopReq req) {
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+		GetTopExamScoreQueueReq getTopExamScoreQueueReq = new GetTopExamScoreQueueReq();
+		getTopExamScoreQueueReq.setRootOrgId(req.getRootOrgId());
+		GetTopExamScoreQueueResp getTopExamScoreQueueResp = examScoreObtainQueueCloudService.getTopExamScoreQueue(getTopExamScoreQueueReq);
+		OuterGetScoreQueueTopResp resp = new OuterGetScoreQueueTopResp();
+
+		//返回值不为空数据
+		if(!getTopExamScoreQueueResp.getIsEmpty()){
+			resp.setQueueId(getTopExamScoreQueueResp.getQueueId());
+			resp.setExamRecordDataId(getTopExamScoreQueueResp.getExamRecordDataId());
+			Long examId=getTopExamScoreQueueResp.getExamId();
+			GetExamReq getExamReq=new GetExamReq();
+			getExamReq.setId(examId);
+			//获取考试详情
+			GetExamResp getExamResp = examCloudService.getExam(getExamReq);
+			if(getExamResp!=null) {
+				resp.setExamId(examId);//考试id
+				ExamBean examBean = getExamResp.getExamBean();
+				if(examBean!=null) {
+					//需求调整201911216:code和name都返回为code
+					resp.setExamCode(examBean.getCode());
+					resp.setExamName(examBean.getCode());
+				}
+			}
+			resp.setIsEmpty(false);//返回的为非空数据
+		}else {
+			resp.setIsEmpty(true);//返回的为空数据
+		}
+		return resp;
+	}
+
+	@ApiOperation(value = "删除队列最顶层记录", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterDeleteScoreQueueTopResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("/deleteScoreQueueTop")
+	@Override
+	public OuterDeleteScoreQueueTopResp deleteScoreQueueTop(@RequestBody OuterDeleteScoreQueueTopReq req) {
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+		GetTopExamScoreQueueReq getTopExamScoreQueueReq = new GetTopExamScoreQueueReq();
+		getTopExamScoreQueueReq.setRootOrgId(req.getRootOrgId());
+		GetTopExamScoreQueueResp getTopExamScoreQueueResp = examScoreObtainQueueCloudService.getTopExamScoreQueue(getTopExamScoreQueueReq);
+
+		if(getTopExamScoreQueueResp.getQueueId()==null || (getTopExamScoreQueueResp.getQueueId()!=null && !getTopExamScoreQueueResp.getQueueId().equals(req.getQueueId()))){
+			throw new StatusException("1000003", "queueId is wrong");
+		}
+
+		DeleteExamScoreQueueReq deleteExamScoreQueueReq = new DeleteExamScoreQueueReq();
+		deleteExamScoreQueueReq.setQueueId(req.getQueueId());
+		deleteExamScoreQueueReq.setRootOrgId(req.getRootOrgId());
+		examScoreObtainQueueCloudService.deleteExamScoreQueue(deleteExamScoreQueueReq);
+		OuterDeleteScoreQueueTopResp resp = new OuterDeleteScoreQueueTopResp();
+		resp.setIsSuccess(true);
+		resp.setDesc("删除成功");
+		return resp;
+	}
+
+}

+ 269 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/StudentOuterServiceProvider.java

@@ -0,0 +1,269 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 com.google.common.collect.Lists;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.HttpClientUtil;
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.SaveStudentReq;
+import cn.com.qmth.examcloud.core.basic.api.request.UpdatePasswordReq;
+import cn.com.qmth.examcloud.core.basic.api.request.UpdateStudentStatusReq;
+import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.StudentOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.Student4BatchBean;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.StudentStatus4BatchBean;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterBatchSaveStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdatePasswordReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdateStudentStatusReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterBatchSaveStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdatePasswordResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdateStudentStatusResp;
+import cn.com.qmth.examcloud.exchange.outer.service.FaceService;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api(value = "学生服务")
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.outer}/student")
+public class StudentOuterServiceProvider extends ControllerSupport implements StudentOuterService {
+
+	private static final long serialVersionUID = -8252740695302763716L;
+
+	@Autowired
+	StudentCloudService studentCloudService;
+
+	@Autowired
+	private FaceService faceService;
+
+	@Autowired
+	SystemProperties systemConfig;
+
+	@ApiOperation(value = "保存学生信息", httpMethod = "POST")
+	@ApiResponses({@ApiResponse(code = 200, message = "成功", response = OuterSaveStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("saveStudent")
+	@Override
+	public OuterSaveStudentResp saveStudent(
+			@RequestBody @ApiParam(required = true) OuterSaveStudentReq req) {
+		trim(req);
+		Long rootOrgId = req.getRootOrgId();
+		if (!getEnterpriseRootOrgId().equals(rootOrgId)) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		SaveStudentReq request = new SaveStudentReq();
+		request.setEnable(req.getEnable());
+		request.setIdentityNumber(req.getIdentityNumber());
+		request.setName(req.getName());
+		request.setOrgCode(req.getOrgCode());
+		request.setOrgId(req.getOrgId());
+		request.setOrgName(req.getOrgName());
+		request.setPhoneNumber(req.getPhoneNumber());
+		request.setRemark(req.getRemark());
+		request.setRootOrgId(req.getRootOrgId());
+		if (StringUtils.isNotBlank(req.getStudentCode())) {
+			List<String> studentCodeList = Lists.newArrayList();
+			studentCodeList.add(req.getStudentCode());
+			request.setStudentCodeList(studentCodeList);
+		}
+
+		// 保存学生
+		SaveStudentResp response = studentCloudService.saveStudent(request);
+		// 处理照片
+		processPhotoUrl(rootOrgId, req.getIdentityNumber(), req.getPhotoUrl(), req.getOperator());
+
+		OuterSaveStudentResp resp = new OuterSaveStudentResp();
+		resp.setOrgId(response.getOrgId());
+		resp.setOrgName(response.getOrgName());
+		resp.setRootOrgId(response.getRootOrgId());
+		resp.setStudentId(response.getStudentId());
+		return resp;
+	}
+
+	/**
+	 * 处理照片
+	 *
+	 * @author WANGWEI
+	 * @param rootOrgId
+	 * @param identityNumber
+	 * @param photoUrl
+	 * @param operator
+	 */
+	private void processPhotoUrl(Long rootOrgId, String identityNumber, String photoUrl,
+			String operator) {
+
+		if (StringUtils.isNotBlank(photoUrl)) {
+			byte[] bs = HttpClientUtil.get(photoUrl);
+
+			int lastIndexOf = photoUrl.lastIndexOf(".");
+			if (0 > lastIndexOf) {
+				throw new StatusException("100002", "photoPath is not end with photo file suffix.");
+			}
+			String fileSuffix = photoUrl.substring(lastIndexOf);
+
+			String fileName = System.currentTimeMillis() + fileSuffix;
+			File temp = new File(systemConfig.getTempDataDir() + File.separator + "student_photo"
+					+ File.separator + fileName);
+
+			try {
+				FileUtils.writeByteArrayToFile(temp, bs);
+			} catch (IOException e) {
+				try {
+					FileUtils.forceDelete(temp);
+				} catch (IOException ex) {
+					// ignore
+				}
+				throw new StatusException("100003", "文件读写失败", e);
+			}
+
+			try {
+				faceService.processFace(rootOrgId, identityNumber, fileSuffix, temp, operator);
+			} finally {
+				try {
+					FileUtils.forceDelete(temp);
+				} catch (IOException ex) {
+					// ignore
+				}
+			}
+		}
+	}
+
+	@ApiOperation(value = "批量保存学生信息", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterBatchSaveStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("batchSaveStudent")
+	@Override
+	public OuterBatchSaveStudentResp batchSaveStudent(
+			@RequestBody @ApiParam(required = true) OuterBatchSaveStudentReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		List<Student4BatchBean> studentList = req.getStudentList();
+
+		List<StudentStatus4BatchBean> successList = Lists.newArrayList();
+		List<StudentStatus4BatchBean> failureList = Lists.newArrayList();
+
+		for (Student4BatchBean cur : studentList) {
+			SaveStudentReq ssReq = new SaveStudentReq();
+			ssReq.setEnable(cur.getEnable());
+			ssReq.setIdentityNumber(cur.getIdentityNumber());
+			ssReq.setName(cur.getName());
+			ssReq.setOrgCode(cur.getOrgCode());
+			ssReq.setOrgId(cur.getOrgId());
+			ssReq.setOrgName(cur.getOrgName());
+			ssReq.setPhoneNumber(cur.getPhoneNumber());
+			ssReq.setRemark(cur.getRemark());
+			ssReq.setRootOrgId(cur.getRootOrgId());
+			if (StringUtils.isNotBlank(cur.getStudentCode())) {
+				List<String> studentCodeList = Lists.newArrayList();
+				studentCodeList.add(cur.getStudentCode());
+				ssReq.setStudentCodeList(studentCodeList);
+			}
+
+			try {
+
+				// 保存学生
+				SaveStudentResp ssResp = studentCloudService.saveStudent(ssReq);
+				// 处理照片
+				processPhotoUrl(req.getRootOrgId(), cur.getIdentityNumber(), cur.getPhotoUrl(),
+						cur.getOperator());
+
+				StudentStatus4BatchBean studentStatus4BatchBeanSuccess = new StudentStatus4BatchBean();
+				studentStatus4BatchBeanSuccess.setStudentId(ssResp.getStudentId());
+				studentStatus4BatchBeanSuccess.setIdentityNumber(cur.getIdentityNumber());
+				studentStatus4BatchBeanSuccess.setName(cur.getName());
+				studentStatus4BatchBeanSuccess.setStudentCode(cur.getStudentCode());
+				successList.add(studentStatus4BatchBeanSuccess);
+			} catch (Exception e) {
+				StudentStatus4BatchBean studentStatus4BatchBeanfailure = new StudentStatus4BatchBean();
+				studentStatus4BatchBeanfailure.setIdentityNumber(cur.getIdentityNumber());
+				studentStatus4BatchBeanfailure.setName(cur.getName());
+				studentStatus4BatchBeanfailure.setStudentCode(cur.getStudentCode());
+				failureList.add(studentStatus4BatchBeanfailure);
+			}
+		}
+		OuterBatchSaveStudentResp resq = new OuterBatchSaveStudentResp();
+		resq.setSuccessList(successList);
+		resq.setFailureList(failureList);
+		return resq;
+	}
+
+	@ApiOperation(value = "更新密码", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterUpdatePasswordResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("updatePassword")
+	@Override
+	public OuterUpdatePasswordResp updatePassword(
+			@RequestBody @ApiParam(required = true) OuterUpdatePasswordReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		UpdatePasswordReq upReq = new UpdatePasswordReq();
+		upReq.setIdentityNumber(req.getIdentityNumber());
+		upReq.setRootOrgId(req.getRootOrgId());
+		upReq.setStudentId(req.getStudentId());
+		upReq.setPassword(req.getPassword());
+		studentCloudService.updatePassword(upReq);
+
+		OuterUpdatePasswordResp resp = new OuterUpdatePasswordResp();
+		return resp;
+	}
+
+	@ApiOperation(value = "更新学生状态", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = OuterUpdateStudentStatusResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("updateStudentStatus")
+	@Override
+	public OuterUpdateStudentStatusResp updateStudentStatus(
+			@RequestBody @ApiParam(required = true) OuterUpdateStudentStatusReq req) {
+
+		if (!getEnterpriseRootOrgId().equals(req.getRootOrgId())) {
+			throw new StatusException("1000001", "rootOrgId is wrong");
+		}
+
+		UpdateStudentStatusReq ussReq = new UpdateStudentStatusReq();
+		ussReq.setIdentityNumber(req.getIdentityNumber());
+		ussReq.setRootOrgId(req.getRootOrgId());
+		ussReq.setStudentId(req.getStudentId());
+		ussReq.setEnable(req.getEnable());
+		studentCloudService.updateStudentStatus(ussReq);
+
+		OuterUpdateStudentStatusResp resp = new OuterUpdateStudentStatusResp();
+		return resp;
+	}
+
+}

+ 204 - 0
examcloud-exchange-outer-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/provider/cug/CugOuterServiceProvider.java

@@ -0,0 +1,204 @@
+package cn.com.qmth.examcloud.exchange.outer.api.provider.cug;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 com.google.common.collect.Lists;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.HttpClientUtil;
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.SaveStudentReq;
+import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStudentBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamStudentReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamResp;
+import cn.com.qmth.examcloud.examwork.api.response.SaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.CugOuterService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.cug.OuterSaveCugStudentAndExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.cug.SaveCugStudentAndExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.service.CourseGroupService;
+import cn.com.qmth.examcloud.exchange.outer.service.FaceService;
+import cn.com.qmth.examcloud.exchange.outer.service.bean.Course;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 中国地质大学(武汉)
+ *
+ * @author WANGWEI
+ * @date 2018年9月4日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Api("废弃接口")
+@RestController
+@RequestMapping("/api/ecs_outlet/cug")
+public class CugOuterServiceProvider extends ControllerSupport implements CugOuterService {
+
+	private static final long serialVersionUID = -2082287868965834214L;
+
+	@Autowired
+	StudentCloudService studentCloudService;
+
+	@Autowired
+	private FaceService faceService;
+
+	@Autowired
+	CourseGroupService courseGroupService;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	@Autowired
+	SystemProperties systemConfig;
+
+	@ApiOperation(value = "废弃接口,考生接入", httpMethod = "POST")
+	@ApiResponses({
+			@ApiResponse(code = 200, message = "成功", response = SaveCugStudentAndExamStudentResp.class),
+			@ApiResponse(code = 500, message = "系统异常(异常信息见响应体)", response = StatusResponse.class)})
+	@PostMapping("saveCugStudentAndExamStudent")
+	@Override
+	public SaveCugStudentAndExamStudentResp saveCugStudentAndExamStudent(
+			@RequestBody @ApiParam(required = true) OuterSaveCugStudentAndExamStudentReq req) {
+
+		trim(req);
+
+		Long rootOrgId = req.getRootOrgId();
+		String identityNumber = req.getIdentityNumber();
+
+		String courseGroupName = req.getCourseGroupName();
+		String examName = req.getExamName();
+		String specialtyName = req.getSpecialtyName();
+
+		List<Course> courseList = courseGroupService.getCourseList(rootOrgId, courseGroupName);
+
+		SaveStudentReq request = new SaveStudentReq();
+		request.setIdentityNumber(identityNumber);
+		request.setName(req.getName());
+		request.setOrgCode(req.getOrgCode());
+		request.setOrgName(req.getOrgName());
+		request.setPhoneNumber(req.getPhoneNumber());
+		request.setRemark(req.getRemark());
+		request.setRootOrgId(req.getRootOrgId());
+
+		SaveStudentResp response = studentCloudService.saveStudent(request);
+
+		Long studentId = response.getStudentId();
+
+		String photoUrl = req.getPhotoUrl();
+		if (StringUtils.isNotBlank(photoUrl)) {
+			byte[] bs;
+			try {
+				bs = HttpClientUtil.get(photoUrl);
+			} catch (Exception e) {
+				throw new StatusException("100002", "photoUrl is wrong");
+			}
+
+			int lastIndexOf = photoUrl.lastIndexOf(".");
+			if (0 > lastIndexOf) {
+				throw new StatusException("100002", "photoPath is not end with photo file suffix.");
+			}
+			String fileSuffix = photoUrl.substring(lastIndexOf);
+
+			String fileName = identityNumber + fileSuffix;
+			File temp = new File(systemConfig.getTempDataDir() + File.separator + "student_photo"
+					+ File.separator + fileName);
+
+			try {
+				FileUtils.writeByteArrayToFile(temp, bs);
+			} catch (IOException e) {
+				try {
+					FileUtils.forceDelete(temp);
+				} catch (IOException ex) {
+					// ignore
+				}
+				throw new StatusException("100003", "文件读写失败");
+			}
+
+			try {
+				faceService.processFace(rootOrgId, identityNumber, fileSuffix, temp,
+						req.getOperator());
+			} finally {
+				try {
+					FileUtils.forceDelete(temp);
+				} catch (IOException ex) {
+					// ignore
+				}
+			}
+		}
+
+		GetExamReq getExamReq = new GetExamReq();
+		//如果考试代码为空,则将考试名称作为考试代码
+		if (StringUtils.isEmpty(req.getExamCode())){
+			getExamReq.setCode(examName);
+		}else {
+			getExamReq.setCode(req.getExamCode());
+		}
+		getExamReq.setRootOrgId(rootOrgId);
+		GetExamResp getExamResp = examCloudService.getExam(getExamReq);
+
+		Long examId = getExamResp.getId();
+
+		List<Long> examStudentIdList = Lists.newArrayList();
+
+		for (Course course : courseList) {
+			SaveExamStudentReq sReq = new SaveExamStudentReq();
+			sReq.setCourseLevel(course.getLevel());
+			sReq.setCourseCode(course.getCode());
+			sReq.setCourseName(course.getName());
+
+			sReq.setExamId(examId);
+			sReq.setExamName(examName);
+
+			sReq.setStudentId(studentId);
+			sReq.setIdentityNumber(req.getIdentityNumber());
+			sReq.setRootOrgId(rootOrgId);
+			sReq.setStudentCode(req.getStudentCode());
+			sReq.setStudentName(req.getName());
+			sReq.setSpecialtyName(specialtyName);
+
+			sReq.setRemark(req.getRemark());
+			sReq.setPaperType(req.getPaperType());
+			if (null == req.getInfoCollector()) {
+				sReq.setInfoCollector(req.getRemark());
+			} else {
+				sReq.setInfoCollector(req.getInfoCollector());
+			}
+
+			SaveExamStudentResp savedExamStudent = examStudentCloudService.saveExamStudent(sReq);
+			ExamStudentBean examStudentBean = savedExamStudent.getExamStudentBean();
+			examStudentIdList.add(examStudentBean.getId());
+		}
+
+		SaveCugStudentAndExamStudentResp resp = new SaveCugStudentAndExamStudentResp();
+		resp.setOrgId(response.getOrgId());
+		resp.setOrgName(response.getOrgName());
+		resp.setRootOrgId(response.getRootOrgId());
+		resp.setStudentId(response.getStudentId());
+		resp.setExamStudentIdList(examStudentIdList);
+
+		return resp;
+	}
+
+}

+ 19 - 0
examcloud-exchange-outer-api/pom.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>cn.com.qmth.examcloud.exchange</groupId>
+		<artifactId>examcloud-exchange</artifactId>
+		<version>2019-SNAPSHOT</version>
+	</parent>
+	<artifactId>examcloud-exchange-outer-api</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud</groupId>
+			<artifactId>examcloud-api-commons</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+	</dependencies>
+
+</project>

+ 25 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/CourseGroupOuterService.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetCourseListReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetCourseListResp;
+
+/**
+ * 课程组服务
+ *
+ * @author WANGWEI
+ * @date 2019年1月7日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface CourseGroupOuterService extends EnterpriseService {
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterGetCourseListResp getCourseList(OuterGetCourseListReq req);
+
+}

+ 26 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/CugOuterService.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.cug.OuterSaveCugStudentAndExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.cug.SaveCugStudentAndExamStudentResp;
+
+/**
+ * 中国地质大学(武汉)
+ *
+ * @author WANGWEI
+ * @date 2018年9月4日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface CugOuterService extends EnterpriseService {
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	SaveCugStudentAndExamStudentResp saveCugStudentAndExamStudent(
+			OuterSaveCugStudentAndExamStudentReq req);
+
+}

+ 36 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamOuterService.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetExamReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveExamReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetExamResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveExamResp;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface ExamOuterService extends EnterpriseService {
+
+	/**
+	 * 保存考试
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterSaveExamResp saveExam(OuterSaveExamReq req);
+
+	/**
+	 * 查询考试
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterGetExamResp getExam(OuterGetExamReq req);
+
+}

+ 57 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamQuestionOuterService.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetPaperStructReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetQuestionAnswerReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectivePaperStructReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetSubjectiveQuestionReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetPaperStructResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetQuestionAnswerResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectivePaperStructResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetSubjectiveQuestionResp;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description 考试作答服务
+ * @Author lideyin
+ * @Date 2020/3/30 15:19
+ * @Version 1.0
+ */
+public interface ExamQuestionOuterService extends EnterpriseService {
+
+    /**
+     * 获取主观题试卷结构
+     *
+     * @param req
+     * @return
+     */
+    OuterGetSubjectivePaperStructResp getSubjectivePaperStruct(OuterGetSubjectivePaperStructReq req);
+
+    /**
+     * 获取主观题作答结果
+     *
+     * @param req
+     * @return
+     */
+    OuterGetSubjectiveQuestionResp getSubjectiveQuestion(OuterGetSubjectiveQuestionReq req);
+
+    /**
+     * 获取题目答案
+     *
+     * @param req
+     * @return
+     */
+    OuterGetQuestionAnswerResp getQuestionAnswer(OuterGetQuestionAnswerReq req);
+
+    /**
+     * 获取试卷结构(题库中的原始试卷结构)
+     * @param req
+     * @return
+     */
+    OuterGetPaperStructResp getPaperStruct(OuterGetPaperStructReq req);
+}

+ 36 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ExamStudentOuterService.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterBatchSaveExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterResetExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveExamStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdateExamStudentStatusReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterBatchSaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterResetExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveExamStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdateExamStudentStatusResp;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface ExamStudentOuterService extends EnterpriseService {
+
+	OuterSaveExamStudentResp saveExamStudent(OuterSaveExamStudentReq req);
+
+	OuterBatchSaveExamStudentResp batchSaveExamStudent(OuterBatchSaveExamStudentReq req);
+
+	OuterUpdateExamStudentStatusResp updateExamStudentStatus(OuterUpdateExamStudentStatusReq req);
+
+	/**
+	 * 重置考生
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterResetExamStudentResp resetExamStudent(OuterResetExamStudentReq req);
+}

+ 29 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/FaceOuterService.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年9月4日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface FaceOuterService extends EnterpriseService {
+
+	void addPhotoByUrl(@RequestParam Long rootOrgId, @RequestParam String identityNumber,
+			@RequestParam String photoUrl, @RequestParam String operator);
+
+	void addPhoto(Long rootOrgId, String identityNumber, String operator,
+			CommonsMultipartFile file);
+
+	List<Map<String, String>> importPhotos(Long rootOrgId, String operator,
+			CommonsMultipartFile file);
+
+}

+ 18 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/GetExamRecordAuditInfoService.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetExamRecordAuditInfoReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetExamRecordAuditInfoResp;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 下午2:43:14
+ * @company 	QMTH
+ * @description 获取考试记录审核信息
+ */
+public interface GetExamRecordAuditInfoService extends EnterpriseService{
+
+	public OuterGetExamRecordAuditInfoResp getExamRecordAuditInfo(OuterGetExamRecordAuditInfoReq req);
+	
+}

+ 22 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/GetScoreDataService.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetScoreDataReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterQueryScoreDataReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetScoreDataResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterQueryScoreDataResp;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 上午11:32:53
+ * @company 	QMTH
+ * @description 获取成绩数据
+ */
+public interface GetScoreDataService extends EnterpriseService{
+
+	public OuterGetScoreDataResp getScoreData(OuterGetScoreDataReq req);
+	
+	
+	public OuterQueryScoreDataResp queryScoreData(OuterQueryScoreDataReq req);
+}

+ 18 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/QueryCapturePhotoService.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterQueryCapturePhotoReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterQueryCapturePhotoResp;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 下午2:33:21
+ * @company 	QMTH
+ * @description 获取抓拍照片数据
+ */
+public interface QueryCapturePhotoService extends EnterpriseService{
+
+	public OuterQueryCapturePhotoResp queryCapturePhotoList(OuterQueryCapturePhotoReq req);
+	
+}

+ 32 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/ScoreQueueService.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterDeleteScoreQueueTopReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterGetScoreQueueTopReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterDeleteScoreQueueTopResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterGetScoreQueueTopResp;
+
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 下午3:02:45
+ * @company 	QMTH
+ * @description 成绩队列处理
+ */
+public interface ScoreQueueService extends EnterpriseService{
+	
+	/**
+	 * 取队列最顶层记录
+	 * @param req
+	 * @return
+	 */
+	public OuterGetScoreQueueTopResp getScoreQueueTop(OuterGetScoreQueueTopReq req);
+	
+	/**
+	 * 删除队列最顶层记录
+	 * @param req
+	 * @return
+	 */
+	public OuterDeleteScoreQueueTopResp deleteScoreQueueTop(OuterDeleteScoreQueueTopReq req);
+}

+ 57 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/StudentOuterService.java

@@ -0,0 +1,57 @@
+package cn.com.qmth.examcloud.exchange.outer.api;
+
+import cn.com.qmth.examcloud.api.commons.EnterpriseService;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterBatchSaveStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterSaveStudentReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdatePasswordReq;
+import cn.com.qmth.examcloud.exchange.outer.api.request.OuterUpdateStudentStatusReq;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterBatchSaveStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterSaveStudentResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdatePasswordResp;
+import cn.com.qmth.examcloud.exchange.outer.api.response.OuterUpdateStudentStatusResp;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public interface StudentOuterService extends EnterpriseService {
+
+	/**
+	 * 保存学生
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterSaveStudentResp saveStudent(OuterSaveStudentReq req);
+
+	/**
+	 * 批量创建学生
+	 * 
+	 * @param req
+	 * @return
+	 */
+	OuterBatchSaveStudentResp batchSaveStudent(OuterBatchSaveStudentReq req);
+
+	/**
+	 * 修改密码
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterUpdatePasswordResp updatePassword(OuterUpdatePasswordReq req);
+
+	/**
+	 * 更新学生状态
+	 *
+	 * @author WANGWEI
+	 * @param req
+	 * @return
+	 */
+	OuterUpdateStudentStatusResp updateStudentStatus(OuterUpdateStudentStatusReq req);
+
+}

+ 46 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/CourseBean.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年9月4日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class CourseBean implements JsonSerializable {
+
+	private static final long serialVersionUID = 2064501395377152957L;
+
+	private String code;
+
+	private String name;
+
+	private String level;
+
+	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 String getLevel() {
+		return level;
+	}
+
+	public void setLevel(String level) {
+		this.level = level;
+	}
+
+}

+ 56 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultPaperBean.java

@@ -0,0 +1,56 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 试卷结构
+ *
+ * @author WANGWEI
+ * @date 2018年8月15日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class DefaultPaperBean implements Serializable {
+
+	private static final long serialVersionUID = -5979287118960427883L;
+
+	/**
+	 * 试卷名称
+	 */
+	private String name;
+
+	/**
+	 * 是否全是客观题
+	 */
+	private Boolean fullyObjective;
+
+	/**
+	 * 分组集合
+	 */
+	private List<DefaultQuestionGroupBean> questionGroupList;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Boolean getFullyObjective() {
+		return fullyObjective;
+	}
+
+	public void setFullyObjective(Boolean fullyObjective) {
+		this.fullyObjective = fullyObjective;
+	}
+
+	public List<DefaultQuestionGroupBean> getQuestionGroupList() {
+		return questionGroupList;
+	}
+
+	public void setQuestionGroupList(List<DefaultQuestionGroupBean> questionGroupList) {
+		this.questionGroupList = questionGroupList;
+	}
+
+}

+ 56 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionGroupBean.java

@@ -0,0 +1,56 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 题分组集合
+ *
+ * @author WANGWEI
+ * @date 2018年8月15日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class DefaultQuestionGroupBean implements Serializable {
+
+	private static final long serialVersionUID = 2149814711274942645L;
+
+	/**
+	 * 题组名称
+	 */
+	private String groupName;
+
+	/**
+	 * 题包装器集合<br>
+	 */
+	private List<DefaultQuestionStructureWrapperBean> questionWrapperList;
+
+	/**
+	 * 题组总分
+	 */
+	private Double groupScore;
+
+	public String getGroupName() {
+		return groupName;
+	}
+
+	public void setGroupName(String groupName) {
+		this.groupName = groupName;
+	}
+
+	public List<DefaultQuestionStructureWrapperBean> getQuestionWrapperList() {
+		return questionWrapperList;
+	}
+
+	public void setQuestionWrapperList(List<DefaultQuestionStructureWrapperBean> questionWrapperList) {
+		this.questionWrapperList = questionWrapperList;
+	}
+
+	public Double getGroupScore() {
+		return groupScore;
+	}
+
+	public void setGroupScore(Double groupScore) {
+		this.groupScore = groupScore;
+	}
+
+}

+ 109 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionStructureWrapperBean.java

@@ -0,0 +1,109 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 题结构包装器
+ *
+ * @author WANGWEI
+ * @date 2018年8月15日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class DefaultQuestionStructureWrapperBean implements Serializable {
+
+	private static final long serialVersionUID = 8423916951155451548L;
+
+	/**
+	 * 题ID
+	 */
+	private String questionId;
+
+	/**
+	 * 版本号
+	 */
+	private String version;
+
+	/**
+	 * 题分数
+	 */
+	private Double questionScore;
+
+	/**
+	 * 限制播放次数
+	 */
+	private Integer limitedPlayTimes;
+
+	/**
+	 * 已播放次数
+	 */
+	private Integer playedTimes;
+
+	/**
+	 * 作答限时
+	 */
+	private Long timeLimit;
+
+	/**
+	 * 题单元包装器
+	 */
+	private List<DefaultQuestionUnitWrapperBean> questionUnitWrapperList;
+
+	public String getQuestionId() {
+		return questionId;
+	}
+
+	public void setQuestionId(String questionId) {
+		this.questionId = questionId;
+	}
+
+	public String getVersion() {
+		return version;
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+	public Double getQuestionScore() {
+		return questionScore;
+	}
+
+	public void setQuestionScore(Double questionScore) {
+		this.questionScore = questionScore;
+	}
+
+	public Integer getLimitedPlayTimes() {
+		return limitedPlayTimes;
+	}
+
+	public void setLimitedPlayTimes(Integer limitedPlayTimes) {
+		this.limitedPlayTimes = limitedPlayTimes;
+	}
+
+	public Integer getPlayedTimes() {
+		return playedTimes;
+	}
+
+	public void setPlayedTimes(Integer playedTimes) {
+		this.playedTimes = playedTimes;
+	}
+
+	public Long getTimeLimit() {
+		return timeLimit;
+	}
+
+	public void setTimeLimit(Long timeLimit) {
+		this.timeLimit = timeLimit;
+	}
+
+	public List<DefaultQuestionUnitWrapperBean> getQuestionUnitWrapperList() {
+		return questionUnitWrapperList;
+	}
+
+	public void setQuestionUnitWrapperList(
+			List<DefaultQuestionUnitWrapperBean> questionUnitWrapperList) {
+		this.questionUnitWrapperList = questionUnitWrapperList;
+	}
+
+}

+ 67 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/DefaultQuestionUnitWrapperBean.java

@@ -0,0 +1,67 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+
+/**
+ * 题单元包装器
+ *
+ * @author WANGWEI
+ * @date 2018年8月16日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class DefaultQuestionUnitWrapperBean implements Serializable {
+
+	private static final long serialVersionUID = 7584275153456817959L;
+
+	/**
+	 * 选项排序值
+	 */
+	private Integer[] optionPermutation;
+
+	/**
+	 * 题分数
+	 */
+	private Double questionScore;
+
+	/**
+	 * 题型
+	 */
+	private String questionType;
+
+	/**
+	 * 作答类型
+	 */
+	private String answerType;
+
+	public Integer[] getOptionPermutation() {
+		return optionPermutation;
+	}
+
+	public void setOptionPermutation(Integer[] optionPermutation) {
+		this.optionPermutation = optionPermutation;
+	}
+
+	public Double getQuestionScore() {
+		return questionScore;
+	}
+
+	public void setQuestionScore(Double questionScore) {
+		this.questionScore = questionScore;
+	}
+
+	public String getQuestionType() {
+		return questionType;
+	}
+
+	public void setQuestionType(String questionType) {
+		this.questionType = questionType;
+	}
+
+	public String getAnswerType() {
+		return answerType;
+	}
+
+	public void setAnswerType(String answerType) {
+		this.answerType = answerType;
+	}
+}

+ 206 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/ExamStudent4BatchBean.java

@@ -0,0 +1,206 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年11月14日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@ApiModel(value = "examStudent4BatchBean", description = "考生信息(批量接入)")
+public class ExamStudent4BatchBean implements JsonSerializable {
+
+	private static final long serialVersionUID = 4259890948495983284L;
+
+	@ApiModelProperty(value = "学生姓名", example = "陈圆圆", required = true)
+	private String studentName;
+
+	@ApiModelProperty(value = "学生学号", example = "2018001001", required = true)
+	private String studentCode;
+
+	@ApiModelProperty(value = "学生身份证号", example = "XXXXXXXXXXXXXXXXXX", required = true)
+	private String identityNumber;
+
+	@ApiModelProperty(value = "考试课程名称", example = "大学英语", required = true)
+	private String courseName;
+
+	@ApiModelProperty(value = "考试课程code", example = "K2", required = true)
+	private String courseCode;
+
+	@ApiModelProperty(value = "考试课程level.  ZSB:专升本;GQZ:高起专;GQB:高起本;ALL:不限", example = "ALL", required = true)
+	private String courseLevel;
+
+	@ApiModelProperty(value = "试卷类型,大写字母A-Z", example = "X", required = true)
+	private String paperType;
+
+	@ApiModelProperty(value = "信息采集人", example = "赵飞燕", required = false)
+	private String infoCollector;
+
+	@ApiModelProperty(value = "专业名称", example = "计算机", required = false)
+	private String specialtyName;
+
+	@ApiModelProperty(value = "考点", example = "武汉", required = false)
+	private String examSite;
+
+	@ApiModelProperty(value = "年级", example = "2018", required = false)
+	private String grade;
+
+	@ApiModelProperty(value = "备注", example = "XX", required = false)
+	private String remark;
+
+	@ApiModelProperty(value = "扩展属性1", example = "XX", required = false)
+	private String ext1;
+
+	@ApiModelProperty(value = "扩展属性2", example = "XX", required = false)
+	private String ext2;
+
+	@ApiModelProperty(value = "扩展属性3", example = "XX", required = false)
+	private String ext3;
+
+	@ApiModelProperty(value = "扩展属性4", example = "XX", required = false)
+	private String ext4;
+
+	@ApiModelProperty(value = "扩展属性5", example = "XX", required = false)
+	private String ext5;
+
+	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 getExamSite() {
+		return examSite;
+	}
+
+	public void setExamSite(String examSite) {
+		this.examSite = examSite;
+	}
+
+	public String getGrade() {
+		return grade;
+	}
+
+	public void setGrade(String grade) {
+		this.grade = grade;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getExt1() {
+		return ext1;
+	}
+
+	public void setExt1(String ext1) {
+		this.ext1 = ext1;
+	}
+
+	public String getExt2() {
+		return ext2;
+	}
+
+	public void setExt2(String ext2) {
+		this.ext2 = ext2;
+	}
+
+	public String getExt3() {
+		return ext3;
+	}
+
+	public void setExt3(String ext3) {
+		this.ext3 = ext3;
+	}
+
+	public String getExt4() {
+		return ext4;
+	}
+
+	public void setExt4(String ext4) {
+		this.ext4 = ext4;
+	}
+
+	public String getExt5() {
+		return ext5;
+	}
+
+	public void setExt5(String ext5) {
+		this.ext5 = ext5;
+	}
+
+}

+ 136 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/ExamStudentStatus4BatchBean.java

@@ -0,0 +1,136 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+
+/**
+ * 考生接入状态
+ *
+ * @author WANGWEI
+ * @date 2019年1月8日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class ExamStudentStatus4BatchBean implements Serializable {
+
+	private static final long serialVersionUID = -6794614626330803366L;
+
+	private String code;
+
+	private String desc;
+
+	private Long examId;
+
+	private String examName;
+
+	private Long id;
+
+	private Long studentId;
+
+	private String name;
+
+	private String studentCode;
+
+	private String identityNumber;
+
+	private String courseCode;
+
+	private String courseName;
+
+	private String courseLevel;
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+	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 Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	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 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 getCourseLevel() {
+		return courseLevel;
+	}
+
+	public void setCourseLevel(String courseLevel) {
+		this.courseLevel = courseLevel;
+	}
+
+}

+ 63 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterBlockBean.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.util.Map;
+
+/**
+ * @Description 从题库拷过来的代码,用于处理导出阅卷数据 ,见ExamRecordQuestionsCloudServiceProvider
+ * @Author lideyin
+ * @Date 2020/3/2 18:35
+ * @Version 1.0
+ */
+public class OuterBlockBean {
+    /**
+     * text:文字
+     * image:图片
+     * audio:音频
+     * video:视频
+     */
+    private String type;
+    /**
+     * 资源相对路径
+     */
+    private String value;
+    /**
+     * 播放次数
+     */
+    private Integer playTime;
+
+    private Map<String, Object> param;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public Map<String, Object> getParam() {
+        return param;
+    }
+
+    public void setParam(Map<String, Object> param) {
+        this.param = param;
+    }
+
+    public Integer getPlayTime() {
+        return playTime;
+    }
+
+    public void setPlayTime(Integer playTime) {
+        this.playTime = playTime;
+    }
+
+}
+

+ 128 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamRecordBean.java

@@ -0,0 +1,128 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+/**
+ * @Description 主观题考试记录实体
+ * @Author lideyin
+ * @Date 2020/3/30 16:06
+ * @Version 1.0
+ */
+@ApiModel(value = "OuterExamRecordBean", description = "主观题考试记录")
+public class OuterExamRecordBean implements JsonSerializable{
+	private static final long serialVersionUID = 2318585091725308489L;
+
+	@ApiModelProperty(value = "考试id", example = "1", required = true)
+	private Long examId;
+
+	@ApiModelProperty(value = "考生学号(对应网考的身份证号)", example = "111", required = true)
+	private String studentCode;
+	
+	@ApiModelProperty(value = "考生姓名", example = "XX", required = true)
+	private String name;
+	
+	@ApiModelProperty(value = "学院/年级", example = "XX", required = false)
+	private String college;
+
+	@ApiModelProperty(value = "班级", example = "", required = false)
+	private String className;
+
+	@ApiModelProperty(value = "教师", example = "", required = false)
+	private String teacher;
+
+	@ApiModelProperty(value = "科目代码", example = "", required = true)
+	private String subjectCode;
+
+	@ApiModelProperty(value = "科目名称", example = "", required = true)
+	private String subjectName;
+
+	@ApiModelProperty(value = "考生唯一标识(对应网考的考试记录id)", example = "", required = true)
+	private String examNumber;
+
+	@ApiModelProperty(value = "主观题作答集合", example = "[{}]", required = false)
+	private List<OuterSubjectiveQuestionRecordBean> subjectives;
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getCollege() {
+		return college;
+	}
+
+	public void setCollege(String college) {
+		this.college = college;
+	}
+
+	public String getClassName() {
+		return className;
+	}
+
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+	public String getTeacher() {
+		return teacher;
+	}
+
+	public void setTeacher(String teacher) {
+		this.teacher = teacher;
+	}
+
+	public String getSubjectCode() {
+		return subjectCode;
+	}
+
+	public void setSubjectCode(String subjectCode) {
+		this.subjectCode = subjectCode;
+	}
+
+	public String getSubjectName() {
+		return subjectName;
+	}
+
+	public void setSubjectName(String subjectName) {
+		this.subjectName = subjectName;
+	}
+
+	public String getExamNumber() {
+		return examNumber;
+	}
+
+	public void setExamNumber(String examNumber) {
+		this.examNumber = examNumber;
+	}
+
+	public List<OuterSubjectiveQuestionRecordBean> getSubjectives() {
+		return subjectives;
+	}
+
+	public void setSubjectives(List<OuterSubjectiveQuestionRecordBean> subjectives) {
+		this.subjectives = subjectives;
+	}
+}

+ 173 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudent4ResetReqBean.java

@@ -0,0 +1,173 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2019年8月20日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@ApiModel(value = "outerExamStudent4ResetReqBean", description = "考生信息(重置)")
+public class OuterExamStudent4ResetReqBean implements JsonSerializable {
+
+	private static final long serialVersionUID = 2079003980099252759L;
+
+	@ApiModelProperty(value = "考试课程名称", example = "大学英语", required = true)
+	private String courseName;
+
+	@ApiModelProperty(value = "考试课程code", example = "K2", required = true)
+	private String courseCode;
+
+	@ApiModelProperty(value = "考试课程level.  ZSB:专升本;GQZ:高起专;GQB:高起本;ALL:不限", example = "ALL", required = true)
+	private String courseLevel;
+
+	@ApiModelProperty(value = "考试课程level.  ZSB:专升本;GQZ:高起专;GQB:高起本;ALL:不限", example = "ALL", required = true)
+	private String paperType;
+
+	@ApiModelProperty(value = "信息采集人", example = "赵飞燕", required = false)
+	private String infoCollector;
+
+	@ApiModelProperty(value = "考点", example = "武汉", required = false)
+	private String examSite;
+
+	@ApiModelProperty(value = "专业名称", example = "计算机", required = false)
+	private String specialtyName;
+
+	@ApiModelProperty(value = "年级", example = "2018", required = false)
+	private String grade;
+
+	@ApiModelProperty(value = "备注", example = "XX", required = false)
+	private String remark;
+
+	@ApiModelProperty(value = "扩展属性1", example = "XX", required = false)
+	private String ext1;
+
+	@ApiModelProperty(value = "扩展属性2", example = "XX", required = false)
+	private String ext2;
+
+	@ApiModelProperty(value = "扩展属性3", example = "XX", required = false)
+	private String ext3;
+
+	@ApiModelProperty(value = "扩展属性4", example = "XX", required = false)
+	private String ext4;
+
+	@ApiModelProperty(value = "扩展属性5", example = "XX", required = false)
+	private String ext5;
+
+	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 getExamSite() {
+		return examSite;
+	}
+
+	public void setExamSite(String examSite) {
+		this.examSite = examSite;
+	}
+
+	public String getSpecialtyName() {
+		return specialtyName;
+	}
+
+	public void setSpecialtyName(String specialtyName) {
+		this.specialtyName = specialtyName;
+	}
+
+	public String getGrade() {
+		return grade;
+	}
+
+	public void setGrade(String grade) {
+		this.grade = grade;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getExt1() {
+		return ext1;
+	}
+
+	public void setExt1(String ext1) {
+		this.ext1 = ext1;
+	}
+
+	public String getExt2() {
+		return ext2;
+	}
+
+	public void setExt2(String ext2) {
+		this.ext2 = ext2;
+	}
+
+	public String getExt3() {
+		return ext3;
+	}
+
+	public void setExt3(String ext3) {
+		this.ext3 = ext3;
+	}
+
+	public String getExt4() {
+		return ext4;
+	}
+
+	public void setExt4(String ext4) {
+		this.ext4 = ext4;
+	}
+
+	public String getExt5() {
+		return ext5;
+	}
+
+	public void setExt5(String ext5) {
+		this.ext5 = ext5;
+	}
+
+}

+ 285 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudent4ResetRespBean.java

@@ -0,0 +1,285 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2019年8月20日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class OuterExamStudent4ResetRespBean implements JsonSerializable {
+	private static final long serialVersionUID = 2079003980099252759L;
+
+	private Long id;
+
+	/**
+	 * 学生ID
+	 */
+	private Long studentId;
+
+	/**
+	 * 机构ID
+	 */
+	private Long orgId;
+
+	/**
+	 * 机构名称
+	 */
+	private String orgName;
+
+	/**
+	 * 机构编码
+	 */
+	private String orgCode;
+
+	/**
+	 * 顶级机构ID
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 考试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 specialtyName;
+
+	/**
+	 * 课程ID
+	 */
+	private Long courseId;
+
+	/**
+	 * 年级
+	 */
+	private String grade;
+
+	/**
+	 * 备注
+	 */
+	private String remark;
+
+	/**
+	 * 考点
+	 */
+	private String examSite;
+
+	/**
+	 * 信息采集人
+	 */
+	private String infoCollector;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long 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 Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	public String getOrgCode() {
+		return orgCode;
+	}
+
+	public void setOrgCode(String orgCode) {
+		this.orgCode = orgCode;
+	}
+
+	public String getSpecialtyName() {
+		return specialtyName;
+	}
+
+	public void setSpecialtyName(String specialtyName) {
+		this.specialtyName = specialtyName;
+	}
+
+	public Long getCourseId() {
+		return courseId;
+	}
+
+	public void setCourseId(Long courseId) {
+		this.courseId = courseId;
+	}
+
+	public String getGrade() {
+		return grade;
+	}
+
+	public void setGrade(String grade) {
+		this.grade = grade;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getExamSite() {
+		return examSite;
+	}
+
+	public void setExamSite(String examSite) {
+		this.examSite = examSite;
+	}
+
+	public String getInfoCollector() {
+		return infoCollector;
+	}
+
+	public void setInfoCollector(String infoCollector) {
+		this.infoCollector = infoCollector;
+	}
+
+}

+ 160 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterExamStudentBean.java

@@ -0,0 +1,160 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年11月14日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@ApiModel(value = "examStudentBean", description = "考生信息")
+public class OuterExamStudentBean implements JsonSerializable {
+	private static final long serialVersionUID = 2079003980099252759L;
+
+	/**
+	 * 顶级机构ID
+	 */
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+
+	/**
+	 * 考试ID
+	 */
+	@ApiModelProperty(value = "考试ID", example = "100", required = true)
+	private Long examId;
+
+	/**
+	 * 考试名称
+	 */
+	@ApiModelProperty(value = "考试名称(废弃属性,实际上为考试编码)", example = "2018年秋季入学考试", required = true)
+	@Deprecated
+	private String examName;
+
+	/**
+	 * 学生姓名
+	 */
+	@ApiModelProperty(value = "学生姓名", example = "陈圆圆", required = true)
+	private String studentName;
+
+	/**
+	 * 学生学号
+	 */
+	@ApiModelProperty(value = "学生学号", example = "2018001001", required = true)
+	private String studentCode;
+
+	/**
+	 * 学生身份证号
+	 */
+	@ApiModelProperty(value = "学生身份证号", example = "XXXXXXXXXXXXXXXXXX", required = true)
+	private String identityNumber;
+
+	/**
+	 * 考试课程名称
+	 */
+	@ApiModelProperty(value = "考试课程名称", example = "大学英语", required = true)
+	private String courseName;
+
+	/**
+	 * 考试课程code
+	 */
+	@ApiModelProperty(value = "考试课程code", example = "K2", required = true)
+	private String courseCode;
+
+	/**
+	 * 考试课程level
+	 */
+	@ApiModelProperty(value = "考试课程level.  ZSB:专升本;GQZ:高起专;GQB:高起本;ALL:不限", example = "ALL", required = true)
+
+	private String courseLevel;
+
+	/**
+	 * 试卷类型
+	 */
+	@ApiModelProperty(value = "试卷类型,大写字母A-Z", example = "X", required = true)
+	private String paperType;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = 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;
+	}
+
+}

+ 60 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterGetCapturePhotoBean.java

@@ -0,0 +1,60 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 下午1:50:02
+ * @company 	QMTH
+ * @description OuterGetCapturePhotoBean.java
+ */
+@ApiModel(value = "capturePhotoBean", description = "抓拍照片信息")
+public class OuterGetCapturePhotoBean implements JsonSerializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 2867275034372864464L;
+	
+	@ApiModelProperty(value = "文件URL", example = "https://ecs-XXX.qmth.com.cn/capture_photo/XXX/XXX.jpg", required = true)
+    private String fileUrl;
+    
+	@ApiModelProperty(value = "人脸比对是否通过", example = "true", required = true)
+    private Boolean isPass;
+    
+	@ApiModelProperty(value = "人脸比对是否有陌生人脸", example = "false", required = true)
+    private Boolean isStranger;
+    
+	@ApiModelProperty(value = "人脸真实性是否通过", example = "true", required = true)
+    private Boolean isLivenessPass;
+	
+	public String getFileUrl() {
+		return fileUrl;
+	}
+	public void setFileUrl(String fileUrl) {
+		this.fileUrl = fileUrl;
+	}
+	public Boolean getIsPass() {
+		return isPass;
+	}
+	public void setIsPass(Boolean isPass) {
+		this.isPass = isPass;
+	}
+	public Boolean getIsStranger() {
+		return isStranger;
+	}
+	public void setIsStranger(Boolean isStranger) {
+		this.isStranger = isStranger;
+	}
+	public Boolean getIsLivenessPass() {
+		return isLivenessPass;
+	}
+	public void setIsLivenessPass(Boolean isLivenessPass) {
+		this.isLivenessPass = isLivenessPass;
+	}
+	
+}

+ 135 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterScoreDataBean.java

@@ -0,0 +1,135 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月27日 下午5:41:09
+ * @company 	QMTH
+ * @description OuterGetScoreDataBean.java
+ */
+@ApiModel(value = "scoreDataBean", description = "考生成绩数据")
+public class OuterScoreDataBean implements JsonSerializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7476060044159007486L;
+
+	@ApiModelProperty(value = "考试记录ID", example = "1", required = true)
+	private Long examRecordDataId;
+	
+	@ApiModelProperty(value = "学生姓名", example = "XX", required = true)
+	private String studentName;
+	
+	@ApiModelProperty(value = "学生学号", example = "X000001", required = true)
+	private String studentCode;
+	
+	@ApiModelProperty(value = "学生身份证号码", example = "10XXXX", required = true)
+	private String identityNumber;
+	
+	@ApiModelProperty(value = "课程名称", example = "语文001", required = true)
+	private String courseName;
+	
+	@ApiModelProperty(value = "课程code", example = "A000001", required = true)
+	private String courseCode;
+	
+	@ApiModelProperty(value = "开考时间", example = "2018-11-16 10:00:00", required = true)
+	private Date startTime;
+	
+	@ApiModelProperty(value = "交卷时间", example = "2018-11-16 10:30:00", required = true)
+	private Date endTime;
+	
+	@ApiModelProperty(value = "得分", example = "100.0", required = true)
+	private Double totalScore;
+	
+	@ApiModelProperty(value = "是否异常数据", example = "false", required = true)
+	private Boolean isWarn;
+	
+	@ApiModelProperty(value = "是否被审核", example = "false", required = true)
+	private Boolean isAudit;
+	
+	@ApiModelProperty(value = "是否违纪", example = "false", required = true)
+	private Boolean isIllegality;
+	
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+	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 Date getStartTime() {
+		return startTime;
+	}
+	public void setStartTime(Date startTime) {
+		this.startTime = startTime;
+	}
+	public Date getEndTime() {
+		return endTime;
+	}
+	public void setEndTime(Date endTime) {
+		this.endTime = endTime;
+	}
+	public Double getTotalScore() {
+		return totalScore;
+	}
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+	public Boolean getIsWarn() {
+		return isWarn;
+	}
+	public void setIsWarn(Boolean isWarn) {
+		this.isWarn = isWarn;
+	}
+	public Boolean getIsAudit() {
+		return isAudit;
+	}
+	public void setIsAudit(Boolean isAudit) {
+		this.isAudit = isAudit;
+	}
+	public Boolean getIsIllegality() {
+		return isIllegality;
+	}
+	public void setIsIllegality(Boolean isIllegality) {
+		this.isIllegality = isIllegality;
+	}
+	
+	
+}

+ 25 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSectionBean.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.util.List;
+
+/**
+ * @Description 节点
+ * @Author lideyin
+ * @Date 2020/3/30 17:00
+ * @Version 1.0
+ */
+public class OuterSectionBean {
+
+    private List<OuterBlockBean> blocks;
+
+    public List<OuterBlockBean> getBlocks() {
+        return blocks;
+    }
+
+    public void setBlocks(List<OuterBlockBean> blocks) {
+        this.blocks = blocks;
+    }
+
+
+}
+

+ 25 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSectionCollectionBean.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.util.List;
+
+/**
+ * @Description 节点集合
+ * @Author lideyin
+ * @Date 2020/3/30 16:59
+ * @Version 1.0
+ */
+public class OuterSectionCollectionBean {
+
+    private List<OuterSectionBean> sections;
+
+    public List<OuterSectionBean> getSections() {
+        return sections;
+    }
+
+    public void setSections(List<OuterSectionBean> sections) {
+        this.sections = sections;
+    }
+
+
+}
+

+ 63 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectivePaperStructBean.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+/**
+ * @Description 主观题试卷结构实体
+ * @Author lideyin
+ * @Date 2020/3/30 15:37
+ * @Version 1.0
+ */
+@ApiModel(value = "OuterSubjectivePaperStructBean", description = "考生成绩数据")
+public class OuterSubjectivePaperStructBean implements JsonSerializable{
+
+	private static final long serialVersionUID = -861207406409903426L;
+
+	@ApiModelProperty(value = "考试ID", example = "1", required = true)
+	private Long examId;
+
+	@ApiModelProperty(value = "科目代码", example = "XX", required = true)
+	private String subjectCode;
+
+	@ApiModelProperty(value = "科目名称", example = "XX", required = true)
+	private String subjectName;
+
+	@ApiModelProperty(value = "主观题集合", example = "[]", required = true)
+	private List<OuterSubjectiveQuestionBean> questions;
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getSubjectCode() {
+		return subjectCode;
+	}
+
+	public void setSubjectCode(String subjectCode) {
+		this.subjectCode = subjectCode;
+	}
+
+	public String getSubjectName() {
+		return subjectName;
+	}
+
+	public void setSubjectName(String subjectName) {
+		this.subjectName = subjectName;
+	}
+
+	public List<OuterSubjectiveQuestionBean> getQuestions() {
+		return questions;
+	}
+
+	public void setQuestions(List<OuterSubjectiveQuestionBean> questions) {
+		this.questions = questions;
+	}
+}

+ 61 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectiveQuestionBean.java

@@ -0,0 +1,61 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 主观题实体
+ * @Author lideyin
+ * @Date 2020/3/30 16:05
+ * @Version 1.0
+ */
+@ApiModel(value = "OuterSubjectiveQuestionBean", description = "考生成绩数据")
+public class OuterSubjectiveQuestionBean implements JsonSerializable{
+
+	private static final long serialVersionUID = -861207406409903426L;
+
+	@ApiModelProperty(value = "大题号", example = "1", required = true)
+	private Integer mainNumber;
+
+	@ApiModelProperty(value = "大题名称", example = "XX", required = true)
+	private String mainTitle;
+
+	@ApiModelProperty(value = "小题号", example = "XX", required = true)
+	private Integer subNumber;
+
+	@ApiModelProperty(value = "小题分", example = "1", required = true)
+	private Double totalScore;
+
+	public Integer getMainNumber() {
+		return mainNumber;
+	}
+
+	public void setMainNumber(Integer mainNumber) {
+		this.mainNumber = mainNumber;
+	}
+
+	public String getMainTitle() {
+		return mainTitle;
+	}
+
+	public void setMainTitle(String mainTitle) {
+		this.mainTitle = mainTitle;
+	}
+
+	public Integer getSubNumber() {
+		return subNumber;
+	}
+
+	public void setSubNumber(Integer subNumber) {
+		this.subNumber = subNumber;
+	}
+
+	public Double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+}

+ 93 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/OuterSubjectiveQuestionRecordBean.java

@@ -0,0 +1,93 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 主观题作答记录实体
+ * @Author lideyin
+ * @Date 2020/3/30 16:43
+ * @Version 1.0
+ */
+@ApiModel(value = "OuterSubjectiveQuestionRecordBean", description = "主观题作答记录实体")
+public class OuterSubjectiveQuestionRecordBean implements JsonSerializable{
+	private static final long serialVersionUID = 5992269834285704045L;
+
+	@ApiModelProperty(value = "大题号", example = "1", required = true)
+	private Integer mainNumber;
+
+	@ApiModelProperty(value = "小题号", example = "XX", required = true)
+	private Integer subNumber;
+
+	@ApiModelProperty(value = "试题id,String,一个套题共用一个questionId", example = "1", required = true)
+	private String questionId;
+
+	@ApiModelProperty(value = "标准答案", example = "{}", required = false)
+	private OuterSectionCollectionBean answer;
+
+	@ApiModelProperty(value = "学生答案", example = "{}", required = false)
+	private OuterSectionCollectionBean studentAnswer;
+
+	@ApiModelProperty(value = "题干", example = "{}", required = true)
+	private OuterSectionCollectionBean body;
+
+	@ApiModelProperty(value = "父题干", example = "{}", required = false)
+	private OuterSectionCollectionBean parentBody;
+
+	public Integer getMainNumber() {
+		return mainNumber;
+	}
+
+	public void setMainNumber(Integer mainNumber) {
+		this.mainNumber = mainNumber;
+	}
+
+	public Integer getSubNumber() {
+		return subNumber;
+	}
+
+	public void setSubNumber(Integer subNumber) {
+		this.subNumber = subNumber;
+	}
+
+	public String getQuestionId() {
+		return questionId;
+	}
+
+	public void setQuestionId(String questionId) {
+		this.questionId = questionId;
+	}
+
+	public OuterSectionCollectionBean getAnswer() {
+		return answer;
+	}
+
+	public void setAnswer(OuterSectionCollectionBean answer) {
+		this.answer = answer;
+	}
+
+	public OuterSectionCollectionBean getStudentAnswer() {
+		return studentAnswer;
+	}
+
+	public void setStudentAnswer(OuterSectionCollectionBean studentAnswer) {
+		this.studentAnswer = studentAnswer;
+	}
+
+	public OuterSectionCollectionBean getBody() {
+		return body;
+	}
+
+	public void setBody(OuterSectionCollectionBean body) {
+		this.body = body;
+	}
+
+	public OuterSectionCollectionBean getParentBody() {
+		return parentBody;
+	}
+
+	public void setParentBody(OuterSectionCollectionBean parentBody) {
+		this.parentBody = parentBody;
+	}
+}

+ 183 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/Student4BatchBean.java

@@ -0,0 +1,183 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * @author chenken
+ * @date 2019年1月23日 上午9:59:27
+ * @company QMTH
+ * @description Student4BatchBean.java
+ */
+public class Student4BatchBean implements Serializable {
+
+	private static final long serialVersionUID = -4695731347447671839L;
+
+	@ApiModelProperty(value = "是否可用", example = "true", required = false)
+	private Boolean enable;
+
+	/**
+	 * 学生姓名
+	 */
+	@ApiModelProperty(value = "学生姓名", example = "赵飞燕", required = true)
+	private String name;
+
+	/**
+	 * 顶级机构ID
+	 */
+	@ApiModelProperty(value = "顶级机构ID", example = "0", required = true)
+	private Long rootOrgId;
+
+	/**
+	 * 机构ID
+	 */
+	@ApiModelProperty(value = "学习中心ID", example = "1", required = false)
+	private Long orgId;
+
+	/**
+	 * 学习中心编码
+	 */
+	@ApiModelProperty(value = "学习中心编码", example = "LC111111", required = true)
+	private String orgCode;
+
+	/**
+	 * 学习中心名称
+	 */
+	@ApiModelProperty(value = "学习中心名称", example = "LC111111", required = true)
+	private String orgName;
+
+	/**
+	 * 学生code
+	 */
+	@ApiModelProperty(value = "学号", example = "1111", required = true)
+	private String studentCode;
+
+	/**
+	 * 身份证号码
+	 */
+	@ApiModelProperty(value = "身份证号", example = "XXXXXXXXXXXXXXXXXX", required = true)
+	private String identityNumber;
+
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注", example = "xx", required = false)
+	private String remark;
+
+	/**
+	 * 图片地址
+	 */
+	@ApiModelProperty(value = "图片URL", example = "http://xxxx.xx/photo.jpg", required = false)
+	private String photoUrl;
+
+	/**
+	 * 手机号码
+	 */
+	@ApiModelProperty(value = "手机号码", example = "XXXXXXXXXXX", required = true)
+	private String phoneNumber;
+
+	/**
+	 * 操作者
+	 */
+	@ApiModelProperty(value = "操作者", example = "XXX", required = true)
+	private String operator;
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	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 getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	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 getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getPhotoUrl() {
+		return photoUrl;
+	}
+
+	public void setPhotoUrl(String photoUrl) {
+		this.photoUrl = photoUrl;
+	}
+
+	public String getPhoneNumber() {
+		return phoneNumber;
+	}
+
+	public void setPhoneNumber(String phoneNumber) {
+		this.phoneNumber = phoneNumber;
+	}
+
+	public String getOperator() {
+		return operator;
+	}
+
+	public void setOperator(String operator) {
+		this.operator = operator;
+	}
+
+}

+ 52 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/bean/StudentStatus4BatchBean.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.examcloud.exchange.outer.api.bean;
+
+import java.io.Serializable;
+
+public class StudentStatus4BatchBean implements Serializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -2088122629950881541L;
+
+	private Long studentId;
+	
+	private String name;
+	
+	private String studentCode;
+
+	private String identityNumber;
+
+	public Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	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;
+	}
+	
+}

+ 76 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterBatchSaveExamStudentReq.java

@@ -0,0 +1,76 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.ExamStudent4BatchBean;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2019年1月8日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class OuterBatchSaveExamStudentReq extends EnterpriseRequest {
+
+	private static final long serialVersionUID = 9086274932441194883L;
+
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+
+	@ApiModelProperty(value = "考试ID", example = "100", required = false)
+	private Long examId;
+
+	@ApiModelProperty(value = "考试名称(废弃属性,实际上作为考试编码使用)", example = "2018年秋季入学考试", required = false)
+	@Deprecated
+	private String examName;
+
+	@ApiModelProperty(value = "考试编码", example = "2018年秋季入学考试", required = true)
+	private String examCode;
+
+	@ApiModelProperty(value = "考生集合", example = "", required = true)
+	List<ExamStudent4BatchBean> examStudentList;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = 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 getExamCode() {
+		return examCode;
+	}
+
+	public void setExamCode(String examCode) {
+		this.examCode = examCode;
+	}
+
+	public List<ExamStudent4BatchBean> getExamStudentList() {
+		return examStudentList;
+	}
+
+	public void setExamStudentList(List<ExamStudent4BatchBean> examStudentList) {
+		this.examStudentList = examStudentList;
+	}
+
+}

+ 35 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterBatchSaveStudentReq.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.Student4BatchBean;
+
+public class OuterBatchSaveStudentReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -5950300030279373369L;
+	
+	private Long rootOrgId;
+	
+	private List<Student4BatchBean> studentList;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public List<Student4BatchBean> getStudentList() {
+		return studentList;
+	}
+
+	public void setStudentList(List<Student4BatchBean> studentList) {
+		this.studentList = studentList;
+	}
+
+}

+ 43 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterDeleteScoreQueueTopReq.java

@@ -0,0 +1,43 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 下午3:12:02
+ * @company 	QMTH
+ * @description 删除队列请求
+ */
+public class OuterDeleteScoreQueueTopReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 6340573640799250911L;
+	
+	@ApiModelProperty(value = "顶级机构ID", example = "1", required = true)
+	private Long rootOrgId;
+	
+	@ApiModelProperty(value = "队列ID", example = "1", required = true)
+	private Long queueId;
+
+	public Long getQueueId() {
+		return queueId;
+	}
+
+	public void setQueueId(Long queueId) {
+		this.queueId = queueId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+	
+}

+ 32 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetCourseListReq.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OuterGetCourseListReq extends EnterpriseRequest {
+
+	private static final long serialVersionUID = -8374755306658040184L;
+
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+
+	@ApiModelProperty(value = "课程组", example = "计算机本科", required = true)
+	private String courseGroupName;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public String getCourseGroupName() {
+		return courseGroupName;
+	}
+
+	public void setCourseGroupName(String courseGroupName) {
+		this.courseGroupName = courseGroupName;
+	}
+
+}

+ 35 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetExamRecordAuditInfoReq.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OuterGetExamRecordAuditInfoReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 492449120567501650L;
+	
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+	
+	@ApiModelProperty(value = "考试记录ID", example = "1", required = true)
+	private Long examRecordDataId;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+	
+}

+ 62 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetExamReq.java

@@ -0,0 +1,62 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年11月16日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class OuterGetExamReq extends EnterpriseRequest {
+
+	private static final long serialVersionUID = -2827676106721670081L;
+
+	@ApiModelProperty(value = "考试ID", example = "128", required = true)
+	private Long id;
+
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+
+	@ApiModelProperty(value = "考试名称(废弃属性,实际上作为考试编码使用)", example = "2018年6月期末考试", required = false)
+	@Deprecated
+	private String name;
+
+	@ApiModelProperty(value = "考试编码(不传时取考试名称)", example = "2018年6月期末考试", required = true)
+	private String code;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+}

+ 59 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetPaperStructReq.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 获取试卷结构
+ * @Author lideyin
+ * @Date 2020/5/25 15:56
+ * @Version 1.0
+ */
+public class OuterGetPaperStructReq extends EnterpriseRequest {
+
+    private static final long serialVersionUID = -8374755306658040184L;
+
+    @ApiModelProperty(value = "考试id", example = "123", required = true)
+    private Long examId;
+
+    @ApiModelProperty(value = "课程id", example = "123", required = true)
+    private Long courseId;
+
+    @ApiModelProperty(value = "卷型", example = "123", required = true)
+    private String paperType;
+
+    @ApiModelProperty(value = "原始试卷id", example = "123", required = true)
+    private String basePaperId;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Long courseId) {
+        this.courseId = courseId;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public String getBasePaperId() {
+        return basePaperId;
+    }
+
+    public void setBasePaperId(String basePaperId) {
+        this.basePaperId = basePaperId;
+    }
+}

+ 26 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetQuestionAnswerReq.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 获取作答结果请求
+ * @Author lideyin
+ * @Date 2020/4/25 18:58
+ * @Version 1.0
+ */
+public class OuterGetQuestionAnswerReq extends EnterpriseRequest {
+
+    private static final long serialVersionUID = -8374755306658040184L;
+
+    @ApiModelProperty(value = "题目id", example = "123", required = true)
+    private String questionId;
+
+    public String getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(String questionId) {
+        this.questionId = questionId;
+    }
+}

+ 42 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetScoreDataReq.java

@@ -0,0 +1,42 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 上午11:22:27
+ * @company 	QMTH
+ * @description OuterGetScoreInfoReq.java
+ */
+public class OuterGetScoreDataReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -7514465576897689892L;
+
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+	
+	@ApiModelProperty(value = "考试记录ID", example = "1", required = true)
+	private Long examRecordDataId;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+
+}

+ 24 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetScoreQueueTopReq.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OuterGetScoreQueueTopReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -8881081085095233235L;
+	
+	@ApiModelProperty(value = "机构ID", example = "1", required = true)
+	private Long rootOrgId;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+	
+}

+ 26 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetSubjectivePaperStructReq.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 获取主观题试卷结构请求类
+ * @Author lideyin
+ * @Date 2020/3/30 15:24
+ * @Version 1.0
+ */
+public class OuterGetSubjectivePaperStructReq extends EnterpriseRequest {
+
+	private static final long serialVersionUID = 8892205616387684966L;
+
+	@ApiModelProperty(value = "考试ID", example = "128", required = true)
+	private Long examId;
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+}

+ 59 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterGetSubjectiveQuestionReq.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description 获取主观题考试作答请求类
+ * @Author lideyin
+ * @Date 2020/3/30 15:25
+ * @Version 1.0
+ */
+public class OuterGetSubjectiveQuestionReq extends EnterpriseRequest {
+
+    private static final long serialVersionUID = 8303860788475413215L;
+
+    @ApiModelProperty(value = "考试ID", example = "128", required = true)
+    private Long examId;
+
+    @ApiModelProperty(value = "科目代码", example = "128", required = true)
+    private String subjectCode;
+
+    @ApiModelProperty(value = "考生id,Long,第一次调用传0,下次调用,用返回的nextId", example = "0", required = true)
+    private Long startId;
+
+    @ApiModelProperty(value = "考试记录集合大小,最大不得超过500", example = "200", required = true)
+    private Integer size;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Long getStartId() {
+        return startId;
+    }
+
+    public void setStartId(Long startId) {
+        this.startId = startId;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+}

+ 42 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterQueryCapturePhotoReq.java

@@ -0,0 +1,42 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 
+ * @author  	chenken
+ * @date    	2018年11月16日 上午11:35:15
+ * @company 	QMTH
+ * @description OuterGetCapturePhotoReq.java
+ */
+public class OuterQueryCapturePhotoReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -3913911619514532603L;
+	
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+	
+	@ApiModelProperty(value = "考试记录ID", example = "1", required = true)
+	private Long examRecordDataId;
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+	
+}

+ 82 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterQueryScoreDataReq.java

@@ -0,0 +1,82 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ * @author  	chenken
+ * @date    	2018年11月27日 下午5:51:08
+ * @company 	QMTH
+ * @description OuterQueryScoreDataReq.java
+ */
+public class OuterQueryScoreDataReq extends EnterpriseRequest{
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = -5033520077132433253L;
+
+	@ApiModelProperty(value = "考试代码,推荐使用")
+	private String examCode;
+	@ApiModelProperty(value = "考试名称(废弃属性,实际上作为考试编码使用)", example = "2018年6月期末考试", required = false)
+	@Deprecated
+	private String examName;
+
+	private Long rootOrgId;
+
+	private String studentCode;
+
+	private String identityNumber;
+
+	private String courseCode;
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public String getExamCode() {
+		return examCode;
+	}
+
+	public void setExamCode(String examCode) {
+		this.examCode = examCode;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	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 getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+}

+ 102 - 0
examcloud-exchange-outer-api/src/main/java/cn/com/qmth/examcloud/exchange/outer/api/request/OuterResetExamStudentReq.java

@@ -0,0 +1,102 @@
+package cn.com.qmth.examcloud.exchange.outer.api.request;
+
+import java.util.List;
+
+import cn.com.qmth.examcloud.api.commons.exchange.EnterpriseRequest;
+import cn.com.qmth.examcloud.exchange.outer.api.bean.OuterExamStudent4ResetReqBean;
+import io.swagger.annotations.ApiModelProperty;
+
+public class OuterResetExamStudentReq extends EnterpriseRequest {
+
+	private static final long serialVersionUID = 3633974018347041831L;
+
+	@ApiModelProperty(value = "顶级机构", example = "0", required = true)
+	private Long rootOrgId;
+
+	@ApiModelProperty(value = "考试ID", example = "100", required = false)
+	private Long examId;
+
+	@ApiModelProperty(value = "考试名称(废弃属性,实际上作为考试编码使用)", example = "2018年秋季入学考试", required = false)
+	@Deprecated
+	private String examName;
+
+	@ApiModelProperty(value = "考试编码", example = "2018年秋季入学考试", required = true)
+	private String examCode;
+
+	@ApiModelProperty(value = "学生姓名", example = "陈圆圆", required = true)
+	private String studentName;
+
+	@ApiModelProperty(value = "学生学号", example = "2018001001", required = false)
+	private String studentCode;
+
+	@ApiModelProperty(value = "学生身份证号", example = "XXXXXXXXXXXXXXXXXX", required = true)
+	private String identityNumber;
+
+	@ApiModelProperty(value = "考生集合", example = "", required = true)
+	private List<OuterExamStudent4ResetReqBean> examStudentList;
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getExamCode() {
+		return examCode;
+	}
+
+	public void setExamCode(String examCode) {
+		this.examCode = examCode;
+	}
+
+	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 List<OuterExamStudent4ResetReqBean> getExamStudentList() {
+		return examStudentList;
+	}
+
+	public void setExamStudentList(List<OuterExamStudent4ResetReqBean> examStudentList) {
+		this.examStudentList = examStudentList;
+	}
+
+}

部分文件因为文件数量过多而无法显示