瀏覽代碼

merge from release_v4.0.1

deason 4 年之前
父節點
當前提交
677260e71e
共有 56 個文件被更改,包括 5501 次插入4462 次删除
  1. 12 4
      .gitignore
  2. 15 14
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/AppController.java
  3. 85 89
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/Auth2Controller.java
  4. 196 188
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/AuthController.java
  5. 494 503
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/CourseController.java
  6. 85 88
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/CourseSpeciatlyRelationController.java
  7. 47 50
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/FaceController.java
  8. 65 69
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/LogController.java
  9. 61 0
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/LoginRuleController.java
  10. 577 573
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/OrgController.java
  11. 178 191
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/ResourceController.java
  12. 15 38
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/RolePrivilegeController.java
  13. 350 358
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SpecialtyController.java
  14. 51 1
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/StudentController.java
  15. 157 0
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SysNoticeController.java
  16. 110 118
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SystemPropertyController.java
  17. 37 40
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/TestController.java
  18. 670 680
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/UserController.java
  19. 59 16
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/VerifyCodeController.java
  20. 105 0
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/bean/SysNoticeDomain.java
  21. 21 20
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/AuthCloudServiceProvider.java
  22. 127 127
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/CourseCloudServiceProvider.java
  23. 120 120
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/FaceCloudServiceProvider.java
  24. 184 185
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/OrgCloudServiceProvider.java
  25. 97 99
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/RolePrivilegeCloudServiceProvider.java
  26. 227 237
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/StudentCloudServiceProvider.java
  27. 47 46
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/SystemPropertyCloudServiceProvider.java
  28. 290 291
      examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/UserCloudServiceProvider.java
  29. 9 1
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/LoginRuleRepo.java
  30. 12 16
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/OrgRepo.java
  31. 21 0
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/SysNoticeRepo.java
  32. 30 10
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/entity/LoginRuleEntity.java
  33. 102 0
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/entity/SysNoticeEntity.java
  34. 29 0
      examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/enums/LoginRuleType.java
  35. 19 3
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/LoginRuleService.java
  36. 48 39
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/OrgService.java
  37. 11 3
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/VerifyCodeService.java
  38. 56 0
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/GeetestLoginInfo.java
  39. 49 0
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleForm.java
  40. 94 0
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleInfo.java
  41. 36 0
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleQuery.java
  42. 1 1
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/VerifyCodeLoginInfo.java
  43. 8 19
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/cache/LoginRuleCacheBean.java
  44. 5 3
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/AuthServiceImpl.java
  45. 42 0
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/GeetestSessionImpl.java
  46. 201 18
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/LoginRuleServiceImpl.java
  47. 33 27
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/OrgServiceImpl.java
  48. 65 11
      examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/VerifyCodeServiceImpl.java
  49. 0 15
      examcloud-core-basic-starter/.springBeans
  50. 2 4
      examcloud-core-basic-starter/src/main/java/cn/com/qmth/examcloud/core/basic/starter/config/ScheduleConfig.java
  51. 45 29
      examcloud-core-basic-starter/src/main/resources/aliyun.xml
  52. 2 2
      examcloud-core-basic-starter/src/main/resources/application.properties
  53. 98 77
      examcloud-core-basic-starter/src/main/resources/log4j2.xml
  54. 1 1
      examcloud-core-basic-starter/src/main/resources/security.properties
  55. 0 19
      jenkins-dev.sh
  56. 0 19
      jenkins-test.sh

+ 12 - 4
.gitignore

@@ -1,12 +1,20 @@
+*.class
+
+# Proguard folder generated by ide
 .project
 .classpath
+*.springBeans
 .settings
 target/
 .idea/
 *.iml
-*test/
-# Package Files #
-*.jar
-logs/
 
+# Log Files
+*.log
+*.class
 
+
+# Package Files #
+*.jar
+*.war
+*.ear

+ 15 - 14
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/AppController.java

@@ -1,33 +1,34 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.List;
-
+import cn.com.qmth.examcloud.core.basic.dao.AppRepo;
+import cn.com.qmth.examcloud.core.basic.dao.entity.AppEntity;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Sort;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import cn.com.qmth.examcloud.core.basic.dao.AppRepo;
-import cn.com.qmth.examcloud.core.basic.dao.entity.AppEntity;
-import cn.com.qmth.examcloud.web.support.ControllerSupport;
-import io.swagger.annotations.ApiOperation;
+import java.util.List;
 
 /**
  * 应用服务API Created by ting.yin on 17/3/9.
  */
 @RestController
+@Api(tags = "应用相关接口")
 @RequestMapping("${$rmp.ctr.basic}/app")
 public class AppController extends ControllerSupport {
 
-	@Autowired
-	AppRepo appRepo;
+    @Autowired
+    AppRepo appRepo;
 
-	@ApiOperation(value = "查询所有应用")
-	@GetMapping("getAllApp")
-	public List<AppEntity> getAllApp() {
-		Sort sort = new Sort(Sort.Direction.ASC, "id");
-		return appRepo.findAll(sort);
-	}
+    @ApiOperation(value = "查询所有应用")
+    @GetMapping("getAllApp")
+    public List<AppEntity> getAllApp() {
+        Sort sort = new Sort(Sort.Direction.ASC, "id");
+        return appRepo.findAll(sort);
+    }
 
 }

+ 85 - 89
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/Auth2Controller.java

@@ -1,18 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PathVariable;
-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 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.core.basic.base.enums.AccountType;
@@ -23,7 +10,15 @@ import cn.com.qmth.examcloud.core.basic.service.bean.LoginInfo;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import cn.com.qmth.examcloud.web.support.Naked;
 import cn.com.qmth.examcloud.web.support.WithoutStackTrace;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 废弃登陆. 保留原因:第三方接口鉴权
@@ -33,92 +28,93 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "登录相关接口")
 @RequestMapping("/api/ecs_core/user")
 public class Auth2Controller extends ControllerSupport {
 
-	@Autowired
-	UserRepo userRepo;
+    @Autowired
+    UserRepo userRepo;
 
-	@Autowired
-	AuthService authService;
+    @Autowired
+    AuthService authService;
 
-	/**
-	 * 系统遗留,谨慎修改
-	 *
-	 * @author WANGWEI
-	 * @param loginName
-	 * @return
-	 */
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "登录1", notes = "登录")
-	@PostMapping("/login")
-	public Map<String, Object> login1(@RequestParam String loginName,
-			@RequestParam(required = false) Long rootOrgId) {
-		String password = getRequiredStringParam("password");
-		return login(loginName, password, rootOrgId);
-	}
+    /**
+     * 系统遗留,谨慎修改
+     *
+     * @param loginName
+     * @return
+     * @author WANGWEI
+     */
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "登录1", notes = "登录")
+    @PostMapping("/login")
+    public Map<String, Object> login1(@RequestParam String loginName,
+                                      @RequestParam(required = false) Long rootOrgId) {
+        String password = getRequiredStringParam("password");
+        return login(loginName, password, rootOrgId);
+    }
 
-	/**
-	 * 系统遗留,谨慎修改
-	 *
-	 * @author WANGWEI
-	 * @param rootOrgId
-	 * @param loginName
-	 */
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "登录2", notes = "登录")
-	@PostMapping("/login/{rootOrgId}")
-	public Map<String, Object> login2(@PathVariable long rootOrgId,
-			@RequestParam String loginName) {
-		String password = getRequiredStringParam("password");
-		return login(loginName, password, rootOrgId);
-	}
+    /**
+     * 系统遗留,谨慎修改
+     *
+     * @param rootOrgId
+     * @param loginName
+     * @author WANGWEI
+     */
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "登录2", notes = "登录")
+    @PostMapping("/login/{rootOrgId}")
+    public Map<String, Object> login2(@PathVariable long rootOrgId,
+                                      @RequestParam String loginName) {
+        String password = getRequiredStringParam("password");
+        return login(loginName, password, rootOrgId);
+    }
 
-	/**
-	 * 废弃的登陆
-	 *
-	 * @author WANGWEI
-	 * @param loginName
-	 * @param password
-	 * @param rootOrgId
-	 * @return
-	 */
-	private Map<String, Object> login(String loginName, String password, Long rootOrgId) {
+    /**
+     * 废弃的登陆
+     *
+     * @param loginName
+     * @param password
+     * @param rootOrgId
+     * @return
+     * @author WANGWEI
+     */
+    private Map<String, Object> login(String loginName, String password, Long rootOrgId) {
 
-		UserEntity user = null;
-		if (null != rootOrgId) {
-			user = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
-		} else {
-			List<UserEntity> userList = userRepo.findByLoginName(loginName);
-			if (CollectionUtils.isNotEmpty(userList)) {
-				user = null;
-			}
-			if (1 == userList.size()) {
-				user = userList.get(0);
-			} else if (1 < userList.size()) {
-				throw new StatusException("001003", "不同顶级机构下存在相同登录名");
-			}
-		}
+        UserEntity user = null;
+        if (null != rootOrgId) {
+            user = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
+        } else {
+            List<UserEntity> userList = userRepo.findByLoginName(loginName);
+            if (CollectionUtils.isNotEmpty(userList)) {
+                user = null;
+            }
+            if (1 == userList.size()) {
+                user = userList.get(0);
+            } else if (1 < userList.size()) {
+                throw new StatusException("001003", "不同顶级机构下存在相同登录名");
+            }
+        }
 
-		if (user == null) {
-			throw new StatusException("001001", "该用户不存在");
-		} else if (!user.getEnable()) {
-			throw new StatusException("001002", "该用户被禁用");
-		}
+        if (user == null) {
+            throw new StatusException("001001", "该用户不存在");
+        } else if (!user.getEnable()) {
+            throw new StatusException("001002", "该用户被禁用");
+        }
 
-		LoginInfo loginInfo = new LoginInfo();
-		loginInfo.setAccountType(AccountType.COMMON_LOGIN_NAME.name());
-		loginInfo.setAccountValue(user.getLoginName());
-		loginInfo.setPassword(password);
-		loginInfo.setRootOrgId(user.getRootOrgId());
-		User loginUser = authService.login(loginInfo, false);
+        LoginInfo loginInfo = new LoginInfo();
+        loginInfo.setAccountType(AccountType.COMMON_LOGIN_NAME.name());
+        loginInfo.setAccountValue(user.getLoginName());
+        loginInfo.setPassword(password);
+        loginInfo.setRootOrgId(user.getRootOrgId());
+        User loginUser = authService.login(loginInfo, false);
 
-		Map<String, Object> ret = Maps.newHashMap();
-		ret.put("userId", loginUser.getUserId());
-		ret.put("token", loginUser.getKey() + ":" + loginUser.getToken());
-		return ret;
-	}
+        Map<String, Object> ret = Maps.newHashMap();
+        ret.put("userId", loginUser.getUserId());
+        ret.put("token", loginUser.getKey() + ":" + loginUser.getToken());
+        return ret;
+    }
 
 }

+ 196 - 188
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/AuthController.java

@@ -1,15 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import javax.servlet.http.HttpServletRequest;
-
-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.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
@@ -22,20 +12,24 @@ import cn.com.qmth.examcloud.core.basic.service.bean.LoginInfo;
 import cn.com.qmth.examcloud.core.basic.service.cache.StudentCache;
 import cn.com.qmth.examcloud.reports.commons.bean.OnlineStudentReport;
 import cn.com.qmth.examcloud.reports.commons.bean.OnlineUserReport;
+import cn.com.qmth.examcloud.reports.commons.bean.OperateReport;
+import cn.com.qmth.examcloud.reports.commons.enums.OperateContent;
 import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
-import cn.com.qmth.examcloud.web.support.ApiId;
-import cn.com.qmth.examcloud.web.support.ControllerSupport;
-import cn.com.qmth.examcloud.web.support.Naked;
-import cn.com.qmth.examcloud.web.support.StatusResponseX;
-import cn.com.qmth.examcloud.web.support.WithoutStackTrace;
+import cn.com.qmth.examcloud.web.support.*;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
 
 /**
  * {@link StatusException} 状态码范围:002XXX<br>
  * {@link ApiId}范围: 200-299<br>
- *
+ * <p>
  * 鉴权
  *
  * @author WANGWEI
@@ -43,180 +37,194 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "登录相关接口")
 @RequestMapping("${$rmp.ctr.basic}/" + "auth")
 public class AuthController extends ControllerSupport {
 
-	@Autowired
-	AuthService authService;
-
-	@Autowired
-	RedisClient redisClient;
-
-	@Autowired
-	SmsCodeService smsCodeService;
-
-	@Autowired
-	StudentRepo studentRepo;
-
-	@Autowired
-	StudentService studentService;
-
-	@Autowired
-	StudentCache studentCache;
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "登入", notes = "")
-	@PostMapping("login")
-	public Object login(@RequestBody LoginInfo loginInfo, HttpServletRequest request) {
-
-		Boolean alwaysOK = loginInfo.getAlwaysOK();
-		if (null != alwaysOK && alwaysOK) {
-			setAlwaysOKResponse();
-		}
-
-		trim(loginInfo, false);
-
-		String realIp = request.getHeader("x-forwarded-for");
-		if (StringUtils.isBlank(realIp)) {
-			realIp = request.getHeader("x-real-ip");
-		}
-		if (StringUtils.isNotBlank(realIp)) {
-			loginInfo.setClientIp(realIp);
-		} else {
-			loginInfo.setClientIp(null);
-		}
-
-		User user = authService.login(loginInfo, true);
-		// 在线数据打点 start
-		if (UserType.STUDENT.equals(user.getUserType())) {
-			// 在线学生登录打点
-			ReportsUtil.report(new OnlineStudentReport(user.getRootOrgId(), user.getUserId()));
-		} else if (UserType.COMMON.equals(user.getUserType())) {
-			// 在线用户登录打点
-			ReportsUtil.report(new OnlineUserReport(user.getRootOrgId(), user.getUserId()));
-		}
-		// 在线数据打点 end
-		if (null != alwaysOK && alwaysOK) {
-			return new StatusResponseX<User>(user);
-		} else {
-			return user;
-		}
-	}
-
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "登出", notes = "")
-	@PostMapping("logout")
-	public void logout() {
-		User user = getAccessUser();
-		authService.logout(user);
-	}
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "获取登录用户", notes = "")
-	@PostMapping("getLoginUser")
-	public User getLoginUser(@RequestParam String key, @RequestParam String token) {
-
-		if (StringUtils.isBlank(key)) {
-			throw new StatusException("001009", "key is blank");
-		}
-		if (StringUtils.isBlank(token)) {
-			throw new StatusException("001010", "token is blank");
-		}
-
-		return authService.getLoginUser(key, token);
-	}
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "第三方普通用户接入", notes = "")
-	@PostMapping("/thirdPartyAccess")
-	public User thirdPartyCommonUserAccess(HttpServletRequest request, @RequestParam Long orgId,
-			@RequestParam String loginName, @RequestParam String appId,
-			@RequestParam String timestamp, @RequestParam String token) {
-		String realIp = request.getHeader("x-forwarded-for");
-		if (StringUtils.isBlank(realIp)) {
-			realIp = request.getHeader("x-real-ip");
-		}
-		return authService.thirdPartyCommonUserAccess(orgId, loginName, appId, timestamp, token,
-				realIp);
-	}
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "第三方学生接入", notes = "")
-	@PostMapping("/thirdPartyStudentAccess")
-	public User thirdPartyStudentAccess(HttpServletRequest request, @RequestParam Long rootOrgId,
-			@RequestParam String accountType, @RequestParam String accountValue,
-			@RequestParam String appId, @RequestParam String timestamp,
-			@RequestParam String token) {
-		String realIp = request.getHeader("x-forwarded-for");
-		if (StringUtils.isBlank(realIp)) {
-			realIp = request.getHeader("x-real-ip");
-		}
-		return authService.thirdPartyStudentAccess(rootOrgId, accountType, accountValue, appId,
-				timestamp, token, realIp);
-	}
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "发送验证码", notes = "")
-	@PostMapping("sendVerificationCode4Student")
-	public void sendVerificationCode4Student(@RequestParam(required = true) String phone,
-			@RequestParam(required = true) Boolean bound) {
-
-		Boolean hasBeBound = studentService.hasBeBound(phone);
-		if (bound && !hasBeBound) {
-			throw new StatusException("002050", "手机号未被关联");
-		} else if ((!bound) && hasBeBound) {
-			throw new StatusException("002050", "手机号已被关联");
-		}
-
-		smsCodeService.sendSmsCode(phone);
-	}
-
-	@Naked
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "发送验证码", notes = "")
-	@PostMapping("/sendVerificationCode")
-	public void sendVerificationCode(@RequestParam String phone) {
-		smsCodeService.sendSmsCode(phone);
-	}
-
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "校验验证码", notes = "")
-	@PostMapping("/checkVerificationCode")
-	public void checkVerificationCode(@RequestParam String phone,
-			@RequestParam String verificationCode) {
-		smsCodeService.checkSmsCode(phone, verificationCode);
-	}
-
-	@WithoutStackTrace(true)
-	@ApiOperation(value = "学生绑定手机号", notes = "")
-	@PostMapping("/bindSecurityPhone")
-	public void bindStudentSecurityPhone(@RequestParam String phone,
-			@RequestParam String verificationCode) {
-
-		smsCodeService.checkSmsCode(phone, verificationCode);
-
-		User accessUser = getAccessUser();
-		Long studentId = accessUser.getUserId();
-
-		StudentEntity sb = studentRepo.findBySecurityPhone(phone);
-		if (null != sb) {
-			if (!sb.getId().equals(studentId)) {
-				throw new StatusException("001052", "手机号已被其他用户绑定,请更换手机号");
-			} else {
-				throw new StatusException("001053", "手机号已绑定成功,无需重复绑定");
-			}
-		}
-
-		StudentEntity s = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
-		s.setSecurityPhone(phone);
-		StudentEntity saved = studentRepo.saveAndFlush(s);
-
-		studentCache.remove(saved.getId());
-	}
+    @Autowired
+    AuthService authService;
+
+    @Autowired
+    RedisClient redisClient;
+
+    @Autowired
+    SmsCodeService smsCodeService;
+
+    @Autowired
+    StudentRepo studentRepo;
+
+    @Autowired
+    StudentService studentService;
+
+    @Autowired
+    StudentCache studentCache;
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "登入", notes = "")
+    @PostMapping("login")
+    public Object login(@RequestBody LoginInfo loginInfo, HttpServletRequest request) {
+
+        Boolean alwaysOK = loginInfo.getAlwaysOK();
+        if (null != alwaysOK && alwaysOK) {
+            setAlwaysOKResponse();
+        }
+
+        trim(loginInfo, false);
+
+        String realIp = request.getHeader("x-forwarded-for");
+        if (StringUtils.isBlank(realIp)) {
+            realIp = request.getHeader("x-real-ip");
+        }
+        if (StringUtils.isNotBlank(realIp)) {
+            loginInfo.setClientIp(realIp);
+        } else {
+            loginInfo.setClientIp(null);
+        }
+
+        User user;
+
+        String isApp = request.getHeader("isApp");
+        if (StringUtils.isNotEmpty(isApp) && "true".equals(isApp)) {
+            log.info("App login ... " + loginInfo.getAccountValue());
+            user = authService.login(loginInfo, false);
+        } else {
+            user = authService.login(loginInfo, true);
+        }
+
+        // 在线数据打点 start
+        if (UserType.STUDENT.equals(user.getUserType())) {
+            //操作日志
+            ReportsUtil.report(new OperateReport(user.getRootOrgId(), user.getUserId(), user.getUserId(), null, UserType.STUDENT, OperateContent.STUDENT_LOGIN.getDesc()));
+
+            // 在线学生登录打点
+            ReportsUtil.report(new OnlineStudentReport(user.getRootOrgId(), user.getUserId()));
+        } else if (UserType.COMMON.equals(user.getUserType())) {
+            // 在线用户登录打点
+            ReportsUtil.report(new OnlineUserReport(user.getRootOrgId(), user.getUserId()));
+        }
+
+        // 在线数据打点 end
+        if (null != alwaysOK && alwaysOK) {
+            return new StatusResponseX<User>(user);
+        } else {
+            return user;
+        }
+    }
+
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "登出", notes = "")
+    @PostMapping("logout")
+    public void logout() {
+        User user = getAccessUser();
+        authService.logout(user);
+    }
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "获取登录用户", notes = "")
+    @PostMapping("getLoginUser")
+    public User getLoginUser(@RequestParam String key, @RequestParam String token) {
+
+        if (StringUtils.isBlank(key)) {
+            throw new StatusException("001009", "key is blank");
+        }
+        if (StringUtils.isBlank(token)) {
+            throw new StatusException("001010", "token is blank");
+        }
+
+        return authService.getLoginUser(key, token);
+    }
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "第三方普通用户接入", notes = "")
+    @PostMapping("/thirdPartyAccess")
+    public User thirdPartyCommonUserAccess(HttpServletRequest request, @RequestParam Long orgId,
+                                           @RequestParam String loginName, @RequestParam String appId,
+                                           @RequestParam String timestamp, @RequestParam String token) {
+        String realIp = request.getHeader("x-forwarded-for");
+        if (StringUtils.isBlank(realIp)) {
+            realIp = request.getHeader("x-real-ip");
+        }
+        return authService.thirdPartyCommonUserAccess(orgId, loginName, appId, timestamp, token,
+                realIp);
+    }
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "第三方学生接入", notes = "")
+    @PostMapping("/thirdPartyStudentAccess")
+    public User thirdPartyStudentAccess(HttpServletRequest request, @RequestParam Long rootOrgId,
+                                        @RequestParam String accountType, @RequestParam String accountValue,
+                                        @RequestParam String appId, @RequestParam String timestamp,
+                                        @RequestParam String token) {
+        String realIp = request.getHeader("x-forwarded-for");
+        if (StringUtils.isBlank(realIp)) {
+            realIp = request.getHeader("x-real-ip");
+        }
+        return authService.thirdPartyStudentAccess(rootOrgId, accountType, accountValue, appId,
+                timestamp, token, realIp);
+    }
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "发送验证码", notes = "")
+    @PostMapping("sendVerificationCode4Student")
+    public void sendVerificationCode4Student(@RequestParam(required = true) String phone,
+                                             @RequestParam(required = true) Boolean bound) {
+
+        Boolean hasBeBound = studentService.hasBeBound(phone);
+        if (bound && !hasBeBound) {
+            throw new StatusException("002050", "手机号未被关联");
+        } else if ((!bound) && hasBeBound) {
+            throw new StatusException("002050", "手机号已被关联");
+        }
+
+        smsCodeService.sendSmsCode(phone);
+    }
+
+    @Naked
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "发送验证码", notes = "")
+    @PostMapping("/sendVerificationCode")
+    public void sendVerificationCode(@RequestParam String phone) {
+        smsCodeService.sendSmsCode(phone);
+    }
+
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "校验验证码", notes = "")
+    @PostMapping("/checkVerificationCode")
+    public void checkVerificationCode(@RequestParam String phone,
+                                      @RequestParam String verificationCode) {
+        smsCodeService.checkSmsCode(phone, verificationCode);
+    }
+
+    @WithoutStackTrace(true)
+    @ApiOperation(value = "学生绑定手机号", notes = "")
+    @PostMapping("/bindSecurityPhone")
+    public void bindStudentSecurityPhone(@RequestParam String phone,
+                                         @RequestParam String verificationCode) {
+
+        smsCodeService.checkSmsCode(phone, verificationCode);
+
+        User accessUser = getAccessUser();
+        Long studentId = accessUser.getUserId();
+
+        StudentEntity sb = studentRepo.findBySecurityPhone(phone);
+        if (null != sb) {
+            if (!sb.getId().equals(studentId)) {
+                throw new StatusException("001052", "手机号已被其他用户绑定,请更换手机号");
+            } else {
+                throw new StatusException("001053", "手机号已绑定成功,无需重复绑定");
+            }
+        }
+
+        StudentEntity s = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
+        s.setSecurityPhone(phone);
+        StudentEntity saved = studentRepo.saveAndFlush(s);
+
+        studentCache.remove(saved.getId());
+    }
 
 }

+ 494 - 503
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/CourseController.java

@@ -1,43 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.Subquery;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.fileupload.disk.DiskFileItem;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.domain.Sort.Direction;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-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.enums.CourseLevel;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
@@ -55,478 +17,507 @@ import cn.com.qmth.examcloud.task.api.request.SyncCourseReq;
 import cn.com.qmth.examcloud.web.config.SystemProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 课程服务API Created by songyue on 17/1/14.
  */
 @RestController
+@Api(tags = "课程相关接口")
 @RequestMapping("${$rmp.ctr.basic}/course")
 public class CourseController extends ControllerSupport {
 
-	@Autowired
-	CourseRepo courseRepo;
-
-	@Autowired
-	SystemProperties systemConfig;
-
-	@Autowired
-	CourseService courseService;
-
-	@Autowired
-	CourseCloudService courseCloudService;
-
-	@Autowired
-	DataSyncCloudService dataSyncCloudService;
-
-	private static final String[] EXCEL_HEADER = new String[]{"课程名称", "课程代码", "层次(ZSB,GQZ,ALL)"};
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param curPage
-	 * @param pageSize
-	 * @param name
-	 * @param code
-	 * @param level
-	 * @param enable
-	 * @param specialtyId
-	 * @return
-	 */
-	@ApiOperation(value = "分页查询课程")
-	@GetMapping("coursePage/{curPage}/{pageSize}")
-	public Page<CourseEntity> getCoursePage(@PathVariable Integer curPage,
-			@PathVariable Integer pageSize, @RequestParam(required = false) String name,
-			@RequestParam(required = false) String code,
-			@RequestParam(required = false) String level,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long specialtyId) {
-
-		User accessUser = getAccessUser();
-
-		Specification<CourseEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (StringUtils.isNotBlank(code)) {
-				predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
-			}
-			if (StringUtils.isNotBlank(level)) {
-				predicates.add(cb.equal(root.get("level"), CourseLevel.valueOf(level)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != specialtyId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("courseId"));
-				Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
-				Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-				new Sort(Direction.DESC, "updateTime", "id"));
-
-		Page<CourseEntity> page = courseRepo.findAll(specification, pageRequest);
-		return page;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param name
-	 * @param level
-	 * @param enable
-	 * @param specialtyId
-	 * @return
-	 */
-	@ApiOperation(value = "查询课程")
-	@GetMapping("query")
-	public List<CourseEntity> query(@RequestParam(required = false) Long rootOrgId,
-			@RequestParam(required = false) String name,
-			@RequestParam(required = false) String level,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long specialtyId) {
-
-		User accessUser = getAccessUser();
-		if (null == rootOrgId) {
-			rootOrgId = accessUser.getRootOrgId();
-		}
-
-		final Long finalRootOrgId = rootOrgId;
-
-		Specification<CourseEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
-
-			Predicate pr1 = cb.like(root.get("name"), toSqlSearchPattern(name));
-			Predicate pr2 = cb.like(root.get("code"), toSqlSearchPattern(name));
-
-			predicates.add(cb.or(pr1, pr2));
-
-			if (StringUtils.isNotBlank(level)) {
-				predicates.add(cb.equal(root.get("level"), toSqlSearchPattern(level)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != specialtyId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("courseId"));
-				Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
-				Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		PageRequest pageRequest = PageRequest.of(0, 50, new Sort(Direction.DESC, "updateTime"));
-
-		Page<CourseEntity> page = courseRepo.findAll(specification, pageRequest);
-
-		Iterator<CourseEntity> iterator = page.iterator();
-		List<CourseEntity> list = Lists.newArrayList();
-
-		while (iterator.hasNext()) {
-			CourseEntity next = iterator.next();
-
-			CourseEntity bean = new CourseEntity();
-			bean.setCode(next.getCode());
-			bean.setEnable(next.getEnable());
-			bean.setId(next.getId());
-			bean.setLevel(next.getLevel());
-			bean.setName(next.getName());
-			bean.setRootOrgId(next.getRootOrgId());
-
-			list.add(bean);
-		}
-
-		return list;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param id
-	 * @return
-	 */
-	@ApiOperation(value = "按ID查询课程", notes = "ID查询")
-	@GetMapping("{id}")
-	public CourseEntity getCourseById(@PathVariable Long id) {
-		CourseEntity course = GlobalHelper.getEntity(courseRepo, id, CourseEntity.class);
-		if (null == course) {
-			throw new StatusException("540001", "课程不存在");
-		}
-
-		Long rootOrgId = course.getRootOrgId();
-		validateRootOrgIsolation(rootOrgId);
-		return course;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param rootOrgId
-	 * @param code
-	 * @return
-	 */
-	@ApiOperation(value = "按code查询课程", notes = "code查询")
-	@GetMapping("byCode")
-	public CourseEntity getCourseByCode(@RequestParam Long rootOrgId, @RequestParam String code) {
-		validateRootOrgIsolation(rootOrgId);
-
-		CourseEntity course = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
-		if (null == course) {
-			throw new StatusException("540001", "课程不存在");
-		}
-
-		return course;
-	}
-
-	/**
-	 * 修正
-	 *
-	 * @author WANGWEI
-	 * @param domain
-	 * @return
-	 */
-	@ApiOperation(value = "新增课程", notes = "新增")
-	@PostMapping
-	@Transactional
-	public Long addCourse(@RequestBody CourseDomain domain) {
-		trim(domain, true);
-
-		User accessUser = getAccessUser();
-		Long rootOrgId = accessUser.getRootOrgId();
-
-		String code = domain.getCode();
-		String name = domain.getName();
-		if (StringUtils.isBlank(code)) {
-			throw new StatusException("620001", "课程编码不能为空");
-		}
-		if (StringUtils.isBlank(name)) {
-			throw new StatusException("620002", "课程名称不能为空");
-		}
-		if (name.length() > 50) {
-			throw new StatusException("620003", "课程名称不能超过50个字符");
-		}
-		CourseEntity course = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
-		if (null != course) {
-			throw new StatusException("620002", "课程编码已被占用");
-		}
-
-		CourseInfo info = new CourseInfo();
-		info.setRootOrgId(rootOrgId);
-		info.setCode(domain.getCode());
-		info.setEnable(domain.getEnable());
-		info.setId(domain.getId());
-		info.setLevel(domain.getLevel());
-		info.setName(domain.getName());
-
-		CourseEntity saved = courseService.saveCourse(info);
-		return saved.getId();
-	}
-
-	/**
-	 * 修正
-	 *
-	 * @author WANGWEI
-	 * @param domain
-	 * @return
-	 */
-	@ApiOperation(value = "更新课程", notes = "更新")
-	@PutMapping
-	@Transactional
-	public Long updateCourse(@RequestBody CourseDomain domain) {
-		trim(domain, true);
-
-		User accessUser = getAccessUser();
-		Long rootOrgId = accessUser.getRootOrgId();
-
-		String code = domain.getCode();
-		String name = domain.getName();
-		if (StringUtils.isBlank(code)) {
-			throw new StatusException("620001", "课程编码不能为空");
-		}
-		if (StringUtils.isBlank(name)) {
-			throw new StatusException("620002", "课程名称不能为空");
-		}
-		if (name.length() > 50) {
-			throw new StatusException("620003", "课程名称不能超过50个字符");
-		}
-
-		CourseInfo info = new CourseInfo();
-		info.setRootOrgId(rootOrgId);
-		info.setCode(domain.getCode());
-		info.setEnable(domain.getEnable());
-		info.setId(domain.getId());
-		info.setLevel(domain.getLevel());
-		info.setName(domain.getName());
-
-		CourseEntity saved = courseService.saveCourse(info);
-		return saved.getId();
-	}
-
-	@ApiOperation(value = "删除课程", notes = "删除")
-	@DeleteMapping("{ids}")
-	@Transactional
-	public void deleteCourse(@PathVariable String ids) {
-		List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-		for (Long courseId : courseIds) {
-			CourseEntity one = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
-			if (null == one) {
-				continue;
-			}
-			validateRootOrgIsolation(one.getRootOrgId());
-			courseRepo.delete(one);
-		}
-	}
-
-	@ApiOperation(value = "下载导入模板", notes = "下载导入模板")
-	@GetMapping("importTemplate")
-	public void getImportTemplate(HttpServletResponse response) {
-		String resoucePath = PathUtil.getResoucePath("templates/courseImportTemplate.xlsx");
-		exportFile("课程导入模板.xlsx", new File(resoucePath));
-	}
-
-	@ApiOperation(value = "导入课程", notes = "导入")
-	@PostMapping("import")
-	@Transactional
-	public Map<String, Object> importCourse(@RequestParam CommonsMultipartFile file) {
-		DiskFileItem item = (DiskFileItem) file.getFileItem();
-		File storeLocation = item.getStoreLocation();
-		List<Map<String, Object>> failRecords = courseService.importCourse(getRootOrgId(),
-				storeLocation);
-		Map<String, Object> map = Maps.newHashMap();
-		map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
-		map.put("failRecords", failRecords);
-		return map;
-	}
-
-	@ApiOperation(value = "导出课程", notes = "导出")
-	@GetMapping("export")
-	public void export(@RequestParam(required = false) String name,
-			@RequestParam(required = false) String code,
-			@RequestParam(required = false) String level,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long specialtyId) {
-
-		User accessUser = getAccessUser();
-
-		Specification<CourseEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (StringUtils.isNotBlank(code)) {
-				predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
-			}
-			if (StringUtils.isNotBlank(level)) {
-				predicates.add(cb.equal(root.get("level"), CourseLevel.valueOf(level)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != specialtyId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("courseId"));
-				Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
-				Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		long count = courseRepo.count(specification);
-		if (100000 < count) {
-			throw new StatusException("620200", "数据量过大,无法导出");
-		}
-
-		List<CourseEntity> list = courseRepo.findAll(specification);
-
-		List<Object[]> datas = Lists.newArrayList();
-
-		for (CourseEntity cur : list) {
-			datas.add(new Object[]{cur.getName(), cur.getCode(), cur.getLevel().getName()});
-		}
-
-		String filePath = systemConfig.getTempDataDir() + File.separator
-				+ System.currentTimeMillis() + ".xlsx";
-		File file = new File(filePath);
-
-		ExcelWriter.write(EXCEL_HEADER, new Class[]{String.class, String.class, String.class},
-				datas, new File(filePath));
-
-		exportFile("课程列表-" + getRootOrgId() + ".xlsx", file);
-
-		FileUtils.deleteQuietly(file);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param ids
-	 * @return
-	 */
-	@ApiOperation(value = "禁用课程", notes = "禁用")
-	@PutMapping("disable/{ids}")
-	@Transactional
-	public List<Long> disableCourse(@PathVariable String ids) {
-		List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-
-		List<CourseEntity> savedList = Lists.newArrayList();
-		for (Long courseId : courseIds) {
-			CourseEntity course = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
-			course.setEnable(false);
-			CourseEntity saved = courseRepo.saveAndFlush(course);
-			savedList.add(saved);
-		}
-
-		for (CourseEntity ce : savedList) {
-			SyncCourseReq req = new SyncCourseReq();
-			req.setCode(ce.getCode());
-			req.setEnable(ce.getEnable());
-			req.setId(ce.getId());
-			req.setLevel(ce.getLevel().name());
-			req.setName(ce.getName());
-			req.setRootOrgId(ce.getRootOrgId());
-			req.setSyncType("update");
-			dataSyncCloudService.syncCourse(req);
-		}
-
-		return courseIds;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param ids
-	 * @return
-	 */
-	@ApiOperation(value = "启用课程", notes = "启用")
-	@PutMapping("enable/{ids}")
-	@Transactional
-	public List<Long> enableCourse(@PathVariable String ids) {
-		List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-
-		List<CourseEntity> savedList = Lists.newArrayList();
-		for (Long courseId : courseIds) {
-			CourseEntity course = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
-			course.setEnable(true);
-			CourseEntity saved = courseRepo.saveAndFlush(course);
-			savedList.add(saved);
-		}
-
-		for (CourseEntity ce : savedList) {
-			SyncCourseReq req = new SyncCourseReq();
-			req.setCode(ce.getCode());
-			req.setEnable(ce.getEnable());
-			req.setId(ce.getId());
-			req.setLevel(ce.getLevel().name());
-			req.setName(ce.getName());
-			req.setRootOrgId(ce.getRootOrgId());
-			req.setSyncType("update");
-			dataSyncCloudService.syncCourse(req);
-		}
-
-		return courseIds;
-	}
+    @Autowired
+    CourseRepo courseRepo;
+
+    @Autowired
+    SystemProperties systemConfig;
+
+    @Autowired
+    CourseService courseService;
+
+    @Autowired
+    CourseCloudService courseCloudService;
+
+    @Autowired
+    DataSyncCloudService dataSyncCloudService;
+
+    private static final String[] EXCEL_HEADER = new String[]{"课程名称", "课程代码", "层次(ZSB,GQZ,ALL)"};
+
+    /**
+     * 方法注释
+     *
+     * @param curPage
+     * @param pageSize
+     * @param name
+     * @param code
+     * @param level
+     * @param enable
+     * @param specialtyId
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "分页查询课程")
+    @GetMapping("coursePage/{curPage}/{pageSize}")
+    public Page<CourseEntity> getCoursePage(@PathVariable Integer curPage,
+                                            @PathVariable Integer pageSize, @RequestParam(required = false) String name,
+                                            @RequestParam(required = false) String code,
+                                            @RequestParam(required = false) String level,
+                                            @RequestParam(required = false) Boolean enable,
+                                            @RequestParam(required = false) Long specialtyId) {
+
+        User accessUser = getAccessUser();
+
+        Specification<CourseEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (StringUtils.isNotBlank(code)) {
+                predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
+            }
+            if (StringUtils.isNotBlank(level)) {
+                predicates.add(cb.equal(root.get("level"), CourseLevel.valueOf(level)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != specialtyId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("courseId"));
+                Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
+                Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        PageRequest pageRequest = PageRequest.of(curPage, pageSize,
+                new Sort(Direction.DESC, "updateTime", "id"));
+
+        Page<CourseEntity> page = courseRepo.findAll(specification, pageRequest);
+        return page;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param name
+     * @param level
+     * @param enable
+     * @param specialtyId
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "查询课程")
+    @GetMapping("query")
+    public List<CourseEntity> query(@RequestParam(required = false) Long rootOrgId,
+                                    @RequestParam(required = false) String name,
+                                    @RequestParam(required = false) String level,
+                                    @RequestParam(required = false) Boolean enable,
+                                    @RequestParam(required = false) Long specialtyId) {
+
+        User accessUser = getAccessUser();
+        if (null == rootOrgId) {
+            rootOrgId = accessUser.getRootOrgId();
+        }
+
+        final Long finalRootOrgId = rootOrgId;
+
+        Specification<CourseEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
+
+            Predicate pr1 = cb.like(root.get("name"), toSqlSearchPattern(name));
+            Predicate pr2 = cb.like(root.get("code"), toSqlSearchPattern(name));
+
+            predicates.add(cb.or(pr1, pr2));
+
+            if (StringUtils.isNotBlank(level)) {
+                predicates.add(cb.equal(root.get("level"), toSqlSearchPattern(level)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != specialtyId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("courseId"));
+                Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
+                Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        PageRequest pageRequest = PageRequest.of(0, 50, new Sort(Direction.DESC, "updateTime"));
+
+        Page<CourseEntity> page = courseRepo.findAll(specification, pageRequest);
+
+        Iterator<CourseEntity> iterator = page.iterator();
+        List<CourseEntity> list = Lists.newArrayList();
+
+        while (iterator.hasNext()) {
+            CourseEntity next = iterator.next();
+
+            CourseEntity bean = new CourseEntity();
+            bean.setCode(next.getCode());
+            bean.setEnable(next.getEnable());
+            bean.setId(next.getId());
+            bean.setLevel(next.getLevel());
+            bean.setName(next.getName());
+            bean.setRootOrgId(next.getRootOrgId());
+
+            list.add(bean);
+        }
+
+        return list;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param id
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按ID查询课程", notes = "ID查询")
+    @GetMapping("{id}")
+    public CourseEntity getCourseById(@PathVariable Long id) {
+        CourseEntity course = GlobalHelper.getEntity(courseRepo, id, CourseEntity.class);
+        if (null == course) {
+            throw new StatusException("540001", "课程不存在");
+        }
+
+        Long rootOrgId = course.getRootOrgId();
+        validateRootOrgIsolation(rootOrgId);
+        return course;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param rootOrgId
+     * @param code
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按code查询课程", notes = "code查询")
+    @GetMapping("byCode")
+    public CourseEntity getCourseByCode(@RequestParam Long rootOrgId, @RequestParam String code) {
+        validateRootOrgIsolation(rootOrgId);
+
+        CourseEntity course = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
+        if (null == course) {
+            throw new StatusException("540001", "课程不存在");
+        }
+
+        return course;
+    }
+
+    /**
+     * 修正
+     *
+     * @param domain
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "新增课程", notes = "新增")
+    @PostMapping
+    @Transactional
+    public Long addCourse(@RequestBody CourseDomain domain) {
+        trim(domain, true);
+
+        User accessUser = getAccessUser();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        String code = domain.getCode();
+        String name = domain.getName();
+        if (StringUtils.isBlank(code)) {
+            throw new StatusException("620001", "课程编码不能为空");
+        }
+        if (StringUtils.isBlank(name)) {
+            throw new StatusException("620002", "课程名称不能为空");
+        }
+        if (name.length() > 50) {
+            throw new StatusException("620003", "课程名称不能超过50个字符");
+        }
+        CourseEntity course = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
+        if (null != course) {
+            throw new StatusException("620002", "课程编码已被占用");
+        }
+
+        CourseInfo info = new CourseInfo();
+        info.setRootOrgId(rootOrgId);
+        info.setCode(domain.getCode());
+        info.setEnable(domain.getEnable());
+        info.setId(domain.getId());
+        info.setLevel(domain.getLevel());
+        info.setName(domain.getName());
+
+        CourseEntity saved = courseService.saveCourse(info);
+        return saved.getId();
+    }
+
+    /**
+     * 修正
+     *
+     * @param domain
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "更新课程", notes = "更新")
+    @PutMapping
+    @Transactional
+    public Long updateCourse(@RequestBody CourseDomain domain) {
+        trim(domain, true);
+
+        User accessUser = getAccessUser();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        String code = domain.getCode();
+        String name = domain.getName();
+        if (StringUtils.isBlank(code)) {
+            throw new StatusException("620001", "课程编码不能为空");
+        }
+        if (StringUtils.isBlank(name)) {
+            throw new StatusException("620002", "课程名称不能为空");
+        }
+        if (name.length() > 50) {
+            throw new StatusException("620003", "课程名称不能超过50个字符");
+        }
+
+        CourseInfo info = new CourseInfo();
+        info.setRootOrgId(rootOrgId);
+        info.setCode(domain.getCode());
+        info.setEnable(domain.getEnable());
+        info.setId(domain.getId());
+        info.setLevel(domain.getLevel());
+        info.setName(domain.getName());
+
+        CourseEntity saved = courseService.saveCourse(info);
+        return saved.getId();
+    }
+
+    @ApiOperation(value = "删除课程", notes = "删除")
+    @DeleteMapping("{ids}")
+    @Transactional
+    public void deleteCourse(@PathVariable String ids) {
+        List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+        for (Long courseId : courseIds) {
+            CourseEntity one = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
+            if (null == one) {
+                continue;
+            }
+            validateRootOrgIsolation(one.getRootOrgId());
+            courseRepo.delete(one);
+        }
+    }
+
+    @ApiOperation(value = "下载导入模板", notes = "下载导入模板")
+    @GetMapping("importTemplate")
+    public void getImportTemplate(HttpServletResponse response) {
+        String resoucePath = PathUtil.getResoucePath("templates/courseImportTemplate.xlsx");
+        exportFile("课程导入模板.xlsx", new File(resoucePath));
+    }
+
+    @ApiOperation(value = "导入课程", notes = "导入")
+    @PostMapping("import")
+    @Transactional
+    public Map<String, Object> importCourse(@RequestParam CommonsMultipartFile file) {
+        DiskFileItem item = (DiskFileItem) file.getFileItem();
+        File storeLocation = item.getStoreLocation();
+        List<Map<String, Object>> failRecords = courseService.importCourse(getRootOrgId(),
+                storeLocation);
+        Map<String, Object> map = Maps.newHashMap();
+        map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
+        map.put("failRecords", failRecords);
+        return map;
+    }
+
+    @ApiOperation(value = "导出课程", notes = "导出")
+    @GetMapping("export")
+    public void export(@RequestParam(required = false) String name,
+                       @RequestParam(required = false) String code,
+                       @RequestParam(required = false) String level,
+                       @RequestParam(required = false) Boolean enable,
+                       @RequestParam(required = false) Long specialtyId) {
+
+        User accessUser = getAccessUser();
+
+        Specification<CourseEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (StringUtils.isNotBlank(code)) {
+                predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
+            }
+            if (StringUtils.isNotBlank(level)) {
+                predicates.add(cb.equal(root.get("level"), CourseLevel.valueOf(level)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != specialtyId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("courseId"));
+                Predicate p1 = cb.equal(subRoot.get("specialtyId"), specialtyId);
+                Predicate p2 = cb.equal(subRoot.get("courseId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        long count = courseRepo.count(specification);
+        if (100000 < count) {
+            throw new StatusException("620200", "数据量过大,无法导出");
+        }
+
+        List<CourseEntity> list = courseRepo.findAll(specification);
+
+        List<Object[]> datas = Lists.newArrayList();
+
+        for (CourseEntity cur : list) {
+            datas.add(new Object[]{cur.getName(), cur.getCode(), cur.getLevel().getName()});
+        }
+
+        String filePath = systemConfig.getTempDataDir() + File.separator
+                + System.currentTimeMillis() + ".xlsx";
+        File file = new File(filePath);
+
+        ExcelWriter.write(EXCEL_HEADER, new Class[]{String.class, String.class, String.class},
+                datas, new File(filePath));
+
+        exportFile("课程列表-" + getRootOrgId() + ".xlsx", file);
+
+        FileUtils.deleteQuietly(file);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param ids
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "禁用课程", notes = "禁用")
+    @PutMapping("disable/{ids}")
+    @Transactional
+    public List<Long> disableCourse(@PathVariable String ids) {
+        List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+
+        List<CourseEntity> savedList = Lists.newArrayList();
+        for (Long courseId : courseIds) {
+            CourseEntity course = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
+            course.setEnable(false);
+            CourseEntity saved = courseRepo.saveAndFlush(course);
+            savedList.add(saved);
+        }
+
+        for (CourseEntity ce : savedList) {
+            SyncCourseReq req = new SyncCourseReq();
+            req.setCode(ce.getCode());
+            req.setEnable(ce.getEnable());
+            req.setId(ce.getId());
+            req.setLevel(ce.getLevel().name());
+            req.setName(ce.getName());
+            req.setRootOrgId(ce.getRootOrgId());
+            req.setSyncType("update");
+            dataSyncCloudService.syncCourse(req);
+        }
+
+        return courseIds;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param ids
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "启用课程", notes = "启用")
+    @PutMapping("enable/{ids}")
+    @Transactional
+    public List<Long> enableCourse(@PathVariable String ids) {
+        List<Long> courseIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+
+        List<CourseEntity> savedList = Lists.newArrayList();
+        for (Long courseId : courseIds) {
+            CourseEntity course = GlobalHelper.getEntity(courseRepo, courseId, CourseEntity.class);
+            course.setEnable(true);
+            CourseEntity saved = courseRepo.saveAndFlush(course);
+            savedList.add(saved);
+        }
+
+        for (CourseEntity ce : savedList) {
+            SyncCourseReq req = new SyncCourseReq();
+            req.setCode(ce.getCode());
+            req.setEnable(ce.getEnable());
+            req.setId(ce.getId());
+            req.setLevel(ce.getLevel().name());
+            req.setName(ce.getName());
+            req.setRootOrgId(ce.getRootOrgId());
+            req.setSyncType("update");
+            dataSyncCloudService.syncCourse(req);
+        }
+
+        return courseIds;
+    }
 }

+ 85 - 88
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/CourseSpeciatlyRelationController.java

@@ -1,13 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-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 cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.dao.CourseRepo;
@@ -19,120 +11,125 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.CourseSpeciatlyRelationPK;
 import cn.com.qmth.examcloud.core.basic.dao.entity.SpecialtyEntity;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
 
 /**
- * @Description 课程专业关联API
  * @author Administrator
+ * @Description 课程专业关联API
  * @Date 2017年8月8号
  */
 @RestController
+@Api(tags = "课程专业相关接口")
 @RequestMapping("${$rmp.ctr.basic}/courseSpeciatlyRelation")
 public class CourseSpeciatlyRelationController extends ControllerSupport {
 
-	@Autowired
-	CourseSpeciatlyRelationRepo courseSpeciatlyRelationRepo;
+    @Autowired
+    CourseSpeciatlyRelationRepo courseSpeciatlyRelationRepo;
 
-	@Autowired
-	CourseRepo courseRepo;
+    @Autowired
+    CourseRepo courseRepo;
 
-	@Autowired
-	SpecialtyRepo specialtyRepo;
+    @Autowired
+    SpecialtyRepo specialtyRepo;
 
-	@ApiOperation(value = "新增关联课程专业")
-	@PostMapping("add")
-	@Transactional
-	public CourseSpeciatlyRelationEntity add(@RequestParam(required = true) Long courseId,
-			@RequestParam(required = true) Long specialtyId) {
-		User accessUser = getAccessUser();
+    @ApiOperation(value = "新增关联课程专业")
+    @PostMapping("add")
+    @Transactional
+    public CourseSpeciatlyRelationEntity add(@RequestParam(required = true) Long courseId,
+                                             @RequestParam(required = true) Long specialtyId) {
+        User accessUser = getAccessUser();
 
-		if (null == courseId) {
-			throw new StatusException("320001", "courseId is null");
-		}
+        if (null == courseId) {
+            throw new StatusException("320001", "courseId is null");
+        }
 
-		if (null == specialtyId) {
-			throw new StatusException("320002", "specialtyId is null");
-		}
+        if (null == specialtyId) {
+            throw new StatusException("320002", "specialtyId is null");
+        }
 
-		CourseEntity courseEntity = GlobalHelper.getEntity(courseRepo, courseId,
-				CourseEntity.class);
-		if (null == courseEntity) {
-			throw new StatusException("320001", "courseId is wrong");
-		}
+        CourseEntity courseEntity = GlobalHelper.getEntity(courseRepo, courseId,
+                CourseEntity.class);
+        if (null == courseEntity) {
+            throw new StatusException("320001", "courseId is wrong");
+        }
 
-		this.validateRootOrgIsolation(courseEntity.getRootOrgId());
+        this.validateRootOrgIsolation(courseEntity.getRootOrgId());
 
-		SpecialtyEntity specialtyEntity = GlobalHelper.getEntity(specialtyRepo, specialtyId,
-				SpecialtyEntity.class);
-		if (null == specialtyEntity) {
-			throw new StatusException("320001", "specialtyId is wrong");
-		}
+        SpecialtyEntity specialtyEntity = GlobalHelper.getEntity(specialtyRepo, specialtyId,
+                SpecialtyEntity.class);
+        if (null == specialtyEntity) {
+            throw new StatusException("320001", "specialtyId is wrong");
+        }
 
-		this.validateRootOrgIsolation(specialtyEntity.getRootOrgId());
+        this.validateRootOrgIsolation(specialtyEntity.getRootOrgId());
 
-		CourseSpeciatlyRelationPK pk = new CourseSpeciatlyRelationPK();
-		pk.setCourseId(courseId);
-		pk.setSpecialtyId(specialtyId);
+        CourseSpeciatlyRelationPK pk = new CourseSpeciatlyRelationPK();
+        pk.setCourseId(courseId);
+        pk.setSpecialtyId(specialtyId);
 
-		CourseSpeciatlyRelationEntity one = GlobalHelper.getEntity(courseSpeciatlyRelationRepo, pk,
-				CourseSpeciatlyRelationEntity.class);
-		if (null != one) {
-			throw new StatusException("320003", "课程专业已关联");
-		}
+        CourseSpeciatlyRelationEntity one = GlobalHelper.getEntity(courseSpeciatlyRelationRepo, pk,
+                CourseSpeciatlyRelationEntity.class);
+        if (null != one) {
+            throw new StatusException("320003", "课程专业已关联");
+        }
 
-		one = new CourseSpeciatlyRelationEntity();
-		one.setCourseId(courseId);
-		one.setSpecialtyId(specialtyId);
-		one.setCreator(accessUser.getUserId());
+        one = new CourseSpeciatlyRelationEntity();
+        one.setCourseId(courseId);
+        one.setSpecialtyId(specialtyId);
+        one.setCreator(accessUser.getUserId());
 
-		CourseSpeciatlyRelationEntity saved = courseSpeciatlyRelationRepo.save(one);
+        CourseSpeciatlyRelationEntity saved = courseSpeciatlyRelationRepo.save(one);
 
-		return saved;
-	}
+        return saved;
+    }
 
-	@ApiOperation(value = "删除关联课程专业")
-	@DeleteMapping("delete")
-	@Transactional
-	public CourseSpeciatlyRelationEntity delete(@RequestParam(required = true) Long courseId,
-			@RequestParam(required = true) Long specialtyId) {
+    @ApiOperation(value = "删除关联课程专业")
+    @DeleteMapping("delete")
+    @Transactional
+    public CourseSpeciatlyRelationEntity delete(@RequestParam(required = true) Long courseId,
+                                                @RequestParam(required = true) Long specialtyId) {
 
-		if (null == courseId) {
-			throw new StatusException("320001", "courseId is null");
-		}
+        if (null == courseId) {
+            throw new StatusException("320001", "courseId is null");
+        }
 
-		if (null == specialtyId) {
-			throw new StatusException("320002", "specialtyId is null");
-		}
+        if (null == specialtyId) {
+            throw new StatusException("320002", "specialtyId is null");
+        }
 
-		CourseEntity courseEntity = GlobalHelper.getEntity(courseRepo, courseId,
-				CourseEntity.class);
-		if (null == courseEntity) {
-			throw new StatusException("320001", "courseId is wrong");
-		}
+        CourseEntity courseEntity = GlobalHelper.getEntity(courseRepo, courseId,
+                CourseEntity.class);
+        if (null == courseEntity) {
+            throw new StatusException("320001", "courseId is wrong");
+        }
 
-		this.validateRootOrgIsolation(courseEntity.getRootOrgId());
+        this.validateRootOrgIsolation(courseEntity.getRootOrgId());
 
-		SpecialtyEntity specialtyEntity = GlobalHelper.getEntity(specialtyRepo, specialtyId,
-				SpecialtyEntity.class);
-		if (null == specialtyEntity) {
-			throw new StatusException("320001", "specialtyId is wrong");
-		}
+        SpecialtyEntity specialtyEntity = GlobalHelper.getEntity(specialtyRepo, specialtyId,
+                SpecialtyEntity.class);
+        if (null == specialtyEntity) {
+            throw new StatusException("320001", "specialtyId is wrong");
+        }
 
-		this.validateRootOrgIsolation(specialtyEntity.getRootOrgId());
+        this.validateRootOrgIsolation(specialtyEntity.getRootOrgId());
 
-		CourseSpeciatlyRelationPK pk = new CourseSpeciatlyRelationPK();
-		pk.setCourseId(courseId);
-		pk.setSpecialtyId(specialtyId);
+        CourseSpeciatlyRelationPK pk = new CourseSpeciatlyRelationPK();
+        pk.setCourseId(courseId);
+        pk.setSpecialtyId(specialtyId);
 
-		CourseSpeciatlyRelationEntity one = GlobalHelper.getEntity(courseSpeciatlyRelationRepo, pk,
-				CourseSpeciatlyRelationEntity.class);
-		if (null == one) {
-			throw new StatusException("320003", "课程专业未关联");
-		}
+        CourseSpeciatlyRelationEntity one = GlobalHelper.getEntity(courseSpeciatlyRelationRepo, pk,
+                CourseSpeciatlyRelationEntity.class);
+        if (null == one) {
+            throw new StatusException("320003", "课程专业未关联");
+        }
 
-		courseSpeciatlyRelationRepo.delete(one);
+        courseSpeciatlyRelationRepo.delete(one);
 
-		return one;
-	}
+        return one;
+    }
 
 }

+ 47 - 50
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/FaceController.java

@@ -1,15 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.controller.bean.StudentFaceDomain;
 import cn.com.qmth.examcloud.core.basic.dao.StudentFaceRepo;
@@ -20,7 +10,13 @@ import cn.com.qmth.examcloud.core.basic.service.FaceService;
 import cn.com.qmth.examcloud.core.basic.service.bean.StudentFaceInfo;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 人脸接口<br>
@@ -31,60 +27,61 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 // @RestController
+@Api(tags = "学生人脸相关接口")
 @RequestMapping("${$rmp.ctr.basic}/face")
 public class FaceController extends ControllerSupport {
 
-	@Autowired
-	StudentFaceRepo studentFaceRepo;
+    @Autowired
+    StudentFaceRepo studentFaceRepo;
 
-	@Autowired
-	StudentRepo studentRepo;
+    @Autowired
+    StudentRepo studentRepo;
 
-	@Autowired
-	FaceService studentFaceService;
+    @Autowired
+    FaceService studentFaceService;
 
-	@ApiOperation(value = "保存学生人脸数据")
-	@PostMapping("saveStudentFace")
-	@Transactional
-	public StudentFaceEntity saveStudentFace(@RequestBody StudentFaceDomain req) {
-		StudentFaceInfo info = new StudentFaceInfo();
-		info.setFacesetToken(req.getFacesetToken());
-		info.setFaceToken(req.getFaceToken());
-		info.setOperator(req.getOperator());
-		info.setPhotoName(req.getPhotoName());
-		info.setRootOrgId(req.getRootOrgId());
-		info.setStudentId(req.getStudentId());
-		info.setFaceCount(req.getFaceCount());
+    @ApiOperation(value = "保存学生人脸数据")
+    @PostMapping("saveStudentFace")
+    @Transactional
+    public StudentFaceEntity saveStudentFace(@RequestBody StudentFaceDomain req) {
+        StudentFaceInfo info = new StudentFaceInfo();
+        info.setFacesetToken(req.getFacesetToken());
+        info.setFaceToken(req.getFaceToken());
+        info.setOperator(req.getOperator());
+        info.setPhotoName(req.getPhotoName());
+        info.setRootOrgId(req.getRootOrgId());
+        info.setStudentId(req.getStudentId());
+        info.setFaceCount(req.getFaceCount());
 
-		StudentFaceEntity saved = studentFaceService.saveStudentFace(info);
-		return saved;
-	}
+        StudentFaceEntity saved = studentFaceService.saveStudentFace(info);
+        return saved;
+    }
 
-	@ApiOperation(value = "获取可用的faceset集合")
-	@GetMapping("getUsableFacesetList")
-	public List<FacesetEntity> getUsableFacesetList() {
+    @ApiOperation(value = "获取可用的faceset集合")
+    @GetMapping("getUsableFacesetList")
+    public List<FacesetEntity> getUsableFacesetList() {
 
-		List<FacesetEntity> facesetList = studentFaceService.getUsableFacesetList();
+        List<FacesetEntity> facesetList = studentFaceService.getUsableFacesetList();
 
-		return facesetList;
-	}
+        return facesetList;
+    }
 
-	@ApiOperation(value = "获取学生人脸信息")
-	@GetMapping("studentFace/{studentId}")
-	public StudentFaceEntity getStudentFace(@PathVariable Long studentId) {
+    @ApiOperation(value = "获取学生人脸信息")
+    @GetMapping("studentFace/{studentId}")
+    public StudentFaceEntity getStudentFace(@PathVariable Long studentId) {
 
-		if (null == studentId) {
-			throw new StatusException("710001", "studentId is null");
-		}
+        if (null == studentId) {
+            throw new StatusException("710001", "studentId is null");
+        }
 
-		StudentFaceEntity studentFaceEntity = GlobalHelper.getEntity(studentFaceRepo, studentId,
-				StudentFaceEntity.class);
+        StudentFaceEntity studentFaceEntity = GlobalHelper.getEntity(studentFaceRepo, studentId,
+                StudentFaceEntity.class);
 
-		if (null == studentFaceEntity) {
-			throw new StatusException("710001", "studentFaceEntity is null");
-		}
+        if (null == studentFaceEntity) {
+            throw new StatusException("710001", "studentFaceEntity is null");
+        }
 
-		return studentFaceEntity;
-	}
+        return studentFaceEntity;
+    }
 
 }

+ 65 - 69
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/LogController.java

@@ -1,23 +1,18 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.Map;
-
-import org.apache.commons.lang3.RegExUtils;
-import org.slf4j.MDC;
-import org.springframework.web.bind.annotation.PathVariable;
-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.Maps;
-
 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.web.support.ControllerSupport;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.RegExUtils;
+import org.slf4j.MDC;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
 
 /**
  * 日志服务
@@ -27,69 +22,70 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "日志相关接口")
 @RequestMapping("${$rmp.ctr.basic}/log")
 public class LogController extends ControllerSupport {
 
-	private static Map<String, ExamCloudLog> loggersHolder = Maps.newConcurrentMap();
+    private static Map<String, ExamCloudLog> loggersHolder = Maps.newConcurrentMap();
 
-	private static Object lock = new Object();
+    private static Object lock = new Object();
 
-	@ApiOperation(value = "学生客户端日志")
-	@PostMapping("studentClient/{level}/{code}")
-	public String logByStudentClient(@PathVariable String level, @PathVariable String code,
-			@RequestBody String info) {
-		log("STUDENT_CLIENT_LOGGER", level, code, info);
-		return DateUtil.chinaNow();
-	}
+    @ApiOperation(value = "学生客户端日志")
+    @PostMapping("studentClient/{level}/{code}")
+    public String logByStudentClient(@PathVariable String level, @PathVariable String code,
+                                     @RequestBody String info) {
+        log("STUDENT_CLIENT_LOGGER", level, code, info);
+        return DateUtil.chinaNow();
+    }
 
-	/**
-	 * 写日志
-	 *
-	 * @author WANGWEI
-	 * @param logger
-	 * @param level
-	 * @param code
-	 * @param info
-	 */
-	private void log(String logger, String level, String code, String info) {
-		if (!code.matches("\\w{1,2}\\-\\d{6}")) {
-			throw new StatusException("500002",
-					"code must match regular expression:  \\w{1,2}\\-\\d{6}");
-		}
-		info = RegExUtils.replaceAll(info, "[\n\r]", "  ");
-		ExamCloudLog log = getLogger(logger);
-		MDC.put("CODE", code);
-		if ("debug".equalsIgnoreCase(level)) {
-			log.debug(info);
-		} else if ("info".equalsIgnoreCase(level)) {
-			log.info(info);
-		} else if ("error".equalsIgnoreCase(level)) {
-			log.error(info);
-		} else {
-			throw new StatusException("500001", "level must be [debug,info,error]");
-		}
-	}
+    /**
+     * 写日志
+     *
+     * @param logger
+     * @param level
+     * @param code
+     * @param info
+     * @author WANGWEI
+     */
+    private void log(String logger, String level, String code, String info) {
+        if (!code.matches("\\w{1,2}\\-\\d{6}")) {
+            throw new StatusException("500002",
+                    "code must match regular expression:  \\w{1,2}\\-\\d{6}");
+        }
+        info = RegExUtils.replaceAll(info, "[\n\r]", "  ");
+        ExamCloudLog log = getLogger(logger);
+        MDC.put("CODE", code);
+        if ("debug".equalsIgnoreCase(level)) {
+            log.debug(info);
+        } else if ("info".equalsIgnoreCase(level)) {
+            log.info(info);
+        } else if ("error".equalsIgnoreCase(level)) {
+            log.error(info);
+        } else {
+            throw new StatusException("500001", "level must be [debug,info,error]");
+        }
+    }
 
-	/**
-	 * 获取日志对象
-	 *
-	 * @author WANGWEI
-	 * @param logger
-	 * @return
-	 */
-	private ExamCloudLog getLogger(String logger) {
-		ExamCloudLog log = loggersHolder.get(logger);
-		if (null == log) {
-			synchronized (lock) {
-				if (null == log) {
-					log = ExamCloudLogFactory.getLog(logger);
-					loggersHolder.put(logger, log);
-				}
-				return log;
-			}
-		} else {
-			return log;
-		}
-	}
+    /**
+     * 获取日志对象
+     *
+     * @param logger
+     * @return
+     * @author WANGWEI
+     */
+    private ExamCloudLog getLogger(String logger) {
+        ExamCloudLog log = loggersHolder.get(logger);
+        if (null == log) {
+            synchronized (lock) {
+                if (null == log) {
+                    log = ExamCloudLogFactory.getLog(logger);
+                    loggersHolder.put(logger, log);
+                }
+                return log;
+            }
+        } else {
+            return log;
+        }
+    }
 
 }

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

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-12 16:19:29
+ */
+
+package cn.com.qmth.examcloud.core.basic.api.controller;
+
+import cn.com.qmth.examcloud.core.basic.service.LoginRuleService;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleForm;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleInfo;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleQuery;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.web.support.Naked;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@Api(tags = "登录规则相关接口")
+@RequestMapping("${$rmp.ctr.basic}/sys/xlogin/rule")
+public class LoginRuleController extends ControllerSupport {
+
+    @Autowired
+    private LoginRuleService loginRuleService;
+
+    @PostMapping("/top/list")
+    @ApiOperation(value = "查询“顶级”登录规则列表")
+    public List<LoginRuleInfo> list() {
+        return loginRuleService.getLoginRuleTopList();
+    }
+
+    @PostMapping("/list")
+    @ApiOperation(value = "查询登录规则列表(分页)")
+    public Page<LoginRuleInfo> list(@RequestBody LoginRuleQuery req) {
+        return loginRuleService.getLoginRuleList(req);
+    }
+
+    @PostMapping("/save")
+    @ApiOperation(value = "保存登录规则")
+    public void save(@RequestBody LoginRuleForm req) {
+        loginRuleService.addOrUpdateLoginRule(req);
+    }
+
+    @PostMapping("/delete")
+    @ApiOperation(value = "删除某个登录规则")
+    public void delete(@RequestParam Long ruleId) {
+        loginRuleService.deleteLoginRuleById(ruleId);
+    }
+
+    @Naked
+    @PostMapping("/refresh")
+    @ApiOperation(value = "刷新登录规则")
+    public void refresh() {
+        loginRuleService.refreshAllLoginRule();
+    }
+
+}

文件差異過大導致無法顯示
+ 577 - 573
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/OrgController.java


+ 178 - 191
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/ResourceController.java

@@ -1,38 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.persistence.criteria.Predicate;
-import javax.validation.constraints.NotNull;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.domain.Sort.Direction;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-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.RequestParam;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-
-import com.google.common.collect.Lists;
-
 import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
@@ -43,172 +10,192 @@ import cn.com.qmth.examcloud.core.basic.service.ResourceService;
 import cn.com.qmth.examcloud.core.basic.service.bean.ResourceInfo;
 import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.persistence.criteria.Predicate;
+import javax.validation.constraints.NotNull;
+import java.util.*;
+import java.util.regex.Pattern;
 
-@Api(tags = "资源管理")
 @RestController
+@Api(tags = "资源相关接口")
 @RequestMapping("${$rmp.ctr.basic}/resource")
 public class ResourceController extends ControllerSupport {
-	private static int fileSize=10;
-	private static Set<String> suffSet=new HashSet<String>();
-	static {
-		suffSet.add("txt");
-		suffSet.add("xlsx");
-		suffSet.add("docx");
-		suffSet.add("pptx");
-	}
-
-	@Autowired
-	private ResourceRepo resourceRepo;
-
-	@Autowired
-	private ResourceService resourceService;
-
-	@ApiOperation(value = "分页查询资源")
-	@GetMapping("page/{pageNo}/{pageSize}")
-	public PageInfo<ResourceDomain> getPage(@PathVariable Integer pageNo,
-			@PathVariable Integer pageSize, @RequestParam(required = false) String name,
-			@RequestParam(required = false) Long parentId,
-			@RequestParam(required = true) Long rootOrgId) {
-
-		if (!isSuperAdmin()) {
-			User accessUser = getAccessUser();
-			if (!rootOrgId.equals(accessUser.getRootOrgId())) {
-				throw new StatusException("100000", "无效的请求");
-			}
-		}
-
-		Specification<ResourceEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (null == parentId || -1 == parentId) {
-				predicates.add(cb.isNull(root.get("parentId")));
-			} else {
-				predicates.add(cb.equal(root.get("parentId"), parentId));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-		PageRequest pageRequest = PageRequest.of(pageNo, pageSize,
-				new Sort(Direction.ASC, "isFile").and(new Sort(Direction.DESC, "creationTime")));
-
-		Page<ResourceEntity> page = resourceRepo.findAll(specification, pageRequest);
-		Iterator<ResourceEntity> iterator = page.iterator();
-
-		List<ResourceDomain> resourceDomainList = Lists.newArrayList();
+
+    private static int fileSize = 10;
+
+    private static Set<String> suffSet = new HashSet<String>();
+
+    static {
+        suffSet.add("txt");
+        suffSet.add("xlsx");
+        suffSet.add("docx");
+        suffSet.add("pptx");
+    }
+
+    @Autowired
+    private ResourceRepo resourceRepo;
+
+    @Autowired
+    private ResourceService resourceService;
+
+    @ApiOperation(value = "分页查询资源")
+    @GetMapping("page/{pageNo}/{pageSize}")
+    public PageInfo<ResourceDomain> getPage(@PathVariable Integer pageNo,
+                                            @PathVariable Integer pageSize, @RequestParam(required = false) String name,
+                                            @RequestParam(required = false) Long parentId,
+                                            @RequestParam(required = true) Long rootOrgId) {
+
+        if (!isSuperAdmin()) {
+            User accessUser = getAccessUser();
+            if (!rootOrgId.equals(accessUser.getRootOrgId())) {
+                throw new StatusException("100000", "无效的请求");
+            }
+        }
+
+        Specification<ResourceEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (null == parentId || -1 == parentId) {
+                predicates.add(cb.isNull(root.get("parentId")));
+            } else {
+                predicates.add(cb.equal(root.get("parentId"), parentId));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+        PageRequest pageRequest = PageRequest.of(pageNo, pageSize,
+                new Sort(Direction.ASC, "isFile").and(new Sort(Direction.DESC, "creationTime")));
+
+        Page<ResourceEntity> page = resourceRepo.findAll(specification, pageRequest);
+        Iterator<ResourceEntity> iterator = page.iterator();
+
+        List<ResourceDomain> resourceDomainList = Lists.newArrayList();
 
 //		String upyunFileUrl = PropertyHolder.getString("$upyun.site.1.domain");
-		while (iterator.hasNext()) {
-			ResourceEntity next = iterator.next();
-			ResourceDomain bean = new ResourceDomain();
-			BeanUtils.copyProperties(next, bean);
+        while (iterator.hasNext()) {
+            ResourceEntity next = iterator.next();
+            ResourceDomain bean = new ResourceDomain();
+            BeanUtils.copyProperties(next, bean);
 //			bean.setFileUrl(upyunFileUrl + bean.getFilePath());
-			//通用存储
-			bean.setFileUrl(FileStorageUtil.realPath(bean.getFileTreatyPath()));
-			resourceDomainList.add(bean);
-		}
-		PageInfo<ResourceDomain> ret = new PageInfo<ResourceDomain>();
-		ret.setList(resourceDomainList);
-		ret.setTotal(page.getTotalElements());
-		return ret;
-	}
-
-	@ApiOperation(value = "新增资源")
-	@PostMapping("addFile")
-	@Transactional
-	public void addResource(@RequestParam @NotNull(message = "RootOrgId不能为空!") Long rootOrgId,
-			@RequestParam @NotNull(message = "parentId不能为空!") Long parentId,
-			@RequestPart @NotNull(message = "上传文件不能为空!") MultipartFile dataFile) {
-
-		if (-1 == parentId) {
-			parentId = null;
-		}
-
-		if (!isSuperAdmin()) {
-			User accessUser = getAccessUser();
-			if (!rootOrgId.equals(accessUser.getRootOrgId())) {
-				throw new StatusException("100021", "无效的请求");
-			}
-		}
-		String fileName = dataFile.getOriginalFilename();
-		String regex = "^[a-zA-Z\\-_0-9.]{1,50}$";
-		if (!Pattern.matches(regex, fileName)) {
-			throw new StatusException("100022", "文件名长度最大为50且只能包含字母,数字,'-','_','.'");
-		}
-		if(fileName.indexOf(".")==-1||fileName.indexOf(".")==fileName.length()-1) {
-			throw new StatusException("100023", "文件类型未知");
-		}
-		String suff=fileName.substring(fileName.lastIndexOf(".")+1);
-		if(!suffSet.contains(suff.toLowerCase())) {
-			throw new StatusException("100024", "文件类型只能是"+StringUtils.join(suffSet, ','));
-		}
-		if(dataFile.getSize()>fileSize*1024*1024) {
-			throw new StatusException("100025", "文件大小限制为"+fileSize+"M");
-		}
-		resourceService.addFile(rootOrgId, parentId, dataFile);
-	}
-
-	@ApiOperation(value = "删除资源")
-	@DeleteMapping("/{id}")
-	@Transactional
-	public void delResource(@PathVariable Long id) {
-		Optional<ResourceEntity> op = resourceRepo.findById(id);
-		if (op.isPresent()) {
-			ResourceEntity e = op.get();
-			if (!isSuperAdmin()) {
-				User accessUser = getAccessUser();
-				if (!e.getRootOrgId().equals(accessUser.getRootOrgId())) {
-					throw new StatusException("100031", "无效的请求");
-				}
-			}
-			if (!e.getIsFile()
-					&& resourceRepo.countByRootOrgIdAndParentId(e.getRootOrgId(), id) > 0) {
-				throw new StatusException("100032", "请先删除该目录下的文件及目录");
-			}
-			resourceRepo.deleteById(id);
-		} else {
-			throw new StatusException("100033", "文件或目录不存在");
-
-		}
-	}
-
-	@ApiOperation(value = "新增目录")
-	@PostMapping("addDir")
-	@Transactional
-	public void addDir(@RequestBody ResourceDomain domain) {
-		if (StringUtils.isBlank(domain.getName())) {
-			throw new StatusException("100001", "目录名称不能为空");
-		}
-		String regex = "^[a-zA-Z\\-_0-9]{1,50}$";
-		if (!Pattern.matches(regex, domain.getName())) {
-			throw new StatusException("100005", "目录名称必须为1-50位字母,数字,'-','_'组合");
-		}
-		if (domain.getRootOrgId() == null) {
-			throw new StatusException("100002", "RootOrgId不能为空");
-		}
-		if (domain.getParentId() == null) {
-			throw new StatusException("100003", "ParentId不能为空");
-		}
-		if (!isSuperAdmin()) {
-			User accessUser = getAccessUser();
-			if (!domain.getRootOrgId().equals(accessUser.getRootOrgId())) {
-				throw new StatusException("100004", "无效的请求");
-			}
-		}
-		Long parentId = domain.getParentId();
-		if (-1 == parentId) {
-			domain.setParentId(null);
-		}
-
-		ResourceInfo info = new ResourceInfo();
-		BeanUtils.copyProperties(domain, info);
-		resourceService.addDir(info);
-	}
+            //通用存储
+            bean.setFileUrl(FileStorageUtil.realPath(bean.getFileTreatyPath()));
+            resourceDomainList.add(bean);
+        }
+        PageInfo<ResourceDomain> ret = new PageInfo<ResourceDomain>();
+        ret.setList(resourceDomainList);
+        ret.setTotal(page.getTotalElements());
+        return ret;
+    }
+
+    @ApiOperation(value = "新增资源")
+    @PostMapping("addFile")
+    @Transactional
+    public void addResource(@RequestParam @NotNull(message = "RootOrgId不能为空!") Long rootOrgId,
+                            @RequestParam @NotNull(message = "parentId不能为空!") Long parentId,
+                            @RequestPart @NotNull(message = "上传文件不能为空!") MultipartFile dataFile) {
+
+        if (-1 == parentId) {
+            parentId = null;
+        }
+
+        if (!isSuperAdmin()) {
+            User accessUser = getAccessUser();
+            if (!rootOrgId.equals(accessUser.getRootOrgId())) {
+                throw new StatusException("100021", "无效的请求");
+            }
+        }
+        String fileName = dataFile.getOriginalFilename();
+        String regex = "^[a-zA-Z\\-_0-9.]{1,50}$";
+        if (!Pattern.matches(regex, fileName)) {
+            throw new StatusException("100022", "文件名长度最大为50且只能包含字母,数字,'-','_','.'");
+        }
+        if (fileName.indexOf(".") == -1 || fileName.indexOf(".") == fileName.length() - 1) {
+            throw new StatusException("100023", "文件类型未知");
+        }
+        String suff = fileName.substring(fileName.lastIndexOf(".") + 1);
+        if (!suffSet.contains(suff.toLowerCase())) {
+            throw new StatusException("100024", "文件类型只能是" + StringUtils.join(suffSet, ','));
+        }
+        if (dataFile.getSize() > fileSize * 1024 * 1024) {
+            throw new StatusException("100025", "文件大小限制为" + fileSize + "M");
+        }
+        resourceService.addFile(rootOrgId, parentId, dataFile);
+    }
+
+    @ApiOperation(value = "删除资源")
+    @DeleteMapping("/{id}")
+    @Transactional
+    public void delResource(@PathVariable Long id) {
+        Optional<ResourceEntity> op = resourceRepo.findById(id);
+        if (op.isPresent()) {
+            ResourceEntity e = op.get();
+            if (!isSuperAdmin()) {
+                User accessUser = getAccessUser();
+                if (!e.getRootOrgId().equals(accessUser.getRootOrgId())) {
+                    throw new StatusException("100031", "无效的请求");
+                }
+            }
+            if (!e.getIsFile()
+                    && resourceRepo.countByRootOrgIdAndParentId(e.getRootOrgId(), id) > 0) {
+                throw new StatusException("100032", "请先删除该目录下的文件及目录");
+            }
+            resourceRepo.deleteById(id);
+        } else {
+            throw new StatusException("100033", "文件或目录不存在");
+
+        }
+    }
+
+    @ApiOperation(value = "新增目录")
+    @PostMapping("addDir")
+    @Transactional
+    public void addDir(@RequestBody ResourceDomain domain) {
+        if (StringUtils.isBlank(domain.getName())) {
+            throw new StatusException("100001", "目录名称不能为空");
+        }
+        String regex = "^[a-zA-Z\\-_0-9]{1,50}$";
+        if (!Pattern.matches(regex, domain.getName())) {
+            throw new StatusException("100005", "目录名称必须为1-50位字母,数字,'-','_'组合");
+        }
+        if (domain.getRootOrgId() == null) {
+            throw new StatusException("100002", "RootOrgId不能为空");
+        }
+        if (domain.getParentId() == null) {
+            throw new StatusException("100003", "ParentId不能为空");
+        }
+        if (!isSuperAdmin()) {
+            User accessUser = getAccessUser();
+            if (!domain.getRootOrgId().equals(accessUser.getRootOrgId())) {
+                throw new StatusException("100004", "无效的请求");
+            }
+        }
+        Long parentId = domain.getParentId();
+        if (-1 == parentId) {
+            domain.setParentId(null);
+        }
+
+        ResourceInfo info = new ResourceInfo();
+        BeanUtils.copyProperties(domain, info);
+        resourceService.addDir(info);
+    }
 
 }

+ 15 - 38
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/RolePrivilegeController.java

@@ -1,48 +1,15 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import cn.com.qmth.examcloud.core.basic.api.controller.bean.*;
-import org.apache.commons.collections.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
 import cn.com.qmth.examcloud.api.commons.enums.PrivilegeGroupType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.RegExpUtil;
 import cn.com.qmth.examcloud.core.basic.api.bean.RoleBean;
+import cn.com.qmth.examcloud.core.basic.api.controller.bean.*;
 import cn.com.qmth.examcloud.core.basic.base.constants.BasicConsts;
-import cn.com.qmth.examcloud.core.basic.dao.PrivilegeGroupRepo;
-import cn.com.qmth.examcloud.core.basic.dao.PrivilegeRepo;
-import cn.com.qmth.examcloud.core.basic.dao.RolePrivilegeRelationRepo;
-import cn.com.qmth.examcloud.core.basic.dao.RoleRepo;
-import cn.com.qmth.examcloud.core.basic.dao.RootOrgPrivilegeRelationRepo;
-import cn.com.qmth.examcloud.core.basic.dao.entity.PrivilegeEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.PrivilegeGroupEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.RoleEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.RolePrivilegeRelationEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.RootOrgPrivilegeRelationEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.RootOrgPrivilegeRelationPK;
+import cn.com.qmth.examcloud.core.basic.dao.*;
+import cn.com.qmth.examcloud.core.basic.dao.entity.*;
 import cn.com.qmth.examcloud.core.basic.service.RolePrivilegeService;
 import cn.com.qmth.examcloud.core.basic.service.bean.RoleInfo;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
@@ -50,8 +17,18 @@ import cn.com.qmth.examcloud.web.helpers.tree.EleTreeNode;
 import cn.com.qmth.examcloud.web.helpers.tree.TreeUtil;
 import cn.com.qmth.examcloud.web.interceptor.GlobalSequenceLock;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 角色权限
@@ -60,14 +37,14 @@ import io.swagger.annotations.ApiOperation;
  * @date 2018年6月12日
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
-@Api("角色权限")
 @RestController
+@Api(tags = "角色权限相关接口")
 @RequestMapping("${$rmp.ctr.basic}/rolePrivilege")
 public class RolePrivilegeController extends ControllerSupport {
 
     private static List<String> disabledPrivilegeCodeList = Arrays
             .asList(new String[]{"index_privilege_group_list", "index_app_list", "index_school",
-                    "school_config", "index_school_privilege_settings", "system"});
+                    "school_config", "index_school_privilege_settings", "system","online_num"});
 
     @Autowired
     PrivilegeGroupRepo privilegeGroupRepo;

+ 350 - 358
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SpecialtyController.java

@@ -1,42 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.Subquery;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.fileupload.disk.DiskFileItem;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.domain.Sort.Direction;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-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.helpers.poi.ExcelWriter;
@@ -52,335 +15,364 @@ import cn.com.qmth.examcloud.core.basic.service.bean.SpecialtyInfo;
 import cn.com.qmth.examcloud.web.config.SystemProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
- * @Description: 专业服务API
  * @author weiwenhai
+ * @Description: 专业服务API
  * @Date 2017年8月7号
  */
 @RestController
+@Api(tags = "专业相关接口")
 @RequestMapping("${$rmp.ctr.basic}/specialty")
 public class SpecialtyController extends ControllerSupport {
 
-	@Autowired
-	SpecialtyService specialtyService;
-
-	@Autowired
-	SystemProperties systemConfig;
-
-	@Autowired
-	SpecialtyRepo specialtyRepo;
-
-	@Autowired
-	CourseRepo courseRepo;
-
-	@Autowired
-	CourseSpeciatlyRelationRepo courseSpeciatlyRelationRepo;
-
-	private static final String[] EXCEL_HEADER = new String[]{"专业名称", "专业代码"};
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param curPage
-	 * @param pageSize
-	 * @param name
-	 * @param code
-	 * @param enable
-	 * @param courseId
-	 * @return
-	 */
-	@ApiOperation(value = "分页查询专业")
-	@GetMapping("specialtyPage/{curPage}/{pageSize}")
-	public Page<SpecialtyEntity> getSpecialtyPage(@PathVariable Integer curPage,
-			@PathVariable Integer pageSize, @RequestParam(required = false) String name,
-			@RequestParam(required = false) String code,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long courseId) {
-		User accessUser = getAccessUser();
-
-		Specification<SpecialtyEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (StringUtils.isNotBlank(code)) {
-				predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != courseId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("specialtyId"));
-				Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
-				Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-				new Sort(Direction.DESC, "updateTime", "id"));
-
-		Page<SpecialtyEntity> page = specialtyRepo.findAll(specification, pageRequest);
-		return page;
-	}
-
-	@ApiOperation(value = "查询专业")
-	@GetMapping("query")
-	public List<SpecialtyEntity> query(@RequestParam(required = false) String name,
-			@RequestParam(required = false) String code,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long courseId) {
-
-		User accessUser = getAccessUser();
-		Long rootOrgId = accessUser.getRootOrgId();
-
-		Specification<SpecialtyEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (StringUtils.isNotBlank(code)) {
-				predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != courseId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("specialtyId"));
-				Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
-				Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		// 过载保护
-		long total = specialtyRepo.count(specification);
-		if (total > 1000) {
-			List<SpecialtyEntity> list = Lists.newArrayList();
-			return list;
-		}
-
-		List<SpecialtyEntity> list = specialtyRepo.findAll(specification,
-				new Sort(Direction.DESC, "updateTime"));
-		return list;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param orgId
-	 * @param code
-	 * @return
-	 */
-	@ApiOperation(value = "查询专业")
-	@GetMapping("byCode")
-	public SpecialtyEntity getByCode(@RequestParam Long orgId, @RequestParam String code) {
-		SpecialtyEntity specialty = specialtyRepo.findByRootOrgIdAndCode(orgId, code);
-		if (null == specialty) {
-			throw new StatusException("620002", "专业不存在");
-		}
-		validateRootOrgIsolation(specialty.getRootOrgId());
-		return specialty;
-	}
-
-	/**
-	 * 修正
-	 *
-	 * @author WANGWEI
-	 * @param domain
-	 * @return
-	 */
-	@ApiOperation(value = "新增专业", notes = "新增")
-	@PostMapping
-	@Transactional
-	public Long addSpecialty(@RequestBody SpecialtyDomain domain) {
-		trim(domain, true);
-
-		User accessUser = getAccessUser();
-		Long rootOrgId = accessUser.getRootOrgId();
-
-		String code = domain.getCode();
-		if (StringUtils.isBlank(code)) {
-			throw new StatusException("620001", "code is blank");
-		}
-		SpecialtyEntity course = specialtyRepo.findByRootOrgIdAndCode(rootOrgId, code);
-		if (null != course) {
-			throw new StatusException("620002", "专业编码已被占用");
-		}
-
-		SpecialtyInfo info = new SpecialtyInfo();
-		info.setRootOrgId(rootOrgId);
-		info.setCode(domain.getCode());
-		info.setEnable(domain.getEnable());
-		info.setId(domain.getId());
-		info.setName(domain.getName());
-		info.setEnable(domain.getEnable());
-
-		SpecialtyEntity saved = specialtyService.saveSpecialty(info);
-		return saved.getId();
-	}
-
-	/**
-	 * 修正
-	 *
-	 * @author WANGWEI
-	 * @param domain
-	 * @return
-	 */
-	@ApiOperation(value = "修改专业", notes = "新增")
-	@PutMapping
-	@Transactional
-	public Long updateSpecialty(@RequestBody SpecialtyDomain domain) {
-		trim(domain, true);
-
-		User accessUser = getAccessUser();
-		Long rootOrgId = accessUser.getRootOrgId();
-
-		SpecialtyInfo info = new SpecialtyInfo();
-		info.setId(info.getId());
-		info.setRootOrgId(rootOrgId);
-		info.setCode(domain.getCode());
-		info.setEnable(domain.getEnable());
-		info.setId(domain.getId());
-		info.setName(domain.getName());
-		info.setEnable(domain.getEnable());
-
-		SpecialtyEntity saved = specialtyService.saveSpecialty(info);
-		return saved.getId();
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param ids
-	 */
-	@ApiOperation(value = "删除专业")
-	@DeleteMapping("{ids}")
-	@Transactional
-	public void delete(@PathVariable String ids) {
-		List<Long> specialtyIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-		for (Long specialtyId : specialtyIds) {
-			SpecialtyEntity one = GlobalHelper.getEntity(specialtyRepo, specialtyId,
-					SpecialtyEntity.class);
-			if (null == one) {
-				continue;
-			}
-			validateRootOrgIsolation(one.getRootOrgId());
-			specialtyRepo.delete(one);
-
-			courseSpeciatlyRelationRepo.deleteBySpecialtyId(specialtyId);
-		}
-	}
-
-	@ApiOperation(value = "下载导入模板", notes = "下载导入模板")
-	@GetMapping("importTemplate")
-	public void getDownloadTemplate(HttpServletResponse response) {
-		String resoucePath = PathUtil.getResoucePath("templates/specialtyImportTemplate.xlsx");
-		exportFile("专业导入模板.xlsx", new File(resoucePath));
-	}
-
-	@ApiOperation(value = "导入", notes = "导入")
-	@PostMapping("import")
-	@Transactional
-	public Map<String, Object> importSpecialty(@RequestParam CommonsMultipartFile file) {
-		DiskFileItem item = (DiskFileItem) file.getFileItem();
-		File storeLocation = item.getStoreLocation();
-		List<Map<String, Object>> failRecords = specialtyService.importSpecialty(getRootOrgId(),
-				storeLocation);
-		Map<String, Object> map = Maps.newHashMap();
-		map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
-		map.put("failRecords", failRecords);
-		return map;
-	}
-
-	@ApiOperation(value = "导出专业")
-	@GetMapping("export")
-	public void export(@RequestParam(required = false) String name,
-			@RequestParam(required = false) String code,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long courseId) {
-		User accessUser = getAccessUser();
-
-		Specification<SpecialtyEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
-
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (StringUtils.isNotBlank(code)) {
-				predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			if (null != courseId) {
-				Subquery<CourseSpeciatlyRelationEntity> subquery = query
-						.subquery(CourseSpeciatlyRelationEntity.class);
-				Root<CourseSpeciatlyRelationEntity> subRoot = subquery
-						.from(CourseSpeciatlyRelationEntity.class);
-				subquery.select(subRoot.get("specialtyId"));
-				Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
-				Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		long count = specialtyRepo.count(specification);
-		if (100000 < count) {
-			throw new StatusException("620200", "数据量过大,无法导出");
-		}
-
-		List<SpecialtyEntity> list = specialtyRepo.findAll(specification);
-
-		List<Object[]> datas = Lists.newArrayList();
-
-		for (SpecialtyEntity cur : list) {
-			datas.add(new Object[]{cur.getName(), cur.getCode()});
-		}
-
-		String filePath = systemConfig.getTempDataDir() + File.separator
-				+ System.currentTimeMillis() + ".xlsx";
-		File file = new File(filePath);
-
-		ExcelWriter.write(EXCEL_HEADER, new Class[]{String.class, String.class}, datas,
-				new File(filePath));
-
-		exportFile("专业列表-" + getRootOrgId() + ".xlsx", file);
-
-		FileUtils.deleteQuietly(file);
-	}
+    @Autowired
+    SpecialtyService specialtyService;
+
+    @Autowired
+    SystemProperties systemConfig;
+
+    @Autowired
+    SpecialtyRepo specialtyRepo;
+
+    @Autowired
+    CourseRepo courseRepo;
+
+    @Autowired
+    CourseSpeciatlyRelationRepo courseSpeciatlyRelationRepo;
+
+    private static final String[] EXCEL_HEADER = new String[]{"专业名称", "专业代码"};
+
+    /**
+     * 方法注释
+     *
+     * @param curPage
+     * @param pageSize
+     * @param name
+     * @param code
+     * @param enable
+     * @param courseId
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "分页查询专业")
+    @GetMapping("specialtyPage/{curPage}/{pageSize}")
+    public Page<SpecialtyEntity> getSpecialtyPage(@PathVariable Integer curPage,
+                                                  @PathVariable Integer pageSize,
+                                                  @RequestParam(required = false) String name,
+                                                  @RequestParam(required = false) String code,
+                                                  @RequestParam(required = false) Boolean enable,
+                                                  @RequestParam(required = false) Long courseId) {
+        User accessUser = getAccessUser();
+
+        Specification<SpecialtyEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (StringUtils.isNotBlank(code)) {
+                predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != courseId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("specialtyId"));
+                Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
+                Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        PageRequest pageRequest = PageRequest.of(curPage, pageSize,
+                new Sort(Direction.DESC, "updateTime", "id"));
+
+        Page<SpecialtyEntity> page = specialtyRepo.findAll(specification, pageRequest);
+        return page;
+    }
+
+    @ApiOperation(value = "查询专业")
+    @GetMapping("query")
+    public List<SpecialtyEntity> query(@RequestParam(required = false) String name,
+                                       @RequestParam(required = false) String code,
+                                       @RequestParam(required = false) Boolean enable,
+                                       @RequestParam(required = false) Long courseId) {
+
+        User accessUser = getAccessUser();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        Specification<SpecialtyEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (StringUtils.isNotBlank(code)) {
+                predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != courseId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("specialtyId"));
+                Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
+                Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        // 过载保护
+        long total = specialtyRepo.count(specification);
+        if (total > 1000) {
+            List<SpecialtyEntity> list = Lists.newArrayList();
+            return list;
+        }
+
+        List<SpecialtyEntity> list = specialtyRepo.findAll(specification,
+                new Sort(Direction.DESC, "updateTime"));
+        return list;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param orgId
+     * @param code
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "查询专业")
+    @GetMapping("byCode")
+    public SpecialtyEntity getByCode(@RequestParam Long orgId, @RequestParam String code) {
+        SpecialtyEntity specialty = specialtyRepo.findByRootOrgIdAndCode(orgId, code);
+        if (null == specialty) {
+            throw new StatusException("620002", "专业不存在");
+        }
+        validateRootOrgIsolation(specialty.getRootOrgId());
+        return specialty;
+    }
+
+    /**
+     * 修正
+     *
+     * @param domain
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "新增专业", notes = "新增")
+    @PostMapping
+    @Transactional
+    public Long addSpecialty(@RequestBody SpecialtyDomain domain) {
+        trim(domain, true);
+
+        User accessUser = getAccessUser();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        String code = domain.getCode();
+        if (StringUtils.isBlank(code)) {
+            throw new StatusException("620001", "code is blank");
+        }
+        SpecialtyEntity course = specialtyRepo.findByRootOrgIdAndCode(rootOrgId, code);
+        if (null != course) {
+            throw new StatusException("620002", "专业编码已被占用");
+        }
+
+        SpecialtyInfo info = new SpecialtyInfo();
+        info.setRootOrgId(rootOrgId);
+        info.setCode(domain.getCode());
+        info.setEnable(domain.getEnable());
+        info.setId(domain.getId());
+        info.setName(domain.getName());
+        info.setEnable(domain.getEnable());
+
+        SpecialtyEntity saved = specialtyService.saveSpecialty(info);
+        return saved.getId();
+    }
+
+    /**
+     * 修正
+     *
+     * @param domain
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "修改专业", notes = "新增")
+    @PutMapping
+    @Transactional
+    public Long updateSpecialty(@RequestBody SpecialtyDomain domain) {
+        trim(domain, true);
+
+        User accessUser = getAccessUser();
+        Long rootOrgId = accessUser.getRootOrgId();
+
+        SpecialtyInfo info = new SpecialtyInfo();
+        info.setId(info.getId());
+        info.setRootOrgId(rootOrgId);
+        info.setCode(domain.getCode());
+        info.setEnable(domain.getEnable());
+        info.setId(domain.getId());
+        info.setName(domain.getName());
+        info.setEnable(domain.getEnable());
+
+        SpecialtyEntity saved = specialtyService.saveSpecialty(info);
+        return saved.getId();
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param ids
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "删除专业")
+    @DeleteMapping("{ids}")
+    @Transactional
+    public void delete(@PathVariable String ids) {
+        List<Long> specialtyIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+        for (Long specialtyId : specialtyIds) {
+            SpecialtyEntity one = GlobalHelper.getEntity(specialtyRepo, specialtyId,
+                    SpecialtyEntity.class);
+            if (null == one) {
+                continue;
+            }
+            validateRootOrgIsolation(one.getRootOrgId());
+            specialtyRepo.delete(one);
+
+            courseSpeciatlyRelationRepo.deleteBySpecialtyId(specialtyId);
+        }
+    }
+
+    @ApiOperation(value = "下载导入模板", notes = "下载导入模板")
+    @GetMapping("importTemplate")
+    public void getDownloadTemplate(HttpServletResponse response) {
+        String resoucePath = PathUtil.getResoucePath("templates/specialtyImportTemplate.xlsx");
+        exportFile("专业导入模板.xlsx", new File(resoucePath));
+    }
+
+    @ApiOperation(value = "导入", notes = "导入")
+    @PostMapping("import")
+    @Transactional
+    public Map<String, Object> importSpecialty(@RequestParam CommonsMultipartFile file) {
+        DiskFileItem item = (DiskFileItem) file.getFileItem();
+        File storeLocation = item.getStoreLocation();
+        List<Map<String, Object>> failRecords = specialtyService.importSpecialty(getRootOrgId(),
+                storeLocation);
+        Map<String, Object> map = Maps.newHashMap();
+        map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
+        map.put("failRecords", failRecords);
+        return map;
+    }
+
+    @ApiOperation(value = "导出专业")
+    @GetMapping("export")
+    public void export(@RequestParam(required = false) String name,
+                       @RequestParam(required = false) String code,
+                       @RequestParam(required = false) Boolean enable,
+                       @RequestParam(required = false) Long courseId) {
+        User accessUser = getAccessUser();
+
+        Specification<SpecialtyEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
+
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (StringUtils.isNotBlank(code)) {
+                predicates.add(cb.like(root.get("code"), toSqlSearchPattern(code)));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            if (null != courseId) {
+                Subquery<CourseSpeciatlyRelationEntity> subquery = query
+                        .subquery(CourseSpeciatlyRelationEntity.class);
+                Root<CourseSpeciatlyRelationEntity> subRoot = subquery
+                        .from(CourseSpeciatlyRelationEntity.class);
+                subquery.select(subRoot.get("specialtyId"));
+                Predicate p1 = cb.equal(subRoot.get("courseId"), courseId);
+                Predicate p2 = cb.equal(subRoot.get("specialtyId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        long count = specialtyRepo.count(specification);
+        if (100000 < count) {
+            throw new StatusException("620200", "数据量过大,无法导出");
+        }
+
+        List<SpecialtyEntity> list = specialtyRepo.findAll(specification);
+
+        List<Object[]> datas = Lists.newArrayList();
+
+        for (SpecialtyEntity cur : list) {
+            datas.add(new Object[]{cur.getName(), cur.getCode()});
+        }
+
+        String filePath = systemConfig.getTempDataDir() + File.separator
+                + System.currentTimeMillis() + ".xlsx";
+        File file = new File(filePath);
+
+        ExcelWriter.write(EXCEL_HEADER, new Class[]{String.class, String.class}, datas,
+                new File(filePath));
+
+        exportFile("专业列表-" + getRootOrgId() + ".xlsx", file);
+
+        FileUtils.deleteQuietly(file);
+    }
 }

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

@@ -3,6 +3,7 @@ package cn.com.qmth.examcloud.core.basic.api.controller;
 import cn.com.qmth.examcloud.api.commons.enums.BooleanSelect;
 import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.helpers.poi.ExcelWriter;
@@ -19,6 +20,10 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.UserEntity;
 import cn.com.qmth.examcloud.core.basic.service.StudentService;
 import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
 import cn.com.qmth.examcloud.core.basic.service.cache.StudentCache;
+import cn.com.qmth.examcloud.reports.commons.bean.OnlineStudentReport;
+import cn.com.qmth.examcloud.reports.commons.bean.OperateReport;
+import cn.com.qmth.examcloud.reports.commons.enums.OperateContent;
+import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.OrgCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.StudentCacheBean;
@@ -32,6 +37,7 @@ import cn.com.qmth.examcloud.web.config.SystemProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -59,6 +65,7 @@ import java.util.stream.Stream;
  * 学生服务API Created by songyue on 17/1/14.
  */
 @RestController
+@Api(tags = "学生相关接口")
 @RequestMapping("${$rmp.ctr.basic}/student")
 public class StudentController extends ControllerSupport {
 
@@ -108,6 +115,7 @@ public class StudentController extends ControllerSupport {
             @RequestParam String studentCode, @RequestParam String identityNumber,
             @RequestParam(required = false) Long rootOrgId,
             @RequestParam(required = false) Long orgId,
+            @RequestParam(required = false) BooleanSelect enable,
             @RequestParam(required = false) BooleanSelect hasPhoto) {
 
         User accessUser = getAccessUser();
@@ -130,6 +138,13 @@ public class StudentController extends ControllerSupport {
                 predicates.add(cb.like(root.get("identityNumber"), toSqlRightLike(identityNumber)));
             }
 
+            if (null != enable) {
+                Boolean enableBoolean = enable.getBoolean();
+                if (null != enableBoolean) {
+                    predicates.add(cb.equal(root.get("enable"), enableBoolean));
+                }
+            }
+
             if (null != hasPhoto) {
                 Boolean hasPhotoBoolean = hasPhoto.getBoolean();
                 if (null != hasPhotoBoolean) {
@@ -224,7 +239,8 @@ public class StudentController extends ControllerSupport {
 //				bean.setPhotoPath(
 //						UrlUtil.joinUrl(upyunDomain, "student_base_photo", next.getPhotoPath()));
                 //通用存储
-                bean.setPhotoPath(FileStorageUtil.realPath(FileStorageUtil.getIntactPath("student_base_photo", next.getPhotoPath())));
+                bean.setPhotoPath(FileStorageUtil.realPath(FileStorageUtil.getIntactPath("student_base_photo",
+                        next.getPhotoPath())));
             }
             bean.setPhoneNumber(next.getPhoneNumber());
             bean.setSecurityPhone(next.getSecurityPhone());
@@ -398,6 +414,9 @@ public class StudentController extends ControllerSupport {
             StudentEntity s = GlobalHelper.getEntity(studentRepo, cur, StudentEntity.class);
             s.setEnable(true);
             studentRepo.save(s);
+            //操作日志
+            ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(),s.getId(), null, UserType.COMMON,
+            		OperateContent.STUDENT_ENABLE.getDesc()));
             ret.add(s.getId() + ":" + s.getName());
         }
         for (Long cur : studentIds) {
@@ -424,6 +443,9 @@ public class StudentController extends ControllerSupport {
             StudentEntity s = GlobalHelper.getEntity(studentRepo, cur, StudentEntity.class);
             s.setEnable(false);
             studentRepo.save(s);
+            //操作日志
+            ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(), s.getId(),null, UserType.COMMON,
+            		OperateContent.STUDENT_DISABLE.getDesc()));
             ret.add(s.getId() + ":" + s.getName());
         }
         for (Long cur : studentIds) {
@@ -452,6 +474,9 @@ public class StudentController extends ControllerSupport {
             }
             s.setUpdateTime(new Date());
             studentRepo.save(s);
+            //操作日志
+            ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(),s.getId(), null, UserType.COMMON,
+            		OperateContent.STUDENT_PASSWORD_RESET.getDesc()));
         }
     }
 
@@ -474,6 +499,9 @@ public class StudentController extends ControllerSupport {
             }
             s.setUpdateTime(new Date());
             studentRepo.save(s);
+            //操作日志
+            ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(),s.getId(), null, UserType.COMMON,
+            		OperateContent.STUDENT_PASSWORD_RESET.getDesc()));
         }
     }
 
@@ -501,6 +529,9 @@ public class StudentController extends ControllerSupport {
                 StudentEntity.class);
         s.setPassword(newPassword);
         studentRepo.save(s);
+        //操作日志
+        ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(), s.getId(),null, UserType.STUDENT,
+        		OperateContent.STUDENT_PASSWORD_UPDATE.getDesc()));
         return s.getId();
     }
 
@@ -536,6 +567,9 @@ public class StudentController extends ControllerSupport {
         }
         s.setPassword(newPassword);
         studentRepo.save(s);
+        //操作日志
+        ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(), s.getId(),null, UserType.STUDENT,
+        		OperateContent.STUDENT_PASSWORD_UPDATE.getDesc()));
         return s.getId();
     }
 
@@ -622,6 +656,9 @@ public class StudentController extends ControllerSupport {
 
         for (Long cur : studentIdList) {
             studentCache.remove(cur);
+            //操作日志
+            ReportsUtil.report(new OperateReport(rootOrgId, getAccessUser().getUserId(),cur, null, UserType.COMMON,
+            		OperateContent.STUDENT_UNBIND_STUDENTCODE.getDesc()));
         }
 
         return studentIdList;
@@ -643,6 +680,10 @@ public class StudentController extends ControllerSupport {
 
         for (Long cur : studentIds) {
             studentService.unbindSecurityPhone(cur);
+            StudentEntity s = GlobalHelper.getEntity(studentRepo, cur, StudentEntity.class);
+            //操作日志
+            ReportsUtil.report(new OperateReport(s.getRootOrgId(), getAccessUser().getUserId(),s.getId(), null, UserType.COMMON,
+            		OperateContent.STUDENT_UNBIND_PHONE.getDesc()));
         }
 
         for (Long cur : studentIds) {
@@ -650,5 +691,14 @@ public class StudentController extends ControllerSupport {
         }
 
     }
+    
+    @ApiOperation(value = "学生在线信号", notes = "学生在线信号")
+    @GetMapping("online_signal/{studentId}")
+    public void onlineSignal(@PathVariable Long studentId) {
+    	User accessUser = getAccessUser();
+
+        //在线学生
+        ReportsUtil.report(new OnlineStudentReport(accessUser.getRootOrgId(), studentId));
+    }
 
 }

+ 157 - 0
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SysNoticeController.java

@@ -0,0 +1,157 @@
+package cn.com.qmth.examcloud.core.basic.api.controller;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.core.basic.api.controller.bean.SysNoticeDomain;
+import cn.com.qmth.examcloud.core.basic.dao.SysNoticeRepo;
+import cn.com.qmth.examcloud.core.basic.dao.entity.SysNoticeEntity;
+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.helpers.GlobalHelper;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.mysql.cj.util.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @Description 系统通知 状态码范围007XXX
+ * @Author lideyin
+ * @Date 2020/8/16 10:49
+ * @Version 1.0
+ */
+@RestController
+@Api(tags = "系统通知")
+@RequestMapping("${$rmp.ctr.basic}/sys/notice")
+public class SysNoticeController extends ControllerSupport {
+
+    @Autowired
+    SysNoticeRepo sysNoticeRepo;
+    @Autowired
+    SystemProperties systemConfig;
+
+    @ApiOperation(value = "查询系统通知")
+    @GetMapping("getSysNotice")
+    public SysNoticeDomain getSysNotice(@RequestParam(required = false) Long rootOrgId) {
+        //不传默认取全部
+        if (null == rootOrgId) {
+            rootOrgId = -1L;
+        }
+
+        SysNoticeEntity entity = sysNoticeRepo.findTopByRootOrgIdOrderByIdDesc(rootOrgId);
+        if (null == entity) {
+            return null;
+        }
+
+        SysNoticeDomain domain = new SysNoticeDomain();
+        domain.setId(entity.getId());
+        domain.setRootOrgId(entity.getRootOrgId());
+        domain.setContent(entity.getContent());
+        domain.setStartTime(DateUtil.format(entity.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+        domain.setEndTime(DateUtil.format(entity.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+        domain.setTitle(entity.getTitle());
+        domain.setEnable(entity.getEnable());
+
+        return domain;
+    }
+
+    @ApiOperation(value = "保存系统通知", notes = "")
+    @PutMapping("saveSysNotice")
+    public String saveOrgProperties(@RequestBody SysNoticeDomain domain) {
+        if (StringUtils.isNullOrEmpty(domain.getContent())) {
+            throw new StatusException("007001", "通知标题不允许为空");
+        }
+
+        if (StringUtils.isNullOrEmpty(domain.getContent())) {
+            throw new StatusException("007002", "通知内容不允许为空");
+        }
+
+        if (StringUtils.isNullOrEmpty(domain.getStartTime()) ||
+                StringUtils.isNullOrEmpty(domain.getEndTime())) {
+            throw new StatusException("007003", "通知有效期不允许为空");
+        }
+
+        if (StringUtils.isNullOrEmpty(domain.getContent())) {
+            throw new StatusException("007004", "通知状态不允许为空");
+        }
+
+        SysNoticeEntity entity = null;
+        //新增
+        if (null == domain.getId()) {
+            entity = new SysNoticeEntity();
+            entity.setRootOrgId(domain.getRootOrgId() == null ? -1 : domain.getRootOrgId());
+            entity.setContent(domain.getContent());
+            entity.setStartTime(DateUtil.parse(domain.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+            entity.setEndTime(DateUtil.parse(domain.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+            entity.setTitle(domain.getTitle());
+            entity.setEnable(domain.getEnable());
+
+            sysNoticeRepo.save(entity);
+        }
+        //修改
+        else {
+            entity = GlobalHelper.getEntity(sysNoticeRepo, domain.getId(), SysNoticeEntity.class);
+            if (null == entity) {
+                throw new StatusException("007005", "请求参数不正确请重试");
+            }
+
+            entity.setContent(domain.getContent());
+            entity.setStartTime(DateUtil.parse(domain.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+            entity.setEndTime(DateUtil.parse(domain.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+            entity.setRootOrgId(domain.getRootOrgId() == null ? -1 : domain.getRootOrgId());
+            entity.setTitle(domain.getTitle());
+            entity.setEnable(domain.getEnable());
+
+            sysNoticeRepo.save(entity);
+        }
+
+        //保存通知数据到阿里云
+        SysNoticeDomain resultNotice = new SysNoticeDomain();
+        resultNotice.setId(entity.getId());
+        resultNotice.setRootOrgId(entity.getRootOrgId());
+        resultNotice.setContent(entity.getContent());
+        resultNotice.setStartTime(DateUtil.format(entity.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+        resultNotice.setEndTime(DateUtil.format(entity.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT));
+        resultNotice.setTitle(entity.getTitle());
+        resultNotice.setEnable(entity.getEnable());
+
+        String prettyJson = JsonUtil.toPrettyJson(resultNotice);
+
+        String fileSuffix = ".json";
+        String filePath = systemConfig.getTempDataDir() + File.separator + "notice"
+                + File.separator + resultNotice.getRootOrgId() + fileSuffix;
+        filePath = PathUtil.getCanonicalPath(filePath);
+        File file = new File(filePath);
+
+        try {
+            FileUtils.write(file, prettyJson, "UTF-8");
+
+            //通用存储
+            YunPathInfo pi = null;
+            FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+            env.setFileSuffix(fileSuffix);
+            String strRootOrgId = -1 == resultNotice.getRootOrgId()
+                    ? "all"
+                    : String.valueOf(resultNotice.getRootOrgId());
+            env.setRootOrgId(strRootOrgId);
+            pi = FileStorageUtil.saveFile("sysNotice", env, file, null);
+
+            return pi.getUrl();//返回通知保存的地址
+
+        } catch (IOException e) {
+            throw new ExamCloudRuntimeException(e);
+        } finally {
+            FileUtils.deleteQuietly(file);
+        }
+    }
+}

+ 110 - 118
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/SystemPropertyController.java

@@ -1,13 +1,16 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.criteria.Predicate;
-import javax.validation.Valid;
-
+import cn.com.qmth.examcloud.core.basic.api.controller.bean.SystemPropertyDomain;
+import cn.com.qmth.examcloud.core.basic.dao.SystemPropertyRepo;
+import cn.com.qmth.examcloud.core.basic.dao.entity.SystemPropertyEntity;
+import cn.com.qmth.examcloud.core.basic.service.SystemPropertyService;
+import cn.com.qmth.examcloud.core.basic.service.bean.SystemPropertyInfo;
+import cn.com.qmth.examcloud.core.basic.service.cache.SystemPropertyCache;
+import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -17,27 +20,14 @@ import org.springframework.data.domain.Sort;
 import org.springframework.data.domain.Sort.Direction;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-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.bind.annotation.*;
 
-import com.google.common.collect.Lists;
-
-import cn.com.qmth.examcloud.core.basic.api.controller.bean.SystemPropertyDomain;
-import cn.com.qmth.examcloud.core.basic.dao.SystemPropertyRepo;
-import cn.com.qmth.examcloud.core.basic.dao.entity.SystemPropertyEntity;
-import cn.com.qmth.examcloud.core.basic.service.SystemPropertyService;
-import cn.com.qmth.examcloud.core.basic.service.bean.SystemPropertyInfo;
-import cn.com.qmth.examcloud.core.basic.service.cache.SystemPropertyCache;
-import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
-import cn.com.qmth.examcloud.web.support.ControllerSupport;
-import io.swagger.annotations.ApiOperation;
+import javax.persistence.criteria.Predicate;
+import javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 系统配置
@@ -47,98 +37,100 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "系统配置相关接口")
 @RequestMapping("${$rmp.ctr.basic}/systemProperty")
 public class SystemPropertyController extends ControllerSupport {
 
-	@Autowired
-	SystemPropertyService systemPropertyService;
-
-	@Autowired
-	SystemPropertyRepo systemPropertyRepo;
-
-	@Autowired
-	SystemPropertyCache systemPropertyCache;
-
-	@ApiOperation(value = "查询系统配置")
-	@GetMapping("{key}")
-	public Object get(@PathVariable String key) {
-		Object object = systemPropertyService.get(key);
-		return object;
-	}
-
-	@ApiOperation(value = "查询系统配置")
-	@GetMapping("page/{curPage}/{pageSize}")
-	public Page<SystemPropertyEntity> get(@PathVariable Integer curPage,
-			@PathVariable Integer pageSize, @RequestParam(required = false) String propKey,
-			@RequestParam(required = false) String description,
-			@RequestParam(required = false) String propValue) {
-
-		Specification<SystemPropertyEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			if (StringUtils.isNotBlank(propKey)) {
-				predicates.add(cb.like(root.get("propKey"), toSqlSearchPattern(propKey)));
-			}
-			if (StringUtils.isNotBlank(description)) {
-				predicates.add(cb.like(root.get("description"), toSqlSearchPattern(description)));
-			}
-			if (StringUtils.isNotBlank(propValue)) {
-				predicates.add(cb.like(root.get("propValue"), toSqlSearchPattern(propValue)));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-				new Sort(Direction.DESC, "updateTime", "propKey"));
-
-		Page<SystemPropertyEntity> page = systemPropertyRepo.findAll(specification, pageRequest);
-
-		return page;
-	}
-
-	@ApiOperation(value = "新增系统参数")
-	@PostMapping
-	@Transactional
-	public void addSysProp(@RequestBody @Valid SystemPropertyDomain domain) {
-		SystemPropertyInfo info = new SystemPropertyInfo();
-		info.setDescription(domain.getDescription());
-		info.setPropKey(domain.getPropKey());
-		info.setPropValue(domain.getPropValue());
-		info.setPropValueType(domain.getPropValueType());
-		systemPropertyService.addSysProp(info);
-	}
-
-	@ApiOperation(value = "更新系统参数")
-	@PutMapping
-	@Transactional
-	public void updateSysProp(@RequestBody @Valid SystemPropertyDomain domain) {
-		SystemPropertyInfo info = new SystemPropertyInfo();
-		info.setDescription(domain.getDescription());
-		info.setPropKey(domain.getPropKey());
-		info.setPropValue(domain.getPropValue());
-		info.setPropValueType(domain.getPropValueType());
-		systemPropertyService.updateSysProp(info);
-	}
-
-	@ApiOperation(value = "删除系统参数")
-	@DeleteMapping("{ids}")
-	@Transactional
-	public void deleteSysProp(@PathVariable @Required String ids) {
-		List<String> propKeys = Stream.of(ids.split(",")).map(s -> s.trim())
-				.collect(Collectors.toList());
-		List<SystemPropertyEntity> list = Lists.newArrayList();
-		for (String key : propKeys) {
-			SystemPropertyEntity prop = GlobalHelper.getPresentEntity(systemPropertyRepo, key,
-					SystemPropertyEntity.class);
-			systemPropertyRepo.delete(prop);
-			list.add(prop);
-		}
-
-		for (SystemPropertyEntity cur : list) {
-			systemPropertyCache.refresh(cur.getPropKey());
-		}
-
-	}
+    @Autowired
+    SystemPropertyService systemPropertyService;
+
+    @Autowired
+    SystemPropertyRepo systemPropertyRepo;
+
+    @Autowired
+    SystemPropertyCache systemPropertyCache;
+
+    @ApiOperation(value = "查询系统配置")
+    @GetMapping("{key}")
+    public Object get(@PathVariable String key) {
+        Object object = systemPropertyService.get(key);
+        return object;
+    }
+
+    @ApiOperation(value = "查询系统配置")
+    @GetMapping("page/{curPage}/{pageSize}")
+    public Page<SystemPropertyEntity> get(@PathVariable Integer curPage,
+                                          @PathVariable Integer pageSize,
+                                          @RequestParam(required = false) String propKey,
+                                          @RequestParam(required = false) String description,
+                                          @RequestParam(required = false) String propValue) {
+
+        Specification<SystemPropertyEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            if (StringUtils.isNotBlank(propKey)) {
+                predicates.add(cb.like(root.get("propKey"), toSqlSearchPattern(propKey)));
+            }
+            if (StringUtils.isNotBlank(description)) {
+                predicates.add(cb.like(root.get("description"), toSqlSearchPattern(description)));
+            }
+            if (StringUtils.isNotBlank(propValue)) {
+                predicates.add(cb.like(root.get("propValue"), toSqlSearchPattern(propValue)));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        PageRequest pageRequest = PageRequest.of(curPage, pageSize,
+                new Sort(Direction.DESC, "updateTime", "propKey"));
+
+        Page<SystemPropertyEntity> page = systemPropertyRepo.findAll(specification, pageRequest);
+
+        return page;
+    }
+
+    @ApiOperation(value = "新增系统参数")
+    @PostMapping
+    @Transactional
+    public void addSysProp(@RequestBody @Valid SystemPropertyDomain domain) {
+        SystemPropertyInfo info = new SystemPropertyInfo();
+        info.setDescription(domain.getDescription());
+        info.setPropKey(domain.getPropKey());
+        info.setPropValue(domain.getPropValue());
+        info.setPropValueType(domain.getPropValueType());
+        systemPropertyService.addSysProp(info);
+    }
+
+    @ApiOperation(value = "更新系统参数")
+    @PutMapping
+    @Transactional
+    public void updateSysProp(@RequestBody @Valid SystemPropertyDomain domain) {
+        SystemPropertyInfo info = new SystemPropertyInfo();
+        info.setDescription(domain.getDescription());
+        info.setPropKey(domain.getPropKey());
+        info.setPropValue(domain.getPropValue());
+        info.setPropValueType(domain.getPropValueType());
+        systemPropertyService.updateSysProp(info);
+    }
+
+    @ApiOperation(value = "删除系统参数")
+    @DeleteMapping("{ids}")
+    @Transactional
+    public void deleteSysProp(@PathVariable @Required String ids) {
+        List<String> propKeys = Stream.of(ids.split(",")).map(s -> s.trim())
+                .collect(Collectors.toList());
+        List<SystemPropertyEntity> list = Lists.newArrayList();
+        for (String key : propKeys) {
+            SystemPropertyEntity prop = GlobalHelper.getPresentEntity(systemPropertyRepo, key,
+                    SystemPropertyEntity.class);
+            systemPropertyRepo.delete(prop);
+            list.add(prop);
+        }
+
+        for (SystemPropertyEntity cur : list) {
+            systemPropertyCache.refresh(cur.getPropKey());
+        }
+
+    }
 
 }

+ 37 - 40
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/TestController.java

@@ -1,18 +1,14 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.Collections;
-
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
+import org.springframework.http.*;
 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.commons.util.DateUtil;
-import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import java.util.Collections;
 
 /**
  * 测试状态.勿修改或删除
@@ -22,39 +18,40 @@ import cn.com.qmth.examcloud.web.support.ControllerSupport;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "其它接口")
 @RequestMapping("${$rmp.ctr.basic}")
 public class TestController extends ControllerSupport {
 
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.GET)
-	public String get() {
-		return DateUtil.chinaNow();
-	}
-
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.HEAD)
-	public ResponseEntity<?> head() {
-		return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);
-	}
-
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.OPTIONS)
-	public HttpEntity<?> options() {
-		HttpHeaders headers = new HttpHeaders();
-		headers.setAllow(Collections.singleton(HttpMethod.GET));
-		return new ResponseEntity<Object>(headers, HttpStatus.OK);
-	}
-
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.POST)
-	public String post() {
-		return DateUtil.chinaNow();
-	}
-
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.PUT)
-	public String put() {
-		return DateUtil.chinaNow();
-	}
-
-	@RequestMapping(value = {"/", ""}, method = RequestMethod.DELETE)
-	public String delete() {
-		return DateUtil.chinaNow();
-	}
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.GET)
+    public String get() {
+        return DateUtil.chinaNow();
+    }
+
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.HEAD)
+    public ResponseEntity<?> head() {
+        return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);
+    }
+
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.OPTIONS)
+    public HttpEntity<?> options() {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setAllow(Collections.singleton(HttpMethod.GET));
+        return new ResponseEntity<Object>(headers, HttpStatus.OK);
+    }
+
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.POST)
+    public String post() {
+        return DateUtil.chinaNow();
+    }
+
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.PUT)
+    public String put() {
+        return DateUtil.chinaNow();
+    }
+
+    @RequestMapping(value = {"/", ""}, method = RequestMethod.DELETE)
+    public String delete() {
+        return DateUtil.chinaNow();
+    }
 
 }

+ 670 - 680
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/UserController.java

@@ -1,41 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.Subquery;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.domain.Sort.Direction;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
 import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
@@ -54,658 +18,684 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.UserRoleRelationEntity;
 import cn.com.qmth.examcloud.core.basic.service.UserService;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 用户服务API Created by songyue on 17/1/13.
  */
 @RestController
+@Api(tags = "用户相关接口")
 @RequestMapping("${$rmp.ctr.basic}/user")
 public class UserController extends ControllerSupport {
 
-	@Autowired
-	UserService userService;
-
-	@Autowired
-	UserRepo userRepo;
-
-	@Autowired
-	OrgRepo orgRepo;
-
-	@Autowired
-	RoleRepo roleRepo;
-
-	@Autowired
-	UserRoleRelationRepo userRoleRelationRepo;
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param curPage
-	 * @param pageSize
-	 * @param rootOrgId
-	 * @param loginName
-	 * @param name
-	 * @param enable
-	 * @param roleId
-	 * @param roleCode
-	 * @return
-	 */
-	@ApiOperation(value = "查询所有用户", notes = "")
-	@GetMapping("all/{curPage}/{pageSize}")
-	public PageInfo<UserDomain> getUserPage(@PathVariable Integer curPage,
-			@PathVariable Integer pageSize, @RequestParam(required = false) Long rootOrgId,
-			@RequestParam String loginName, @RequestParam String name,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long roleId, @RequestParam(required = false) Long orgId,
-			@RequestParam(required = false) String roleCode) {
-
-		User accessUser = getAccessUser();
-
-		if (null == rootOrgId) {
-			rootOrgId = accessUser.getRootOrgId();
-		} else {
-			validateRootOrgIsolation(rootOrgId);
-		}
-
-		final Long finalRootOrgId = rootOrgId;
-
-		OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
-		if (null == rootOrg) {
-			throw new StatusException("150003", "机构不存在");
-		}
-		if (null != rootOrg.getParentId()) {
-			throw new StatusException("150004", "机构错误");
-		}
-
-		if (null != roleId) {
-			RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
-			if (null == roleEntity) {
-				throw new StatusException("150002", "角色不存在");
-			}
-		} else if (StringUtils.isNotBlank(roleCode)) {
-			RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
-			if (null == roleEntity) {
-				roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(),
-						accessUser.getRootOrgId());
-			}
-			if (null == roleEntity) {
-				throw new StatusException("150002", "角色不存在");
-			}
-			roleId = roleEntity.getId();
-		}
-
-		final Long finalRoleId = roleId;
-
-		Specification<UserEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-			predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
-
-			if (StringUtils.isNotBlank(loginName)) {
-				predicates.add(cb.like(root.get("loginName"), toSqlSearchPattern(loginName)));
-			}
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (null != orgId) {
-				predicates.add(cb.equal(root.get("orgId"), orgId));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-			if (null != finalRoleId) {
-				Subquery<UserRoleRelationEntity> subquery = query
-						.subquery(UserRoleRelationEntity.class);
-				Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
-				subquery.select(subRoot.get("userId"));
-				Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
-				Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-		Pageable pageable = PageRequest.of(curPage - 1, pageSize, Sort.Direction.DESC, "updateTime",
-				"id");
-
-		Page<UserEntity> userList = userRepo.findAll(specification, pageable);
-
-		Iterator<UserEntity> iterator = userList.iterator();
-
-		List<UserDomain> fullUserInfoList = Lists.newArrayList();
-		while (iterator.hasNext()) {
-			UserEntity next = iterator.next();
-			UserDomain bean = new UserDomain();
-			bean.setId(next.getId());
-			bean.setLoginName(next.getLoginName());
-			bean.setName(next.getName());
-			bean.setRootOrgId(next.getRootOrgId());
-			bean.setUpdateTime(next.getUpdateTime());
-			bean.setCreationTime(next.getCreationTime());
-			bean.setOrgId(next.getOrgId());
-			bean.setPhoneNumber(next.getPhoneNumber());
-			if (null != bean.getOrgId()) {
-				OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
-						OrgEntity.class);
-				if (null != org) {
-					bean.setOrgName(org.getName());
-					bean.setOrgCode(org.getCode());
-				}
-			}
-			bean.setRootOrgName(rootOrg.getName());
-			bean.setEnable(next.getEnable());
-
-			List<UserRoleRelationEntity> relationList = userRoleRelationRepo
-					.findAllByUserId(next.getId());
-			List<String> roleNameList = Lists.newArrayList();
-			List<Long> roleIdList = Lists.newArrayList();
-			List<String> roleCodeList = Lists.newArrayList();
-			for (UserRoleRelationEntity cur : relationList) {
-				RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur.getRoleId(),
-						RoleEntity.class);
-				if (null == curRoleEntity) {
-					throw new StatusException("150002", "角色错误");
-				}
-				roleNameList.add(curRoleEntity.getName());
-				roleIdList.add(curRoleEntity.getId());
-				roleCodeList.add(curRoleEntity.getCode());
-			}
-			bean.setRoleNamesStr(StringUtils.join(roleNameList, ","));
-			bean.setRoleIds(roleIdList);
-			bean.setRoleCodes(roleCodeList);
-
-			fullUserInfoList.add(bean);
-		}
-
-		PageInfo<UserDomain> ret = new PageInfo<UserDomain>();
-		ret.setList(fullUserInfoList);
-		ret.setTotal(userList.getTotalElements());
-		return ret;
-	}
-
-	@ApiOperation(value = "模糊查询用户", notes = "")
-	@GetMapping("query")
-	public List<UserDomain> query(@RequestParam(required = false) Long rootOrgId,
-			@RequestParam(required = false) String rootOrgCode,
-			@RequestParam(required = false) String loginName,
-			@RequestParam(required = false) String name,
-			@RequestParam(required = false) Boolean enable,
-			@RequestParam(required = false) Long roleId, @RequestParam(required = false) Long orgId,
-			@RequestParam(required = false) String roleCode) {
-
-		OrgEntity rootOrg = null;
-
-		if (null != rootOrgId) {
-			rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
-			if (null == rootOrg) {
-				throw new StatusException("150003", "机构不存在");
-			}
-		} else if (StringUtils.isNotBlank(rootOrgCode)) {
-			rootOrg = orgRepo.findByParentIdIsNullAndCode(rootOrgCode);
-			if (null == rootOrg) {
-				throw new StatusException("150003", "机构不存在");
-			}
-		}
-
-		if (null != rootOrg) {
-			if (null != rootOrg.getParentId()) {
-				throw new StatusException("150004", "机构错误");
-			}
-			rootOrgId = rootOrg.getId();
-		}
-
-		final Long finalRootOrgId = rootOrgId;
-
-		if (null != roleId) {
-			RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
-			if (null == roleEntity) {
-				throw new StatusException("150002", "角色不存在");
-			}
-		} else if (StringUtils.isNotBlank(roleCode)) {
-			RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
-			if (null == roleEntity) {
-				roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(), rootOrgId);
-			}
-			if (null == roleEntity) {
-				throw new StatusException("150002", "角色不存在");
-			}
-			roleId = roleEntity.getId();
-		}
-
-		final Long finalRoleId = roleId;
-
-		Specification<UserEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			if (null != finalRootOrgId) {
-				predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
-			}
-
-			if (StringUtils.isNotBlank(loginName)) {
-				predicates.add(cb.like(root.get("loginName"), toSqlSearchPattern(loginName)));
-			}
-			if (StringUtils.isNotBlank(name)) {
-				predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
-			}
-			if (null != orgId) {
-				predicates.add(cb.equal(root.get("orgId"), orgId));
-			}
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-			if (null != finalRoleId) {
-				Subquery<UserRoleRelationEntity> subquery = query
-						.subquery(UserRoleRelationEntity.class);
-				Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
-				subquery.select(subRoot.get("userId"));
-				Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
-				Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
-				subquery.where(cb.and(p1, p2));
-				predicates.add(cb.exists(subquery));
-			}
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		PageRequest pageRequest = PageRequest.of(0, 50, new Sort(Direction.DESC, "updateTime"));
-
-		Page<UserEntity> userList = userRepo.findAll(specification, pageRequest);
-
-		Iterator<UserEntity> iterator = userList.iterator();
-
-		List<UserDomain> fullUserInfoList = Lists.newArrayList();
-		while (iterator.hasNext()) {
-			UserEntity next = iterator.next();
-			UserDomain bean = new UserDomain();
-			bean.setId(next.getId());
-			bean.setLoginName(next.getLoginName());
-			bean.setName(next.getName());
-			bean.setRootOrgId(next.getRootOrgId());
-			bean.setUpdateTime(next.getUpdateTime());
-			bean.setCreationTime(next.getCreationTime());
-			bean.setOrgId(next.getOrgId());
-			if (null != bean.getOrgId()) {
-				OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
-						OrgEntity.class);
-				if (null != org) {
-					bean.setOrgName(org.getName());
-					bean.setOrgCode(org.getCode());
-				}
-			}
-			bean.setRootOrgName(rootOrg.getName());
-			bean.setEnable(next.getEnable());
-
-			List<UserRoleRelationEntity> relationList = userRoleRelationRepo
-					.findAllByUserId(next.getId());
-			List<String> roleNameList = Lists.newArrayList();
-			List<Long> roleIdList = Lists.newArrayList();
-			List<String> roleCodeList = Lists.newArrayList();
-			for (UserRoleRelationEntity cur : relationList) {
-				RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur.getRoleId(),
-						RoleEntity.class);
-				if (null == curRoleEntity) {
-					throw new StatusException("150002", "角色错误");
-				}
-				roleNameList.add(curRoleEntity.getName());
-				roleIdList.add(curRoleEntity.getId());
-				roleCodeList.add(curRoleEntity.getCode());
-			}
-			bean.setRoleNamesStr(StringUtils.join(roleNameList, ","));
-			bean.setRoleIds(roleIdList);
-			bean.setRoleCodes(roleCodeList);
-
-			fullUserInfoList.add(bean);
-		}
-
-		return fullUserInfoList;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param id
-	 * @return
-	 */
-	@ApiOperation(value = "查询登陆用户", notes = "")
-	@GetMapping("getUserBySession")
-	public UserDomain getUserBySession() {
-		User accessUser = getAccessUser();
-		UserEntity userEntity = GlobalHelper.getEntity(userRepo, accessUser.getUserId(),
-				UserEntity.class);
-
-		UserDomain bean = new UserDomain();
-		bean.setId(userEntity.getId());
-		bean.setLoginName(userEntity.getLoginName());
-		bean.setName(userEntity.getName());
-		bean.setRootOrgId(userEntity.getRootOrgId());
-		bean.setUpdateTime(userEntity.getUpdateTime());
-		bean.setCreationTime(userEntity.getCreationTime());
-		bean.setOrgId(userEntity.getOrgId());
-		if (null != bean.getOrgId()) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
-					OrgEntity.class);
-			if (null != org) {
-				bean.setOrgName(org.getName());
-				bean.setOrgCode(org.getCode());
-			}
-		}
-		bean.setEnable(userEntity.getEnable());
-		return bean;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param id
-	 * @return
-	 */
-	@ApiOperation(value = "按id查询用户", notes = "id查询")
-	@GetMapping("/{id}")
-	public UserDomain getUserById(@PathVariable long id) {
-		UserEntity userEntity = GlobalHelper.getEntity(userRepo, id, UserEntity.class);
-
-		UserDomain bean = new UserDomain();
-		bean.setId(userEntity.getId());
-		bean.setLoginName(userEntity.getLoginName());
-		bean.setName(userEntity.getName());
-		bean.setRootOrgId(userEntity.getRootOrgId());
-		bean.setUpdateTime(userEntity.getUpdateTime());
-		bean.setCreationTime(userEntity.getCreationTime());
-		bean.setOrgId(userEntity.getOrgId());
-		if (null != bean.getOrgId()) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
-					OrgEntity.class);
-			if (null != org) {
-				bean.setOrgName(org.getName());
-				bean.setOrgCode(org.getCode());
-			}
-		}
-		bean.setEnable(userEntity.getEnable());
-		return bean;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param orgId
-	 * @return
-	 */
-	@ApiOperation(value = "按orgId查询用户", notes = "机构id查询机构用户")
-	@GetMapping("/org/{orgId}")
-	public List<UserEntity> getUserByOrgId(@PathVariable long orgId) {
-		List<UserEntity> userList = userRepo.findByOrgId(orgId);
-		return userList;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param rootOrgId
-	 * @return
-	 */
-	@ApiOperation(value = "按rootOrgId查询用户", notes = "根机构id查询机构用户")
-	@GetMapping("/rootOrg/{rootOrgId}")
-	public List<UserEntity> getUserByRootOrgId(@PathVariable long rootOrgId) {
-		List<UserEntity> userList = userRepo.findByRootOrgId(rootOrgId);
-		return userList;
-	}
-
-	/**
-	 * 重构 2018年6月26日
-	 *
-	 * @author WANGWEI
-	 * @param userForm
-	 * @return
-	 */
-	@ApiOperation(value = "新增用户", notes = "新增")
-	@PostMapping
-	@Transactional
-	public Map<String, Object> addUser(@RequestBody UserFormDomain userForm) {
-		trim(userForm, true);
-		userForm.setId(null);
-		return saveUser(userForm);
-	}
-
-	/**
-	 * 重构 2018年6月26日
-	 *
-	 * @author WANGWEI
-	 * @param userForm
-	 * @return
-	 */
-	@ApiOperation(value = "更新用户", notes = "更新")
-	@PutMapping
-	@Transactional
-	public Map<String, Object> updateUser(@RequestBody UserFormDomain userForm) {
-		trim(userForm, true);
-		if (null == userForm.getId()) {
-			throw new StatusException("150009", "user ID is null");
-		}
-
-		UserEntity userEntity = GlobalHelper.getEntity(userRepo, userForm.getId(),
-				UserEntity.class);
-		if (null == userEntity) {
-			throw new StatusException("150010", "用户不存在");
-		}
-
-		if (!userEntity.getRootOrgId().equals(userForm.getRootOrgId())) {
-			throw new StatusException("150010", "顶级机构错误");
-		}
-
-		userForm.setPassword(userEntity.getPassword());
-
-		return saveUser(userForm);
-	}
-
-	/**
-	 * 新增或更新用户
-	 *
-	 * @author WANGWEI
-	 * @param userForm
-	 * @return
-	 */
-	private Map<String, Object> saveUser(UserFormDomain userForm) {
-
-		Long rootOrgId = userForm.getRootOrgId();
-		Long orgId = userForm.getOrgId();
-
-		if (StringUtils.isBlank(userForm.getName())) {
-			throw new StatusException("130001", "用户名不能为空");
-		}
-		if (StringUtils.isBlank(userForm.getLoginName())) {
-			throw new StatusException("130002", "登陆名不能为空");
-		}
-		if (StringUtils.isBlank(userForm.getPassword())) {
-			throw new StatusException("130003", "密码不能为空");
-		}
-
-		if (null == rootOrgId) {
-			throw new StatusException("150002", "rootOrgId is null");
-		}
-		OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
-		if (null == rootOrg) {
-			throw new StatusException("150003", "机构不存在");
-		}
-		if (null != rootOrg.getParentId()) {
-			throw new StatusException("150004", "机构错误");
-		}
-
-		validateRootOrgIsolation(rootOrgId);
-
-		if (null != orgId) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, orgId, OrgEntity.class);
-			if (null == org) {
-				throw new StatusException("150101", "子机构不存在");
-			}
-			if (null == org.getParentId()) {
-				throw new StatusException("150102", "子机构错误");
-			}
-			if (!org.getRootId().equals(rootOrgId)) {
-				throw new StatusException("150103", "子机构错误");
-			}
-		}
-
-		UserEntity userEntity = new UserEntity();
-		userEntity.setId(userForm.getId());
-		userEntity.setEnable(userForm.getEnable());
-		userEntity.setLoginName(userForm.getLoginName());
-		userEntity.setPhoneNumber(userForm.getPhoneNumber());
-		userEntity.setName(userForm.getName());
-		userEntity.setOrgId(orgId);
-		userEntity.setRootOrgId(rootOrgId);
-		userEntity.setPassword(userForm.getPassword());
-		userEntity.setUpdateTime(new Date());
-
-		UserEntity saved = userService.save(userEntity);
-
-		List<UserRoleRelationEntity> userRoles = Lists.newArrayList();
-		List<Long> roleIds = userForm.getRoleIds();
-		for (Long cur : roleIds) {
-			RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur, RoleEntity.class);
-			if (null == curRoleEntity) {
-				throw new StatusException("150005", "角色错误");
-			}
-
-			Long roleRootOrgId = curRoleEntity.getRootOrgId();
-			if (null != roleRootOrgId && (!roleRootOrgId.equals(rootOrgId))) {
-				throw new StatusException("150006", "角色错误");
-			}
-
-			if (curRoleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-				throw new StatusException("150007", "不允许新增或修改超级管理员");
-			}
-
-			if (curRoleEntity.getCode().equals(RoleMeta.LC_USER.name())) {
-				if (null == saved.getOrgId()) {
-					throw new StatusException("150008", "学习中心角色必须指定学习中心");
-				}
-			}
-
-			UserRoleRelationEntity relation = new UserRoleRelationEntity(saved.getId(),
-					curRoleEntity.getId());
-			userRoles.add(relation);
-		}
-
-		userRoleRelationRepo.deleteByUserId(saved.getId());
-		List<UserRoleRelationEntity> savedRelationList = userRoleRelationRepo.saveAll(userRoles);
-
-		Map<String, Object> ret = Maps.newHashMap();
-		ret.put("userId", saved.getId());
-		ret.put("loginName", saved.getLoginName());
-		ret.put("roleList", savedRelationList);
-		return ret;
-	}
-
-	/**
-	 * 判断是否是超级管理员
-	 *
-	 * @author WANGWEI
-	 * @param userId
-	 * @return
-	 */
-	private boolean isSuperAdmin(Long userId) {
-		List<UserRoleRelationEntity> relationList = userRoleRelationRepo.findAllByUserId(userId);
-		if (CollectionUtils.isNotEmpty(relationList)) {
-			for (UserRoleRelationEntity cur : relationList) {
-				Long roleId = cur.getRoleId();
-				RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
-				if (roleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-					return true;
-				}
-			}
-		}
-
-		return false;
-	}
-
-	@ApiOperation(value = "重置用户密码", notes = "重置密码")
-	@PutMapping("/resetPass/{id}")
-	@Transactional
-	public void resetPass(@PathVariable String id) {
-		List<Long> ids = Stream.of(id.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-
-		for (Long userId : ids) {
-			if (isSuperAdmin(userId)) {
-				throw new StatusException("150410", "超级管理员账号不允许修改");
-			}
-			UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
-			user.setPassword(BasicConsts.DEFAULT_PASSWORD);
-			userRepo.save(user);
-		}
-	}
-
-	@ApiOperation(value = "启用用户", notes = "启用用户")
-	@PutMapping("/enable/{ids}")
-	@Transactional
-	public List<String> enableUser(@PathVariable String ids) {
-		List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-		List<String> ret = Lists.newArrayList();
-		for (Long userId : userIds) {
-			if (isSuperAdmin(userId)) {
-				throw new StatusException("150410", "超级管理员账号不允许修改");
-			}
-			UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
-			user.setEnable(true);
-			userRepo.save(user);
-			ret.add(user.getId() + ":" + user.getName());
-		}
-		return ret;
-	}
-
-	@ApiOperation(value = "禁用用户", notes = "禁用用户")
-	@PutMapping("/disable/{ids}")
-	@Transactional
-	public List<String> disableUser(@PathVariable String ids) {
-		List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-		List<String> ret = Lists.newArrayList();
-		for (Long userId : userIds) {
-			if (isSuperAdmin(userId)) {
-				throw new StatusException("150410", "超级管理员账号不允许修改");
-			}
-			UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
-			user.setEnable(false);
-			userRepo.save(user);
-			ret.add(user.getId() + ":" + user.getName());
-		}
-		return ret;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param userId
-	 * @param password
-	 */
-	@ApiOperation(value = "修改用户密码", notes = "修改密码")
-	@PutMapping("/password")
-	@Transactional
-	public void updatePass(@RequestParam long userId, @RequestParam String password) {
-		String realPassword = StringEscapeUtils.unescapeJavaScript(password);
-		userRepo.updatePasswordById(userId, realPassword);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param ids
-	 */
-	@ApiOperation(value = "按id删除用户", notes = "删除")
-	@DeleteMapping("/{ids}")
-	public void deleteUser(@PathVariable String ids) {
-		List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
-				.collect(Collectors.toList());
-		for (Long userId : userIds) {
-			userRepo.deleteById(userId);
-		}
-	}
+    @Autowired
+    UserService userService;
+
+    @Autowired
+    UserRepo userRepo;
+
+    @Autowired
+    OrgRepo orgRepo;
+
+    @Autowired
+    RoleRepo roleRepo;
+
+    @Autowired
+    UserRoleRelationRepo userRoleRelationRepo;
+
+    /**
+     * 方法注释
+     *
+     * @param curPage
+     * @param pageSize
+     * @param rootOrgId
+     * @param loginName
+     * @param name
+     * @param enable
+     * @param roleId
+     * @param roleCode
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "查询所有用户", notes = "")
+    @GetMapping("all/{curPage}/{pageSize}")
+    public PageInfo<UserDomain> getUserPage(@PathVariable Integer curPage,
+                                            @PathVariable Integer pageSize,
+                                            @RequestParam(required = false) Long rootOrgId,
+                                            @RequestParam String loginName, @RequestParam String name,
+                                            @RequestParam(required = false) Boolean enable,
+                                            @RequestParam(required = false) Long roleId, @RequestParam(required =
+            false) Long orgId,
+                                            @RequestParam(required = false) String roleCode) {
+
+        User accessUser = getAccessUser();
+
+        if (null == rootOrgId) {
+            rootOrgId = accessUser.getRootOrgId();
+        } else {
+            validateRootOrgIsolation(rootOrgId);
+        }
+
+        final Long finalRootOrgId = rootOrgId;
+
+        OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
+        if (null == rootOrg) {
+            throw new StatusException("150003", "机构不存在");
+        }
+        if (null != rootOrg.getParentId()) {
+            throw new StatusException("150004", "机构错误");
+        }
+
+        if (null != roleId) {
+            RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
+            if (null == roleEntity) {
+                throw new StatusException("150002", "角色不存在");
+            }
+        } else if (StringUtils.isNotBlank(roleCode)) {
+            RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
+            if (null == roleEntity) {
+                roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(),
+                        accessUser.getRootOrgId());
+            }
+            if (null == roleEntity) {
+                throw new StatusException("150002", "角色不存在");
+            }
+            roleId = roleEntity.getId();
+        }
+
+        final Long finalRoleId = roleId;
+
+        Specification<UserEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
+
+            if (StringUtils.isNotBlank(loginName)) {
+                predicates.add(cb.like(root.get("loginName"), toSqlSearchPattern(loginName)));
+            }
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (null != orgId) {
+                predicates.add(cb.equal(root.get("orgId"), orgId));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+            if (null != finalRoleId) {
+                Subquery<UserRoleRelationEntity> subquery = query
+                        .subquery(UserRoleRelationEntity.class);
+                Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
+                subquery.select(subRoot.get("userId"));
+                Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
+                Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+        Pageable pageable = PageRequest.of(curPage - 1, pageSize, Sort.Direction.DESC, "updateTime",
+                "id");
+
+        Page<UserEntity> userList = userRepo.findAll(specification, pageable);
+
+        Iterator<UserEntity> iterator = userList.iterator();
+
+        List<UserDomain> fullUserInfoList = Lists.newArrayList();
+        while (iterator.hasNext()) {
+            UserEntity next = iterator.next();
+            UserDomain bean = new UserDomain();
+            bean.setId(next.getId());
+            bean.setLoginName(next.getLoginName());
+            bean.setName(next.getName());
+            bean.setRootOrgId(next.getRootOrgId());
+            bean.setUpdateTime(next.getUpdateTime());
+            bean.setCreationTime(next.getCreationTime());
+            bean.setOrgId(next.getOrgId());
+            bean.setPhoneNumber(next.getPhoneNumber());
+            if (null != bean.getOrgId()) {
+                OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
+                        OrgEntity.class);
+                if (null != org) {
+                    bean.setOrgName(org.getName());
+                    bean.setOrgCode(org.getCode());
+                }
+            }
+            bean.setRootOrgName(rootOrg.getName());
+            bean.setEnable(next.getEnable());
+
+            List<UserRoleRelationEntity> relationList = userRoleRelationRepo
+                    .findAllByUserId(next.getId());
+            List<String> roleNameList = Lists.newArrayList();
+            List<Long> roleIdList = Lists.newArrayList();
+            List<String> roleCodeList = Lists.newArrayList();
+            for (UserRoleRelationEntity cur : relationList) {
+                RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur.getRoleId(),
+                        RoleEntity.class);
+                if (null == curRoleEntity) {
+                    throw new StatusException("150002", "角色错误");
+                }
+                roleNameList.add(curRoleEntity.getName());
+                roleIdList.add(curRoleEntity.getId());
+                roleCodeList.add(curRoleEntity.getCode());
+            }
+            bean.setRoleNamesStr(StringUtils.join(roleNameList, ","));
+            bean.setRoleIds(roleIdList);
+            bean.setRoleCodes(roleCodeList);
+
+            fullUserInfoList.add(bean);
+        }
+
+        PageInfo<UserDomain> ret = new PageInfo<UserDomain>();
+        ret.setList(fullUserInfoList);
+        ret.setTotal(userList.getTotalElements());
+        return ret;
+    }
+
+    @ApiOperation(value = "模糊查询用户", notes = "")
+    @GetMapping("query")
+    public List<UserDomain> query(@RequestParam(required = false) Long rootOrgId,
+                                  @RequestParam(required = false) String rootOrgCode,
+                                  @RequestParam(required = false) String loginName,
+                                  @RequestParam(required = false) String name,
+                                  @RequestParam(required = false) Boolean enable,
+                                  @RequestParam(required = false) Long roleId,
+                                  @RequestParam(required = false) Long orgId,
+                                  @RequestParam(required = false) String roleCode) {
+
+        OrgEntity rootOrg = null;
+
+        if (null != rootOrgId) {
+            rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
+            if (null == rootOrg) {
+                throw new StatusException("150003", "机构不存在");
+            }
+        } else if (StringUtils.isNotBlank(rootOrgCode)) {
+            rootOrg = orgRepo.findByParentIdIsNullAndCode(rootOrgCode);
+            if (null == rootOrg) {
+                throw new StatusException("150003", "机构不存在");
+            }
+        }
+
+        if (null != rootOrg) {
+            if (null != rootOrg.getParentId()) {
+                throw new StatusException("150004", "机构错误");
+            }
+            rootOrgId = rootOrg.getId();
+        }
+
+        final Long finalRootOrgId = rootOrgId;
+
+        if (null != roleId) {
+            RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
+            if (null == roleEntity) {
+                throw new StatusException("150002", "角色不存在");
+            }
+        } else if (StringUtils.isNotBlank(roleCode)) {
+            RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
+            if (null == roleEntity) {
+                roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(), rootOrgId);
+            }
+            if (null == roleEntity) {
+                throw new StatusException("150002", "角色不存在");
+            }
+            roleId = roleEntity.getId();
+        }
+
+        final Long finalRoleId = roleId;
+
+        Specification<UserEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            if (null != finalRootOrgId) {
+                predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
+            }
+
+            if (StringUtils.isNotBlank(loginName)) {
+                predicates.add(cb.like(root.get("loginName"), toSqlSearchPattern(loginName)));
+            }
+            if (StringUtils.isNotBlank(name)) {
+                predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
+            }
+            if (null != orgId) {
+                predicates.add(cb.equal(root.get("orgId"), orgId));
+            }
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+            if (null != finalRoleId) {
+                Subquery<UserRoleRelationEntity> subquery = query
+                        .subquery(UserRoleRelationEntity.class);
+                Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
+                subquery.select(subRoot.get("userId"));
+                Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
+                Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
+                subquery.where(cb.and(p1, p2));
+                predicates.add(cb.exists(subquery));
+            }
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        PageRequest pageRequest = PageRequest.of(0, 50, new Sort(Direction.DESC, "updateTime"));
+
+        Page<UserEntity> userList = userRepo.findAll(specification, pageRequest);
+
+        Iterator<UserEntity> iterator = userList.iterator();
+
+        List<UserDomain> fullUserInfoList = Lists.newArrayList();
+        while (iterator.hasNext()) {
+            UserEntity next = iterator.next();
+            UserDomain bean = new UserDomain();
+            bean.setId(next.getId());
+            bean.setLoginName(next.getLoginName());
+            bean.setName(next.getName());
+            bean.setRootOrgId(next.getRootOrgId());
+            bean.setUpdateTime(next.getUpdateTime());
+            bean.setCreationTime(next.getCreationTime());
+            bean.setOrgId(next.getOrgId());
+            if (null != bean.getOrgId()) {
+                OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
+                        OrgEntity.class);
+                if (null != org) {
+                    bean.setOrgName(org.getName());
+                    bean.setOrgCode(org.getCode());
+                }
+            }
+            bean.setRootOrgName(rootOrg.getName());
+            bean.setEnable(next.getEnable());
+
+            List<UserRoleRelationEntity> relationList = userRoleRelationRepo
+                    .findAllByUserId(next.getId());
+            List<String> roleNameList = Lists.newArrayList();
+            List<Long> roleIdList = Lists.newArrayList();
+            List<String> roleCodeList = Lists.newArrayList();
+            for (UserRoleRelationEntity cur : relationList) {
+                RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur.getRoleId(),
+                        RoleEntity.class);
+                if (null == curRoleEntity) {
+                    throw new StatusException("150002", "角色错误");
+                }
+                roleNameList.add(curRoleEntity.getName());
+                roleIdList.add(curRoleEntity.getId());
+                roleCodeList.add(curRoleEntity.getCode());
+            }
+            bean.setRoleNamesStr(StringUtils.join(roleNameList, ","));
+            bean.setRoleIds(roleIdList);
+            bean.setRoleCodes(roleCodeList);
+
+            fullUserInfoList.add(bean);
+        }
+
+        return fullUserInfoList;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param id
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "查询登陆用户", notes = "")
+    @GetMapping("getUserBySession")
+    public UserDomain getUserBySession() {
+        User accessUser = getAccessUser();
+        UserEntity userEntity = GlobalHelper.getEntity(userRepo, accessUser.getUserId(),
+                UserEntity.class);
+
+        UserDomain bean = new UserDomain();
+        bean.setId(userEntity.getId());
+        bean.setLoginName(userEntity.getLoginName());
+        bean.setName(userEntity.getName());
+        bean.setRootOrgId(userEntity.getRootOrgId());
+        bean.setUpdateTime(userEntity.getUpdateTime());
+        bean.setCreationTime(userEntity.getCreationTime());
+        bean.setOrgId(userEntity.getOrgId());
+        if (null != bean.getOrgId()) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
+                    OrgEntity.class);
+            if (null != org) {
+                bean.setOrgName(org.getName());
+                bean.setOrgCode(org.getCode());
+            }
+        }
+        bean.setEnable(userEntity.getEnable());
+        return bean;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param id
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按id查询用户", notes = "id查询")
+    @GetMapping("/{id}")
+    public UserDomain getUserById(@PathVariable long id) {
+        UserEntity userEntity = GlobalHelper.getEntity(userRepo, id, UserEntity.class);
+
+        UserDomain bean = new UserDomain();
+        bean.setId(userEntity.getId());
+        bean.setLoginName(userEntity.getLoginName());
+        bean.setName(userEntity.getName());
+        bean.setRootOrgId(userEntity.getRootOrgId());
+        bean.setUpdateTime(userEntity.getUpdateTime());
+        bean.setCreationTime(userEntity.getCreationTime());
+        bean.setOrgId(userEntity.getOrgId());
+        if (null != bean.getOrgId()) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, Long.valueOf(bean.getOrgId()),
+                    OrgEntity.class);
+            if (null != org) {
+                bean.setOrgName(org.getName());
+                bean.setOrgCode(org.getCode());
+            }
+        }
+        bean.setEnable(userEntity.getEnable());
+        return bean;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param orgId
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按orgId查询用户", notes = "机构id查询机构用户")
+    @GetMapping("/org/{orgId}")
+    public List<UserEntity> getUserByOrgId(@PathVariable long orgId) {
+        List<UserEntity> userList = userRepo.findByOrgId(orgId);
+        return userList;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param rootOrgId
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按rootOrgId查询用户", notes = "根机构id查询机构用户")
+    @GetMapping("/rootOrg/{rootOrgId}")
+    public List<UserEntity> getUserByRootOrgId(@PathVariable long rootOrgId) {
+        List<UserEntity> userList = userRepo.findByRootOrgId(rootOrgId);
+        return userList;
+    }
+
+    /**
+     * 重构 2018年6月26日
+     *
+     * @param userForm
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "新增用户", notes = "新增")
+    @PostMapping
+    @Transactional
+    public Map<String, Object> addUser(@RequestBody UserFormDomain userForm) {
+        trim(userForm, true);
+        userForm.setId(null);
+        return saveUser(userForm);
+    }
+
+    /**
+     * 重构 2018年6月26日
+     *
+     * @param userForm
+     * @return
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "更新用户", notes = "更新")
+    @PutMapping
+    @Transactional
+    public Map<String, Object> updateUser(@RequestBody UserFormDomain userForm) {
+        trim(userForm, true);
+        if (null == userForm.getId()) {
+            throw new StatusException("150009", "user ID is null");
+        }
+
+        UserEntity userEntity = GlobalHelper.getEntity(userRepo, userForm.getId(),
+                UserEntity.class);
+        if (null == userEntity) {
+            throw new StatusException("150010", "用户不存在");
+        }
+
+        if (!userEntity.getRootOrgId().equals(userForm.getRootOrgId())) {
+            throw new StatusException("150010", "顶级机构错误");
+        }
+
+        userForm.setPassword(userEntity.getPassword());
+
+        return saveUser(userForm);
+    }
+
+    /**
+     * 新增或更新用户
+     *
+     * @param userForm
+     * @return
+     * @author WANGWEI
+     */
+    private Map<String, Object> saveUser(UserFormDomain userForm) {
+
+        Long rootOrgId = userForm.getRootOrgId();
+        Long orgId = userForm.getOrgId();
+
+        if (StringUtils.isBlank(userForm.getName())) {
+            throw new StatusException("130001", "用户名不能为空");
+        }
+        if (StringUtils.isBlank(userForm.getLoginName())) {
+            throw new StatusException("130002", "登陆名不能为空");
+        }
+        if (StringUtils.isBlank(userForm.getPassword())) {
+            throw new StatusException("130003", "密码不能为空");
+        }
+
+        if (null == rootOrgId) {
+            throw new StatusException("150002", "rootOrgId is null");
+        }
+        OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
+        if (null == rootOrg) {
+            throw new StatusException("150003", "机构不存在");
+        }
+        if (null != rootOrg.getParentId()) {
+            throw new StatusException("150004", "机构错误");
+        }
+
+        validateRootOrgIsolation(rootOrgId);
+
+        if (null != orgId) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, orgId, OrgEntity.class);
+            if (null == org) {
+                throw new StatusException("150101", "子机构不存在");
+            }
+            if (null == org.getParentId()) {
+                throw new StatusException("150102", "子机构错误");
+            }
+            if (!org.getRootId().equals(rootOrgId)) {
+                throw new StatusException("150103", "子机构错误");
+            }
+        }
+
+        UserEntity userEntity = new UserEntity();
+        userEntity.setId(userForm.getId());
+        userEntity.setEnable(userForm.getEnable());
+        userEntity.setLoginName(userForm.getLoginName());
+        userEntity.setPhoneNumber(userForm.getPhoneNumber());
+        userEntity.setName(userForm.getName());
+        userEntity.setOrgId(orgId);
+        userEntity.setRootOrgId(rootOrgId);
+        userEntity.setPassword(userForm.getPassword());
+        userEntity.setUpdateTime(new Date());
+
+        UserEntity saved = userService.save(userEntity);
+
+        List<UserRoleRelationEntity> userRoles = Lists.newArrayList();
+        List<Long> roleIds = userForm.getRoleIds();
+        for (Long cur : roleIds) {
+            RoleEntity curRoleEntity = GlobalHelper.getEntity(roleRepo, cur, RoleEntity.class);
+            if (null == curRoleEntity) {
+                throw new StatusException("150005", "角色错误");
+            }
+
+            Long roleRootOrgId = curRoleEntity.getRootOrgId();
+            if (null != roleRootOrgId && (!roleRootOrgId.equals(rootOrgId))) {
+                throw new StatusException("150006", "角色错误");
+            }
+
+            if (curRoleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+                throw new StatusException("150007", "不允许新增或修改超级管理员");
+            }
+
+            if (curRoleEntity.getCode().equals(RoleMeta.LC_USER.name())) {
+                if (null == saved.getOrgId()) {
+                    throw new StatusException("150008", "学习中心角色必须指定学习中心");
+                }
+            }
+
+            UserRoleRelationEntity relation = new UserRoleRelationEntity(saved.getId(),
+                    curRoleEntity.getId());
+            userRoles.add(relation);
+        }
+
+        userRoleRelationRepo.deleteByUserId(saved.getId());
+        List<UserRoleRelationEntity> savedRelationList = userRoleRelationRepo.saveAll(userRoles);
+
+        Map<String, Object> ret = Maps.newHashMap();
+        ret.put("userId", saved.getId());
+        ret.put("loginName", saved.getLoginName());
+        ret.put("roleList", savedRelationList);
+        return ret;
+    }
+
+    /**
+     * 判断是否是超级管理员
+     *
+     * @param userId
+     * @return
+     * @author WANGWEI
+     */
+    private boolean isSuperAdmin(Long userId) {
+        List<UserRoleRelationEntity> relationList = userRoleRelationRepo.findAllByUserId(userId);
+        if (CollectionUtils.isNotEmpty(relationList)) {
+            for (UserRoleRelationEntity cur : relationList) {
+                Long roleId = cur.getRoleId();
+                RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
+                if (roleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @ApiOperation(value = "重置用户密码", notes = "重置密码")
+    @PutMapping("/resetPass/{id}")
+    @Transactional
+    public void resetPass(@PathVariable String id) {
+        List<Long> ids = Stream.of(id.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+
+        for (Long userId : ids) {
+            if (isSuperAdmin(userId)) {
+                throw new StatusException("150410", "超级管理员账号不允许修改");
+            }
+            UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
+            user.setPassword(BasicConsts.DEFAULT_PASSWORD);
+            userRepo.save(user);
+        }
+    }
+
+    @ApiOperation(value = "启用用户", notes = "启用用户")
+    @PutMapping("/enable/{ids}")
+    @Transactional
+    public List<String> enableUser(@PathVariable String ids) {
+        List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+        List<String> ret = Lists.newArrayList();
+        for (Long userId : userIds) {
+            if (isSuperAdmin(userId)) {
+                throw new StatusException("150410", "超级管理员账号不允许修改");
+            }
+            UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
+            user.setEnable(true);
+            userRepo.save(user);
+            ret.add(user.getId() + ":" + user.getName());
+        }
+        return ret;
+    }
+
+    @ApiOperation(value = "禁用用户", notes = "禁用用户")
+    @PutMapping("/disable/{ids}")
+    @Transactional
+    public List<String> disableUser(@PathVariable String ids) {
+        List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+        List<String> ret = Lists.newArrayList();
+        for (Long userId : userIds) {
+            if (isSuperAdmin(userId)) {
+                throw new StatusException("150410", "超级管理员账号不允许修改");
+            }
+            UserEntity user = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
+            user.setEnable(false);
+            userRepo.save(user);
+            ret.add(user.getId() + ":" + user.getName());
+        }
+        return ret;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param userId
+     * @param password
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "修改用户密码", notes = "修改密码")
+    @PutMapping("/password")
+    @Transactional
+    public void updatePass(@RequestParam long userId, @RequestParam String password) {
+        String realPassword = StringEscapeUtils.unescapeJavaScript(password);
+        userRepo.updatePasswordById(userId, realPassword);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param ids
+     * @author WANGWEI
+     */
+    @ApiOperation(value = "按id删除用户", notes = "删除")
+    @DeleteMapping("/{ids}")
+    public void deleteUser(@PathVariable String ids) {
+        List<Long> userIds = Stream.of(ids.split(",")).map(s -> Long.parseLong(s.trim()))
+                .collect(Collectors.toList());
+        for (Long userId : userIds) {
+            userRepo.deleteById(userId);
+        }
+    }
 
 }

+ 59 - 16
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/VerifyCodeController.java

@@ -1,17 +1,25 @@
 package cn.com.qmth.examcloud.core.basic.api.controller;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
+import cn.com.qmth.examcloud.core.basic.service.LoginRuleService;
 import cn.com.qmth.examcloud.core.basic.service.VerifyCodeService;
-import cn.com.qmth.examcloud.core.basic.service.bean.VerifyCodeLoginInfo;
+import cn.com.qmth.examcloud.core.basic.service.bean.GeetestLoginInfo;
+import cn.com.qmth.examcloud.starters.greetest.model.RegisterReq;
+import cn.com.qmth.examcloud.starters.greetest.model.RegisterResp;
+import cn.com.qmth.examcloud.starters.greetest.model.ValidateResp;
+import cn.com.qmth.examcloud.starters.greetest.service.GeetestService;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import cn.com.qmth.examcloud.web.support.Naked;
 import cn.com.qmth.examcloud.web.support.StatusResponseX;
 import cn.com.qmth.examcloud.web.support.WithoutStackTrace;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -19,42 +27,77 @@ import javax.servlet.http.HttpServletRequest;
  * 验证码相关接口
  */
 @RestController
-@Api(tags = "验证码相关接口")
+@Api(tags = "验证码登录相关接口")
 public class VerifyCodeController extends ControllerSupport {
 
+    @Autowired
+    private LoginRuleService loginRuleService;
+
     @Autowired
     private VerifyCodeService verifyCodeService;
 
+    @Autowired
+    private GeetestService geetestService;
+
     @Naked
-    @ApiOperation(value = "验证码生成接口")
+    @ApiOperation(value = "极验-验证初始化接口")
+    @PostMapping(value = "/api/ecs_core/verifyCode/register")
+    public RegisterResp register(@RequestBody RegisterReq req, HttpServletRequest request) {
+        req.setIp_address(super.getIp(request));
+        return geetestService.register(req);
+    }
+
+    @Naked
+    @WithoutStackTrace
+    @ApiOperation(value = "极验-验证码登录接口")
+    @PostMapping(value = "/api/ecs_core/verifyCode/gt/login")
+    public StatusResponseX<User> geetestLogin(@RequestBody GeetestLoginInfo info, HttpServletRequest request) {
+        setAlwaysOKResponse();
+
+        if (info.getRootOrgId() == null) {
+            throw new StatusException("400", "顶级机构ID不能为空");
+        }
+
+        // 当前机构是否“开放极验验证码登录”
+        boolean open = loginRuleService.isLoginRuleAllow(info.getRootOrgId(), LoginRuleType.GEETEST_LOGIN);
+        if (open) {
+            info.setIp_address(super.getIp(request));
+            ValidateResp resp = geetestService.validate(info);
+            if (!resp.getSuccess()) {
+                throw new StatusException("400", resp.getMsg());
+            }
+        }
+
+        User user = verifyCodeService.geetestLogin(info);
+        return new StatusResponseX<>(user);
+    }
+
+    /*@Naked
+    @Deprecated
+    @ApiOperation(value = "数字公式-验证码生成接口(待废弃)")
     @PostMapping(value = "/api/ecs_core/verifyCode/generate")
     public String generate(@RequestParam Long rootOrgId, @RequestParam String accountValue) {
         return verifyCodeService.verifyCodeGenerate(rootOrgId, accountValue);
     }
 
     @Naked
+    @Deprecated
     @WithoutStackTrace
-    @ApiOperation(value = "验证码登录接口")
+    @ApiOperation(value = "数字公式-验证码登录接口(待废弃)")
     @PostMapping(value = "/api/ecs_core/verifyCode/login")
     public StatusResponseX<User> login(@RequestBody VerifyCodeLoginInfo info, HttpServletRequest request) {
-        String ip = request.getHeader("x-forwarded-for");
-        if (StringUtils.isBlank(ip)) {
-            ip = request.getHeader("x-real-ip");
-        }
-        if (StringUtils.isNotBlank(ip)) {
-            info.setClientIp(ip);
-        }
-
         setAlwaysOKResponse();
+
+        info.setClientIp(super.getIp(request));
         User user = verifyCodeService.verifyCodeLogin(info);
         return new StatusResponseX<>(user);
     }
 
     @Naked
-    @ApiOperation(value = "Resource接口")
+    @ApiOperation(value = "Resource接口(待废弃)")
     @GetMapping(value = {"/resource.js"})
     public void resource(@RequestParam String u) {
         verifyCodeService.verifyCodeResource(u);
-    }
+    }*/
 
 }

+ 105 - 0
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/controller/bean/SysNoticeDomain.java

@@ -0,0 +1,105 @@
+package cn.com.qmth.examcloud.core.basic.api.controller.bean;
+
+import cn.com.qmth.examcloud.api.commons.enums.CourseLevel;
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+import javax.persistence.Column;
+import java.util.Date;
+
+/**
+ * @Description 系统通知
+ * @Author lideyin
+ * @Date 2020/8/16 11:00
+ * @Version 1.0
+ */
+public class SysNoticeDomain implements JsonSerializable {
+
+	private static final long serialVersionUID = -6261302618070108336L;
+
+	private Long id;
+
+	/**
+	 * 组织机构id,(-1代表所有组织机构)
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 通知内容
+	 */
+	private String content;
+
+	/**
+	 * 生效开始时间
+	 */
+	private String startTime;
+	/**
+	 * 生效截止时间
+	 */
+	private String endTime;
+
+	/**
+	 * 通知标题
+	 */
+	private String title;
+
+	/**
+	 * 启用标识
+	 */
+	private Boolean enable;
+
+	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 getContent() {
+		return content;
+	}
+
+	public void setContent(String content) {
+		this.content = content;
+	}
+
+	public String getStartTime() {
+		return startTime;
+	}
+
+	public void setStartTime(String startTime) {
+		this.startTime = startTime;
+	}
+
+	public String getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(String endTime) {
+		this.endTime = endTime;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+}

+ 21 - 20
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/AuthCloudServiceProvider.java

@@ -1,11 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-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.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.core.basic.api.AuthCloudService;
@@ -13,29 +7,36 @@ import cn.com.qmth.examcloud.core.basic.api.request.LoginReq;
 import cn.com.qmth.examcloud.core.basic.api.response.LoginResp;
 import cn.com.qmth.examcloud.core.basic.service.AuthService;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+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;
 
 @RestController
+@Api(tags = "登录相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "auth")
 public class AuthCloudServiceProvider extends ControllerSupport implements AuthCloudService {
 
-	private static final long serialVersionUID = 4189424508654646499L;
+    private static final long serialVersionUID = 4189424508654646499L;
 
-	@Autowired
-	AuthService authService;
+    @Autowired
+    AuthService authService;
 
-	@ApiOperation(value = "登录")
-	@PostMapping("login")
-	@Override
-	public LoginResp login(@RequestBody LoginReq req) {
-		Long userId = req.getUserId();
-		UserType userType = req.getUserType();
+    @ApiOperation(value = "登录")
+    @PostMapping("login")
+    @Override
+    public LoginResp login(@RequestBody LoginReq req) {
+        Long userId = req.getUserId();
+        UserType userType = req.getUserType();
 
-		User user = authService.login(userType, userId);
+        User user = authService.login(userType, userId);
 
-		LoginResp resp = new LoginResp();
-		resp.setUser(user);
-		return resp;
-	}
+        LoginResp resp = new LoginResp();
+        resp.setUser(user);
+        return resp;
+    }
 
 }

+ 127 - 127
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/CourseCloudServiceProvider.java

@@ -1,17 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.List;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-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.enums.CourseLevel;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.CourseCloudService;
@@ -29,7 +17,18 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
 import cn.com.qmth.examcloud.core.basic.service.CourseService;
 import cn.com.qmth.examcloud.core.basic.service.bean.CourseInfo;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
+import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+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.List;
 
 /**
  * {@link StatusException} 状态码范围:011XXX<br>
@@ -39,123 +38,124 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "课程相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "course")
 public class CourseCloudServiceProvider implements CourseCloudService {
 
-	private static final long serialVersionUID = -2733647860311223743L;
-
-	@Autowired
-	OrgRepo orgRepo;
-
-	@Autowired
-	CourseRepo courseRepo;
-
-	@Autowired
-	CourseService courseService;
-
-	@ApiOperation(value = "保存课程")
-	@PostMapping("saveCourse")
-	@Transactional
-	@Override
-	public SaveCourseResp saveCourse(@RequestBody SaveCourseReq courseReq) {
-
-		CourseInfo info = new CourseInfo();
-		info.setRootOrgId(courseReq.getRootOrgId());
-		info.setCode(courseReq.getCourseCode());
-		info.setEnable(courseReq.getEnable());
-		info.setId(courseReq.getCourseId());
-		info.setName(courseReq.getCourseName());
-		if (null != courseReq.getCourseLevel()) {
-			info.setLevel(CourseLevel.getCourseLevel(courseReq.getCourseLevel()));
-		}
-
-		CourseEntity saved = courseService.saveCourse(info);
-
-		SaveCourseResp resp = new SaveCourseResp();
-		CourseBean courseBean = new CourseBean();
-		courseBean.setId(saved.getId());
-		courseBean.setCode(saved.getCode());
-		courseBean.setLevel(saved.getLevel().name());
-		courseBean.setName(saved.getName());
-		courseBean.setRootOrgId(saved.getRootOrgId());
-		courseBean.setEnable(saved.getEnable());
-
-		resp.setCourseBean(courseBean);
-
-		return resp;
-	}
-
-	@ApiOperation(value = "查询课程")
-	@PostMapping("getCourse")
-	@Override
-	public GetCourseResp getCourse(@RequestBody GetCourseReq req) {
-		GetCourseResp resp = new GetCourseResp();
-		Long rootOrgId = req.getRootOrgId();
-		String code = req.getCode();
-		Long id = req.getId();
-
-		if (null == rootOrgId) {
-			throw new StatusException("160000", "rootOrgId is null");
-		}
-		OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
-		if (null == rootOrg) {
-			throw new StatusException("160001", "机构不存在");
-		}
-		if (null != rootOrg.getParentId()) {
-			throw new StatusException("160002", "机构错误");
-		}
-
-		CourseEntity c = null;
-		if (null != id) {
-			c = GlobalHelper.getEntity(courseRepo, id, CourseEntity.class);
-
-		} else if (StringUtils.isNotBlank(code)) {
-			c = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
-		} else {
-			throw new StatusException("160002", "id,code can not be all null");
-		}
-
-		if (null == c) {
-			throw new StatusException("160003", "课程不存在");
-		}
-
-		CourseBean courseBean = new CourseBean();
-		courseBean.setId(c.getId());
-		courseBean.setCode(c.getCode());
-		courseBean.setLevel(c.getLevel().name());
-		courseBean.setName(c.getName());
-		courseBean.setRootOrgId(c.getRootOrgId());
-		courseBean.setEnable(c.getEnable());
-		resp.setCourseBean(courseBean);
-
-		return resp;
-	}
-
-	@ApiOperation(value = "按ID查询课程")
-	@PostMapping("getCoursesByIdList")
-	@Override
-	public GetCoursesByIdListResp getCoursesByIdList(@RequestBody GetCoursesByIdListReq req) {
-		List<Long> courseIdList = req.getCourseIdList();
-		final List<CourseBean> list = Lists.newArrayList();
-		for (Long cur : courseIdList) {
-			CourseEntity c = GlobalHelper.getEntity(courseRepo, cur, CourseEntity.class);
-			if (null == c) {
-				throw new StatusException("160001", "no course [id=" + cur + "]");
-			}
-			CourseBean courseBean = new CourseBean();
-			courseBean.setId(c.getId());
-			courseBean.setCode(c.getCode());
-			courseBean.setLevel(c.getLevel().name());
-			courseBean.setName(c.getName());
-			courseBean.setRootOrgId(c.getRootOrgId());
-			courseBean.setEnable(c.getEnable());
-
-			list.add(courseBean);
-		}
-
-		GetCoursesByIdListResp resp = new GetCoursesByIdListResp();
-		resp.setCourseList(list);
-		return resp;
-	}
+    private static final long serialVersionUID = -2733647860311223743L;
+
+    @Autowired
+    OrgRepo orgRepo;
+
+    @Autowired
+    CourseRepo courseRepo;
+
+    @Autowired
+    CourseService courseService;
+
+    @ApiOperation(value = "保存课程")
+    @PostMapping("saveCourse")
+    @Transactional
+    @Override
+    public SaveCourseResp saveCourse(@RequestBody SaveCourseReq courseReq) {
+
+        CourseInfo info = new CourseInfo();
+        info.setRootOrgId(courseReq.getRootOrgId());
+        info.setCode(courseReq.getCourseCode());
+        info.setEnable(courseReq.getEnable());
+        info.setId(courseReq.getCourseId());
+        info.setName(courseReq.getCourseName());
+        if (null != courseReq.getCourseLevel()) {
+            info.setLevel(CourseLevel.getCourseLevel(courseReq.getCourseLevel()));
+        }
+
+        CourseEntity saved = courseService.saveCourse(info);
+
+        SaveCourseResp resp = new SaveCourseResp();
+        CourseBean courseBean = new CourseBean();
+        courseBean.setId(saved.getId());
+        courseBean.setCode(saved.getCode());
+        courseBean.setLevel(saved.getLevel().name());
+        courseBean.setName(saved.getName());
+        courseBean.setRootOrgId(saved.getRootOrgId());
+        courseBean.setEnable(saved.getEnable());
+
+        resp.setCourseBean(courseBean);
+
+        return resp;
+    }
+
+    @ApiOperation(value = "查询课程")
+    @PostMapping("getCourse")
+    @Override
+    public GetCourseResp getCourse(@RequestBody GetCourseReq req) {
+        GetCourseResp resp = new GetCourseResp();
+        Long rootOrgId = req.getRootOrgId();
+        String code = req.getCode();
+        Long id = req.getId();
+
+        if (null == rootOrgId) {
+            throw new StatusException("160000", "rootOrgId is null");
+        }
+        OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, rootOrgId, OrgEntity.class);
+        if (null == rootOrg) {
+            throw new StatusException("160001", "机构不存在");
+        }
+        if (null != rootOrg.getParentId()) {
+            throw new StatusException("160002", "机构错误");
+        }
+
+        CourseEntity c = null;
+        if (null != id) {
+            c = GlobalHelper.getEntity(courseRepo, id, CourseEntity.class);
+
+        } else if (StringUtils.isNotBlank(code)) {
+            c = courseRepo.findByRootOrgIdAndCode(rootOrgId, code);
+        } else {
+            throw new StatusException("160002", "id,code can not be all null");
+        }
+
+        if (null == c) {
+            throw new StatusException("160003", "课程不存在");
+        }
+
+        CourseBean courseBean = new CourseBean();
+        courseBean.setId(c.getId());
+        courseBean.setCode(c.getCode());
+        courseBean.setLevel(c.getLevel().name());
+        courseBean.setName(c.getName());
+        courseBean.setRootOrgId(c.getRootOrgId());
+        courseBean.setEnable(c.getEnable());
+        resp.setCourseBean(courseBean);
+
+        return resp;
+    }
+
+    @ApiOperation(value = "按ID查询课程")
+    @PostMapping("getCoursesByIdList")
+    @Override
+    public GetCoursesByIdListResp getCoursesByIdList(@RequestBody GetCoursesByIdListReq req) {
+        List<Long> courseIdList = req.getCourseIdList();
+        final List<CourseBean> list = Lists.newArrayList();
+        for (Long cur : courseIdList) {
+            CourseEntity c = GlobalHelper.getEntity(courseRepo, cur, CourseEntity.class);
+            if (null == c) {
+                throw new StatusException("160001", "no course [id=" + cur + "]");
+            }
+            CourseBean courseBean = new CourseBean();
+            courseBean.setId(c.getId());
+            courseBean.setCode(c.getCode());
+            courseBean.setLevel(c.getLevel().name());
+            courseBean.setName(c.getName());
+            courseBean.setRootOrgId(c.getRootOrgId());
+            courseBean.setEnable(c.getEnable());
+
+            list.add(courseBean);
+        }
+
+        GetCoursesByIdListResp resp = new GetCoursesByIdListResp();
+        resp.setCourseList(list);
+        return resp;
+    }
 
 }

+ 120 - 120
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/FaceCloudServiceProvider.java

@@ -1,16 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-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.core.basic.api.FaceCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.FacesetBean;
@@ -30,7 +19,17 @@ import cn.com.qmth.examcloud.core.basic.service.FaceService;
 import cn.com.qmth.examcloud.core.basic.service.bean.StudentFaceInfo;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+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.List;
 
 /**
  * 类注释
@@ -40,117 +39,118 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "学生人脸相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "studentFace")
 public class FaceCloudServiceProvider extends ControllerSupport implements FaceCloudService {
 
-	private static final long serialVersionUID = 8674317301051207328L;
-
-	@Autowired
-	StudentFaceRepo studentFaceRepo;
-
-	@Autowired
-	FacesetRepo facesetRepo;
-
-	@Autowired
-	StudentRepo studentRepo;
-
-	@Autowired
-	FaceService studentFaceService;
-
-	@ApiOperation(value = "保存学生人脸数据")
-	@PostMapping("saveStudentFace")
-	@Transactional
-	@Override
-	public SaveStudentFaceResp saveStudentFace(@RequestBody SaveStudentFaceReq req) {
-		trim(req);
-		StudentFaceInfo info = new StudentFaceInfo();
-		info.setFacesetToken(req.getFacesetToken());
-		info.setFaceToken(req.getFaceToken());
-		info.setOperator(req.getOperator());
-		info.setPhotoName(req.getPhotoName());
-		info.setRootOrgId(req.getRootOrgId());
-		info.setStudentId(req.getStudentId());
-		info.setFaceCount(req.getFaceCount());
-		info.setPhotoTreatyPath(req.getPhotoTreatyPath());
-
-		StudentFaceEntity saved = studentFaceService.saveStudentFace(info);
-		SaveStudentFaceResp resp = new SaveStudentFaceResp();
-		resp.setId(saved.getStudentId());
-		return resp;
-	}
-
-	@ApiOperation(value = "获取可用的faceset集合")
-	@PostMapping("getUsableFacesetList")
-	@Override
-	public GetUsableFacesetListResp getUsableFacesetList(@RequestBody GetUsableFacesetListReq req) {
-
-		List<FacesetEntity> facesetList = studentFaceService.getUsableFacesetList();
-
-		List<FacesetBean> list = Lists.newArrayList();
-
-		for (FacesetEntity cur : facesetList) {
-			FacesetBean bean = new FacesetBean();
-			list.add(bean);
-
-			bean.setDisplayName(cur.getDisplayName());
-			bean.setFaceCount(cur.getFaceCount());
-			bean.setFacesetToken(cur.getFacesetToken());
-			bean.setId(cur.getId());
-			bean.setOuterId(cur.getOuterId());
-			bean.setTags(cur.getTags());
-		}
-
-		GetUsableFacesetListResp resp = new GetUsableFacesetListResp();
-		resp.setFacesetBeanList(list);
-		return resp;
-	}
-
-	@ApiOperation(value = "获取学生人脸数据")
-	@PostMapping("getStudentFace")
-	@Override
-	public GetStudentFaceResp getStudentFace(@RequestBody GetStudentFaceReq req) {
-		Long studentId = req.getStudentId();
-
-		if (null == studentId) {
-			throw new StatusException("710001", "studentId is null");
-		}
-
-		StudentFaceEntity studentFaceEntity = GlobalHelper.getEntity(studentFaceRepo, studentId,
-				StudentFaceEntity.class);
-
-		if (null == studentFaceEntity) {
-			throw new StatusException("710001", "studentFaceEntity is null");
-		}
-
-		StudentFaceBean studentFaceBean = new StudentFaceBean();
-
-		studentFaceBean.setCreator(studentFaceEntity.getCreator());
-		studentFaceBean.setFacesetId(studentFaceEntity.getFacesetId());
-		studentFaceBean.setFaceToken(studentFaceEntity.getFaceToken());
-		studentFaceBean.setModifiedBy(studentFaceEntity.getModifiedBy());
-		studentFaceBean.setStudentId(studentFaceEntity.getStudentId());
-
-		GetStudentFaceResp resp = new GetStudentFaceResp();
-		resp.setStudentFaceBean(studentFaceBean);
-
-		if (null != studentFaceEntity.getFacesetId()) {
-			FacesetEntity facesetEntity = GlobalHelper.getEntity(facesetRepo,
-					studentFaceEntity.getFacesetId(), FacesetEntity.class);
-			if (null != facesetEntity) {
-				FacesetBean facesetBean = new FacesetBean();
-				facesetBean.setDisplayName(facesetEntity.getDisplayName());
-				facesetBean.setFaceCount(facesetEntity.getFaceCount());
-				facesetBean.setFacesetToken(facesetEntity.getFacesetToken());
-				facesetBean.setId(facesetEntity.getId());
-				facesetBean.setOuterId(facesetEntity.getOuterId());
-				facesetBean.setTags(facesetEntity.getTags());
-
-				resp.setFacesetBean(facesetBean);
-			}
-
-		}
-
-		return resp;
-	}
+    private static final long serialVersionUID = 8674317301051207328L;
+
+    @Autowired
+    StudentFaceRepo studentFaceRepo;
+
+    @Autowired
+    FacesetRepo facesetRepo;
+
+    @Autowired
+    StudentRepo studentRepo;
+
+    @Autowired
+    FaceService studentFaceService;
+
+    @ApiOperation(value = "保存学生人脸数据")
+    @PostMapping("saveStudentFace")
+    @Transactional
+    @Override
+    public SaveStudentFaceResp saveStudentFace(@RequestBody SaveStudentFaceReq req) {
+        trim(req);
+        StudentFaceInfo info = new StudentFaceInfo();
+        info.setFacesetToken(req.getFacesetToken());
+        info.setFaceToken(req.getFaceToken());
+        info.setOperator(req.getOperator());
+        info.setPhotoName(req.getPhotoName());
+        info.setRootOrgId(req.getRootOrgId());
+        info.setStudentId(req.getStudentId());
+        info.setFaceCount(req.getFaceCount());
+        info.setPhotoTreatyPath(req.getPhotoTreatyPath());
+
+        StudentFaceEntity saved = studentFaceService.saveStudentFace(info);
+        SaveStudentFaceResp resp = new SaveStudentFaceResp();
+        resp.setId(saved.getStudentId());
+        return resp;
+    }
+
+    @ApiOperation(value = "获取可用的faceset集合")
+    @PostMapping("getUsableFacesetList")
+    @Override
+    public GetUsableFacesetListResp getUsableFacesetList(@RequestBody GetUsableFacesetListReq req) {
+
+        List<FacesetEntity> facesetList = studentFaceService.getUsableFacesetList();
+
+        List<FacesetBean> list = Lists.newArrayList();
+
+        for (FacesetEntity cur : facesetList) {
+            FacesetBean bean = new FacesetBean();
+            list.add(bean);
+
+            bean.setDisplayName(cur.getDisplayName());
+            bean.setFaceCount(cur.getFaceCount());
+            bean.setFacesetToken(cur.getFacesetToken());
+            bean.setId(cur.getId());
+            bean.setOuterId(cur.getOuterId());
+            bean.setTags(cur.getTags());
+        }
+
+        GetUsableFacesetListResp resp = new GetUsableFacesetListResp();
+        resp.setFacesetBeanList(list);
+        return resp;
+    }
+
+    @ApiOperation(value = "获取学生人脸数据")
+    @PostMapping("getStudentFace")
+    @Override
+    public GetStudentFaceResp getStudentFace(@RequestBody GetStudentFaceReq req) {
+        Long studentId = req.getStudentId();
+
+        if (null == studentId) {
+            throw new StatusException("710001", "studentId is null");
+        }
+
+        StudentFaceEntity studentFaceEntity = GlobalHelper.getEntity(studentFaceRepo, studentId,
+                StudentFaceEntity.class);
+
+        if (null == studentFaceEntity) {
+            throw new StatusException("710001", "studentFaceEntity is null");
+        }
+
+        StudentFaceBean studentFaceBean = new StudentFaceBean();
+
+        studentFaceBean.setCreator(studentFaceEntity.getCreator());
+        studentFaceBean.setFacesetId(studentFaceEntity.getFacesetId());
+        studentFaceBean.setFaceToken(studentFaceEntity.getFaceToken());
+        studentFaceBean.setModifiedBy(studentFaceEntity.getModifiedBy());
+        studentFaceBean.setStudentId(studentFaceEntity.getStudentId());
+
+        GetStudentFaceResp resp = new GetStudentFaceResp();
+        resp.setStudentFaceBean(studentFaceBean);
+
+        if (null != studentFaceEntity.getFacesetId()) {
+            FacesetEntity facesetEntity = GlobalHelper.getEntity(facesetRepo,
+                    studentFaceEntity.getFacesetId(), FacesetEntity.class);
+            if (null != facesetEntity) {
+                FacesetBean facesetBean = new FacesetBean();
+                facesetBean.setDisplayName(facesetEntity.getDisplayName());
+                facesetBean.setFaceCount(facesetEntity.getFaceCount());
+                facesetBean.setFacesetToken(facesetEntity.getFacesetToken());
+                facesetBean.setId(facesetEntity.getId());
+                facesetBean.setOuterId(facesetEntity.getOuterId());
+                facesetBean.setTags(facesetEntity.getTags());
+
+                resp.setFacesetBean(facesetBean);
+            }
+
+        }
+
+        return resp;
+    }
 
 }

+ 184 - 185
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/OrgCloudServiceProvider.java

@@ -1,26 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.persistence.criteria.Predicate;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-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.core.basic.api.OrgCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.OrgBean;
@@ -39,7 +18,26 @@ import cn.com.qmth.examcloud.core.basic.service.bean.OrgInfo;
 import cn.com.qmth.examcloud.core.basic.service.impl.OrgServiceImpl;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+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.persistence.criteria.Predicate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * {@link StatusException} 状态码范围:010XXX<br>
@@ -49,172 +47,173 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "机构相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "org")
 public class OrgCloudServiceProvider extends ControllerSupport implements OrgCloudService {
 
-	private static final long serialVersionUID = -7858439296389761341L;
-
-	@Autowired
-	private OrgServiceImpl orgService;
-
-	@Autowired
-	private OrgRepo orgRepo;
-
-	@Autowired
-	OrgPropertyRepo orgPropertyRepo;
-
-	@ApiOperation(value = "保存机构")
-	@PostMapping("saveOrg")
-	@Transactional
-	@Override
-	public SaveOrgResp saveOrg(@RequestBody SaveOrgReq req) {
-		OrgInfo info = new OrgInfo();
-		info.setCode(req.getCode());
-		info.setName(req.getName());
-		info.setContacts(req.getContacts());
-		info.setTelephone(req.getTelephone());
-		info.setDomainName(req.getDomainName());
-		info.setRemark(req.getRemark());
-
-		OrgEntity saved = orgService.saveRootOrg(info);
-
-		SaveOrgResp orgResp = new SaveOrgResp();
-		orgResp.setId(saved.getId());
-		orgResp.setName(saved.getName());
-		return orgResp;
-	}
-
-	@ApiOperation(value = "获取机构")
-	@PostMapping("getOrg")
-	@Override
-	public GetOrgResp getOrg(@RequestBody GetOrgReq req) {
-		Long orgId = req.getOrgId();
-		String orgCode = req.getOrgCode();
-		Long rootOrgId = req.getRootOrgId();
-
-		OrgEntity org = null;
-		if (null != orgId) {
-			org = GlobalHelper.getEntity(orgRepo, orgId, OrgEntity.class);
-		} else if (StringUtils.isNotBlank(orgCode)) {
-			if (null == rootOrgId) {
-				throw new StatusException("150001", "rootOrgId is null");
-			}
-			org = orgRepo.findByRootIdAndCode(rootOrgId, orgCode);
-		} else {
-			throw new StatusException("150001", "orgId,orgCode不能都不为空");
-		}
-
-		if (null == org) {
-			throw new StatusException("150001", "机构不存在");
-		}
-
-		OrgBean orgBean = new OrgBean();
-		orgBean.setId(org.getId());
-		orgBean.setName(org.getName());
-		orgBean.setCode(org.getCode());
-		orgBean.setParentId(org.getParentId());
-		orgBean.setRootId(org.getRootId());
-		orgBean.setEnable(org.getEnable());
-
-		GetOrgResp resp = new GetOrgResp();
-		resp.setOrg(orgBean);
-		return resp;
-	}
-
-	@ApiOperation(value = "按ID集合查询机构")
-	@PostMapping("getOrgsByIdList")
-	@Override
-	public GetOrgsByIdListResp getOrgsByIdList(@RequestBody GetOrgsByIdListReq req) {
-
-		List<Long> orgIdList = req.getOrgIdList();
-
-		final List<OrgBean> orgList = Lists.newArrayList();
-		for (Long cur : orgIdList) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, cur, OrgEntity.class);
-			if (null == org) {
-				throw new StatusException("010001", "no org. [id=" + cur + "]");
-			}
-			OrgBean orgBean = new OrgBean();
-			orgBean.setId(org.getId());
-			orgBean.setName(org.getName());
-			orgBean.setCode(org.getCode());
-			orgBean.setParentId(org.getParentId());
-			orgBean.setRootId(org.getRootId());
-			orgBean.setEnable(org.getEnable());
-
-			orgList.add(orgBean);
-		}
-		GetOrgsByIdListResp resp = new GetOrgsByIdListResp();
-		resp.setOrgList(orgList);
-		return resp;
-	}
-
-	@ApiOperation(value = "查询所有机构")
-	@PostMapping("getOrgs")
-	@Override
-	public GetOrgsResp getOrgs(@RequestBody GetOrgsReq req) {
-		Boolean withoutParentId = req.getWithoutParentId();
-		Long rootOrgId = req.getRootOrgId();
-		Boolean enable = req.getEnable();
-
-		final long start = null == req.getStart() ? 1 : req.getStart();
-
-		Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "id");
-
-		Specification<OrgEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-
-			if (null != rootOrgId) {
-				predicates.add(cb.equal(root.get("rootId"), rootOrgId));
-			}
-
-			predicates.add(cb.greaterThanOrEqualTo(root.get("id"), start));
-
-			if (null != withoutParentId) {
-				if (withoutParentId) {
-					predicates.add(cb.isNull(root.get("parentId")));
-				} else {
-					predicates.add(cb.isNotNull(root.get("parentId")));
-				}
-			}
-
-			if (null != enable) {
-				predicates.add(cb.equal(root.get("enable"), enable));
-			}
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		Page<OrgEntity> page = orgRepo.findAll(specification, pageable);
-
-		Iterator<OrgEntity> iterator = page.iterator();
-
-		List<OrgBean> list = Lists.newArrayList();
-		long next = start;
-		boolean has = false;
-		while (iterator.hasNext()) {
-			OrgEntity org = iterator.next();
-			OrgBean orgBean = new OrgBean();
-			orgBean.setId(org.getId());
-			orgBean.setName(org.getName());
-			orgBean.setCode(org.getCode());
-			orgBean.setParentId(org.getParentId());
-			orgBean.setRootId(org.getRootId());
-			orgBean.setEnable(org.getEnable());
-
-			next = org.getId();
-			list.add(orgBean);
-			has = true;
-		}
-
-		GetOrgsResp resp = new GetOrgsResp();
-		if (has) {
-			next++;
-		}
-		resp.setNext(next);
-		resp.setOrgBeanList(list);
-
-		return resp;
-	}
+    private static final long serialVersionUID = -7858439296389761341L;
+
+    @Autowired
+    private OrgServiceImpl orgService;
+
+    @Autowired
+    private OrgRepo orgRepo;
+
+    @Autowired
+    OrgPropertyRepo orgPropertyRepo;
+
+    @ApiOperation(value = "保存机构")
+    @PostMapping("saveOrg")
+    @Transactional
+    @Override
+    public SaveOrgResp saveOrg(@RequestBody SaveOrgReq req) {
+        OrgInfo info = new OrgInfo();
+        info.setCode(req.getCode());
+        info.setName(req.getName());
+        info.setContacts(req.getContacts());
+        info.setTelephone(req.getTelephone());
+        info.setDomainName(req.getDomainName());
+        info.setRemark(req.getRemark());
+
+        OrgEntity saved = orgService.saveRootOrg(info);
+
+        SaveOrgResp orgResp = new SaveOrgResp();
+        orgResp.setId(saved.getId());
+        orgResp.setName(saved.getName());
+        return orgResp;
+    }
+
+    @ApiOperation(value = "获取机构")
+    @PostMapping("getOrg")
+    @Override
+    public GetOrgResp getOrg(@RequestBody GetOrgReq req) {
+        Long orgId = req.getOrgId();
+        String orgCode = req.getOrgCode();
+        Long rootOrgId = req.getRootOrgId();
+
+        OrgEntity org = null;
+        if (null != orgId) {
+            org = GlobalHelper.getEntity(orgRepo, orgId, OrgEntity.class);
+        } else if (StringUtils.isNotBlank(orgCode)) {
+            if (null == rootOrgId) {
+                throw new StatusException("150001", "rootOrgId is null");
+            }
+            org = orgRepo.findByRootIdAndCode(rootOrgId, orgCode);
+        } else {
+            throw new StatusException("150001", "orgId,orgCode不能都不为空");
+        }
+
+        if (null == org) {
+            throw new StatusException("150001", "机构不存在");
+        }
+
+        OrgBean orgBean = new OrgBean();
+        orgBean.setId(org.getId());
+        orgBean.setName(org.getName());
+        orgBean.setCode(org.getCode());
+        orgBean.setParentId(org.getParentId());
+        orgBean.setRootId(org.getRootId());
+        orgBean.setEnable(org.getEnable());
+
+        GetOrgResp resp = new GetOrgResp();
+        resp.setOrg(orgBean);
+        return resp;
+    }
+
+    @ApiOperation(value = "按ID集合查询机构")
+    @PostMapping("getOrgsByIdList")
+    @Override
+    public GetOrgsByIdListResp getOrgsByIdList(@RequestBody GetOrgsByIdListReq req) {
+
+        List<Long> orgIdList = req.getOrgIdList();
+
+        final List<OrgBean> orgList = Lists.newArrayList();
+        for (Long cur : orgIdList) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, cur, OrgEntity.class);
+            if (null == org) {
+                throw new StatusException("010001", "no org. [id=" + cur + "]");
+            }
+            OrgBean orgBean = new OrgBean();
+            orgBean.setId(org.getId());
+            orgBean.setName(org.getName());
+            orgBean.setCode(org.getCode());
+            orgBean.setParentId(org.getParentId());
+            orgBean.setRootId(org.getRootId());
+            orgBean.setEnable(org.getEnable());
+
+            orgList.add(orgBean);
+        }
+        GetOrgsByIdListResp resp = new GetOrgsByIdListResp();
+        resp.setOrgList(orgList);
+        return resp;
+    }
+
+    @ApiOperation(value = "查询所有机构")
+    @PostMapping("getOrgs")
+    @Override
+    public GetOrgsResp getOrgs(@RequestBody GetOrgsReq req) {
+        Boolean withoutParentId = req.getWithoutParentId();
+        Long rootOrgId = req.getRootOrgId();
+        Boolean enable = req.getEnable();
+
+        final long start = null == req.getStart() ? 1 : req.getStart();
+
+        Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "id");
+
+        Specification<OrgEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            if (null != rootOrgId) {
+                predicates.add(cb.equal(root.get("rootId"), rootOrgId));
+            }
+
+            predicates.add(cb.greaterThanOrEqualTo(root.get("id"), start));
+
+            if (null != withoutParentId) {
+                if (withoutParentId) {
+                    predicates.add(cb.isNull(root.get("parentId")));
+                } else {
+                    predicates.add(cb.isNotNull(root.get("parentId")));
+                }
+            }
+
+            if (null != enable) {
+                predicates.add(cb.equal(root.get("enable"), enable));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        Page<OrgEntity> page = orgRepo.findAll(specification, pageable);
+
+        Iterator<OrgEntity> iterator = page.iterator();
+
+        List<OrgBean> list = Lists.newArrayList();
+        long next = start;
+        boolean has = false;
+        while (iterator.hasNext()) {
+            OrgEntity org = iterator.next();
+            OrgBean orgBean = new OrgBean();
+            orgBean.setId(org.getId());
+            orgBean.setName(org.getName());
+            orgBean.setCode(org.getCode());
+            orgBean.setParentId(org.getParentId());
+            orgBean.setRootId(org.getRootId());
+            orgBean.setEnable(org.getEnable());
+
+            next = org.getId();
+            list.add(orgBean);
+            has = true;
+        }
+
+        GetOrgsResp resp = new GetOrgsResp();
+        if (has) {
+            next++;
+        }
+        resp.setNext(next);
+        resp.setOrgBeanList(list);
+
+        return resp;
+    }
 
 }

+ 97 - 99
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/RolePrivilegeCloudServiceProvider.java

@@ -1,16 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-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.core.basic.api.RolePrivilegeCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.RoleBean;
 import cn.com.qmth.examcloud.core.basic.api.request.DeleteRoleReq;
@@ -30,8 +19,17 @@ import cn.com.qmth.examcloud.core.basic.service.RolePrivilegeService;
 import cn.com.qmth.examcloud.core.basic.service.bean.RoleInfo;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+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.List;
 
 /**
  * 角色权限服务
@@ -40,96 +38,96 @@ import io.swagger.annotations.ApiOperation;
  * @date 2018年6月8日
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
-@Api("角色权限")
 @RestController
+@Api(tags = "角色权限相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "rolePrivilege")
 public class RolePrivilegeCloudServiceProvider extends ControllerSupport
-		implements
-			RolePrivilegeCloudService {
-
-	private static final long serialVersionUID = -4360164791713797878L;
-
-	@Autowired
-	RoleRepo roleRepo;
-
-	@Autowired
-	RolePrivilegeRelationRepo rolePrivilegeRelationRepo;
-
-	@Autowired
-	PrivilegeRepo privilegeRepo;
-
-	@Autowired
-	PrivilegeGroupRepo privilegeGroupRepo;
-
-	@Autowired
-	RolePrivilegeService rolePrivilegeService;
-
-	@ApiOperation(value = "添加角色")
-	@PostMapping("saveRole")
-	@Transactional
-	@Override
-	public SaveRoleResp saveRole(@RequestBody SaveRoleReq req) {
-		RoleInfo info = new RoleInfo();
-		info.setCode(req.getCode());
-		info.setName(req.getName());
-		info.setRootOrgId(req.getRootOrgId());
-
-		RoleEntity saved = rolePrivilegeService.saveRole(info);
-
-		RoleBean roleBean = new RoleBean();
-		roleBean.setRoleCode(saved.getCode());
-		roleBean.setRoleId(saved.getId());
-		roleBean.setRoleName(saved.getName());
-
-		SaveRoleResp resp = new SaveRoleResp();
-		resp.setRoleBean(roleBean);
-		return resp;
-	}
-
-	@ApiOperation(value = "删除角色")
-	@PostMapping("deleteRole")
-	@Transactional
-	@Override
-	public DeleteRoleResp deleteRole(@RequestBody DeleteRoleReq req) {
-		RoleInfo info = new RoleInfo();
-		info.setId(req.getId());
-		info.setCode(req.getCode());
-		info.setName(req.getName());
-		info.setRootOrgId(req.getRootOrgId());
-
-		RoleEntity saved = rolePrivilegeService.deleteRole(info, req.isCascade());
-
-		RoleBean roleBean = new RoleBean();
-		roleBean.setRoleCode(saved.getCode());
-		roleBean.setRoleId(saved.getId());
-		roleBean.setRoleName(saved.getName());
-
-		DeleteRoleResp resp = new DeleteRoleResp();
-		resp.setRoleBean(roleBean);
-		return resp;
-	}
-
-	@ApiOperation(value = "查询权限集合")
-	@PostMapping("getPrivilegeList")
-	@Override
-	public GetPrivilegeListResp getPrivilegeList(@RequestBody GetPrivilegeListReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		Long roleId = req.getRoleId();
-
-		List<RolePrivilegeRelationEntity> relationList = rolePrivilegeRelationRepo
-				.findAllByRoleIdAndRootOrgId(roleId, rootOrgId);
-
-		List<String> privilegeCodeList = Lists.newArrayList();
-		for (RolePrivilegeRelationEntity cur : relationList) {
-
-			PrivilegeEntity privilegeEntity = GlobalHelper.getEntity(privilegeRepo,
-					cur.getPrivilegeId(), PrivilegeEntity.class);
-			privilegeCodeList.add(privilegeEntity.getCode());
-		}
-
-		GetPrivilegeListResp resp = new GetPrivilegeListResp();
-		resp.setPrivilegeCodeList(privilegeCodeList);
-		return resp;
-	}
+        implements
+        RolePrivilegeCloudService {
+
+    private static final long serialVersionUID = -4360164791713797878L;
+
+    @Autowired
+    RoleRepo roleRepo;
+
+    @Autowired
+    RolePrivilegeRelationRepo rolePrivilegeRelationRepo;
+
+    @Autowired
+    PrivilegeRepo privilegeRepo;
+
+    @Autowired
+    PrivilegeGroupRepo privilegeGroupRepo;
+
+    @Autowired
+    RolePrivilegeService rolePrivilegeService;
+
+    @ApiOperation(value = "添加角色")
+    @PostMapping("saveRole")
+    @Transactional
+    @Override
+    public SaveRoleResp saveRole(@RequestBody SaveRoleReq req) {
+        RoleInfo info = new RoleInfo();
+        info.setCode(req.getCode());
+        info.setName(req.getName());
+        info.setRootOrgId(req.getRootOrgId());
+
+        RoleEntity saved = rolePrivilegeService.saveRole(info);
+
+        RoleBean roleBean = new RoleBean();
+        roleBean.setRoleCode(saved.getCode());
+        roleBean.setRoleId(saved.getId());
+        roleBean.setRoleName(saved.getName());
+
+        SaveRoleResp resp = new SaveRoleResp();
+        resp.setRoleBean(roleBean);
+        return resp;
+    }
+
+    @ApiOperation(value = "删除角色")
+    @PostMapping("deleteRole")
+    @Transactional
+    @Override
+    public DeleteRoleResp deleteRole(@RequestBody DeleteRoleReq req) {
+        RoleInfo info = new RoleInfo();
+        info.setId(req.getId());
+        info.setCode(req.getCode());
+        info.setName(req.getName());
+        info.setRootOrgId(req.getRootOrgId());
+
+        RoleEntity saved = rolePrivilegeService.deleteRole(info, req.isCascade());
+
+        RoleBean roleBean = new RoleBean();
+        roleBean.setRoleCode(saved.getCode());
+        roleBean.setRoleId(saved.getId());
+        roleBean.setRoleName(saved.getName());
+
+        DeleteRoleResp resp = new DeleteRoleResp();
+        resp.setRoleBean(roleBean);
+        return resp;
+    }
+
+    @ApiOperation(value = "查询权限集合")
+    @PostMapping("getPrivilegeList")
+    @Override
+    public GetPrivilegeListResp getPrivilegeList(@RequestBody GetPrivilegeListReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        Long roleId = req.getRoleId();
+
+        List<RolePrivilegeRelationEntity> relationList = rolePrivilegeRelationRepo
+                .findAllByRoleIdAndRootOrgId(roleId, rootOrgId);
+
+        List<String> privilegeCodeList = Lists.newArrayList();
+        for (RolePrivilegeRelationEntity cur : relationList) {
+
+            PrivilegeEntity privilegeEntity = GlobalHelper.getEntity(privilegeRepo,
+                    cur.getPrivilegeId(), PrivilegeEntity.class);
+            privilegeCodeList.add(privilegeEntity.getCode());
+        }
+
+        GetPrivilegeListResp resp = new GetPrivilegeListResp();
+        resp.setPrivilegeCodeList(privilegeCodeList);
+        return resp;
+    }
 
 }

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

@@ -1,34 +1,10 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.persistence.criteria.Predicate;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-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.basic.api.StudentCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.StudentBean;
-import cn.com.qmth.examcloud.core.basic.api.request.CountStudentReq;
-import cn.com.qmth.examcloud.core.basic.api.request.GetStudentReq;
-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.request.UpdatePasswordReq;
-import cn.com.qmth.examcloud.core.basic.api.request.UpdateStudentStatusReq;
-import cn.com.qmth.examcloud.core.basic.api.response.CountStudentResp;
-import cn.com.qmth.examcloud.core.basic.api.response.GetStudentResp;
-import cn.com.qmth.examcloud.core.basic.api.response.SaveStudentResp;
-import cn.com.qmth.examcloud.core.basic.api.response.UnbindStudentCodeResp;
-import cn.com.qmth.examcloud.core.basic.api.response.UpdatePasswordResp;
-import cn.com.qmth.examcloud.core.basic.api.response.UpdateStudentStatusResp;
+import cn.com.qmth.examcloud.core.basic.api.request.*;
+import cn.com.qmth.examcloud.core.basic.api.response.*;
 import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
 import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
 import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
@@ -39,7 +15,20 @@ import cn.com.qmth.examcloud.core.basic.service.bean.StudentInfo;
 import cn.com.qmth.examcloud.core.basic.service.cache.StudentCache;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+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.persistence.criteria.Predicate;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * {@link StatusException} 状态码范围:056XXX<br>
@@ -49,219 +38,220 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "学生相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "student")
 public class StudentCloudServiceProvider extends ControllerSupport implements StudentCloudService {
 
-	private static final long serialVersionUID = -571041158847398070L;
-
-	@Autowired
-	OrgRepo orgRepo;
-
-	@Autowired
-	UserRepo userRepo;
-
-	@Autowired
-	StudentService studentService;
-
-	@Autowired
-	StudentRepo studentRepo;
-
-	@Autowired
-	StudentCache studentCache;
-
-	@ApiOperation(value = "保存学生")
-	@PostMapping("saveStudent")
-	@Transactional
-	@Override
-	public SaveStudentResp saveStudent(@RequestBody SaveStudentReq req) {
-
-		trim(req);
-
-		StudentInfo studentInfo = new StudentInfo();
-		studentInfo.setEnable(req.getEnable());
-		studentInfo.setName(req.getName());
-		studentInfo.setIdentityNumber(req.getIdentityNumber());
-		studentInfo.setStudentCodeList(req.getStudentCodeList());
-		studentInfo.setRootOrgId(req.getRootOrgId());
-
-		studentInfo.setOrgId(req.getOrgId());
-		studentInfo.setOrgCode(req.getOrgCode());
-		studentInfo.setOrgName(req.getOrgName());
-
-		studentInfo.setPhoneNumber(req.getPhoneNumber());
-		studentInfo.setPhotoPath(req.getPhotoPath());
-		studentInfo.setRemark(req.getRemark());
-
-		StudentEntity student = studentService.saveStudent(studentInfo);
-
-		SaveStudentResp resp = new SaveStudentResp();
-		resp.setStudentId(student.getId());
-		resp.setRootOrgId(student.getRootOrgId());
-
-		if (null != student.getOrgId()) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, student.getOrgId(), OrgEntity.class);
-			resp.setOrgId(org.getId());
-			resp.setOrgName(org.getName());
-		}
-
-		studentCache.remove(student.getId());
-
-		return resp;
-	}
-
-	@ApiOperation(value = "查询学生")
-	@PostMapping("getStudent")
-	@Override
-	public GetStudentResp getStudent(@RequestBody GetStudentReq req) {
-		Long studentId = req.getStudentId();
-		Long rootOrgId = req.getRootOrgId();
-		String identityNumber = req.getIdentityNumber();
-		String studentCode = req.getStudentCode();
-		String securityPhone = req.getSecurityPhone();
-
-		StudentInfo student = studentService.getStudentInfo(rootOrgId, studentId, identityNumber,
-				studentCode, securityPhone);
-
-		StudentBean studentBean = new StudentBean();
-		studentBean.setId(student.getId());
-		studentBean.setName(student.getName());
-		studentBean.setIdentityNumber(student.getIdentityNumber());
-		studentBean.setStudentCodeList(student.getStudentCodeList());
-		studentBean.setRootOrgId(student.getRootOrgId());
-		if (null != student.getOrgId()) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, student.getOrgId(), OrgEntity.class);
-			studentBean.setOrgId(org.getId());
-			studentBean.setOrgCode(org.getCode());
-			studentBean.setOrgName(org.getName());
-		}
-		studentBean.setOrgId(student.getOrgId());
-		studentBean.setOrgCode(student.getOrgCode());
-		studentBean.setOrgName(student.getOrgName());
-		studentBean.setPhoneNumber(student.getPhoneNumber());
-		studentBean.setPhotoPath(student.getPhotoPath());
-		studentBean.setRemark(student.getRemark());
-		studentBean.setSecurityPhone(student.getSecurityPhone());
-
-		GetStudentResp resp = new GetStudentResp();
-		resp.setStudentInfo(studentBean);
-		return resp;
-	}
-
-	@ApiOperation(value = "解绑学号")
-	@PostMapping("unbindStudentCode")
-	@Transactional
-	@Override
-	public UnbindStudentCodeResp unbindStudentCode(@RequestBody UnbindStudentCodeReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		String studentCode = req.getStudentCode();
-		String identityNumber = req.getIdentityNumber();
-
-		if (null == rootOrgId) {
-			throw new StatusException("160001", "rootOrgId is null");
-		}
-		if (StringUtils.isBlank(studentCode)) {
-			throw new StatusException("160002", "studentCode is blank");
-		}
-
-		List<Long> studentIdList = studentService.unbindStudentCode(rootOrgId, studentCode,
-				identityNumber);
-
-		UnbindStudentCodeResp resp = new UnbindStudentCodeResp();
-		resp.setStudentIdList(studentIdList);
-
-		for (Long cur : studentIdList) {
-			studentCache.remove(cur);
-		}
-
-		return resp;
-	}
-
-	@ApiOperation(value = "修改密码")
-	@PostMapping("updatePassword")
-	@Transactional
-	@Override
-	public UpdatePasswordResp updatePassword(@RequestBody UpdatePasswordReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		String identityNumber = req.getIdentityNumber();
-		Long studentId = req.getStudentId();
-		String password = req.getPassword();
-
-		StudentEntity entity = null;
-		if (null != studentId) {
-			entity = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
-		} else if (StringUtils.isNotBlank(identityNumber)) {
-			if (null == rootOrgId) {
-				throw new StatusException("056001", "rootOrgId is needed");
-			}
-			entity = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
-		} else {
-			throw new StatusException("056002", "params is missing");
-		}
-
-		if (null == entity) {
-			throw new StatusException("056003", "no student");
-		}
-
-		entity.setPassword(password);
-		studentRepo.save(entity);
-
-		UpdatePasswordResp resp = new UpdatePasswordResp();
-		return resp;
-	}
-
-	@ApiOperation(value = "更新学生状态")
-	@PostMapping("updateStudentStatus")
-	@Transactional
-	@Override
-	public UpdateStudentStatusResp updateStudentStatus(@RequestBody UpdateStudentStatusReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		String identityNumber = req.getIdentityNumber();
-		Long studentId = req.getStudentId();
-		Boolean enable = req.getEnable();
-
-		StudentEntity entity = null;
-		if (null != studentId) {
-			entity = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
-		} else if (StringUtils.isNotBlank(identityNumber)) {
-			if (null == rootOrgId) {
-				throw new StatusException("056004", "rootOrgId is needed");
-			}
-			entity = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
-		} else {
-			throw new StatusException("056005", "params is missing");
-		}
-
-		if (null == entity) {
-			throw new StatusException("056006", "no student");
-		}
-
-		entity.setEnable(enable);
-		StudentEntity saved = studentRepo.save(entity);
-
-		studentCache.remove(saved.getId());
-
-		UpdateStudentStatusResp resp = new UpdateStudentStatusResp();
-		return resp;
-	}
-
-	@ApiOperation(value = "统计学生")
-	@PostMapping("countStudent")
-	@Override
-	public CountStudentResp countStudent(@RequestBody CountStudentReq req) {
-		Long rootOrgId = req.getRootOrgId();
-
-		Specification<StudentEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-			predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		long count = studentRepo.count(specification);
-
-		CountStudentResp resp = new CountStudentResp();
-		resp.setCount(count);
-		return resp;
-	}
+    private static final long serialVersionUID = -571041158847398070L;
+
+    @Autowired
+    OrgRepo orgRepo;
+
+    @Autowired
+    UserRepo userRepo;
+
+    @Autowired
+    StudentService studentService;
+
+    @Autowired
+    StudentRepo studentRepo;
+
+    @Autowired
+    StudentCache studentCache;
+
+    @ApiOperation(value = "保存学生")
+    @PostMapping("saveStudent")
+    @Transactional
+    @Override
+    public SaveStudentResp saveStudent(@RequestBody SaveStudentReq req) {
+
+        trim(req);
+
+        StudentInfo studentInfo = new StudentInfo();
+        studentInfo.setEnable(req.getEnable());
+        studentInfo.setName(req.getName());
+        studentInfo.setIdentityNumber(req.getIdentityNumber());
+        studentInfo.setStudentCodeList(req.getStudentCodeList());
+        studentInfo.setRootOrgId(req.getRootOrgId());
+
+        studentInfo.setOrgId(req.getOrgId());
+        studentInfo.setOrgCode(req.getOrgCode());
+        studentInfo.setOrgName(req.getOrgName());
+
+        studentInfo.setPhoneNumber(req.getPhoneNumber());
+        studentInfo.setPhotoPath(req.getPhotoPath());
+        studentInfo.setRemark(req.getRemark());
+
+        StudentEntity student = studentService.saveStudent(studentInfo);
+
+        SaveStudentResp resp = new SaveStudentResp();
+        resp.setStudentId(student.getId());
+        resp.setRootOrgId(student.getRootOrgId());
+
+        if (null != student.getOrgId()) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, student.getOrgId(), OrgEntity.class);
+            resp.setOrgId(org.getId());
+            resp.setOrgName(org.getName());
+        }
+
+        studentCache.remove(student.getId());
+
+        return resp;
+    }
+
+    @ApiOperation(value = "查询学生")
+    @PostMapping("getStudent")
+    @Override
+    public GetStudentResp getStudent(@RequestBody GetStudentReq req) {
+        Long studentId = req.getStudentId();
+        Long rootOrgId = req.getRootOrgId();
+        String identityNumber = req.getIdentityNumber();
+        String studentCode = req.getStudentCode();
+        String securityPhone = req.getSecurityPhone();
+
+        StudentInfo student = studentService.getStudentInfo(rootOrgId, studentId, identityNumber,
+                studentCode, securityPhone);
+
+        StudentBean studentBean = new StudentBean();
+        studentBean.setId(student.getId());
+        studentBean.setName(student.getName());
+        studentBean.setIdentityNumber(student.getIdentityNumber());
+        studentBean.setStudentCodeList(student.getStudentCodeList());
+        studentBean.setRootOrgId(student.getRootOrgId());
+        if (null != student.getOrgId()) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, student.getOrgId(), OrgEntity.class);
+            studentBean.setOrgId(org.getId());
+            studentBean.setOrgCode(org.getCode());
+            studentBean.setOrgName(org.getName());
+        }
+        studentBean.setOrgId(student.getOrgId());
+        studentBean.setOrgCode(student.getOrgCode());
+        studentBean.setOrgName(student.getOrgName());
+        studentBean.setPhoneNumber(student.getPhoneNumber());
+        studentBean.setPhotoPath(student.getPhotoPath());
+        studentBean.setRemark(student.getRemark());
+        studentBean.setSecurityPhone(student.getSecurityPhone());
+
+        GetStudentResp resp = new GetStudentResp();
+        resp.setStudentInfo(studentBean);
+        return resp;
+    }
+
+    @ApiOperation(value = "解绑学号")
+    @PostMapping("unbindStudentCode")
+    @Transactional
+    @Override
+    public UnbindStudentCodeResp unbindStudentCode(@RequestBody UnbindStudentCodeReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        String studentCode = req.getStudentCode();
+        String identityNumber = req.getIdentityNumber();
+
+        if (null == rootOrgId) {
+            throw new StatusException("160001", "rootOrgId is null");
+        }
+        if (StringUtils.isBlank(studentCode)) {
+            throw new StatusException("160002", "studentCode is blank");
+        }
+
+        List<Long> studentIdList = studentService.unbindStudentCode(rootOrgId, studentCode,
+                identityNumber);
+
+        UnbindStudentCodeResp resp = new UnbindStudentCodeResp();
+        resp.setStudentIdList(studentIdList);
+
+        for (Long cur : studentIdList) {
+            studentCache.remove(cur);
+        }
+
+        return resp;
+    }
+
+    @ApiOperation(value = "修改密码")
+    @PostMapping("updatePassword")
+    @Transactional
+    @Override
+    public UpdatePasswordResp updatePassword(@RequestBody UpdatePasswordReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        String identityNumber = req.getIdentityNumber();
+        Long studentId = req.getStudentId();
+        String password = req.getPassword();
+
+        StudentEntity entity = null;
+        if (null != studentId) {
+            entity = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
+        } else if (StringUtils.isNotBlank(identityNumber)) {
+            if (null == rootOrgId) {
+                throw new StatusException("056001", "rootOrgId is needed");
+            }
+            entity = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
+        } else {
+            throw new StatusException("056002", "params is missing");
+        }
+
+        if (null == entity) {
+            throw new StatusException("056003", "no student");
+        }
+
+        entity.setPassword(password);
+        studentRepo.save(entity);
+
+        UpdatePasswordResp resp = new UpdatePasswordResp();
+        return resp;
+    }
+
+    @ApiOperation(value = "更新学生状态")
+    @PostMapping("updateStudentStatus")
+    @Transactional
+    @Override
+    public UpdateStudentStatusResp updateStudentStatus(@RequestBody UpdateStudentStatusReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        String identityNumber = req.getIdentityNumber();
+        Long studentId = req.getStudentId();
+        Boolean enable = req.getEnable();
+
+        StudentEntity entity = null;
+        if (null != studentId) {
+            entity = GlobalHelper.getEntity(studentRepo, studentId, StudentEntity.class);
+        } else if (StringUtils.isNotBlank(identityNumber)) {
+            if (null == rootOrgId) {
+                throw new StatusException("056004", "rootOrgId is needed");
+            }
+            entity = studentRepo.findByIdentityNumberAndRootOrgId(identityNumber, rootOrgId);
+        } else {
+            throw new StatusException("056005", "params is missing");
+        }
+
+        if (null == entity) {
+            throw new StatusException("056006", "no student");
+        }
+
+        entity.setEnable(enable);
+        StudentEntity saved = studentRepo.save(entity);
+
+        studentCache.remove(saved.getId());
+
+        UpdateStudentStatusResp resp = new UpdateStudentStatusResp();
+        return resp;
+    }
+
+    @ApiOperation(value = "统计学生")
+    @PostMapping("countStudent")
+    @Override
+    public CountStudentResp countStudent(@RequestBody CountStudentReq req) {
+        Long rootOrgId = req.getRootOrgId();
+
+        Specification<StudentEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        long count = studentRepo.count(specification);
+
+        CountStudentResp resp = new CountStudentResp();
+        resp.setCount(count);
+        return resp;
+    }
 
 }

+ 47 - 46
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/SystemPropertyCloudServiceProvider.java

@@ -1,14 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.Date;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-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.util.DateUtil;
 import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
 import cn.com.qmth.examcloud.core.basic.api.SystemPropertyCloudService;
@@ -18,7 +9,16 @@ import cn.com.qmth.examcloud.core.basic.api.response.GetSystemPropertyResp;
 import cn.com.qmth.examcloud.core.basic.api.response.SetSystemPropertyResp;
 import cn.com.qmth.examcloud.core.basic.service.SystemPropertyService;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+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;
 
 /**
  * 系统配置
@@ -28,51 +28,52 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "系统配置相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "systemProperty")
 public class SystemPropertyCloudServiceProvider extends ControllerSupport
-		implements
-			SystemPropertyCloudService {
+        implements
+        SystemPropertyCloudService {
 
-	private static final long serialVersionUID = 2299432976949405946L;
+    private static final long serialVersionUID = 2299432976949405946L;
 
-	@Autowired
-	SystemPropertyService systemPropertyService;
+    @Autowired
+    SystemPropertyService systemPropertyService;
 
-	@ApiOperation(value = "设置配置")
-	@PostMapping("setSystemProperty")
-	@Transactional
-	@Override
-	public SetSystemPropertyResp setSystemProperty(@RequestBody SetSystemPropertyReq req) {
-		String key = req.getKey();
-		String value = req.getValue();
-		systemPropertyService.set(key, value);
+    @ApiOperation(value = "设置配置")
+    @PostMapping("setSystemProperty")
+    @Transactional
+    @Override
+    public SetSystemPropertyResp setSystemProperty(@RequestBody SetSystemPropertyReq req) {
+        String key = req.getKey();
+        String value = req.getValue();
+        systemPropertyService.set(key, value);
 
-		SetSystemPropertyResp resp = new SetSystemPropertyResp();
-		resp.setKey(key);
-		resp.setValue(value);
-		return resp;
-	}
+        SetSystemPropertyResp resp = new SetSystemPropertyResp();
+        resp.setKey(key);
+        resp.setValue(value);
+        return resp;
+    }
 
-	@ApiOperation(value = "获取配置")
-	@PostMapping("getSystemProperty")
-	@Override
-	public GetSystemPropertyResp getSystemProperty(@RequestBody GetSystemPropertyReq req) {
-		String key = req.getKey();
-		Object value = systemPropertyService.get(key);
+    @ApiOperation(value = "获取配置")
+    @PostMapping("getSystemProperty")
+    @Override
+    public GetSystemPropertyResp getSystemProperty(@RequestBody GetSystemPropertyReq req) {
+        String key = req.getKey();
+        Object value = systemPropertyService.get(key);
 
-		String strValue = null;
-		if (null == value) {
-			strValue = null;
-		} else if (value instanceof Date) {
-			strValue = DateUtil.format((Date) value, DatePatterns.CHINA_DEFAULT);
-		} else {
-			strValue = String.valueOf(value);
-		}
+        String strValue = null;
+        if (null == value) {
+            strValue = null;
+        } else if (value instanceof Date) {
+            strValue = DateUtil.format((Date) value, DatePatterns.CHINA_DEFAULT);
+        } else {
+            strValue = String.valueOf(value);
+        }
 
-		GetSystemPropertyResp resp = new GetSystemPropertyResp();
-		resp.setKey(key);
-		resp.setValue(strValue);
-		return resp;
-	}
+        GetSystemPropertyResp resp = new GetSystemPropertyResp();
+        resp.setKey(key);
+        resp.setValue(strValue);
+        return resp;
+    }
 
 }

+ 290 - 291
examcloud-core-basic-api-provider/src/main/java/cn/com/qmth/examcloud/core/basic/api/provider/UserCloudServiceProvider.java

@@ -1,29 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.api.provider;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.Subquery;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.transaction.annotation.Transactional;
-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.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.UserCloudService;
@@ -49,7 +25,29 @@ import cn.com.qmth.examcloud.core.basic.dao.entity.UserRoleRelationEntity;
 import cn.com.qmth.examcloud.core.basic.service.UserService;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import com.google.common.collect.Lists;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.transaction.annotation.Transactional;
+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.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * {@link StatusException} 状态码范围:008XXX<br>
@@ -59,275 +57,276 @@ import io.swagger.annotations.ApiOperation;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
+@Api(tags = "用户相关接口")
 @RequestMapping("${$rmp.cloud.basic}" + "user")
 public class UserCloudServiceProvider extends ControllerSupport implements UserCloudService {
 
-	private static final long serialVersionUID = -7881522922704971610L;
-
-	@Autowired
-	UserRepo userRepo;
-
-	@Autowired
-	OrgRepo orgRepo;
-
-	@Autowired
-	RoleRepo roleRepo;
-
-	@Autowired
-	UserService userService;
-
-	@Autowired
-	UserRoleRelationRepo userRoleRelationRepo;
-
-	@ApiOperation(value = "保存用户")
-	@PostMapping("addUser")
-	@Transactional
-	@Override
-	public AddUserResp addUser(@RequestBody AddUserReq req) {
-		trim(req);
-		Long rootOrgId = req.getRootOrgId();
-		String loginName = req.getLoginName();
-		String name = req.getName();
-
-		UserEntity userEntity = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
-
-		if (null != userEntity) {
-			throw new StatusException("650001", "用户名已经存在");
-		}
-
-		userEntity = new UserEntity();
-		userEntity.setEnable(true);
-		userEntity.setLoginName(loginName);
-		userEntity.setRootOrgId(rootOrgId);
-		userEntity.setName(name);
-		if (StringUtils.isBlank(req.getPassword())) {
-			userEntity.setPassword(BasicConsts.DEFAULT_PASSWORD);
-		} else {
-			userEntity.setPassword(req.getPassword());
-		}
-
-		UserEntity saved = userService.save(userEntity);
-
-		List<String> roleCodeList = req.getRoleCodeList();
-
-		if (CollectionUtils.isEmpty(roleCodeList)) {
-			throw new StatusException("650002", "角色不能为空");
-		}
-
-		List<UserRoleRelationEntity> userRoles = Lists.newArrayList();
-		for (String roleCode : roleCodeList) {
-			RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode);
-			if (null == roleEntity) {
-				roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode, rootOrgId);
-			}
-			if (null == roleEntity) {
-				throw new StatusException("002002", "role code is wrong. roleCode=" + roleCode);
-			}
-			if (roleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-				throw new StatusException("150007", "不允许新增或修改超级管理员");
-			}
-			UserRoleRelationEntity relation = new UserRoleRelationEntity(saved.getId(),
-					roleEntity.getId());
-			userRoles.add(relation);
-		}
-
-		userRoleRelationRepo.deleteByUserId(saved.getId());
-		userRoleRelationRepo.saveAll(userRoles);
-		AddUserResp resp = new AddUserResp();
-		resp.setUserId(saved.getId());
-
-		return resp;
-	}
-
-	@ApiOperation(value = "获取用户")
-	@PostMapping("getUser")
-	@Override
-	public GetUserResp getUser(@RequestBody GetUserReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		String loginName = req.getLoginName();
-		Long userId = req.getUserId();
-
-		UserEntity userEntity = null;
-		if (null != userId) {
-			userEntity = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
-		} else if (StringUtils.isNotBlank(loginName)) {
-			userEntity = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
-		} else {
-			throw new StatusException("230001", "userId and  loginName can not be all null");
-		}
-
-		GetUserResp resp = new GetUserResp();
-		if (null == userEntity) {
-			resp.setExisting(false);
-			return resp;
-		}
-
-		resp.setExisting(true);
-
-		UserBean userBean = new UserBean();
-		userBean.setUserId(userEntity.getId());
-		userBean.setName(userEntity.getName());
-		userBean.setLoginName(userEntity.getLoginName());
-		userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
-		userBean.setOrgId(userEntity.getOrgId());
-		userBean.setRootOrgId(userEntity.getRootOrgId());
-		OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, userBean.getRootOrgId(),
-				OrgEntity.class);
-		userBean.setRootOrgName(rootOrg.getName());
-
-		if (null != userBean.getOrgId()) {
-			OrgEntity org = GlobalHelper.getEntity(orgRepo, userBean.getOrgId(), OrgEntity.class);
-			userBean.setOrgName(org.getName());
-		}
-
-		List<RoleBean> roleList = getUserRoles(userEntity.getId());
-		userBean.setRoleList(roleList);
-
-		resp.setUserBean(userBean);
-		return resp;
-	}
-
-	/**
-	 * 获取角色集合
-	 *
-	 * @author WANGWEI
-	 * @param userId
-	 * @return
-	 */
-	private List<RoleBean> getUserRoles(Long userId) {
-		List<UserRoleRelationEntity> relationList = userRoleRelationRepo.findAllByUserId(userId);
-		List<RoleBean> roleList = Lists.newArrayList();
-		if (CollectionUtils.isNotEmpty(relationList)) {
-			for (UserRoleRelationEntity cur : relationList) {
-				Long roleId = cur.getRoleId();
-				RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
-				if (null == roleEntity) {
-					throw new StatusException("002002", "roleId wrong. roleId=" + roleId);
-				}
-				RoleBean role = new RoleBean(roleEntity.getRootOrgId(), roleEntity.getId(),
-						roleEntity.getCode(), roleEntity.getName());
-				roleList.add(role);
-			}
-		}
-		return roleList;
-	}
-
-	@ApiOperation(value = "根据角色获取用户集合")
-	@PostMapping("getAllUsersByRole")
-	@Override
-	public GetAllUsersByRoleResp getAllUsersByRole(@RequestBody GetAllUsersByRoleReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		Long roleId = req.getRoleId();
-		String roleCode = req.getRoleCode();
-
-		if (null != roleId) {
-			RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
-			if (null == roleEntity) {
-				throw new StatusException("150001", "角色不存在");
-			}
-		} else if (StringUtils.isNotBlank(roleCode)) {
-			RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
-			if (null == roleEntity) {
-				roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(), rootOrgId);
-			}
-			if (null == roleEntity) {
-				throw new StatusException("150002", "角色不存在");
-			}
-			roleId = roleEntity.getId();
-		} else {
-			throw new StatusException("150003", "roleId,roleCode不能都为空");
-		}
-		final Long finalRoleId = roleId;
-
-		final long start = null == req.getStart() ? 1 : req.getStart();
-
-		Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "id");
-
-		Specification<UserEntity> specification = (root, query, cb) -> {
-			List<Predicate> predicates = new ArrayList<>();
-			predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
-
-			predicates.add(cb.greaterThanOrEqualTo(root.get("id"), start));
-
-			Subquery<UserRoleRelationEntity> subquery = query
-					.subquery(UserRoleRelationEntity.class);
-			Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
-			subquery.select(subRoot.get("userId"));
-			Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
-			Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
-			subquery.where(cb.and(p1, p2));
-			predicates.add(cb.exists(subquery));
-
-			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-		};
-
-		Page<UserEntity> page = userRepo.findAll(specification, pageable);
-
-		Iterator<UserEntity> iterator = page.iterator();
-
-		List<UserBean> list = Lists.newArrayList();
-		long next = start;
-		boolean has = false;
-		while (iterator.hasNext()) {
-			UserEntity userEntity = iterator.next();
-			UserBean userBean = new UserBean();
-			userBean.setUserId(userEntity.getId());
-			userBean.setName(userEntity.getName());
-			userBean.setLoginName(userEntity.getLoginName());
-			userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
-			userBean.setOrgId(userEntity.getOrgId());
-			userBean.setRootOrgId(userEntity.getRootOrgId());
-
-			next = userEntity.getId();
-			list.add(userBean);
-			has = true;
-		}
-
-		GetAllUsersByRoleResp resp = new GetAllUsersByRoleResp();
-		if (has) {
-			next++;
-		}
-		resp.setNext(next);
-		resp.setUserBeanList(list);
-
-		return resp;
-	}
-
-	@ApiOperation(value = "根据ID获取用户集合")
-	@PostMapping("getUserListByIds")
-	@Override
-	public GetUserListByIdsResp getUserListByIds(@RequestBody GetUserListByIdsReq req) {
-		Long rootOrgId = req.getRootOrgId();
-		List<Long> userIdList = req.getUserIdList();
-		if (CollectionUtils.isEmpty(userIdList)) {
-			throw new StatusException("008001", "userIdList is empty");
-		}
-		if (100 < userIdList.size()) {
-			throw new StatusException("008002", "size of userIdList is too large");
-		}
-
-		List<UserEntity> userEntityList = userRepo.findByIdIn(userIdList);
-
-		List<UserBean> list = Lists.newArrayList();
-		for (UserEntity userEntity : userEntityList) {
-			UserBean userBean = new UserBean();
-			userBean.setUserId(userEntity.getId());
-			userBean.setName(userEntity.getName());
-			userBean.setLoginName(userEntity.getLoginName());
-			userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
-			userBean.setOrgId(userEntity.getOrgId());
-			userBean.setRootOrgId(userEntity.getRootOrgId());
-
-			if (!userBean.getRootOrgId().equals(rootOrgId)) {
-				throw new StatusException("008003", "params error");
-			}
-			list.add(userBean);
-		}
-
-		GetUserListByIdsResp resp = new GetUserListByIdsResp();
-		resp.setUserBeanList(list);
-
-		return resp;
-	}
+    private static final long serialVersionUID = -7881522922704971610L;
+
+    @Autowired
+    UserRepo userRepo;
+
+    @Autowired
+    OrgRepo orgRepo;
+
+    @Autowired
+    RoleRepo roleRepo;
+
+    @Autowired
+    UserService userService;
+
+    @Autowired
+    UserRoleRelationRepo userRoleRelationRepo;
+
+    @ApiOperation(value = "保存用户")
+    @PostMapping("addUser")
+    @Transactional
+    @Override
+    public AddUserResp addUser(@RequestBody AddUserReq req) {
+        trim(req);
+        Long rootOrgId = req.getRootOrgId();
+        String loginName = req.getLoginName();
+        String name = req.getName();
+
+        UserEntity userEntity = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
+
+        if (null != userEntity) {
+            throw new StatusException("650001", "用户名已经存在");
+        }
+
+        userEntity = new UserEntity();
+        userEntity.setEnable(true);
+        userEntity.setLoginName(loginName);
+        userEntity.setRootOrgId(rootOrgId);
+        userEntity.setName(name);
+        if (StringUtils.isBlank(req.getPassword())) {
+            userEntity.setPassword(BasicConsts.DEFAULT_PASSWORD);
+        } else {
+            userEntity.setPassword(req.getPassword());
+        }
+
+        UserEntity saved = userService.save(userEntity);
+
+        List<String> roleCodeList = req.getRoleCodeList();
+
+        if (CollectionUtils.isEmpty(roleCodeList)) {
+            throw new StatusException("650002", "角色不能为空");
+        }
+
+        List<UserRoleRelationEntity> userRoles = Lists.newArrayList();
+        for (String roleCode : roleCodeList) {
+            RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode);
+            if (null == roleEntity) {
+                roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode, rootOrgId);
+            }
+            if (null == roleEntity) {
+                throw new StatusException("002002", "role code is wrong. roleCode=" + roleCode);
+            }
+            if (roleEntity.getCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+                throw new StatusException("150007", "不允许新增或修改超级管理员");
+            }
+            UserRoleRelationEntity relation = new UserRoleRelationEntity(saved.getId(),
+                    roleEntity.getId());
+            userRoles.add(relation);
+        }
+
+        userRoleRelationRepo.deleteByUserId(saved.getId());
+        userRoleRelationRepo.saveAll(userRoles);
+        AddUserResp resp = new AddUserResp();
+        resp.setUserId(saved.getId());
+
+        return resp;
+    }
+
+    @ApiOperation(value = "获取用户")
+    @PostMapping("getUser")
+    @Override
+    public GetUserResp getUser(@RequestBody GetUserReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        String loginName = req.getLoginName();
+        Long userId = req.getUserId();
+
+        UserEntity userEntity = null;
+        if (null != userId) {
+            userEntity = GlobalHelper.getEntity(userRepo, userId, UserEntity.class);
+        } else if (StringUtils.isNotBlank(loginName)) {
+            userEntity = userRepo.findByRootOrgIdAndLoginName(rootOrgId, loginName);
+        } else {
+            throw new StatusException("230001", "userId and  loginName can not be all null");
+        }
+
+        GetUserResp resp = new GetUserResp();
+        if (null == userEntity) {
+            resp.setExisting(false);
+            return resp;
+        }
+
+        resp.setExisting(true);
+
+        UserBean userBean = new UserBean();
+        userBean.setUserId(userEntity.getId());
+        userBean.setName(userEntity.getName());
+        userBean.setLoginName(userEntity.getLoginName());
+        userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
+        userBean.setOrgId(userEntity.getOrgId());
+        userBean.setRootOrgId(userEntity.getRootOrgId());
+        OrgEntity rootOrg = GlobalHelper.getEntity(orgRepo, userBean.getRootOrgId(),
+                OrgEntity.class);
+        userBean.setRootOrgName(rootOrg.getName());
+
+        if (null != userBean.getOrgId()) {
+            OrgEntity org = GlobalHelper.getEntity(orgRepo, userBean.getOrgId(), OrgEntity.class);
+            userBean.setOrgName(org.getName());
+        }
+
+        List<RoleBean> roleList = getUserRoles(userEntity.getId());
+        userBean.setRoleList(roleList);
+
+        resp.setUserBean(userBean);
+        return resp;
+    }
+
+    /**
+     * 获取角色集合
+     *
+     * @param userId
+     * @return
+     * @author WANGWEI
+     */
+    private List<RoleBean> getUserRoles(Long userId) {
+        List<UserRoleRelationEntity> relationList = userRoleRelationRepo.findAllByUserId(userId);
+        List<RoleBean> roleList = Lists.newArrayList();
+        if (CollectionUtils.isNotEmpty(relationList)) {
+            for (UserRoleRelationEntity cur : relationList) {
+                Long roleId = cur.getRoleId();
+                RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
+                if (null == roleEntity) {
+                    throw new StatusException("002002", "roleId wrong. roleId=" + roleId);
+                }
+                RoleBean role = new RoleBean(roleEntity.getRootOrgId(), roleEntity.getId(),
+                        roleEntity.getCode(), roleEntity.getName());
+                roleList.add(role);
+            }
+        }
+        return roleList;
+    }
+
+    @ApiOperation(value = "根据角色获取用户集合")
+    @PostMapping("getAllUsersByRole")
+    @Override
+    public GetAllUsersByRoleResp getAllUsersByRole(@RequestBody GetAllUsersByRoleReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        Long roleId = req.getRoleId();
+        String roleCode = req.getRoleCode();
+
+        if (null != roleId) {
+            RoleEntity roleEntity = GlobalHelper.getEntity(roleRepo, roleId, RoleEntity.class);
+            if (null == roleEntity) {
+                throw new StatusException("150001", "角色不存在");
+            }
+        } else if (StringUtils.isNotBlank(roleCode)) {
+            RoleEntity roleEntity = roleRepo.findByCodeAndRootOrgIdIsNull(roleCode.trim());
+            if (null == roleEntity) {
+                roleEntity = roleRepo.findByCodeAndRootOrgId(roleCode.trim(), rootOrgId);
+            }
+            if (null == roleEntity) {
+                throw new StatusException("150002", "角色不存在");
+            }
+            roleId = roleEntity.getId();
+        } else {
+            throw new StatusException("150003", "roleId,roleCode不能都为空");
+        }
+        final Long finalRoleId = roleId;
+
+        final long start = null == req.getStart() ? 1 : req.getStart();
+
+        Pageable pageable = PageRequest.of(0, 100, Sort.Direction.ASC, "id");
+
+        Specification<UserEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("rootOrgId"), rootOrgId));
+
+            predicates.add(cb.greaterThanOrEqualTo(root.get("id"), start));
+
+            Subquery<UserRoleRelationEntity> subquery = query
+                    .subquery(UserRoleRelationEntity.class);
+            Root<UserRoleRelationEntity> subRoot = subquery.from(UserRoleRelationEntity.class);
+            subquery.select(subRoot.get("userId"));
+            Predicate p1 = cb.equal(subRoot.get("roleId"), finalRoleId);
+            Predicate p2 = cb.equal(subRoot.get("userId"), root.get("id"));
+            subquery.where(cb.and(p1, p2));
+            predicates.add(cb.exists(subquery));
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        Page<UserEntity> page = userRepo.findAll(specification, pageable);
+
+        Iterator<UserEntity> iterator = page.iterator();
+
+        List<UserBean> list = Lists.newArrayList();
+        long next = start;
+        boolean has = false;
+        while (iterator.hasNext()) {
+            UserEntity userEntity = iterator.next();
+            UserBean userBean = new UserBean();
+            userBean.setUserId(userEntity.getId());
+            userBean.setName(userEntity.getName());
+            userBean.setLoginName(userEntity.getLoginName());
+            userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
+            userBean.setOrgId(userEntity.getOrgId());
+            userBean.setRootOrgId(userEntity.getRootOrgId());
+
+            next = userEntity.getId();
+            list.add(userBean);
+            has = true;
+        }
+
+        GetAllUsersByRoleResp resp = new GetAllUsersByRoleResp();
+        if (has) {
+            next++;
+        }
+        resp.setNext(next);
+        resp.setUserBeanList(list);
+
+        return resp;
+    }
+
+    @ApiOperation(value = "根据ID获取用户集合")
+    @PostMapping("getUserListByIds")
+    @Override
+    public GetUserListByIdsResp getUserListByIds(@RequestBody GetUserListByIdsReq req) {
+        Long rootOrgId = req.getRootOrgId();
+        List<Long> userIdList = req.getUserIdList();
+        if (CollectionUtils.isEmpty(userIdList)) {
+            throw new StatusException("008001", "userIdList is empty");
+        }
+        if (100 < userIdList.size()) {
+            throw new StatusException("008002", "size of userIdList is too large");
+        }
+
+        List<UserEntity> userEntityList = userRepo.findByIdIn(userIdList);
+
+        List<UserBean> list = Lists.newArrayList();
+        for (UserEntity userEntity : userEntityList) {
+            UserBean userBean = new UserBean();
+            userBean.setUserId(userEntity.getId());
+            userBean.setName(userEntity.getName());
+            userBean.setLoginName(userEntity.getLoginName());
+            userBean.setDisplayName(userEntity.getLoginName() + " (" + userEntity.getName() + ")");
+            userBean.setOrgId(userEntity.getOrgId());
+            userBean.setRootOrgId(userEntity.getRootOrgId());
+
+            if (!userBean.getRootOrgId().equals(rootOrgId)) {
+                throw new StatusException("008003", "params error");
+            }
+            list.add(userBean);
+        }
+
+        GetUserListByIdsResp resp = new GetUserListByIdsResp();
+        resp.setUserBeanList(list);
+
+        return resp;
+    }
 
 }

+ 9 - 1
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/LoginRuleRepo.java

@@ -1,8 +1,16 @@
 package cn.com.qmth.examcloud.core.basic.dao;
 
 import cn.com.qmth.examcloud.core.basic.dao.entity.LoginRuleEntity;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 
-public interface LoginRuleRepo extends JpaRepository<LoginRuleEntity, Long> {
+import java.util.List;
+
+public interface LoginRuleRepo extends JpaRepository<LoginRuleEntity, Long>, JpaSpecificationExecutor<LoginRuleEntity> {
+
+    List<LoginRuleEntity> findByType(LoginRuleType type);
+
+    List<LoginRuleEntity> findByRootOrgIdAndType(Long rootOrgId, LoginRuleType type);
 
 }

+ 12 - 16
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/OrgRepo.java

@@ -1,36 +1,32 @@
 package cn.com.qmth.examcloud.core.basic.dao;
 
-import java.util.List;
-
+import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
 
-import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
+import java.util.List;
 
 /**
  * Created by songyue on 17/1/13.
  */
-public interface OrgRepo
-		extends
-			JpaRepository<OrgEntity, Long>,
-			QueryByExampleExecutor<OrgEntity>,
-			JpaSpecificationExecutor<OrgEntity> {
+public interface OrgRepo extends JpaRepository<OrgEntity, Long>,
+        QueryByExampleExecutor<OrgEntity>, JpaSpecificationExecutor<OrgEntity> {
 
-	List<OrgEntity> findByRootId(Long rootId);
+    List<OrgEntity> findByRootId(Long rootId);
 
-	OrgEntity findByParentIdIsNullAndDomainName(String domainName);
+    OrgEntity findByParentIdIsNullAndDomainName(String domainName);
 
-	OrgEntity findByRootIdAndCode(Long rootId, String code);
+    OrgEntity findByRootIdAndCode(Long rootId, String code);
 
-	List<OrgEntity> findByRootIdAndNameLike(Long rootId, String name);
+    List<OrgEntity> findByRootIdAndNameLike(Long rootId, String name);
 
-	OrgEntity findByParentIdIsNullAndCode(String code);
+    OrgEntity findByParentIdIsNullAndCode(String code);
 
-	OrgEntity findByParentIdIsNullAndId(Long id);
+    OrgEntity findByParentIdIsNullAndId(Long id);
 
-	int countByRootIdAndNameLike(Long rootId, String name);
+    int countByRootIdAndNameLike(Long rootId, String name);
 
-	int countByRootIdAndParentId(Long rootId, long parentId);
+    int countByRootIdAndParentId(Long rootId, long parentId);
 
 }

+ 21 - 0
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/SysNoticeRepo.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.examcloud.core.basic.dao;
+
+import cn.com.qmth.examcloud.core.basic.dao.entity.SysNoticeEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+/**
+ * @Description 系统通知
+ * @Author lideyin
+ * @Date 2020/8/16 10:42
+ * @Version 1.0
+ */
+public interface SysNoticeRepo
+        extends
+        JpaRepository<SysNoticeEntity, Long>,
+        QueryByExampleExecutor<SysNoticeEntity>,
+        JpaSpecificationExecutor<SysNoticeEntity> {
+
+	SysNoticeEntity findTopByRootOrgIdOrderByIdDesc(Long rootOrgId);
+}

+ 30 - 10
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/entity/LoginRuleEntity.java

@@ -1,14 +1,18 @@
 package cn.com.qmth.examcloud.core.basic.dao.entity;
 
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
 import cn.com.qmth.examcloud.web.jpa.JpaEntity;
 
 import javax.persistence.*;
 
 /**
- * 登录规则(白名单)
+ * 登录规则
  */
 @Entity
-@Table(name = "ec_b_login_rule", indexes = {@Index(name = "IDX_B_LR_010001", columnList = "rootOrgId")})
+@Table(name = "ec_b_login_rule", indexes = {
+        @Index(name = "IDX_B_LR_001", columnList = "rootOrgId"),
+        @Index(name = "IDX_B_LR_002", columnList = "type")
+})
 public class LoginRuleEntity extends JpaEntity {
 
     private static final long serialVersionUID = 1L;
@@ -18,16 +22,24 @@ public class LoginRuleEntity extends JpaEntity {
     private Long id;
 
     /**
-     * 顶级机构
+     * 顶级机构ID
+     * 为-1时,代表所有机构
      */
     @Column(nullable = false)
     private Long rootOrgId;
 
     /**
-     * 是否白名单
+     * 规则类型
+     */
+    @Enumerated(EnumType.STRING)
+    @Column(length = 50, nullable = false)
+    private LoginRuleType type;
+
+    /**
+     * 是否开放(白名单)
      */
     @Column(nullable = false)
-    private Boolean white;
+    private Boolean allow;
 
     public Long getId() {
         return id;
@@ -45,11 +57,19 @@ public class LoginRuleEntity extends JpaEntity {
         this.rootOrgId = rootOrgId;
     }
 
-    public Boolean getWhite() {
-        return white;
+    public LoginRuleType getType() {
+        return type;
+    }
+
+    public void setType(LoginRuleType type) {
+        this.type = type;
+    }
+
+    public Boolean getAllow() {
+        return allow;
     }
 
-    public void setWhite(Boolean white) {
-        this.white = white;
+    public void setAllow(Boolean allow) {
+        this.allow = allow;
     }
-}
+}

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

@@ -0,0 +1,102 @@
+package cn.com.qmth.examcloud.core.basic.dao.entity;
+
+import cn.com.qmth.examcloud.web.jpa.WithIdJpaEntity;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * @Description 系统通知
+ * @Author lideyin
+ * @Date 2020/8/16 10:34
+ * @Version 1.0
+ */
+@Entity
+@Table(name = "EC_B_SYS_NOTICE")
+@DynamicUpdate
+@DynamicInsert
+public class SysNoticeEntity extends WithIdJpaEntity {
+
+    /**
+     * 组织机构id,(-1代表所有组织机构)
+     */
+    private Long rootOrgId;
+
+    /**
+     * 通知内容
+     */
+    @Column(length = 400)
+    private String content;
+
+    /**
+     * 生效开始时间
+     */
+    private Date startTime;
+    /**
+     * 生效截止时间
+     */
+    private Date endTime;
+
+    /**
+     * 通知标题
+     */
+    @Column(length = 40)
+    private String title;
+
+    /**
+     * 启用标识
+     */
+    private Boolean enable;
+
+    public Long getRootOrgId() {
+        return rootOrgId;
+    }
+
+    public void setRootOrgId(Long rootOrgId) {
+        this.rootOrgId = rootOrgId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    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 String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+}

+ 29 - 0
examcloud-core-basic-dao/src/main/java/cn/com/qmth/examcloud/core/basic/dao/enums/LoginRuleType.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-18 14:57:15
+ */
+
+package cn.com.qmth.examcloud.core.basic.dao.enums;
+
+/**
+ * 登录规则类型
+ */
+public enum LoginRuleType {
+
+    STUDENT_LOGIN("考生WAP登录"),
+
+    STUDENT_CLIENT_LOGIN("考生端登录"),
+
+    GEETEST_LOGIN("极验验证码登录");
+
+    LoginRuleType(String desc) {
+        this.desc = desc;
+    }
+
+    private String desc;
+
+    public String getDesc() {
+        return desc;
+    }
+
+}

+ 19 - 3
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/LoginRuleService.java

@@ -1,9 +1,25 @@
 package cn.com.qmth.examcloud.core.basic.service;
 
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleForm;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleInfo;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleQuery;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
 public interface LoginRuleService {
 
-    void refreshLoginRule();
+    List<LoginRuleInfo> getLoginRuleTopList();
+
+    Page<LoginRuleInfo> getLoginRuleList(LoginRuleQuery req);
+
+    void addOrUpdateLoginRule(LoginRuleForm req);
+
+    void deleteLoginRuleById(Long id);
+
+    void refreshAllLoginRule();
 
-    boolean isLoginRuleWhite(Long rootOrgId);
+    boolean isLoginRuleAllow(Long rootOrgId, LoginRuleType type);
 
-}
+}

+ 48 - 39
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/OrgService.java

@@ -1,11 +1,12 @@
 package cn.com.qmth.examcloud.core.basic.service;
 
+import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
+import cn.com.qmth.examcloud.core.basic.service.bean.OrgInfo;
+
 import java.io.File;
 import java.util.List;
 import java.util.Map;
-
-import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
-import cn.com.qmth.examcloud.core.basic.service.bean.OrgInfo;
+import java.util.Set;
 
 /**
  * 类注释
@@ -16,41 +17,49 @@ import cn.com.qmth.examcloud.core.basic.service.bean.OrgInfo;
  */
 public interface OrgService {
 
-	/**
-	 * 保存顶级机构
-	 *
-	 * @author WANGWEI
-	 * @param orgInfo
-	 * @return
-	 */
-	OrgEntity saveRootOrg(OrgInfo orgInfo);
-
-	/**
-	 * 保存子机构
-	 *
-	 * @author WANGWEI
-	 * @param orgInfo
-	 * @return
-	 */
-	OrgEntity saveSubOrg(OrgInfo orgInfo);
-
-	/**
-	 * 保存机构属性
-	 *
-	 * @author WANGWEI
-	 * @param orgId
-	 * @param properties
-	 */
-	void saveOrgProperties(Long orgId, Map<String, String> properties);
-
-	/**
-	 * 导入子机构
-	 *
-	 * @author WANGWEI
-	 * @param rootOrgId
-	 * @param file
-	 * @return
-	 */
-	public List<Map<String, Object>> importSubOrg(Long rootOrgId, File file);
+    /**
+     * 保存顶级机构
+     *
+     * @param orgInfo
+     * @return
+     * @author WANGWEI
+     */
+    OrgEntity saveRootOrg(OrgInfo orgInfo);
+
+    /**
+     * 保存子机构
+     *
+     * @param orgInfo
+     * @return
+     * @author WANGWEI
+     */
+    OrgEntity saveSubOrg(OrgInfo orgInfo);
+
+    /**
+     * 保存机构属性
+     *
+     * @param orgId
+     * @param properties
+     * @author WANGWEI
+     */
+    void saveOrgProperties(Long orgId, Map<String, String> properties);
+
+    /**
+     * 导入子机构
+     *
+     * @param rootOrgId
+     * @param file
+     * @return
+     * @author WANGWEI
+     */
+    public List<Map<String, Object>> importSubOrg(Long rootOrgId, File file);
+
+    /**
+     * 批量获取顶层机构名称
+     *
+     * @param rootOrgIds
+     * @return
+     */
+    Map<Long, String> findRootOrgNamesByIds(Set<Long> rootOrgIds);
 
 }

+ 11 - 3
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/VerifyCodeService.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.examcloud.core.basic.service;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.core.basic.service.bean.GeetestLoginInfo;
 import cn.com.qmth.examcloud.core.basic.service.bean.VerifyCodeLoginInfo;
 
 /**
@@ -9,21 +10,28 @@ import cn.com.qmth.examcloud.core.basic.service.bean.VerifyCodeLoginInfo;
 public interface VerifyCodeService {
 
     /**
-     * 验证码生成接口
+     * 极验-验证码登录接口
+     *
+     * @return 登录成功信息
+     */
+    User geetestLogin(GeetestLoginInfo info);
+
+    /**
+     * 数字公式-验证码生成接口
      *
      * @return 字符串:uuid(32位) + base64
      */
     String verifyCodeGenerate(Long rootOrgId, String accountValue);
 
     /**
-     * 验证码登录接口
+     * 数字公式-验证码登录接口
      *
      * @return 登录成功信息
      */
     User verifyCodeLogin(VerifyCodeLoginInfo info);
 
     /**
-     * Resource接口
+     * 数字公式-验证码的Resource接口
      */
     void verifyCodeResource(String uuid);
 

+ 56 - 0
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/GeetestLoginInfo.java

@@ -0,0 +1,56 @@
+package cn.com.qmth.examcloud.core.basic.service.bean;
+
+import cn.com.qmth.examcloud.starters.greetest.model.ValidateReq;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 极验-验证码登陆信息
+ */
+public class GeetestLoginInfo extends ValidateReq {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("顶级机构ID")
+    private Long rootOrgId;
+
+    @ApiModelProperty("登陆账号类型")
+    private String accountType;
+
+    @ApiModelProperty("登陆账号")
+    private String accountValue;
+
+    @ApiModelProperty("登陆密码")
+    private String password;
+
+    public Long getRootOrgId() {
+        return rootOrgId;
+    }
+
+    public void setRootOrgId(Long rootOrgId) {
+        this.rootOrgId = rootOrgId;
+    }
+
+    public String getAccountType() {
+        return accountType;
+    }
+
+    public void setAccountType(String accountType) {
+        this.accountType = accountType;
+    }
+
+    public String getAccountValue() {
+        return accountValue;
+    }
+
+    public void setAccountValue(String accountValue) {
+        this.accountValue = accountValue;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 49 - 0
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleForm.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-19 14:04:05
+ */
+
+package cn.com.qmth.examcloud.core.basic.service.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
+import io.swagger.annotations.ApiModelProperty;
+
+public class LoginRuleForm implements JsonSerializable {
+
+    private static final long serialVersionUID = 4853280464208226631L;
+
+    @ApiModelProperty(value = "学校ID")
+    protected Long rootOrgId;
+
+    @ApiModelProperty("规则类型")
+    protected LoginRuleType type;
+
+    @ApiModelProperty("是否开放(白名单)")
+    protected Boolean allow;
+
+    public Long getRootOrgId() {
+        return rootOrgId;
+    }
+
+    public void setRootOrgId(Long rootOrgId) {
+        this.rootOrgId = rootOrgId;
+    }
+
+    public LoginRuleType getType() {
+        return type;
+    }
+
+    public void setType(LoginRuleType type) {
+        this.type = type;
+    }
+
+    public Boolean getAllow() {
+        return allow;
+    }
+
+    public void setAllow(Boolean allow) {
+        this.allow = allow;
+    }
+
+}

+ 94 - 0
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleInfo.java

@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-19 14:04:00
+ */
+
+package cn.com.qmth.examcloud.core.basic.service.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+
+public class LoginRuleInfo implements JsonSerializable {
+
+    private static final long serialVersionUID = 4853280464208226631L;
+
+    @ApiModelProperty(value = "ID")
+    private Long id;
+
+    @ApiModelProperty(value = "学校ID")
+    private Long rootOrgId;
+
+    @ApiModelProperty(value = "学校名称")
+    private String rootOrgName;
+
+    @ApiModelProperty("规则类型")
+    private LoginRuleType type;
+
+    @ApiModelProperty("是否开放(白名单)")
+    private Boolean allow;
+
+    @ApiModelProperty(value = "创建时间")
+    private Date creationTime;
+
+    @ApiModelProperty(value = "更新时间")
+    private Date updateTime;
+
+    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 getRootOrgName() {
+        return rootOrgName;
+    }
+
+    public void setRootOrgName(String rootOrgName) {
+        this.rootOrgName = rootOrgName;
+    }
+
+    public LoginRuleType getType() {
+        return type;
+    }
+
+    public void setType(LoginRuleType type) {
+        this.type = type;
+    }
+
+    public Boolean getAllow() {
+        return allow;
+    }
+
+    public void setAllow(Boolean allow) {
+        this.allow = allow;
+    }
+
+    public Date getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}

+ 36 - 0
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/LoginRuleQuery.java

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-19 14:04:05
+ */
+
+package cn.com.qmth.examcloud.core.basic.service.bean;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class LoginRuleQuery extends LoginRuleForm {
+
+    private static final long serialVersionUID = 4853280464208226631L;
+
+    @ApiModelProperty("当前页数")
+    private Integer pageNo;
+
+    @ApiModelProperty("每页条数")
+    private Integer pageSize;
+
+    public Integer getPageNo() {
+        return pageNo;
+    }
+
+    public void setPageNo(Integer pageNo) {
+        this.pageNo = pageNo;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+}

+ 1 - 1
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/bean/VerifyCodeLoginInfo.java

@@ -4,7 +4,7 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 import io.swagger.annotations.ApiModelProperty;
 
 /**
- * 验证码登陆信息
+ * 数字公式-验证码登陆信息
  */
 public class VerifyCodeLoginInfo implements JsonSerializable {
 

+ 8 - 19
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/cache/LoginRuleCacheBean.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.examcloud.core.basic.service.cache;
 
 import java.io.Serializable;
+import java.util.Map;
 
 /**
  * 登录规则缓存对象
@@ -10,29 +11,17 @@ public class LoginRuleCacheBean implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
-     * 顶级机构ID
+     * 是否开放列表(白名单)
+     * Map<rootOrgId, isAllow>
      */
-    private Long rootOrgId;
+    private Map<Long, Boolean> allowList;
 
-    /**
-     * 是否白名单
-     */
-    private Boolean white;
-
-    public Long getRootOrgId() {
-        return rootOrgId;
-    }
-
-    public void setRootOrgId(Long rootOrgId) {
-        this.rootOrgId = rootOrgId;
-    }
-
-    public Boolean getWhite() {
-        return white;
+    public Map<Long, Boolean> getAllowList() {
+        return allowList;
     }
 
-    public void setWhite(Boolean white) {
-        this.white = white;
+    public void setAllowList(Map<Long, Boolean> allowList) {
+        this.allowList = allowList;
     }
 
 }

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

@@ -10,6 +10,7 @@ import cn.com.qmth.examcloud.core.basic.base.constants.PropKeys;
 import cn.com.qmth.examcloud.core.basic.base.enums.AccountType;
 import cn.com.qmth.examcloud.core.basic.dao.*;
 import cn.com.qmth.examcloud.core.basic.dao.entity.*;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
 import cn.com.qmth.examcloud.core.basic.service.*;
 import cn.com.qmth.examcloud.core.basic.service.bean.LoginInfo;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
@@ -225,9 +226,9 @@ public class AuthServiceImpl implements AuthService {
         } else {
             if (checkLoginRule) {
                 // 是否在登录的白名单
-                boolean isWhite = loginRuleService.isLoginRuleWhite(rootOrgId);
-                if (!isWhite) {
-                    throw new StatusException("500403", "当前机构登录被禁用");
+                boolean allow = loginRuleService.isLoginRuleAllow(rootOrgId, LoginRuleType.STUDENT_LOGIN);
+                if (!allow) {
+                    throw new StatusException("403001", "当前机构登录被禁用");
                 }
             }
 
@@ -241,6 +242,7 @@ public class AuthServiceImpl implements AuthService {
                 student = GlobalHelper.getEntity(studentRepo, scEntity.getStudentId(),
                         StudentEntity.class);
             }
+
             // 学生身份证号登录
             else if (AccountType.STUDENT_IDENTITY_NUMBER.equals(accountTypeEnum)) {
                 student = studentRepo.findByIdentityNumberAndRootOrgId(accountValue, rootOrgId);

+ 42 - 0
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/GeetestSessionImpl.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-07-24 15:20:00
+ */
+
+package cn.com.qmth.examcloud.core.basic.service.impl;
+
+import cn.com.qmth.examcloud.starters.greetest.service.GeetestSessionManager;
+import cn.com.qmth.examcloud.web.redis.RedisClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 极验-验证会话管理
+ */
+@Service
+public class GeetestSessionImpl implements GeetestSessionManager {
+
+    private static final String CACHE_KEY_GEETEST = "B_GEETEST:GT_%s";// 极验“验证码”缓存KEY
+
+    @Autowired
+    private RedisClient redisClient;
+
+    @Override
+    public void setSession(String key, Boolean status) {
+        final String cacheKeyGeetest = String.format(CACHE_KEY_GEETEST, key);
+        redisClient.set(cacheKeyGeetest, status, 60);// N秒
+    }
+
+    @Override
+    public Boolean getSession(String key) {
+        final String cacheKeyGeetest = String.format(CACHE_KEY_GEETEST, key);
+        return redisClient.get(cacheKeyGeetest, Boolean.class);
+    }
+
+    @Override
+    public void removeSession(String key) {
+        final String cacheKeyGeetest = String.format(CACHE_KEY_GEETEST, key);
+        redisClient.delete(cacheKeyGeetest);
+    }
+
+}

+ 201 - 18
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/LoginRuleServiceImpl.java

@@ -1,66 +1,249 @@
+/*
+ * Copyright (c) 2020 "https://github.com/deason" All Rights Reserved.
+ * Created by Deason on 2020-08-18 15:31:08
+ */
+
 package cn.com.qmth.examcloud.core.basic.service.impl;
 
 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.JsonUtil;
 import cn.com.qmth.examcloud.core.basic.dao.LoginRuleRepo;
 import cn.com.qmth.examcloud.core.basic.dao.entity.LoginRuleEntity;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
 import cn.com.qmth.examcloud.core.basic.service.LoginRuleService;
-import cn.com.qmth.examcloud.core.basic.service.cache.LoginRuleCacheBean;
+import cn.com.qmth.examcloud.core.basic.service.OrgService;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleForm;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleInfo;
+import cn.com.qmth.examcloud.core.basic.service.bean.LoginRuleQuery;
+import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
+import cn.com.qmth.examcloud.web.filestorage.FileStoragePathEnvInfo;
+import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.*;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import javax.persistence.criteria.Predicate;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class LoginRuleServiceImpl implements LoginRuleService {
 
     private static final ExamCloudLog log = ExamCloudLogFactory.getLog("INTERFACE_LOGGER");
 
-    private static final String CACHE_KEY_LOGIN_RULE = "B_LOGIN_RULE";// “登录规则”缓存KEY
+    /**
+     * “登录规则”的缓存KEY前缀
+     */
+    private static final String LOGIN_RULE_CACHE_KEY_PREFIX = "$LOGIN_RULE:";
+
+    /**
+     * ../resources/aliyun.xml siteId
+     */
+    private static final String LOGIN_RULE_SITE_ID = "orgProperties";
+
+    private static final long TOP_ID = -1L;
 
     @Autowired
     private LoginRuleRepo loginRuleRepo;
 
+    @Autowired
+    private OrgService orgService;
+
     @Autowired
     private RedisClient redisClient;
 
     @Override
-    public void refreshLoginRule() {
-        log.info("refreshLoginRule start...");
+    public List<LoginRuleInfo> getLoginRuleTopList() {
+        LoginRuleQuery req = new LoginRuleQuery();
+        req.setPageNo(1);
+        req.setPageSize(100);
+        req.setRootOrgId(TOP_ID);
+
+        return this.getLoginRuleList(req).getContent();
+    }
+
+    @Override
+    public Page<LoginRuleInfo> getLoginRuleList(LoginRuleQuery req) {
+        if (req.getPageNo() == null || req.getPageNo() < 1) {
+            req.setPageNo(1);
+        }
+
+        if (req.getPageSize() == null || req.getPageSize() < 1) {
+            req.setPageSize(10);
+        }
+
+        Specification<LoginRuleEntity> spec = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+
+            if (req.getRootOrgId() != null) {
+                predicates.add(cb.equal(root.get("rootOrgId"), req.getRootOrgId()));
+            } else {
+                predicates.add(cb.notEqual(root.get("rootOrgId"), TOP_ID));
+            }
+
+            if (req.getType() != null) {
+                predicates.add(cb.equal(root.get("type"), req.getType()));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        Sort sort = Sort.by(Sort.Order.desc("id"));
+        Pageable pageable = PageRequest.of(req.getPageNo() - 1, req.getPageSize(), sort);
+        Page<LoginRuleEntity> page = loginRuleRepo.findAll(spec, pageable);
+
+        if (!page.hasContent()) {
+            return new PageImpl<>(new ArrayList<>(), pageable, 0);
+        }
+
+        Set<Long> rootOrgIds = page.getContent().stream().filter(e -> e.getRootOrgId() >= 0L).map(e -> e.getRootOrgId()).collect(Collectors.toSet());
+        Map<Long, String> rootOrgNames = orgService.findRootOrgNamesByIds(rootOrgIds);
+
+        List<LoginRuleInfo> list = page.getContent().stream().map(entity -> {
+            LoginRuleInfo info = new LoginRuleInfo();
+            info.setId(entity.getId());
+            info.setRootOrgId(entity.getRootOrgId());
+            info.setRootOrgName(rootOrgNames.get(entity.getRootOrgId()));
+            info.setType(entity.getType());
+            info.setAllow(entity.getAllow());
+            info.setCreationTime(entity.getCreationTime());
+            info.setUpdateTime(entity.getUpdateTime());
+            return info;
+        }).collect(Collectors.toList());
+
+        return new PageImpl<>(list, pageable, page.getTotalElements());
+    }
+
+    @Override
+    public void addOrUpdateLoginRule(LoginRuleForm req) {
+        if (req.getRootOrgId() == null) {
+            throw new StatusException("400400", "顶层机构ID不能为空");
+        }
+
+        if (req.getType() == null) {
+            throw new StatusException("400400", "规则类型不能为空");
+        }
+
+        if (req.getAllow() == null) {
+            throw new StatusException("400400", "是否允许不能为空");
+        }
+
+        List<LoginRuleEntity> rules = loginRuleRepo.findByRootOrgIdAndType(req.getRootOrgId(), req.getType());
+
+        LoginRuleEntity rule;
+        if (CollectionUtils.isNotEmpty(rules)) {
+            // 默认只存在一个值
+            rule = rules.get(0);
+        } else {
+            rule = new LoginRuleEntity();
+        }
+
+        rule.setRootOrgId(req.getRootOrgId());
+        rule.setType(req.getType());
+        rule.setAllow(req.getAllow());
+        loginRuleRepo.save(rule);
+
+        this.refreshLoginRule(rule.getType());
+    }
+
+    @Override
+    public void deleteLoginRuleById(Long id) {
+        Optional<LoginRuleEntity> optional = loginRuleRepo.findById(id);
+        if (optional.isPresent()) {
+            loginRuleRepo.delete(optional.get());
+
+            this.refreshLoginRule(optional.get().getType());
+        }
+    }
 
-        List<LoginRuleEntity> entities = loginRuleRepo.findAll();
-        redisClient.delete(CACHE_KEY_LOGIN_RULE);
+    @Override
+    public void refreshAllLoginRule() {
+        // 按规则类型分别缓存
+        for (LoginRuleType type : LoginRuleType.values()) {
+            this.refreshLoginRule(type);
+        }
+    }
 
+    private void refreshLoginRule(LoginRuleType type) {
+        log.info("refreshLoginRule start...");
+
+        List<LoginRuleEntity> entities = loginRuleRepo.findByType(type);
+        Map<String, Boolean> values = new HashMap<>();
         if (CollectionUtils.isNotEmpty(entities)) {
             for (LoginRuleEntity entity : entities) {
-                LoginRuleCacheBean cacheBean = new LoginRuleCacheBean();
-                cacheBean.setRootOrgId(entity.getRootOrgId());
-                cacheBean.setWhite(entity.getWhite());
-
-                final String subKey = cacheBean.getRootOrgId().toString();
-                redisClient.set(CACHE_KEY_LOGIN_RULE, subKey, cacheBean);
+                values.put(String.valueOf(entity.getRootOrgId()), entity.getAllow());
             }
         }
 
+        String cacheKey = LOGIN_RULE_CACHE_KEY_PREFIX + type.name();
+        redisClient.set(cacheKey, values);
+
+        if (LoginRuleType.GEETEST_LOGIN == type) {
+            String json = JsonUtil.toJson(values);
+            this.uploadJsonFile(json);
+        }
+
         log.info("refreshLoginRule end...");
     }
 
+    private void uploadJsonFile(String json) {
+        try {
+            // 路径:../org_properties/geetestConfig.json
+            FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+            env.setExt1("geetestConfig");
+            YunPathInfo oss = FileStorageUtil.saveFile(LOGIN_RULE_SITE_ID, env, json.getBytes(), true);
+            log.info(oss.getRelativePath());
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 检查当前机构的登录规则配置
+     * 1、未配置时,默认true
+     * 2、优先按“当前机构设置值”,其次按“全局设置值”
+     */
     @Override
-    public boolean isLoginRuleWhite(Long rootOrgId) {
+    public boolean isLoginRuleAllow(Long rootOrgId, LoginRuleType type) {
         if (rootOrgId == null) {
             throw new StatusException("400400", "顶层机构ID不能为空");
         }
 
-        LoginRuleCacheBean cacheBean = redisClient.get(CACHE_KEY_LOGIN_RULE, String.valueOf(rootOrgId), LoginRuleCacheBean.class);
-        if (cacheBean != null && cacheBean.getWhite()) {
-            log.info("LoginRule white = true, rootOrgId = " + rootOrgId);
+        if (type == null) {
+            throw new StatusException("400400", "规则类型不能为空");
+        }
+
+        String cacheKey = LOGIN_RULE_CACHE_KEY_PREFIX + type.name();
+        Map<String, Boolean> values = redisClient.get(cacheKey, HashMap.class);
+        if (MapUtils.isEmpty(values)) {
+            log.warn(String.format("LoginRule not exist, type = %s, rootOrgId = %s", rootOrgId, type.name()));
             return true;
         }
 
-        log.info("LoginRule white = false, rootOrgId = " + rootOrgId);
+        // 全局设置值
+        Boolean globalAllow = values.get(String.valueOf(TOP_ID));
+        // 当前机构设置值
+        Boolean allow = values.get(String.valueOf(rootOrgId));
+
+        if (globalAllow == null || globalAllow) {
+            if (allow == null || allow) {
+                log.info(String.format("LoginRule allow, rootOrgId = %s, type = %s", rootOrgId, type.name()));
+                return true;
+            }
+        } else {
+            if (allow != null && allow) {
+                log.info(String.format("LoginRule allow, rootOrgId = %s, type = %s", rootOrgId, type.name()));
+                return true;
+            }
+        }
+
+        log.info(String.format("LoginRule unAllow, rootOrgId = %s, type = %s", rootOrgId, type.name()));
         return false;
     }
 

+ 33 - 27
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/OrgServiceImpl.java

@@ -1,20 +1,5 @@
 package cn.com.qmth.examcloud.core.basic.service.impl;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.helpers.DynamicEnum;
@@ -22,17 +7,8 @@ import cn.com.qmth.examcloud.commons.helpers.DynamicEnumManager;
 import cn.com.qmth.examcloud.commons.helpers.poi.ExcelReader;
 import cn.com.qmth.examcloud.commons.util.PathUtil;
 import cn.com.qmth.examcloud.core.basic.base.constants.BasicConsts;
-import cn.com.qmth.examcloud.core.basic.dao.OrgPropertyRepo;
-import cn.com.qmth.examcloud.core.basic.dao.OrgRepo;
-import cn.com.qmth.examcloud.core.basic.dao.RoleRepo;
-import cn.com.qmth.examcloud.core.basic.dao.StudentRepo;
-import cn.com.qmth.examcloud.core.basic.dao.UserRepo;
-import cn.com.qmth.examcloud.core.basic.dao.UserRoleRelationRepo;
-import cn.com.qmth.examcloud.core.basic.dao.entity.OrgEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.OrgPropertyEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.RoleEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.UserEntity;
-import cn.com.qmth.examcloud.core.basic.dao.entity.UserRoleRelationEntity;
+import cn.com.qmth.examcloud.core.basic.dao.*;
+import cn.com.qmth.examcloud.core.basic.dao.entity.*;
 import cn.com.qmth.examcloud.core.basic.dao.enums.OrgProperty;
 import cn.com.qmth.examcloud.core.basic.service.OrgService;
 import cn.com.qmth.examcloud.core.basic.service.bean.OrgInfo;
@@ -42,6 +18,19 @@ import cn.com.qmth.examcloud.core.basic.service.cache.RootOrgCache;
 import cn.com.qmth.examcloud.task.api.DataSyncCloudService;
 import cn.com.qmth.examcloud.task.api.request.SyncOrgReq;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.criteria.Predicate;
+import java.io.File;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
 @Service
 public class OrgServiceImpl implements OrgService {
@@ -446,7 +435,24 @@ public class OrgServiceImpl implements OrgService {
         return failRecords;
     }
 
-    public void createLearnerCenterUser(OrgEntity org) {
+    @Override
+    public Map<Long, String> findRootOrgNamesByIds(Set<Long> rootOrgIds) {
+        if (CollectionUtils.isEmpty(rootOrgIds)) {
+            return new HashMap<>();
+        }
+
+        Specification<OrgEntity> spec = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(root.get("id").in(rootOrgIds));
+            predicates.add(cb.isNull(root.get("parentId")));
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        List<OrgEntity> entities = orgRepo.findAll(spec);
+        return entities.stream().collect(Collectors.toMap(v -> v.getId(), v -> v.getName(), (oldValue, newValue) -> newValue));
+    }
+
+    private void createLearnerCenterUser(OrgEntity org) {
         UserEntity user = userRepo.findByRootOrgIdAndLoginName(org.getRootId(), org.getCode());
         if (null != user) {
             return;

+ 65 - 11
examcloud-core-basic-service/src/main/java/cn/com/qmth/examcloud/core/basic/service/impl/VerifyCodeServiceImpl.java

@@ -7,13 +7,17 @@ import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
 import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.commons.util.UUID;
 import cn.com.qmth.examcloud.core.basic.base.util.VerifyCode;
+import cn.com.qmth.examcloud.core.basic.dao.enums.LoginRuleType;
 import cn.com.qmth.examcloud.core.basic.service.AuthService;
+import cn.com.qmth.examcloud.core.basic.service.LoginRuleService;
 import cn.com.qmth.examcloud.core.basic.service.VerifyCodeService;
+import cn.com.qmth.examcloud.core.basic.service.bean.GeetestLoginInfo;
 import cn.com.qmth.examcloud.core.basic.service.bean.LoginInfo;
 import cn.com.qmth.examcloud.core.basic.service.bean.VerifyCodeLoginInfo;
 import cn.com.qmth.examcloud.core.basic.service.cache.VerifyCodeCacheBean;
 import cn.com.qmth.examcloud.reports.commons.bean.OnlineStudentReport;
-import cn.com.qmth.examcloud.reports.commons.bean.OnlineUserReport;
+import cn.com.qmth.examcloud.reports.commons.bean.OperateReport;
+import cn.com.qmth.examcloud.reports.commons.enums.OperateContent;
 import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import org.apache.commons.codec.binary.Base64;
@@ -35,6 +39,9 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
 
     private static final String CACHE_KEY_VERIFY_CODE_RESOURCE = "B_VERIFY_CODE_RESOURCE:%s";// “验证码资源标识”缓存KEY
 
+    @Autowired
+    private LoginRuleService loginRuleService;
+
     @Autowired
     private AuthService authService;
 
@@ -42,7 +49,50 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
     private RedisClient redisClient;
 
     /**
-     * 验证码生成接口
+     * 极验-验证码登录接口
+     *
+     * @return 登录成功信息
+     */
+    @Override
+    public User geetestLogin(GeetestLoginInfo info) {
+        if (info.getRootOrgId() == null) {
+            throw new StatusException("400", "顶级机构ID不能为空");
+        }
+        if (StringUtils.isBlank(info.getAccountType())) {
+            throw new StatusException("400", "登陆账号类型不能为空");
+        }
+        if (StringUtils.isBlank(info.getAccountValue())) {
+            throw new StatusException("400", "登陆账号不能为空");
+        }
+        if (StringUtils.isBlank(info.getPassword())) {
+            throw new StatusException("400", "登陆密码不能为空");
+        }
+
+        // 是否在登录的白名单
+        boolean allow = loginRuleService.isLoginRuleAllow(info.getRootOrgId(), LoginRuleType.STUDENT_CLIENT_LOGIN);
+        if (!allow) {
+            throw new StatusException("403002", "当前机构登录被禁用");
+        }
+
+        LoginInfo loginInfo = new LoginInfo();
+        loginInfo.setRootOrgId(info.getRootOrgId());
+        loginInfo.setAccountType(info.getAccountType());
+        loginInfo.setAccountValue(info.getAccountValue());
+        loginInfo.setPassword(info.getPassword());
+        loginInfo.setClientIp(info.getIp_address());
+        User user = authService.login(loginInfo, false);
+
+        //操作日志
+        ReportsUtil.report(new OperateReport(user.getRootOrgId(), user.getUserId(), user.getUserId(), null, UserType.STUDENT, OperateContent.STUDENT_LOGIN.getDesc()));
+
+        // 在线学生登录打点
+        ReportsUtil.report(new OnlineStudentReport(user.getRootOrgId(), user.getUserId()));
+
+        return user;
+    }
+
+    /**
+     * 数字公式-验证码生成接口
      *
      * @return 字符串:uuid(32位) + base64
      */
@@ -72,7 +122,7 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
     }
 
     /**
-     * 验证码登录接口
+     * 数字公式-验证码登录接口
      *
      * @return 登录成功信息
      */
@@ -94,6 +144,12 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
             throw new StatusException("400", "验证码不能为空");
         }
 
+        // 是否在登录的白名单
+        boolean allow = loginRuleService.isLoginRuleAllow(info.getRootOrgId(), LoginRuleType.STUDENT_CLIENT_LOGIN);
+        if (!allow) {
+            throw new StatusException("403002", "当前机构登录被禁用");
+        }
+
         final String cacheKeyVerifyCode = String.format(CACHE_KEY_VERIFY_CODE, info.getRootOrgId(), info.getAccountValue());
         VerifyCodeCacheBean cacheBean = redisClient.get(cacheKeyVerifyCode, VerifyCodeCacheBean.class);
         if (cacheBean == null) {
@@ -124,19 +180,17 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
         redisClient.delete(cacheKeyVerifyCode);
         redisClient.delete(cacheKeyVerifyCodeResource);
 
-        if (UserType.STUDENT.equals(user.getUserType())) {
-            // 在线学生登录打点
-            ReportsUtil.report(new OnlineStudentReport(user.getRootOrgId(), user.getUserId()));
-        } else if (UserType.COMMON.equals(user.getUserType())) {
-            // 在线用户登录打点
-            ReportsUtil.report(new OnlineUserReport(user.getRootOrgId(), user.getUserId()));
-        }
+        //操作日志
+        ReportsUtil.report(new OperateReport(user.getRootOrgId(), user.getUserId(), user.getUserId(), null, UserType.STUDENT, OperateContent.STUDENT_LOGIN.getDesc()));
+
+        // 在线学生登录打点
+        ReportsUtil.report(new OnlineStudentReport(user.getRootOrgId(), user.getUserId()));
 
         return user;
     }
 
     /**
-     * Resource接口
+     * 数字公式-验证码的Resource接口
      */
     @Override
     public void verifyCodeResource(String uuid) {

+ 0 - 15
examcloud-core-basic-starter/.springBeans

@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beansProjectDescription>
-	<version>1</version>
-	<pluginVersion><![CDATA[3.9.4.201804120850-RELEASE]]></pluginVersion>
-	<configSuffixes>
-		<configSuffix><![CDATA[xml]]></configSuffix>
-	</configSuffixes>
-	<enableImports><![CDATA[false]]></enableImports>
-	<configs>
-	</configs>
-	<autoconfigs>
-	</autoconfigs>
-	<configSets>
-	</configSets>
-</beansProjectDescription>

+ 2 - 4
examcloud-core-basic-starter/src/main/java/cn/com/qmth/examcloud/core/basic/starter/config/ScheduleConfig.java

@@ -3,10 +3,8 @@ package cn.com.qmth.examcloud.core.basic.starter.config;
 import cn.com.qmth.examcloud.core.basic.service.LoginRuleService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
 import java.io.Serializable;
 
 @Component
@@ -21,10 +19,10 @@ public class ScheduleConfig implements Serializable {
     /**
      * 定时刷新登录规则(每N分钟执行)
      */
-    @PostConstruct
+    /*@PostConstruct
     @Scheduled(cron = "0 10/10 * * * ?")
     public void execute() {
         loginRuleService.refreshLoginRule();
-    }
+    }*/
 
 }

+ 45 - 29
examcloud-core-basic-starter/src/main/resources/aliyun.xml

@@ -1,35 +1,51 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <sites>
 
- 	<site>
-		<id>resource</id>
-		<name>资源</name>
-		<aliyunId>1</aliyunId>
-		<maxSize>50M</maxSize>
-		<path>/${relativePath}</path>
-	</site>
-	<site>
-		<id>orgLogo</id>
-		<name>机构logo</name>
-		<aliyunId>1</aliyunId>
-		<maxSize>1M</maxSize>
-		<path>/org_logo/${rootOrgId}/${timeMillis}${fileSuffix}</path>
-	</site>
+    <site>
+        <id>resource</id>
+        <name>资源</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>50M</maxSize>
+        <path>/${relativePath}</path>
+    </site>
+    <site>
+        <id>orgLogo</id>
+        <name>机构logo</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>1M</maxSize>
+        <path>/org_logo/${rootOrgId}/${timeMillis}${fileSuffix}</path>
+    </site>
 
-	<site>
-		<id>orgPropertiesByOrgId</id>
-		<name>机构属性(机构ID查询)</name>
-		<aliyunId>1</aliyunId>
-		<maxSize>1M</maxSize>
-		<path>/org_properties/byOrgId/${rootOrgId}/${ext1}${fileSuffix}</path>
-	</site>
+    <site>
+        <id>orgPropertiesByOrgId</id>
+        <name>机构属性(机构ID查询)</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>1M</maxSize>
+        <path>/org_properties/byOrgId/${rootOrgId}/${ext1}${fileSuffix}</path>
+    </site>
 
-	<site>
-		<id>orgPropertiesByOrgDomain</id>
-		<name>机构属性(机构域名查询)</name>
-		<aliyunId>1</aliyunId>
-		<maxSize>1M</maxSize>
-		<path>/org_properties/byOrgDomain/${rootOrgDomain}/${ext1}${fileSuffix}</path>
-	</site>
+    <site>
+        <id>orgPropertiesByOrgDomain</id>
+        <name>机构属性(机构域名查询)</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>1M</maxSize>
+        <path>/org_properties/byOrgDomain/${rootOrgDomain}/${ext1}${fileSuffix}</path>
+    </site>
 
-</sites>
+    <site>
+        <id>orgProperties</id>
+        <name>机构属性(登录规则配置)</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>1M</maxSize>
+        <path>/org_properties/${ext1}.json</path>
+    </site>
+
+    <site>
+        <id>sysNotice</id>
+        <name>系统通知</name>
+        <aliyunId>1</aliyunId>
+        <maxSize>10M</maxSize>
+        <path>/sys_notice/org_${rootOrgId}${fileSuffix}</path>
+    </site>
+
+</sites>

+ 2 - 2
examcloud-core-basic-starter/src/main/resources/application.properties

@@ -1,7 +1,7 @@
-spring.profiles.active=test
+spring.profiles.active=dev
 
 examcloud.startup.startupCode=8000
-examcloud.startup.configCenterHost=127.0.0.1
+examcloud.startup.configCenterHost=192.168.10.39
 examcloud.startup.configCenterPort=9999
 examcloud.startup.appCode=B
 

+ 98 - 77
examcloud-core-basic-starter/src/main/resources/log4j2.xml

@@ -1,87 +1,108 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Configuration status="WARN" monitorInterval="30">
 
-	<Properties>
-		<Property name="commonLevel" value="${sys:log.commonLevel}" />
-	</Properties>
+    <Properties>
+        <Property name="commonLevel" value="${sys:log.commonLevel}"/>
+        <Property name="logPattern">
+            %d{yyyy-MM-dd HH:mm:ss.SSS} | %clr{%level} | %X{TRACE_ID} %X{CALLER} | %clr{%c{1.1}:%L}{cyan} | %m%n
+        </Property>
+    </Properties>
 
-	<Appenders>
-		<!-- 控制台 日志 -->
-		<Console name="Console" target="SYSTEM_OUT">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m | %l%n" />
-		</Console>
-		<!-- debug 日志 -->
-		<RollingFile name="DEBUG_APPENDER" fileName="./logs/debug/debug.log"
-			filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m | %l%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/debug" maxDepth="1">
-					<IfFileName glob="debug-*.log">
-						<IfAccumulatedFileSize exceeds="2 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-		<!-- 接口日志 -->
-		<RollingFile name="INTERFACE_APPENDER" fileName="./logs/interface/interface.log"
-			filePattern="./logs/interface/interface-%d{yyyy.MM.dd.HH}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/interface" maxDepth="1">
-					<IfFileName glob="interface-*.log">
-						<IfAccumulatedFileSize exceeds="10 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-		<!-- 考生客户端日志 -->
-		<RollingFile name="STUDENT_CLIENT_APPENDER" fileName="./logs/student_client/student_client.log"
-			filePattern="./logs/student_client/student_client-%d{yyyy.MM.dd}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{CALLER} | %m%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/student_client" maxDepth="1">
-					<IfFileName glob="student_client-*.log">
-						<IfAccumulatedFileSize exceeds="5 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-	</Appenders>
+    <Appenders>
+        <!-- 控制台 日志 -->
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+        </Console>
 
-	<Loggers>
-		<Logger name="cn.com.qmth" level="${commonLevel}" additivity="false">
-			<AppenderRef ref="DEBUG_APPENDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- debug 日志 -->
+        <RollingFile name="DEBUG_APPENDER"
+                     fileName="./logs/debug/debug.log"
+                     filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/debug" maxDepth="1">
+                    <IfFileName glob="debug-*.log">
+                        <IfAccumulatedFileSize exceeds="2 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
 
-		<Logger name="INTERFACE_LOGGER" level="INFO" additivity="false">
-			<AppenderRef ref="INTERFACE_APPENDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- 接口日志 -->
+        <RollingFile name="INTERFACE_APPENDER" fileName="./logs/interface/interface.log"
+                     filePattern="./logs/interface/interface-%d{yyyy.MM.dd.HH}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/interface" maxDepth="1">
+                    <IfFileName glob="interface-*.log">
+                        <IfAccumulatedFileSize exceeds="10 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
 
-		<Logger name="STUDENT_CLIENT_LOGGER" level="DEBUG" additivity="false">
-			<AppenderRef ref="STUDENT_CLIENT_APPENDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- 考生客户端日志 -->
+        <RollingFile name="STUDENT_CLIENT_APPENDER" fileName="./logs/student_client/student_client.log"
+                     filePattern="./logs/student_client/student_client-%d{yyyy.MM.dd}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/student_client" maxDepth="1">
+                    <IfFileName glob="student_client-*.log">
+                        <IfAccumulatedFileSize exceeds="5 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
+    </Appenders>
 
-		<Logger name="cn.com.qmth.examcloud.web.actuator" level="ERROR" />
+    <Loggers>
+        <logger name="springfox.documentation" level="ERROR"/>
+        <logger name="org.springframework" level="ERROR"/>
+        <logger name="org.hibernate" level="ERROR"/>
+        <logger name="org.apache" level="ERROR"/>
+        <logger name="org.quartz" level="ERROR"/>
+        <logger name="org.docx4j" level="ERROR"/>
+        <logger name="cn.afterturn" level="ERROR"/>
+        <logger name="com.netflix" level="ERROR"/>
+        <logger name="com.aliyun" level="ERROR"/>
+        <logger name="io.lettuce" level="ERROR"/>
+        <logger name="io.netty" level="ERROR"/>
 
-		<Root level="INFO">
-			<AppenderRef ref="Console" />
-			<AppenderRef ref="DEBUG_APPENDER" />
-		</Root>
-	</Loggers>
+        <!--<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>-->
+        <!--<logger name="org.springframework.data.mongodb" level="DEBUG"/>-->
+        <!--<logger name="org.springframework.data.redis" level="DEBUG"/>-->
 
-</Configuration>
+        <Logger name="cn.com.qmth" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="DEBUG_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Logger name="INTERFACE_LOGGER" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="INTERFACE_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Logger name="STUDENT_CLIENT_LOGGER" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="STUDENT_CLIENT_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Root level="${commonLevel}">
+            <AppenderRef ref="Console"/>
+            <AppenderRef ref="DEBUG_APPENDER"/>
+        </Root>
+    </Loggers>
+
+</Configuration>

+ 1 - 1
examcloud-core-basic-starter/src/main/resources/security.properties

@@ -5,7 +5,7 @@
 [s][${$rmp.ctr.basic}/auth][/bindSecurityPhone][POST]=true
 [s][${$rmp.ctr.basic}/log][studentClient/{level}/{code}][POST]=true
 [s][${$rmp.ctr.basic}/student][password/direct][PUT]=true
-[s][${$rmp.ctr.basic}/auth][/sendVerificationCode][POST]=true
+[s][${$rmp.ctr.basic}/student][online_signal/{studentId}][GET]=true
 [s][${$rmp.ctr.basic}/org][propertyNoSession/{key}][GET]=true
 [s][${$rmp.ctr.basic}/org][property/{orgId}/{key}][GET]=true
 [s][${$rmp.ctr.basic}/systemProperty][{key}][GET]=true

+ 0 - 19
jenkins-dev.sh

@@ -1,19 +0,0 @@
-#!/bin/bash
-pwd
-
-rm -rf ~/project/examcloud/examcloud-core-basic-distribution.zip
-rm -rf ~/project/examcloud/examcloud-core-basic/lib/
-rm -rf ~/project/examcloud/examcloud-core-basic/config/
-
-cp examcloud-core-basic-starter/target/examcloud-core-basic-distribution.zip ~/project/examcloud/
-
-cd  ~/project/examcloud/
-unzip -o examcloud-core-basic-distribution.zip
-
-cd examcloud-core-basic
-echo "--spring.profiles.active=dev --examcloud.startup.configCenterHost=localhost" > start.args
-echo "-server -Xms512m -Xmx512m  -XX:-UseGCOverheadLimit" > start.vmoptions
-
-bash stop.sh
-BUILD_ID=DONTKILLME
-bash start.sh jenkins

+ 0 - 19
jenkins-test.sh

@@ -1,19 +0,0 @@
-#!/bin/bash
-pwd
-
-rm -rf ~/project/examcloud/examcloud-core-basic-distribution.zip
-rm -rf ~/project/examcloud/examcloud-core-basic/lib/
-rm -rf ~/project/examcloud/examcloud-core-basic/config/
-
-cp examcloud-core-basic-starter/target/examcloud-core-basic-distribution.zip ~/project/examcloud/
-
-cd  ~/project/examcloud/
-unzip -o examcloud-core-basic-distribution.zip
-
-cd examcloud-core-basic
-echo "--spring.profiles.active=test --examcloud.startup.configCenterHost=localhost" > start.args
-echo "-server -Xms512m -Xmx512m  -XX:-UseGCOverheadLimit" > start.vmoptions
-
-bash stop.sh
-BUILD_ID=DONTKILLME
-bash start.sh jenkins

部分文件因文件數量過多而無法顯示