ting.yin пре 4 година
родитељ
комит
b05982327b

+ 5 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/dao/SchoolDao.java

@@ -1,11 +1,15 @@
 package cn.com.qmth.stmms.biz.school.dao;
 
+import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.repository.PagingAndSortingRepository;
 
 import cn.com.qmth.stmms.biz.school.model.School;
 
-public interface SchoolDao extends PagingAndSortingRepository<School, Integer>, JpaSpecificationExecutor<School> {
+public interface SchoolDao extends PagingAndSortingRepository<School, Integer>, JpaSpecificationExecutor<School>,
+        JpaRepository<School, Integer> {
 
     School findFirstByAccessKey(String accessKey);
+
+    School findByCode(String code);
 }

+ 14 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/model/School.java

@@ -26,6 +26,11 @@ public class School implements Serializable {
      */
     private String name;
 
+    /**
+     * 代码
+     */
+    private String code;
+
     /**
      * 省份
      */
@@ -182,4 +187,13 @@ public class School implements Serializable {
     public void setUpdateTime(Date updateTime) {
         this.updateTime = updateTime;
     }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
 }

+ 5 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/SchoolService.java

@@ -1,7 +1,10 @@
 package cn.com.qmth.stmms.biz.school.service;
 
+import java.util.List;
+
 import cn.com.qmth.stmms.biz.school.model.School;
 import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
+
 import org.springframework.transaction.annotation.Transactional;
 
 public interface SchoolService {
@@ -20,4 +23,6 @@ public interface SchoolService {
 
     School resetAccessKeyAndSecret(School school);
 
+    void updateOrg();
+
 }

+ 52 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/impl/OrgCornService.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.biz.school.service.impl;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.school.service.SchoolService;
+import cn.com.qmth.stmms.common.enums.LockType;
+
+/**
+ * 机构同步定时任务
+ *
+ */
+
+@Component
+public class OrgCornService {
+
+    protected static final Logger log = LoggerFactory.getLogger(OrgCornService.class);
+
+    @Autowired
+    SchoolService schoolService;
+
+    @Autowired
+    private LockService lockService;
+
+    @Value("${qmth.solar.accessKey}")
+    private String accessKey;
+
+    @Value("${qmth.solar.accessSecret}")
+    private String accessSecret;
+
+    /**
+     * 自动同步
+     */
+    @Scheduled(cron = "${school.updateMinute}")
+    public void cronUpdateOrg() {
+        if (StringUtils.isNotBlank(accessKey) && StringUtils.isNotBlank(accessSecret)) {
+            lockService.trylock(LockType.SCHOOL, "");
+            try {
+                schoolService.updateOrg();
+            } catch (Exception e) {
+                log.error("OrgCornTask error", e);
+            }
+            lockService.unlock(LockType.SCHOOL, "");
+        }
+    }
+}

+ 52 - 15
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/impl/SchoolServiceImpl.java

@@ -1,24 +1,28 @@
 package cn.com.qmth.stmms.biz.school.service.impl;
 
-import cn.com.qmth.stmms.biz.common.BaseQueryService;
-import cn.com.qmth.stmms.biz.school.dao.SchoolDao;
-import cn.com.qmth.stmms.biz.school.model.School;
-import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
-import cn.com.qmth.stmms.biz.school.service.SchoolService;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Page;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.school.dao.SchoolDao;
+import cn.com.qmth.stmms.biz.school.model.School;
+import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
+import cn.com.qmth.stmms.biz.school.service.SchoolService;
+import cn.com.qmth.stmms.biz.utils.OrgUtil;
 
 @Service("schoolService")
 public class SchoolServiceImpl extends BaseQueryService<School> implements SchoolService {
@@ -26,6 +30,18 @@ public class SchoolServiceImpl extends BaseQueryService<School> implements Schoo
     @Autowired
     public SchoolDao schoolDao;
 
+    @Value("${qmth.solar.accessKey}")
+    private String accessKey;
+
+    @Value("${qmth.solar.accessSecret}")
+    private String accessSecret;
+
+    @Value("${qmth.solar.host}")
+    private String host;
+
+    @Value("${qmth.solar.uri}")
+    private String uri;
+
     @Override
     public School findById(Integer id) {
         return schoolDao.findOne(id);
@@ -52,9 +68,8 @@ public class SchoolServiceImpl extends BaseQueryService<School> implements Schoo
                 if (StringUtils.isNotBlank(query.getCity())) {
                     predicates.add(cb.equal(root.get("city"), query.getCity()));
                 }
-                return predicates.isEmpty() ?
-                        cb.conjunction() :
-                        cb.and(predicates.toArray(new Predicate[predicates.size()]));
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
             }
 
         }, query);
@@ -91,4 +106,26 @@ public class SchoolServiceImpl extends BaseQueryService<School> implements Schoo
             }
         }
     }
+
+    @Transactional
+    @Override
+    public void updateOrg() {
+        OrgUtil orgUtil = new OrgUtil(accessKey, accessSecret, host, uri);
+        List<School> list = orgUtil.getOrgs();
+        for (School s : list) {
+            School school = schoolDao.findByCode(s.getCode());
+            if (school == null) {
+                school = s;
+                school.setCreateTime(new Date());
+                school.setProvince("");
+                school.setCity("");
+            }
+            school.setName(s.getName());
+            school.setAccessKey(s.getAccessKey());
+            school.setAccessSecret(s.getAccessSecret());
+            school.setLogoUrl(s.getLogoUrl());
+            school.setUpdateTime(new Date());
+            schoolDao.saveAndFlush(school);
+        }
+    }
 }

+ 32 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/thread/OrgSyncThread.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.stmms.biz.school.thread;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.school.service.SchoolService;
+import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
+import cn.com.qmth.stmms.common.enums.LockType;
+
+public class OrgSyncThread implements Runnable {
+
+    protected static Logger log = LoggerFactory.getLogger(OrgSyncThread.class);
+
+    private SchoolService schoolService;
+
+    public OrgSyncThread(SchoolService schoolService) {
+        this.schoolService = schoolService;
+    }
+
+    @Override
+    public void run() {
+        LockService lockService = SpringContextHolder.getBean(LockService.class);
+        try {
+            schoolService.updateOrg();
+        } catch (Exception e) {
+            log.error("OrgSyncThread error", e);
+        }
+        lockService.unlock(LockType.SCHOOL, "");
+    }
+
+}

+ 239 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/OrgUtil.java

@@ -0,0 +1,239 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.biz.school.model.School;
+import cn.com.qmth.stmms.common.signature.SignatureInfo;
+import cn.com.qmth.stmms.common.signature.SignatureType;
+
+public class OrgUtil {
+
+    private static Logger log = LoggerFactory.getLogger(OrgUtil.class);
+
+    /** 默认的编码格式 */
+    public static final String DEFAULT_CHARSET = "UTF-8";
+
+    public static final String CONTENT_TYPE = "Content-Type";
+
+    public static final String APPLICATION_JSON = "application/x-www-form-urlencoded;charset=utf-8";
+
+    public static final String METHOD_POST = "POST";
+
+    public static final String AUTH = "Authorization";
+
+    protected String host = null;
+
+    protected String uri = null;
+
+    protected String accessKey = null;
+
+    protected String accessSecret = null;
+
+    public OrgUtil(String accessKey, String accessSecret, String host, String uri) {
+        this.accessKey = accessKey;
+        this.accessSecret = accessSecret;
+        this.uri = uri;
+        this.host = host;
+    }
+
+    /**
+     * 
+     * @param params
+     *            headers参数
+     * @param datas
+     *            requestParams参数
+     * @return
+     */
+    public String httpAction(Map<String, String> params, Map<String, Object> datas) {
+        String result = null;
+        HttpsURLConnection conn = null;
+        OutputStream os = null;
+        InputStream is = null;
+
+        try {
+
+            // 获取链接
+            URL url = new URL(host + uri);
+            conn = (HttpsURLConnection) url.openConnection();
+
+            conn.setRequestMethod(METHOD_POST);
+            conn.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON);
+            // 设置鉴权
+            long time = System.currentTimeMillis();
+            String signature = SignatureInfo.build(SignatureType.SECRET, METHOD_POST, uri, time, accessKey,
+                    accessSecret);
+            conn.setRequestProperty(AUTH, signature);
+            conn.setRequestProperty("time", String.valueOf(time));
+            // ssl
+            SSLContext context = SSLContext.getInstance("SSL", "SunJSSE");
+            TrustManager[] tm = new TrustManager[] { new X509TrustManager() {
+
+                @Override
+                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                }
+
+                @Override
+                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                }
+
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+            } };
+            // 初始化
+            context.init(null, tm, new java.security.SecureRandom());
+            // 获取SSLSocketFactory对象
+            SSLSocketFactory ssf = context.getSocketFactory();
+            conn.setSSLSocketFactory(ssf);
+
+            conn.setUseCaches(false);
+            conn.setDoOutput(true);
+
+            // 设置额外的参数
+            if (params != null && !params.isEmpty()) {
+
+                for (Map.Entry<String, String> param : params.entrySet()) {
+                    conn.setRequestProperty(param.getKey(), param.getValue());
+                }
+            }
+            // 创建链接
+            conn.connect();
+            // 设置请求参数
+            if (datas != null) {
+                StringBuilder sb = new StringBuilder();
+                for (Map.Entry<String, Object> data : datas.entrySet()) {
+                    sb.append(data.getKey()).append("=").append(data.getValue()).append("&");
+                }
+                os = conn.getOutputStream();
+                os.write(sb.toString().getBytes());
+                os.flush();
+            }
+
+            result = getResult(conn);
+        } catch (Exception e) {
+            // 操作失败
+            log.error("OrgUtil connection error!", e);
+            e.printStackTrace();
+            return null;
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                    os = null;
+                }
+                if (is != null) {
+                    is.close();
+                    is = null;
+                }
+            } catch (IOException e) {
+                log.error("OrgUtil connection error!", e);
+            }
+
+            if (conn != null) {
+                conn.disconnect();
+                conn = null;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 获得连接请求的返回数据
+     * 
+     * @param conn
+     * 
+     * @return 字符串
+     */
+    private String getResult(HttpURLConnection conn) throws IOException {
+
+        StringBuilder text = new StringBuilder();
+
+        InputStream is = null;
+        InputStreamReader sr = null;
+        BufferedReader br = null;
+
+        int code = conn.getResponseCode();
+
+        try {
+            is = code >= 400 ? conn.getErrorStream() : conn.getInputStream();
+
+            sr = new InputStreamReader(is, DEFAULT_CHARSET);
+            br = new BufferedReader(sr);
+
+            char[] chars = new char[4096];
+            int length = 0;
+
+            while ((length = br.read(chars)) != -1) {
+                text.append(chars, 0, length);
+            }
+        } finally {
+            if (br != null) {
+                br.close();
+                br = null;
+            }
+            if (sr != null) {
+                sr.close();
+                sr = null;
+            }
+            if (is != null) {
+                is.close();
+                is = null;
+            }
+        }
+        if (code >= 400) {
+            throw new IOException(text.toString());
+        }
+        return text.toString();
+    }
+
+    public List<School> getOrgs() {
+        String str = this.httpAction(null, null);
+        List<School> schools = new ArrayList<School>();
+        JSONArray orgArray = JSONArray.fromObject(str);
+        for (int i = 0; i < orgArray.size(); i++) {
+            JSONObject org = orgArray.getJSONObject(i);
+            School school = new School();
+            school.setAccessKey(org.getString("accessKey"));
+            school.setAccessSecret(org.getString("accessSecret"));
+            school.setCode(org.getString("code"));
+            school.setName(org.getString("name"));
+            school.setLogoUrl(org.getString("logo"));
+            school.setEnable(true);
+            schools.add(school);
+        }
+        return schools;
+    }
+
+    public static void main(String[] args) throws IOException {
+        OrgUtil orgUtil = new OrgUtil("7bbdc11570bc474dbf50e0d4a5dff328", "IOodRvbp2LspJTHOScgB7Yx8MRloMpyl",
+                "https://solar.qmth.com.cn", "/api/open/org/query");
+        String str = orgUtil.httpAction(null, null);
+        System.out.println(str);
+
+    }
+}

+ 4 - 4
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/LockType.java

@@ -1,10 +1,10 @@
 package cn.com.qmth.stmms.common.enums;
 
 public enum LockType {
-    EXAM_SUBJECT("exam_subject"), GROUP("group"), GROUP_DELETE("group_delete"), STUDENT("student"), MARKER(
-            "marker"), MARKER_RESET("marker_reset"), USER("user"), FORMAL_LIBRARY("formal_library"), TRIAL_LIBRARY(
-            "trial_library"), ARBITRATE("arbitrate"), BATCH_QUALITY("batch_quality"), SCORE_CALCULATE(
-            "score_calculate"), GROUP_LIBRARY("group_library"), DATA_SYNC("data_sync");
+    EXAM_SUBJECT("exam_subject"), GROUP("group"), GROUP_DELETE("group_delete"), STUDENT("student"), MARKER("marker"), MARKER_RESET(
+            "marker_reset"), USER("user"), FORMAL_LIBRARY("formal_library"), TRIAL_LIBRARY("trial_library"), ARBITRATE(
+            "arbitrate"), BATCH_QUALITY("batch_quality"), SCORE_CALCULATE("score_calculate"), GROUP_LIBRARY(
+            "group_library"), DATA_SYNC("data_sync"), SCHOOL("school");
 
     private String name;
 

+ 40 - 9
stmms-web/src/main/java/cn/com/qmth/stmms/admin/school/SchoolController.java

@@ -1,25 +1,32 @@
 package cn.com.qmth.stmms.admin.school;
 
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.ModelAndView;
+
+import cn.com.qmth.stmms.biz.lock.LockService;
 import cn.com.qmth.stmms.biz.school.model.School;
 import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
 import cn.com.qmth.stmms.biz.school.service.SchoolService;
+import cn.com.qmth.stmms.biz.school.thread.OrgSyncThread;
 import cn.com.qmth.stmms.biz.user.model.User;
 import cn.com.qmth.stmms.biz.user.service.UserService;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.controller.BaseController;
+import cn.com.qmth.stmms.common.enums.LockType;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.enums.Role;
 import cn.com.qmth.stmms.common.enums.UserSource;
 import cn.com.qmth.stmms.common.utils.EncryptUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.servlet.http.HttpServletRequest;
 
 @Controller
 @RequestMapping("/admin/sys/school")
@@ -31,12 +38,27 @@ public class SchoolController extends BaseController {
     @Autowired
     private UserService userService;
 
+    @Qualifier("task-executor")
+    @Autowired
+    private AsyncTaskExecutor taskExecutor;
+
+    @Autowired
+    private LockService lockService;
+
+    @Value("${qmth.solar.accessKey}")
+    private String accessKey;
+
+    @Value("${qmth.solar.accessSecret}")
+    private String accessSecret;
+
     @Logging(menu = "学校查询", type = LogType.QUERY)
     @RequestMapping
     public ModelAndView list(HttpServletRequest request, SchoolSearchQuery query) {
         ModelAndView view = new ModelAndView("modules/sys/schoolList");
         query = schoolService.findByQuery(query);
         view.addObject("query", query);
+        view.addObject("enableUpadteOrg", StringUtils.isNotBlank(accessKey) && StringUtils.isNotBlank(accessSecret));
+        view.addObject("running", lockService.isLocked(LockType.SCHOOL, ""));
         return view;
     }
 
@@ -208,4 +230,13 @@ public class SchoolController extends BaseController {
         view.addObject("school", school);
         return view;
     }
+
+    @RequestMapping(value = "/updateOrg", method = RequestMethod.GET)
+    public String updateOrg(HttpServletRequest request) {
+        if (lockService.trylock(LockType.SCHOOL, "")) {
+            OrgSyncThread thread = new OrgSyncThread(schoolService);
+            taskExecutor.submit(thread);
+        }
+        return "redirect:/admin/sys/school";
+    }
 }

+ 1 - 1
stmms-web/src/main/webapp/WEB-INF/views/modules/sys/schoolEdit.jsp

@@ -76,7 +76,7 @@
             <%-- <shiro:hasPermission name="exam:course:edit"> --%>
         <input id="btnSubmit" class="btn btn-primary" type="submit" value="保 存"/>&nbsp;
             <%-- </shiro:hasPermission> --%>
-		<c:if test="${school.id!=null }">
+		<c:if test="${school.id!=null && school.code==null}">
 	        <a href="${ctx}/admin/sys/school/restAccess?id=${school.id}" class="btn btn-warning" type="button">重置密钥</a>&nbsp;
 		</c:if>
         <input id="btnCancel" class="btn" type="button" value="返 回" onclick="history.go(-1)"/>

+ 10 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/sys/schoolList.jsp

@@ -19,6 +19,14 @@
 			<input id="btnSubmit" class="btn btn-primary" type="button" value="查询" onclick="goSearch()"/>
 			&nbsp;
 			<a href="${ctx}/admin/sys/school/add" class="btn btn-primary">新建</a>
+			<c:if test="${enableUpadteOrg && !running}">
+			&nbsp;
+			<a href="${ctx}/admin/sys/school/updateOrg" class="btn btn-primary">机构同步</a>
+			</c:if>
+			<c:if test="${enableUpadteOrg && running}">
+			&nbsp;
+			<a href="#" class="btn btn-primary" disable>正在同步</a>
+			</c:if>
 		</div>
 	</form>
 	<tags:message content="${message}"/>
@@ -26,6 +34,7 @@
 		<thead>
 			<tr>
 				<th>名称</th>
+				<th>代码</th>
 				<th>省份</th>
 				<th>地市</th>
 				<th>操作</th>
@@ -35,6 +44,7 @@
 		<c:forEach items="${query.result}" var="school">
 			<tr>
 				<td>${school.name}</td>
+				<td>${school.code}</td>
 				<td>${school.province}</td>
 				<td>${school.city}</td>
 				<td>

+ 1 - 0
stmms-web/src/main/webapp/sql/stmms_ft.sql

@@ -15,6 +15,7 @@ CREATE TABLE `b_school`
     `name`          varchar(64) NOT NULL COMMENT '名称',
     `province`      varchar(16) NOT NULL COMMENT '省份',
     `city`          varchar(16) NOT NULL COMMENT '城市',
+    `code`          varchar(64)  DEFAULT NULL COMMENT '代码',
     `address`       varchar(128) DEFAULT NULL COMMENT '地址',
     `phone`         varchar(32)  DEFAULT NULL COMMENT '电话',
     `logo_url`      varchar(64)  DEFAULT NULL COMMENT '图片地址',