Przeglądaj źródła

ip限制,审核人,答题纸上传

qinchao 4 lat temu
rodzic
commit
b65b57b892

+ 112 - 2
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamController.java

@@ -25,6 +25,7 @@ import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
 import cn.com.qmth.examcloud.core.basic.api.response.GetOrgsResp;
 import cn.com.qmth.examcloud.core.examwork.api.controller.bean.CopyExamDomain;
 import cn.com.qmth.examcloud.core.examwork.api.controller.bean.ExamDomain;
+import cn.com.qmth.examcloud.core.examwork.api.controller.bean.ExamIpLimitDomain;
 import cn.com.qmth.examcloud.core.examwork.api.controller.bean.ExamOrgSettingsDomain;
 import cn.com.qmth.examcloud.core.examwork.api.controller.bean.StudentSpecialSettingsDomain;
 import cn.com.qmth.examcloud.core.examwork.base.enums.ExamProperty;
@@ -58,10 +59,12 @@ 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.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.*;
 import org.springframework.data.domain.Sort.Direction;
 import org.springframework.data.jpa.domain.Specification;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.commons.CommonsMultipartFile;
@@ -107,6 +110,9 @@ public class ExamController extends ControllerSupport {
     @Autowired
     ExamStudentRepo examStudentRepo;
 
+    @Autowired
+    ExamIpLimitRepo examIpLimitRepo;
+
     @Autowired
     ExamStudentServiceImpl examStudentService;
 
@@ -140,6 +146,9 @@ public class ExamController extends ControllerSupport {
     @Autowired
     ExamSettingsCache examSettingsCache;
 
+    @Autowired
+    JdbcTemplate jdbcTemplate;
+
     private static final String[] EXAM_ORG_SETTINGS_EXCEL_HEADER = new String[]{"学习中心ID", "学习中心代码",
             "学习中心名称", "是否可以考试(是/否)", "开始考试时间 yyyy-MM-dd hh:mm:ss", "结束考试时间 yyyy-MM-dd hh:mm:ss"};
 
@@ -1051,7 +1060,7 @@ public class ExamController extends ControllerSupport {
     /**
      * 方法注释
      *
-     * @param examOrg
+     * @param domain
      * @return
      * @author WANGWEI
      */
@@ -1065,7 +1074,7 @@ public class ExamController extends ControllerSupport {
     /**
      * 方法注释
      *
-     * @param examOrg
+     * @param domain
      * @return
      * @author WANGWEI
      */
@@ -1385,6 +1394,107 @@ public class ExamController extends ControllerSupport {
         return map;
     }
 
+    @GetMapping("ipLimited/page/{curPage}/{pageSize}")
+    public PageInfo<ExamIpLimitDomain> ipLimited(@PathVariable Integer curPage, @PathVariable Integer pageSize,
+                                                 Long examId, Integer limitType, String ip) {
+        PageInfo<ExamIpLimitEntity> pages = examService.pageIpLimited(curPage, pageSize, examId, limitType, ip);
+        PageInfo<ExamIpLimitDomain> pageInfo = new PageInfo<>();
+        List<ExamIpLimitDomain> list = new ArrayList<>();
+        pages.getList().forEach(e->{
+            ExamIpLimitDomain domain = new ExamIpLimitDomain();
+            BeanUtils.copyProperties(e,domain);
+            domain.setExamName(examRepo.getOne(examId).getName());
+            list.add(domain);
+        });
+        pageInfo.setList(list);
+        pageInfo.setTotal(pages.getTotal());
+        return pageInfo;
+    }
+
+    @GetMapping("ipLimited/property/{examId}")
+    public Map<String,Boolean> ipLimitedProperty(@PathVariable Long examId) {
+        Map<String,Boolean> map = new HashMap<>();
+        map.put("totalLimit", getExamBooleanProperty(examId,49));
+        map.put("centerLimit",getExamBooleanProperty(examId,50));
+        return map;
+    }
+
+    @PutMapping("ipLimited/property/{examId}")
+    public void ipLimitedProperty(@PathVariable Long examId, @RequestBody Map<String,Boolean> map) {
+        updateExamProperty(examId,49,map.get("totalLimit"));
+        updateExamProperty(examId,50,map.get("centerLimit"));
+    }
+
+    private void updateExamProperty(Long examId, Integer keyId, Object value) {
+        //虚拟摄像头进入待审核,且有虚拟摄像头的
+        String valueSql="update ec_e_exam_prop set value = '"+value+"'where exam_id ="+examId+" AND key_id="+keyId;
+        jdbcTemplate.update(valueSql);
+    }
+
+    @GetMapping("ipLimited/{examId}")
+    public boolean ipLimited(HttpServletRequest request, @PathVariable Long examId) {
+        //是否开启Ip限制
+        ExamPropertyCacheBean ipLimitProperty = CacheHelper.getExamProperty(examId, "IP_LIMIT");
+        boolean ipLimited = ipLimitProperty!=null && StringUtil.isTrue(ipLimitProperty.getValue());
+        if (ipLimited) {
+            String realIp = request.getHeader("x-forwarded-for");
+            if (StringUtils.isBlank(realIp)) {
+                realIp = request.getHeader("x-real-ip");
+            }
+            realIp = realIp.trim();
+            //整体控制
+            boolean totalLimit = getExamBooleanProperty(examId,49);
+            if (totalLimit) {
+                //在白名单中
+                int count = examIpLimitRepo.countByExamIdAndLimitTypeAndIp(examId,"0",realIp);
+                if (count>0) {
+                    //学习中心访问控制
+                    boolean centerLimit = getExamBooleanProperty(examId,50);
+                    if (centerLimit) {
+                        User accessUser = getAccessUser();
+                        StudentCacheBean studentCache = CacheHelper.getStudent(accessUser.getUserId());
+                        Long orgId = studentCache.getOrgId();
+                        String key = "IP_" + orgId;
+                        String value = redisClient.get(key, String.class);
+                        //机构是否在时间范围内登陆过
+                        if (value != null) {
+                            @SuppressWarnings("unchecked")
+                            Set<String> userKeyList = JsonUtil.fromJson(value, Set.class);
+
+                            for (String userKey : userKeyList) {
+                                User curUser = redisClient.get(userKey, User.class);
+                                if (null != curUser) {
+                                    String clientIp = curUser.getClientIp();
+                                    if (null != clientIp) {
+                                        // IP取前三段
+                                        clientIp = clientIp.substring(0, clientIp.lastIndexOf(".") + 1);
+                                        if (realIp.startsWith(clientIp)) {
+                                            return false;
+                                        }
+                                    }
+                                }
+
+                            }
+                        }
+                    }
+                }
+            } else {
+                //不在黑名单中
+                int count = examIpLimitRepo.countByExamIdAndLimitTypeAndIp(examId,"1",realIp);
+                return count != 0;
+            }
+
+        }
+        return true;
+    }
+
+    private boolean getExamBooleanProperty(Long examId,Integer keyId) {
+        //虚拟摄像头进入待审核,且有虚拟摄像头的
+        String valueSql="SELECT value FROM ec_e_exam_prop WHERE exam_id ="+examId+" AND key_id="+keyId;
+        List<Boolean> list = jdbcTemplate.query(valueSql, (rs, rowNum) -> rs.getBoolean("value"));
+        return !CollectionUtils.isEmpty(list) && list.get(0);
+    }
+
     @ApiOperation(value = "是否可以微信作答", notes = "")
     @GetMapping("weixinAnswerEnabled/{examId}")
     public Boolean weixinAnswerEnabled(@PathVariable Long examId) {

+ 106 - 0
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/bean/ExamIpLimitDomain.java

@@ -0,0 +1,106 @@
+package cn.com.qmth.examcloud.core.examwork.api.controller.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+import java.util.Date;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年8月17日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class ExamIpLimitDomain implements JsonSerializable {
+
+	private static final long serialVersionUID = 4009839764353162256L;
+
+	private Long id;
+
+	/**
+	 * 考试Id
+	 */
+	private Long examId;
+
+	/**
+	 * 考试Id
+	 */
+	private String examName;
+
+
+	/**
+	 * ip地址
+	 */
+	private String ip;
+
+	/**
+	 * 限制类型:1禁止访问,0允许访问
+	 */
+	private String limitType;
+
+	/**
+	 * 创建时间
+	 */
+	private Date creationTime;
+
+	/**
+	 * 更新时间
+	 */
+	private Date updateTime;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public String getIp() {
+		return ip;
+	}
+
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+
+	public String getLimitType() {
+		return limitType;
+	}
+
+	public void setLimitType(String limitType) {
+		this.limitType = limitType;
+	}
+
+	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;
+	}
+}

+ 16 - 0
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/ExamIpLimitRepo.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.examcloud.core.examwork.dao;
+
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamIpLimitEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+public interface ExamIpLimitRepo extends JpaRepository<ExamIpLimitEntity, Long>,
+			QueryByExampleExecutor<ExamIpLimitEntity>, JpaSpecificationExecutor<ExamIpLimitEntity> {
+
+	@Query(value = "SELECT count(1) from ec_e_exam_ip_limit t where t.exam_id = ?1 " +
+			"AND t.limit_type = ?2 AND 3? REGEXP t.ip ",nativeQuery = true)
+	int countByExamIdAndLimitTypeAndIp(Long examId, String limitType, String ip);
+
+}

+ 77 - 0
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/entity/ExamIpLimitEntity.java

@@ -0,0 +1,77 @@
+package cn.com.qmth.examcloud.core.examwork.dao.entity;
+
+import cn.com.qmth.examcloud.web.jpa.JpaEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+/**
+ * Created by songyue on 17/1/13.
+ */
+@Entity
+@Table(name = "EC_E_EXAM_IP_LIMIT", indexes = {
+		@Index(name = "IDX_E_E_001001", columnList = "examId"),
+		@Index(name = "IDX_E_E_001002", columnList = "limitType")})
+public class ExamIpLimitEntity extends JpaEntity {
+
+	private static final long serialVersionUID = 4009839764353162256L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	private Long id;
+
+	/**
+	 * 考试Id
+	 */
+
+	@Column(nullable = false)
+	private Long examId;
+
+	/**
+	 * ip地址
+	 */
+	private String ip;
+
+	/**
+	 * 限制类型:1禁止访问,0允许访问
+	 */
+	private Integer limitType;
+
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public String getIp() {
+		return ip;
+	}
+
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public Integer getLimitType() {
+		return limitType;
+	}
+
+	public void setLimitType(Integer limitType) {
+		this.limitType = limitType;
+	}
+}

+ 3 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/ExamService.java

@@ -1,7 +1,9 @@
 package cn.com.qmth.examcloud.core.examwork.service;
 
 import cn.com.qmth.examcloud.api.commons.enums.CURD;
+import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamEntity;
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamIpLimitEntity;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamSpecialSettingsEntity;
 import cn.com.qmth.examcloud.core.examwork.service.bean.ExamInfo;
 import cn.com.qmth.examcloud.core.examwork.service.bean.ExamSpecialSettingsInfo;
@@ -82,4 +84,5 @@ public interface ExamService {
 
     Map<Long, ExamEntity> getExamMapsByIds(Set<Long> examIds);
 
+    PageInfo<ExamIpLimitEntity> pageIpLimited(Integer curPage, Integer pageSize, Long examId, Integer limitType, String ip);
 }

+ 27 - 0
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamServiceImpl.java

@@ -2,6 +2,7 @@ package cn.com.qmth.examcloud.core.examwork.service.impl;
 
 import cn.com.qmth.examcloud.api.commons.enums.CURD;
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.helpers.DynamicEnum;
 import cn.com.qmth.examcloud.commons.helpers.DynamicEnumManager;
@@ -15,11 +16,13 @@ import cn.com.qmth.examcloud.core.basic.api.bean.OrgBean;
 import cn.com.qmth.examcloud.core.basic.api.request.GetOrgReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
 import cn.com.qmth.examcloud.core.examwork.base.enums.ExamProperty;
+import cn.com.qmth.examcloud.core.examwork.dao.ExamIpLimitRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamOrgPropertyRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamPropertyRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.ExamSpecialSettingsRepo;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamEntity;
+import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamIpLimitEntity;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamOrgPropertyEntity;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamPropertyEntity;
 import cn.com.qmth.examcloud.core.examwork.dao.entity.ExamSpecialSettingsEntity;
@@ -46,6 +49,8 @@ import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 
@@ -96,6 +101,9 @@ public class ExamServiceImpl implements ExamService {
     @Autowired
     ExamPropertyCache examPropertyCache;
 
+    @Autowired
+    ExamIpLimitRepo examIpLimitRepo;
+
     private static final String[] EXAM_ORG_SETTINGS_EXCEL_HEADER = new String[]{"学习中心ID", "学习中心代码",
             "学习中心名称", "是否可以考试(是/否)", "开始考试时间 yyyy-MM-dd hh:mm:ss", "结束考试时间 yyyy-MM-dd hh:mm:ss"};
 
@@ -819,4 +827,23 @@ public class ExamServiceImpl implements ExamService {
         return entities.stream().collect(Collectors.toMap(v -> v.getId(), v -> v, (k, v) -> v));
     }
 
+    @Override
+    public PageInfo<ExamIpLimitEntity> pageIpLimited(Integer curPage, Integer pageSize, Long examId, Integer limitType, String ip) {
+        Specification<ExamIpLimitEntity> spec = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            if(examId!=null){
+                predicates.add(cb.equal(root.get("examId"), examId));
+            }
+            if(limitType!=null){
+                predicates.add(cb.equal(root.get("limitType"), limitType));
+            }
+            if(StringUtils.isNotBlank(ip)){
+                predicates.add(cb.like(root.get("ip"), "%"+ip+"%"));
+            }
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+        PageRequest pageRequest = PageRequest.of(curPage, pageSize, new Sort(Sort.Direction.DESC, "creationTime"));
+        return new PageInfo<>(examIpLimitRepo.findAll(spec, pageRequest));
+    }
+
 }

+ 12 - 0
examcloud-core-examwork-starter/src/main/resources/exam-properties.xml

@@ -288,4 +288,16 @@
 		<desc>考试周期时间段设置</desc>
 		<valueType>STRING</valueType>
 	</enum>
+	<enum>
+		<id>49</id>
+		<name>IP_TOTAL_LIMIT</name>
+		<desc>IP访问设置-整体控制</desc>
+		<valueType>BOOLEAN</valueType>
+	</enum>
+	<enum>
+		<id>50</id>
+		<name>IP_CENTER_LIMIT</name>
+		<desc>IP访问设置-学习中心控制</desc>
+		<valueType>BOOLEAN</valueType>
+	</enum>
 </enums>