Ver Fonte

merge from release_v4.0.2

deason há 4 anos atrás
pai
commit
dc78212669
21 ficheiros alterados com 414 adições e 312 exclusões
  1. 1 1
      src/main/java/cn/com/qmth/examcloud/app/ApiApplication.java
  2. 7 0
      src/main/java/cn/com/qmth/examcloud/app/controller/ExamController.java
  3. 16 0
      src/main/java/cn/com/qmth/examcloud/app/controller/OfflineExamController.java
  4. 36 0
      src/main/java/cn/com/qmth/examcloud/app/controller/StudentController.java
  5. 32 9
      src/main/java/cn/com/qmth/examcloud/app/controller/UserAuthRestController.java
  6. 8 6
      src/main/java/cn/com/qmth/examcloud/app/core/SysProperty.java
  7. 55 20
      src/main/java/cn/com/qmth/examcloud/app/core/utils/HttpClientBuilder.java
  8. 18 1
      src/main/java/cn/com/qmth/examcloud/app/core/utils/HttpUtils.java
  9. 0 224
      src/main/java/cn/com/qmth/examcloud/app/core/utils/JsonMapper.java
  10. 24 0
      src/main/java/cn/com/qmth/examcloud/app/core/utils/TrustAllCert.java
  11. 13 0
      src/main/java/cn/com/qmth/examcloud/app/core/utils/TrustAllHost.java
  12. 3 0
      src/main/java/cn/com/qmth/examcloud/app/model/Constants.java
  13. 8 1
      src/main/java/cn/com/qmth/examcloud/app/service/CoreAuthService.java
  14. 2 0
      src/main/java/cn/com/qmth/examcloud/app/service/CoreBasicService.java
  15. 7 0
      src/main/java/cn/com/qmth/examcloud/app/service/CoreOeService.java
  16. 2 2
      src/main/java/cn/com/qmth/examcloud/app/service/RedisService.java
  17. 116 20
      src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreAuthServiceImpl.java
  18. 6 0
      src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreBasicServiceImpl.java
  19. 54 22
      src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreOeServiceImpl.java
  20. 5 5
      src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreQuestionServiceImpl.java
  21. 1 1
      src/test/java/cn/com/qmth/examcloud/app/ServiceTest.java

+ 1 - 1
src/main/java/cn/com/qmth/examcloud/app/ApiApplication.java

@@ -30,7 +30,7 @@ public class ApiApplication {
     static {
         String runtimeLevel = System.getProperty("log.commonLevel");
         if (null == runtimeLevel) {
-            System.setProperty("log.commonLevel", "DEBUG");
+            System.setProperty("log.commonLevel", "INFO");
         }
         System.setProperty("hibernate.dialect.storage_engine", "innodb");
     }

+ 7 - 0
src/main/java/cn/com/qmth/examcloud/app/controller/ExamController.java

@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestHeader;
 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.app.model.GetYunSignatureReq;
@@ -20,6 +21,7 @@ import cn.com.qmth.examcloud.app.service.CoreOeService;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 
 @RestController
 @RequestMapping("${$rmp}/v2/exam")
@@ -62,4 +64,9 @@ public class ExamController extends ControllerSupport {
         return oeService.queryObjectiveScoreList(key, token,examStudentId);
     }
 
+    @ApiOperation(value = "开始答题")
+    @PostMapping("/startAnswer")
+    public Result startAnswer(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token,@RequestParam @ApiParam(value = "考试记录id") Long examRecordDataId) throws Exception{
+        return oeService.startAnswer(key, token,examRecordDataId);
+    }
 }

+ 16 - 0
src/main/java/cn/com/qmth/examcloud/app/controller/OfflineExamController.java

@@ -13,6 +13,8 @@ import cn.com.qmth.examcloud.app.service.CoreQuestionService;
 import cn.com.qmth.examcloud.app.service.UpYunService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -75,6 +77,20 @@ public class OfflineExamController {
         }
         return oeService.uploadPaperAnswer(key, token, examRecordId, multipart.getBytes(), multipart.getOriginalFilename(), md5);
     }
+    
+    @ResponseBody
+    @ApiOperation(value = "批量上传作答文件接口")
+    @RequestMapping(value = "/paper/answer/uploadBatch", method = {RequestMethod.POST})
+    public Result uploadPaperAnswerBatch(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token,
+                                    @ApiParam(value = "文件数组") @RequestParam MultipartFile[] fileArray,
+                                    @ApiParam(value = "考试记录id") @RequestParam Long examRecordDataId,
+                                    @ApiParam(value = "文件类型:ZIP/PDF/IMAGE") @RequestParam String fileType,
+                                    @ApiParam(value = "md5加密的文件摘要") @RequestParam String[] fileMd5Array) throws Exception {
+        if (fileArray == null||fileArray.length==0) {
+            return new Result().error("请选择要上传文件!");
+        }
+        return oeService.uploadPaperAnswerBatch(key, token, examRecordDataId, fileArray, fileType, fileMd5Array);
+    }
 
     @ResponseBody
     @ApiOperation(value = "获取某份试卷的详细信息接口")

+ 36 - 0
src/main/java/cn/com/qmth/examcloud/app/controller/StudentController.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.app.controller;
+
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_KEY;
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_TOKEN;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.app.model.Result;
+import cn.com.qmth.examcloud.app.service.CoreBasicService;
+import cn.com.qmth.examcloud.app.service.CoreOeService;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("${$rmp}/v2/student")
+@Api(tags = "学生相关接口")
+public class StudentController extends ControllerSupport {
+
+    @Autowired
+    private CoreBasicService coreBasicService;
+
+    @ApiOperation(value = "学生在线信号", notes = "学生在线信号")
+	@GetMapping("online_signal/{studentId}")
+	public Result onlineSignal(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token,
+			@PathVariable Long studentId) throws Exception{
+	    return coreBasicService.onlineSignal(key, token,studentId);
+	}
+
+
+}

+ 32 - 9
src/main/java/cn/com/qmth/examcloud/app/controller/UserAuthRestController.java

@@ -7,6 +7,19 @@
 
 package cn.com.qmth.examcloud.app.controller;
 
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_KEY;
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_TOKEN;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
 import cn.com.qmth.examcloud.app.model.LoginInfo;
 import cn.com.qmth.examcloud.app.model.LoginType;
 import cn.com.qmth.examcloud.app.model.Result;
@@ -15,13 +28,6 @@ import cn.com.qmth.examcloud.app.service.CoreAuthService;
 import cn.com.qmth.examcloud.app.service.CoreBasicService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_KEY;
-import static cn.com.qmth.examcloud.app.model.Constants.PARAM_APP_TOKEN;
 
 /**
  * 认证中心相关接口
@@ -113,9 +119,9 @@ public class UserAuthRestController {
 
     @ApiOperation(value = "修改密码接口")
     @RequestMapping(value = "/user/update/password", method = {RequestMethod.POST})
-    public Result updatePassword(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token, @RequestParam Long studentId, @RequestParam String password,
+    public Result updatePassword(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token,  @RequestParam String password,
                                  @RequestParam String newPassword) throws Exception {
-        return authService.updateStudentPassword(key, token, studentId, password, newPassword);
+        return authService.updateStudentPassword(key, token,password, newPassword);
     }
 
     @ApiOperation(value = "重置密码接口")
@@ -129,5 +135,22 @@ public class UserAuthRestController {
     public Result userBindingPhone(@RequestHeader(name = PARAM_APP_KEY) String key, @RequestHeader(name = PARAM_APP_TOKEN) String token, @RequestParam String phone, @RequestParam String code) throws Exception {
         return authService.userBindingPhone(key, token, phone, code);
     }
+    
+    @ApiOperation(value = "极验-验证初始化接口")
+    @PostMapping(value = "/verifyCode/register")
+    public Result register(@RequestParam String user_id,@RequestParam String client_type,@RequestParam(required = false) String ip_address) throws Exception{
+        return authService.register(user_id, client_type, ip_address) ;
+    }
+
+    @ApiOperation(value = "极验-验证码登录接口")
+    @PostMapping(value = "/verifyCode/gt/login")
+    public Result geetestLogin(
+    		@RequestParam String seccode,@RequestParam String validate,@RequestParam String challenge,
+    		@RequestParam String user_id,@RequestParam String client_type,@RequestParam(required = false) String ip_address,
+    		@RequestParam String accountValue,@RequestParam String password,@RequestParam String accountType,
+    		@RequestParam Long rootOrgId) throws Exception{
+
+        return authService.geetestLogin(seccode, validate, challenge, user_id, client_type, ip_address, accountValue, password, accountType, rootOrgId);
+    }
 
 }

+ 8 - 6
src/main/java/cn/com/qmth/examcloud/app/core/SysProperty.java

@@ -7,24 +7,24 @@
 
 package cn.com.qmth.examcloud.app.core;
 
-import cn.com.qmth.examcloud.app.core.router.Server;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import cn.com.qmth.examcloud.app.core.router.Server;
+import cn.com.qmth.examcloud.commons.util.PropertiesUtil;
+
 /**
  * 属性配置服务类
  */
 @Component
 public class SysProperty {
-    private static Logger log = LoggerFactory.getLogger(SysProperty.class);
     @Autowired
     private CloudDiscoveryClient discoveryClient;
 
     @Value("${$upyun.site.1.domain}")
     private String domain;//又拍云文件服务
+    
 
     public String getProxyUrl(Server server) {
         return discoveryClient.getInstanceUrl(server.getInstanceName());
@@ -43,11 +43,13 @@ public class SysProperty {
     }
 
     public String getCoreOeAdminUrl() {
-        return discoveryClient.getInstanceUrl(Constants.EC_CORE_OE_ADMIN);
+//        return discoveryClient.getInstanceUrl(Constants.EC_CORE_OE_ADMIN);
+    	return PropertiesUtil.getString("oe.admin.api.domain"); 
     }
 
     public String getCoreQuestionUrl() {
-        return discoveryClient.getInstanceUrl(Constants.EC_CORE_QUESTION);
+//        return discoveryClient.getInstanceUrl(Constants.EC_CORE_QUESTION);
+    	return PropertiesUtil.getString("question.api.domain");
     }
 
     public String getCoreAuthUrl() {

+ 55 - 20
src/main/java/cn/com/qmth/examcloud/app/core/utils/HttpClientBuilder.java

@@ -1,46 +1,81 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-07-16 16:38:13.
- * *************************************************
- */
-
 package cn.com.qmth.examcloud.app.core.utils;
 
 import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import java.security.SecureRandom;
+import java.util.concurrent.TimeUnit;
 
 /**
- * HttpClient单例对象
- *
- * @author: QMTH
- * @since: 2018/8/1
+ * HttpClient
  */
 public class HttpClientBuilder {
+
+    private static Logger log = LoggerFactory.getLogger(HttpClientBuilder.class);
+
     private static OkHttpClient client;
 
     static {
-        client = Singleton.INSTANCE.getInstance();
+        client = Client.INSTANCE.getInstance();
     }
 
     public static OkHttpClient getClient() {
         return client;
     }
 
-    private enum Singleton {
-        /**
-         * Http Client Instance
-         */
-        INSTANCE;
+    private enum Client {
 
-        private OkHttpClient instance;
+        INSTANCE;
 
-        Singleton() {
-            instance = new OkHttpClient();
+        Client() {
+            instance = new OkHttpClient
+                    .Builder()
+                    .connectTimeout(15, TimeUnit.SECONDS)
+                    .readTimeout(30, TimeUnit.SECONDS)
+                    .writeTimeout(30, TimeUnit.SECONDS)
+                    .sslSocketFactory(sslSocketFactory(), new TrustAllCert())
+                    .hostnameVerifier(new TrustAllHost())
+                    .build();
         }
 
+        private OkHttpClient instance;
+
         public OkHttpClient getInstance() {
             return instance;
         }
+
+        private SSLSocketFactory sslSocketFactory() {
+            try {
+                final String type = "TLS";
+                SSLContext sslContext = SSLContext.getInstance(type);
+                sslContext.init(null, new TrustManager[]{new TrustAllCert()}, new SecureRandom());
+                return sslContext.getSocketFactory();
+            } catch (Exception e) {
+                log.error(e.getMessage());
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static byte[] download(String url) throws RuntimeException {
+        Request request = new Request.Builder().url(url).get().build();
+
+        try (Response response = getClient().newCall(request).execute();) {
+            if (response.isSuccessful()) {
+                return response.body().bytes();
+            }
+
+            throw new RuntimeException("download fail, url is " + url);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
     }
 
 }

+ 18 - 1
src/main/java/cn/com/qmth/examcloud/app/core/utils/HttpUtils.java

@@ -10,6 +10,7 @@ package cn.com.qmth.examcloud.app.core.utils;
 import cn.com.qmth.examcloud.app.model.Constants;
 import cn.com.qmth.examcloud.app.model.ResBody;
 import cn.com.qmth.examcloud.app.model.Result;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import com.alibaba.fastjson.JSON;
 import okhttp3.Request;
 import okhttp3.RequestBody;
@@ -73,6 +74,22 @@ public class HttpUtils {
         log.info("[POST] " + requestUrl);
         return call(request, traceId);
     }
+    
+    public static Result<String> doPost(String requestUrl, RequestBody formBody) throws Exception {
+        String traceId = getRandomTraceId();
+
+        //封装请求参数
+        Request request = new Request.Builder()
+                .url(requestUrl)
+                .post(formBody)
+                .addHeader(PARAM_TRACE_ID, traceId)
+                .addHeader(PARAM_CLIENT, PARAM_CLIENT_VALUE)
+                .build();
+
+        //执行请求
+        log.info("[POST] " + requestUrl);
+        return call(request, traceId);
+    }
 
     public static Result<String> doPut(String requestUrl, RequestBody formBody, String key, String token) throws Exception {
         String traceId = getRandomTraceId();
@@ -107,7 +124,7 @@ public class HttpUtils {
             return new Result().success(bodyStr);
         } else {
             log.warn("[Response] is fail! body:" + bodyStr);
-            ResBody body = new JsonMapper().fromJson(bodyStr, ResBody.class);
+            ResBody body = new JsonMapper().parseJson(bodyStr, ResBody.class);
             if (body != null && body.getCode() != null) {
                 if (Constants.CODE_403.equals(body.getCode())) {
                     return new Result().noAuthError();

+ 0 - 224
src/main/java/cn/com/qmth/examcloud/app/core/utils/JsonMapper.java

@@ -1,224 +0,0 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-07-16 15:00:21.
- * *************************************************
- */
-
-package cn.com.qmth.examcloud.app.core.utils;
-
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.*;
-import com.fasterxml.jackson.databind.util.JSONPObject;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 简单封装Jackson,实现JSON 与 Java Object互相转换的Mapper
- * 封装不同的输出风格, 使用不同的builder函数创建实例
- */
-@SuppressWarnings("unchecked")
-public class JsonMapper {
-    private static Logger log = LoggerFactory.getLogger(JsonMapper.class);
-    private ObjectMapper mapper;
-
-    public JsonMapper() {
-        this(null);
-    }
-
-    public JsonMapper(Include include) {
-        mapper = new ObjectMapper();
-        //设置输出时包含属性的风格
-        if (include != null) {
-            mapper.setSerializationInclusion(include);
-        }
-        //设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
-        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-    }
-
-    /**
-     * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用
-     */
-    public static JsonMapper nonEmptyMapper() {
-        return new JsonMapper(Include.NON_EMPTY);
-    }
-
-    public static JsonMapper nonNullMapper() {
-        return new JsonMapper(Include.NON_NULL);
-    }
-
-    /**
-     * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用
-     */
-    public static JsonMapper nonDefaultMapper() {
-        return new JsonMapper(Include.NON_DEFAULT);
-    }
-
-    /**
-     * Object可以是POJO,也可以是Collection或数组
-     * 如果对象为Null, 返回"null"
-     * 如果集合为空集合, 返回"[]"
-     */
-    public String toJson(Object object) {
-        try {
-            return mapper.writeValueAsString(object);
-        } catch (IOException e) {
-            log.error("write to json string error:" + object);
-            return null;
-        }
-    }
-
-    /**
-     * 反序列化POJO或简单Collection如List<String>
-     * 如果JSON字符串为Null或"null"字符串, 返回Null
-     * 如果JSON字符串为"[]", 返回空集合
-     * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
-     */
-    public <T> T fromJson(String jsonString, Class<T> clazz) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return mapper.readValue(jsonString, clazz);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    /**
-     * 反序列化复杂Collection如List<Bean>, 先使用createCollectionType()或constructMapType()构造类型, 然后调用本函数
-     */
-    public <T> T fromJson(String jsonString, JavaType javaType) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return (T) mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    /**
-     * 反序列化复杂的对象,如Page<Bean>
-     */
-    public <T> T fromJson(String jsonString, TypeReference javaType) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return (T) mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    /**
-     * json to list
-     */
-    public <T> List<T> toList(String jsonString, Class<T> bean) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            JavaType javaType = constructCollectionType(List.class, bean);
-            return mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    /**
-     * json to simple HashMap
-     */
-    public <T> Map<String, T> toHashMap(String jsonString, Class<T> bean) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            JavaType javaType = constructMapType(HashMap.class, String.class, bean);
-            return mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error:", e);
-            return null;
-        }
-    }
-
-    /**
-     * 构造Collection类型
-     */
-    public JavaType constructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
-        return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
-    }
-
-    /**
-     * 构造Map类型
-     */
-    public JavaType constructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
-        return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
-    }
-
-    /**
-     * 当JSON里只含有Bean的部分屬性時,更新一個已存在Bean,只覆盖該部分的屬性
-     */
-    public void update(String jsonString, Object object) {
-        try {
-            mapper.readerForUpdating(object).readValue(jsonString);
-        } catch (JsonProcessingException e) {
-            log.error("update json string:" + jsonString + " to object:" + object + " error.");
-        } catch (IOException e) {
-            log.error("update json string:" + jsonString + " to object:" + object + " error.");
-        }
-    }
-
-    /**
-     * 輸出JSONP格式数据
-     */
-    public String toJsonP(String functionName, Object object) {
-        return toJson(new JSONPObject(functionName, object));
-    }
-
-    /**
-     * 設定是否使用Enum的toString函數來读写Enum
-     * 為False時使用Enum的name()函數來读写Enum, 默認為False
-     * 注意本函數一定要在Mapper創建後, 所有的读写動作之前調用
-     */
-    public void enableEnumUseToString() {
-        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
-        mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
-    }
-
-    /**
-     * 取出Mapper做进一步的设置或使用其他序列化API
-     */
-    public ObjectMapper getMapper() {
-        return mapper;
-    }
-
-    /***
-     * 把Json字符串转换成Node对象
-     */
-    public JsonNode getNode(String jsonStr) {
-        try {
-            //mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
-            return mapper.readTree(jsonStr);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return null;
-        }
-    }
-
-}

+ 24 - 0
src/main/java/cn/com/qmth/examcloud/app/core/utils/TrustAllCert.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.examcloud.app.core.utils;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+public class TrustAllCert implements X509TrustManager {
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+    }
+
+}

+ 13 - 0
src/main/java/cn/com/qmth/examcloud/app/core/utils/TrustAllHost.java

@@ -0,0 +1,13 @@
+package cn.com.qmth.examcloud.app.core.utils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+
+public class TrustAllHost implements HostnameVerifier {
+
+    @Override
+    public boolean verify(String hostname, SSLSession sslSession) {
+        return true;
+    }
+
+}

+ 3 - 0
src/main/java/cn/com/qmth/examcloud/app/model/Constants.java

@@ -60,6 +60,9 @@ public interface Constants {
     /* 常用的文件类型 */
     String FILE_TYPE_ZIP = "zip";
     String FILE_TYPE_PDF = "pdf";
+    String FILE_TYPE_JPG = "jpg";
+    String FILE_TYPE_JPEG = "jpeg";
+    String FILE_TYPE_PNG = "png";
 
     /* 系统状态码 */
     String CODE_0 = "0";//错误

+ 8 - 1
src/main/java/cn/com/qmth/examcloud/app/service/CoreAuthService.java

@@ -64,7 +64,7 @@ public interface CoreAuthService {
      * @return
      * @throws Exception
      */
-    Result updateStudentPassword(String key, String token, Long studentId, String password, String newPassword) throws Exception;
+    Result updateStudentPassword(String key, String token, String password, String newPassword) throws Exception;
 
     /**
      * 重置密码
@@ -137,4 +137,11 @@ public interface CoreAuthService {
      */
     void initRequestTrace();
 
+	Result register(String user_id,String client_type, String ip_address) throws Exception;
+
+	Result geetestLogin( String seccode, String validate, String challenge,
+    		 String user_id, String client_type, String ip_address,
+    		 String accountValue, String password, String accountType,
+    		Long rootOrgId) throws Exception;
+
 }

+ 2 - 0
src/main/java/cn/com/qmth/examcloud/app/service/CoreBasicService.java

@@ -27,4 +27,6 @@ public interface CoreBasicService {
      */
     Result getStudentInfo(String key, String token) throws Exception;
 
+	Result onlineSignal(String key, String token, Long studentId) throws Exception ;
+
 }

+ 7 - 0
src/main/java/cn/com/qmth/examcloud/app/service/CoreOeService.java

@@ -6,6 +6,8 @@
 
 package cn.com.qmth.examcloud.app.service;
 
+import org.springframework.web.multipart.MultipartFile;
+
 import cn.com.qmth.examcloud.app.model.GetYunSignatureReq;
 import cn.com.qmth.examcloud.app.model.Result;
 
@@ -306,4 +308,9 @@ public interface CoreOeService {
      */
     Result queryObjectiveScoreList(String key, String token, Long examStudentId) throws Exception;
 
+	Result startAnswer(String key, String token, Long examRecordDataId) throws Exception;
+
+	Result uploadPaperAnswerBatch(String key, String token, Long examRecordDataId, MultipartFile[] fileArray,
+			String fileType, String[] fileMd5Array) throws Exception;
+
 }

+ 2 - 2
src/main/java/cn/com/qmth/examcloud/app/service/RedisService.java

@@ -7,7 +7,7 @@
 
 package cn.com.qmth.examcloud.app.service;
 
-import cn.com.qmth.examcloud.app.core.utils.JsonMapper;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -58,7 +58,7 @@ public class RedisService {
     public <T> T fromJson(String key, Class<T> clazz) {
         String jsonStr = stringRedisTemplate.opsForValue().get(key);
         if (jsonStr != null) {
-            return new JsonMapper().fromJson(jsonStr, clazz);
+            return new JsonMapper().parseJson(jsonStr, clazz);
         }
         return null;
     }

+ 116 - 20
src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreAuthServiceImpl.java

@@ -7,32 +7,48 @@
 
 package cn.com.qmth.examcloud.app.service.impl;
 
+import static cn.com.qmth.examcloud.app.model.Constants.APP_SESSION_EXPIRE_TIME;
+import static cn.com.qmth.examcloud.app.model.Constants.APP_SESSION_USER_KEY_PREFIX;
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_KEY;
+import static cn.com.qmth.examcloud.app.model.Constants.PARAM_TOKEN;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import com.alibaba.fastjson.JSONObject;
+
 import cn.com.qmth.examcloud.app.core.SysProperty;
 import cn.com.qmth.examcloud.app.core.exception.ApiException;
 import cn.com.qmth.examcloud.app.core.utils.HttpClientBuilder;
 import cn.com.qmth.examcloud.app.core.utils.HttpUtils;
-import cn.com.qmth.examcloud.app.core.utils.JsonMapper;
 import cn.com.qmth.examcloud.app.core.utils.ThreadUtils;
-import cn.com.qmth.examcloud.app.model.*;
+import cn.com.qmth.examcloud.app.model.Constants;
+import cn.com.qmth.examcloud.app.model.ExamInfo;
+import cn.com.qmth.examcloud.app.model.LoginInfo;
+import cn.com.qmth.examcloud.app.model.LoginType;
+import cn.com.qmth.examcloud.app.model.ResBody;
+import cn.com.qmth.examcloud.app.model.Result;
+import cn.com.qmth.examcloud.app.model.UserInfo;
 import cn.com.qmth.examcloud.app.service.CoreAuthService;
 import cn.com.qmth.examcloud.app.service.RedisService;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
 import cn.com.qmth.examcloud.core.basic.api.request.GetStudentReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetStudentResp;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.OrgPropertyCacheBean;
-import okhttp3.*;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static cn.com.qmth.examcloud.app.model.Constants.*;
+import okhttp3.FormBody;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
 
 /**
  * 认证中心业务服务接口
@@ -88,7 +104,7 @@ public class CoreAuthServiceImpl implements CoreAuthService {
 
             String bodyStr = response.body().string();
             if (response.isSuccessful()) {
-                ExamInfo info = new JsonMapper().fromJson(bodyStr, ExamInfo.class);
+                ExamInfo info = new JsonMapper().parseJson(bodyStr, ExamInfo.class);
                 if (info != null) {
                     return info.getExistExamingRecord();
                 }
@@ -170,11 +186,11 @@ public class CoreAuthServiceImpl implements CoreAuthService {
             String bodyStr = response.body().string();
             if (response.isSuccessful()) {
                 //获取用户信息
-                UserInfo userInfo = new JsonMapper().fromJson(bodyStr, UserInfo.class);
+                UserInfo userInfo = new JsonMapper().parseJson(bodyStr, UserInfo.class);
                 return new Result().success(userInfo);
             } else {
                 log.warn("Http response is " + bodyStr);
-                ResBody body = new JsonMapper().fromJson(bodyStr, ResBody.class);
+                ResBody body = new JsonMapper().parseJson(bodyStr, ResBody.class);
                 if (body != null && body.getCode() != null) {
                     return new Result().error(body.getDesc());
                 }
@@ -203,12 +219,10 @@ public class CoreAuthServiceImpl implements CoreAuthService {
     }
 
     @Override
-    public Result updateStudentPassword(String key, String token, Long studentId, String password, String newPassword) throws Exception {
-        Assert.notNull(studentId, "StudentId must be not null.");
+    public Result updateStudentPassword(String key, String token, String password, String newPassword) throws Exception {
         //封装请求参数
         final String requestUrl = String.format("%s/api/ecs_core/student/password", sysProperty.getCoreAuthUrl());
         RequestBody formBody = new FormBody.Builder()
-                .add("studentId", studentId.toString())
                 .add("password", password)
                 .add("newPassword", newPassword)
                 .build();
@@ -324,4 +338,86 @@ public class CoreAuthServiceImpl implements CoreAuthService {
         redisService.set(key, millis.toString(), 15);
     }
 
+	@Override
+	public Result register(String user_id,String client_type, String ip_address) throws Exception {
+		final String requestUrl = String.format("%s/api/ecs_core/verifyCode/register", sysProperty.getCoreAuthUrl());
+        Map<String, Object> params = new HashMap<>();
+        params.put("user_id", user_id);
+        params.put("client_type", client_type);
+        String json = new JsonMapper().toJson(params);
+        RequestBody formBody = FormBody.create(MediaType.parse(Constants.CHARSET_JSON_UTF8), json);
+        //发送短信
+        Result<String> result = HttpUtils.doPost(requestUrl, formBody);
+        return result;
+	}
+
+	@Override
+	public Result geetestLogin(String seccode, String validate, String challenge,
+   		 String user_id, String client_type, String ip_address,
+   		 String accountValue, String password, String accountType,
+   		Long rootOrgId) throws Exception {
+        if (StringUtils.isBlank(accountType)) {
+        	accountType=LoginType.STUDENT_PHONE.name();
+        }
+
+        //封装请求参数
+        final String requestUrl = String.format("%s/api/ecs_core/verifyCode/gt/login", sysProperty.getCoreBasicUrl());
+        Map<String, String> params = new HashMap<>();
+        
+        
+        
+        params.put("seccode", seccode);
+        params.put("validate", validate);
+        params.put("challenge", challenge);
+        params.put("user_id", user_id);
+        params.put("client_type", client_type);
+        params.put("ip_address", ip_address);
+        params.put("accountValue", accountValue);
+        params.put("password", password);
+        params.put("accountType", accountType);
+        params.put("rootOrgId", rootOrgId != null ? rootOrgId.toString() : "");
+        String json = new JsonMapper().toJson(params);
+
+        RequestBody formBody = FormBody.create(MediaType.parse(Constants.CHARSET_JSON_UTF8), json);
+        Request request = new Request.Builder()
+                .url(requestUrl)
+                .post(formBody)
+                .addHeader("isApp", "true")
+                .build();
+
+        //执行请求
+        try (Response response = HttpClientBuilder.getClient().newCall(request).execute();) {
+            String bodyStr = response.body().string();
+            if (response.isSuccessful()) {
+                //获取用户信息
+                UserInfo userInfo = of(bodyStr);
+                return new Result().success(userInfo);
+            } else {
+                log.warn("Http response is " + bodyStr);
+                ResBody body = new JsonMapper().parseJson(bodyStr, ResBody.class);
+                if (body != null && body.getCode() != null) {
+                    return new Result().error(body.getDesc());
+                }
+                return new Result().error(bodyStr);
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return new Result().error("登录异常!");
+        }
+	}
+	
+	private UserInfo of(String bodyStr) {
+		JSONObject job=JSONObject.parseObject(bodyStr);
+		JSONObject content=job.getJSONObject("content");
+		UserInfo userInfo = new UserInfo();
+		userInfo.setKey(content.getString("key"));
+		userInfo.setUserId(content.getLong("userId"));
+		userInfo.setUserType(content.getString("userType"));
+		userInfo.setDisplayName(content.getString("displayName"));
+		userInfo.setRootOrgId(content.getLong("rootOrgId"));
+		userInfo.setRootOrgName(content.getString("rootOrgName"));
+		userInfo.setToken(content.getString("token"));
+		return userInfo;
+	}
+
 }

+ 6 - 0
src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreBasicServiceImpl.java

@@ -36,4 +36,10 @@ public class CoreBasicServiceImpl implements CoreBasicService {
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
+	@Override
+	public Result onlineSignal(String key, String token, Long studentId) throws Exception  {
+		final String requestUrl = String.format("%s/api/ecs_core/student/online_signal/"+studentId, sysProperty.getCoreBasicUrl());
+        return HttpUtils.doGet(requestUrl, key, token);
+	}
+
 }

+ 54 - 22
src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreOeServiceImpl.java

@@ -10,7 +10,7 @@ package cn.com.qmth.examcloud.app.service.impl;
 import cn.com.qmth.examcloud.app.core.exception.ApiException;
 import cn.com.qmth.examcloud.app.core.utils.DateUtils;
 import cn.com.qmth.examcloud.app.core.utils.HttpUtils;
-import cn.com.qmth.examcloud.app.core.utils.JsonMapper;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.app.model.Constants;
 import cn.com.qmth.examcloud.app.model.GetYunSignatureReq;
 import cn.com.qmth.examcloud.app.model.Result;
@@ -28,15 +28,13 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static cn.com.qmth.examcloud.app.model.Constants.FILE_TYPE_PDF;
-import static cn.com.qmth.examcloud.app.model.Constants.FILE_TYPE_ZIP;
-
 /**
  * 网考业务服务接口
  *
@@ -64,14 +62,14 @@ public class CoreOeServiceImpl implements CoreOeService {
     @Override
     public Result getOfflineExamCourseList(String key, String token) throws Exception {
         //封装请求参数									
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/offlineExam/getOfflineCourse", sysProperty.getCoreOeAdminUrl());
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/offlineExam/getOfflineCourse", sysProperty.getCoreOeAdminUrl());
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
     @Override
     public Result startOfflineExamRecord(String key, String token, String examStudentId) throws Exception {
         //封装请求参数									
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/offlineExam/startOfflineExam?examStudentId=%s", sysProperty.getCoreOeAdminUrl(), examStudentId);
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/offlineExam/startOfflineExam?examStudentId=%s", sysProperty.getCoreOeAdminUrl(), examStudentId);
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
@@ -80,14 +78,16 @@ public class CoreOeServiceImpl implements CoreOeService {
         Assert.notNull(examRecordId, "FileName must not be null.");
         Assert.notNull(fileName, "ExamRecordId must not be null.");
         String fileType = FilenameUtils.getExtension(fileName.toLowerCase());
-        if (!FILE_TYPE_ZIP.equals(fileType) && !FILE_TYPE_PDF.equals(fileType)) {
-            throw new ApiException("FileType must be zip or pdf.");
+        if (!Constants.FILE_TYPE_ZIP.equals(fileType) && !Constants.FILE_TYPE_PDF.equals(fileType)
+        		&& !Constants.FILE_TYPE_JPG.equals(fileType)&& !Constants.FILE_TYPE_JPEG.equals(fileType)
+        		&& !Constants.FILE_TYPE_PNG.equals(fileType)) {
+            throw new ApiException("FileType must be zip,pdf,jpg,jpeg,png.");
         }
         if (fileBytes.length == 0) {
             throw new ApiException("File must be not empty.");
         }
         //封装请求参数									
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/offlineExam/submitPaper?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/offlineExam/submitPaper?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
         MultipartBody.Builder form = new MultipartBody.Builder().setType(MultipartBody.FORM);
         RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), fileBytes);
         form.addFormDataPart("file", fileName, body);
@@ -99,7 +99,7 @@ public class CoreOeServiceImpl implements CoreOeService {
     @Override
     public Result getPracticeExamCourseList(String key, String token, String examId) throws Exception {
         //封装请求参数
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/practice/queryPracticeCourseList?examId=%s", sysProperty.getCoreOeAdminUrl(), examId);
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/practice/queryPracticeCourseList?examId=%s", sysProperty.getCoreOeAdminUrl(), examId);
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
@@ -122,9 +122,9 @@ public class CoreOeServiceImpl implements CoreOeService {
         //封装请求参数
         String requestUrl=null;
         if("1".equals(fromCache)) {
-            requestUrl = String.format("%s/api/ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
         }else {
-            requestUrl = String.format("%s/api/ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
         }
         return HttpUtils.doGet(requestUrl, key, token);
     }
@@ -181,7 +181,7 @@ public class CoreOeServiceImpl implements CoreOeService {
     @Override
     public Result getExamRecordPracticeHistoryList(String key, String token, String examStudentId) throws Exception {
         //封装请求参数
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/practice/queryPracticeRecordList?examStudentId=%s", sysProperty.getCoreOeAdminUrl(), examStudentId);
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/practice/queryPracticeRecordList?examStudentId=%s", sysProperty.getCoreOeAdminUrl(), examStudentId);
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
@@ -190,9 +190,9 @@ public class CoreOeServiceImpl implements CoreOeService {
         //封装请求参数
         String requestUrl=null;
         if("1".equals(fromCache)) {
-            requestUrl = String.format("%s/api/ecs_oe_admin/practice/getPracticeDetailInfo?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/practice/getPracticeDetailInfo?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
         }else {
-            requestUrl = String.format("%s/api/ecs_oe_admin/practice/getPracticeDetailInfo?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/practice/getPracticeDetailInfo?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordId);
         }
         return HttpUtils.doGet(requestUrl, key, token);
     }
@@ -227,9 +227,9 @@ public class CoreOeServiceImpl implements CoreOeService {
         //封装请求参数
         String requestUrl=null;
         if("1".equals(fromCache)) {
-            requestUrl = String.format("%s/api/ecs_oe_admin/exam/record/data/findExamRecordDataEntity?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/exam/record/data/findExamRecordDataEntity?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
         }else {
-            requestUrl = String.format("%s/api/ecs_oe_admin/exam/record/data/findExamRecordDataEntity?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/exam/record/data/findExamRecordDataEntity?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
         }
         Result<String> result = HttpUtils.doGet(requestUrl, key, token);
         if (result.isSuccess()) {
@@ -244,9 +244,9 @@ public class CoreOeServiceImpl implements CoreOeService {
         //封装请求参数
         String requestUrl=null;
         if("1".equals(fromCache)) {
-            requestUrl = String.format("%s/api/ecs_oe_admin/examRecordQuestions/getExamRecordQuestions?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/examRecordQuestions/getExamRecordQuestions?fromCache=1&examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
         }else {
-            requestUrl = String.format("%s/api/ecs_oe_admin/examRecordQuestions/getExamRecordQuestions?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
+            requestUrl = String.format("%s/api/branch_ecs_oe_admin/examRecordQuestions/getExamRecordQuestions?examRecordDataId=%s", sysProperty.getCoreOeAdminUrl(), examRecordDataId);
         }
         Result<String> result = HttpUtils.doGet(requestUrl, key, token);
         if (result.isSuccess()) {
@@ -266,7 +266,7 @@ public class CoreOeServiceImpl implements CoreOeService {
 
     @Override
     public Result getPaperById(String key, String token, String paperId) throws Exception {
-        final String requestUrl = String.format("%s/api/ecs_ques/paper/"+paperId, sysProperty.getCoreQuestionUrl());
+        final String requestUrl = String.format("%s/api/branch_ecs_ques/paper/"+paperId, sysProperty.getCoreQuestionUrl());
         Result<String> result = HttpUtils.doGet(requestUrl, key, token);
         return result;
     }
@@ -290,7 +290,7 @@ public class CoreOeServiceImpl implements CoreOeService {
 
     @Override
     public Result queryExamList(String key, String token) throws Exception {
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/examControl/queryExamList", sysProperty.getCoreOeAdminUrl());
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/examControl/queryExamList", sysProperty.getCoreOeAdminUrl());
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
@@ -302,8 +302,40 @@ public class CoreOeServiceImpl implements CoreOeService {
 
     @Override
     public Result queryObjectiveScoreList(String key, String token, Long examStudentId) throws Exception {
-        final String requestUrl = String.format("%s/api/ecs_oe_admin/exam/score/queryObjectiveScoreList?examStudentId="+examStudentId, sysProperty.getCoreOeAdminUrl());
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/exam/score/queryObjectiveScoreList?examStudentId="+examStudentId, sysProperty.getCoreOeAdminUrl());
         return HttpUtils.doGet(requestUrl, key, token);
     }
 
+	@Override
+	public Result startAnswer(String key, String token, Long examRecordDataId) throws Exception {
+		final String requestUrl = String.format("%s/api/ecs_oe_student/examControl/startAnswer", sysProperty.getCoreOeStudentUrl());
+		RequestBody formBody = new FormBody.Builder()
+                .add("examRecordDataId", examRecordDataId.toString())
+                .build();
+        return HttpUtils.doPost(requestUrl, formBody, key, token);
+	}
+
+	@Override
+	public Result uploadPaperAnswerBatch(String key, String token, Long examRecordDataId, MultipartFile[] fileArray,
+			String fileType, String[] fileMd5Array) throws Exception {
+        if (!Constants.FILE_TYPE_ZIP.equals(fileType) && !Constants.FILE_TYPE_PDF.equals(fileType)
+        		&& !Constants.FILE_TYPE_JPG.equals(fileType)&& !Constants.FILE_TYPE_JPEG.equals(fileType)
+        		&& !Constants.FILE_TYPE_PNG.equals(fileType)) {
+            throw new ApiException("FileType must be zip,pdf,jpg,jpeg,png.");
+        }
+        //封装请求参数									
+        final String requestUrl = String.format("%s/api/branch_ecs_oe_admin/offlineExam/batchSubmitPaper?examRecordDataId="+examRecordDataId+"&fileType="+fileType, sysProperty.getCoreOeAdminUrl());
+        MultipartBody.Builder form = new MultipartBody.Builder().setType(MultipartBody.FORM);
+        for(MultipartFile file:fileArray) {
+	        RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), file.getBytes());
+	        form.addFormDataPart("fileArray", file.getOriginalFilename(), body);
+        }
+        form.addFormDataPart("fileType", fileType);
+        for(String md5:fileMd5Array) {
+        	form.addFormDataPart("fileMd5Array", md5 != null ? md5 : "");
+        }
+        
+        return HttpUtils.doPost(requestUrl, form.build(), key, token);
+	}
+
 }

+ 5 - 5
src/main/java/cn/com/qmth/examcloud/app/service/impl/CoreQuestionServiceImpl.java

@@ -8,7 +8,7 @@
 package cn.com.qmth.examcloud.app.service.impl;
 
 import cn.com.qmth.examcloud.app.core.utils.HttpUtils;
-import cn.com.qmth.examcloud.app.core.utils.JsonMapper;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.app.model.Constants;
 import cn.com.qmth.examcloud.app.model.ResBody;
 import cn.com.qmth.examcloud.app.model.Result;
@@ -43,13 +43,13 @@ public class CoreQuestionServiceImpl implements CoreQuestionService {
     public String downloadPaper(String key, String token, String paperId, String orgName) throws Exception {
         //封装请求参数
         orgName = URLEncoder.encode(orgName, "utf-8");
-        return String.format("%s/api/ecs_ques/paper/export/%s/PAPER/%s/%s/offLine?$key=%s&$token=%s", sysProperty.getCoreQuestionUrl(), paperId, orgName, paperId, key, token);
+        return String.format("%s/api/branch_ecs_ques/paper/export/%s/PAPER/%s/%s/offLine?$key=%s&$token=%s", sysProperty.getCoreQuestionUrl(), paperId, orgName, paperId, key, token);
     }
 
     @Override
     public Result getPaperDetail(String key, String token, String paperId) throws Exception {
         //封装请求参数
-        final String requestUrl = String.format("%s/api/ecs_ques/paper/%s", sysProperty.getCoreQuestionUrl(), paperId);
+        final String requestUrl = String.format("%s/api/branch_ecs_ques/paper/%s", sysProperty.getCoreQuestionUrl(), paperId);
         Result<String> result = HttpUtils.doGet(requestUrl, key, token);
         if (result.isSuccess()) {
             //过滤掉为空的属性
@@ -61,7 +61,7 @@ public class CoreQuestionServiceImpl implements CoreQuestionService {
     @Override
     public Result getQuestion(String key, String token, String courseCode, Long examId, String groupCode, String questionId) throws Exception {
         //封装请求参数
-        final String requestUrl = String.format("%s/api/ecs_ques/default_question/question", sysProperty.getCoreQuestionUrl());
+        final String requestUrl = String.format("%s/api/branch_ecs_ques/default_question/question", sysProperty.getCoreQuestionUrl());
         Map<String, Object> params = new HashMap<>();
         params.put("courseCode", courseCode);
         params.put("examId", examId);
@@ -78,7 +78,7 @@ public class CoreQuestionServiceImpl implements CoreQuestionService {
         if (!result.isSuccess()) {
             return result;
         }
-        ResBody body = new JsonMapper().fromJson(result.getData(), ResBody.class);
+        ResBody body = new JsonMapper().parseJson(result.getData(), ResBody.class);
         if (body != null && body.getSuccess() != null) {
             if (body.getSuccess() == true) {
                 return new Result().success();

+ 1 - 1
src/test/java/cn/com/qmth/examcloud/app/ServiceTest.java

@@ -1,6 +1,6 @@
 package cn.com.qmth.examcloud.app;
 
-import cn.com.qmth.examcloud.app.core.utils.JsonMapper;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.app.model.LoginInfo;
 import cn.com.qmth.examcloud.app.model.UserInfo;
 import cn.com.qmth.examcloud.app.service.RedisService;