|
@@ -0,0 +1,334 @@
|
|
|
+package cn.com.qmth.examcloud.commons.web.boot;
|
|
|
+
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Map.Entry;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.http.client.config.RequestConfig;
|
|
|
+import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
+import org.apache.http.entity.StringEntity;
|
|
|
+import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
+import org.apache.http.util.EntityUtils;
|
|
|
+import org.springframework.boot.SpringApplication;
|
|
|
+import org.springframework.context.ConfigurableApplicationContext;
|
|
|
+
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.google.common.collect.Sets;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.commons.base.exception.ExamCloudRuntimeException;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.HttpClientPool;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.HttpClientUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.JsonUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.PropertiesUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.SecurityUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.base.util.Util;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 启动器<br>
|
|
|
+ *
|
|
|
+ * 配置文件优先级:参数>配置中心>本地配置
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @date 2018年12月3日
|
|
|
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
|
|
|
+ */
|
|
|
+public class ExamCloudApp {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 启动配置中心
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param source
|
|
|
+ * @param password
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static ConfigurableApplicationContext runConfigServer(Object source, String... args) {
|
|
|
+ Properties props = new Properties();
|
|
|
+ PropertiesUtil.loadFromResource("application.properties", props);
|
|
|
+
|
|
|
+ String active = null;
|
|
|
+ String password = null;
|
|
|
+ if (null != args) {
|
|
|
+ for (String s : args) {
|
|
|
+ s = s.trim();
|
|
|
+ if (s.startsWith("--startup.password=")) {
|
|
|
+ password = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ if (s.startsWith("--spring.profiles.active=")) {
|
|
|
+ active = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == active) {
|
|
|
+ String value = props.getProperty("spring.profiles.active");
|
|
|
+ if (null != value) {
|
|
|
+ active = value.trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println("active=" + active);
|
|
|
+ if (StringUtils.isBlank(active)) {
|
|
|
+ throw new ExamCloudRuntimeException("active is not specified");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(password)) {
|
|
|
+ throw new ExamCloudRuntimeException("password is not specified");
|
|
|
+ }
|
|
|
+
|
|
|
+ PropertiesUtil.loadFromResource(active + "/application.properties", props);
|
|
|
+ PropertiesUtil.loadFromResource(active + "/application-config.properties", props);
|
|
|
+
|
|
|
+ String testPassword = props.getProperty("$encrypted.$testPassword");
|
|
|
+ if (StringUtils.isBlank(testPassword)) {
|
|
|
+ throw new ExamCloudRuntimeException(
|
|
|
+ "property[$encrypted.$testPassword] is not configured");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ SecurityUtil.decrypt(testPassword, password);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ExamCloudRuntimeException("password is wrong!");
|
|
|
+ }
|
|
|
+
|
|
|
+ SecurityUtil.decrypt(props, password);
|
|
|
+
|
|
|
+ Set<String> argSet = Sets.newLinkedHashSet();
|
|
|
+ for (Entry<Object, Object> p : props.entrySet()) {
|
|
|
+ PropertiesUtil.setProperty((String) p.getKey(), (String) p.getValue());
|
|
|
+ String arg = "--" + p.getKey() + "=" + p.getValue();
|
|
|
+ argSet.add(arg);
|
|
|
+ }
|
|
|
+
|
|
|
+ String[] newArgs = argSet.toArray(new String[argSet.size()]);
|
|
|
+
|
|
|
+ BootSecurityManager.getInstance().setSecretKey(password);
|
|
|
+ BootSecurityManager.getInstance().setActive(active);
|
|
|
+
|
|
|
+ return SpringApplication.run(source, newArgs);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 启动
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param source
|
|
|
+ * @param appSimpleName
|
|
|
+ * @param args
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static ConfigurableApplicationContext run(Object source, String appSimpleName,
|
|
|
+ String... args) {
|
|
|
+
|
|
|
+ Properties props = new Properties();
|
|
|
+ PropertiesUtil.loadFromResource("application.properties", props);
|
|
|
+
|
|
|
+ String securityCode = null;
|
|
|
+ String active = null;
|
|
|
+ String host = null;
|
|
|
+ String port = null;
|
|
|
+ if (null != args) {
|
|
|
+ for (String s : args) {
|
|
|
+ s = s.trim();
|
|
|
+ if (s.startsWith("--startup.securityCode=")) {
|
|
|
+ securityCode = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ if (s.startsWith("--spring.profiles.active=")) {
|
|
|
+ active = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ if (s.startsWith("--config.server.host=")) {
|
|
|
+ host = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ if (s.startsWith("--config.server.port=")) {
|
|
|
+ port = s.substring(s.indexOf("=") + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (null == active) {
|
|
|
+ String value = props.getProperty("spring.profiles.active");
|
|
|
+ if (null != value) {
|
|
|
+ active = value.trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("active=" + active);
|
|
|
+ if (StringUtils.isBlank(active)) {
|
|
|
+ throw new ExamCloudRuntimeException("active is not specified");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == host) {
|
|
|
+ host = props.getProperty("config.server.host");
|
|
|
+ }
|
|
|
+ System.out.println("config server host=" + host);
|
|
|
+
|
|
|
+ if (null == port) {
|
|
|
+ port = props.getProperty("config.server.port", "9999");
|
|
|
+ }
|
|
|
+ System.out.println("config server port=" + port);
|
|
|
+
|
|
|
+ if ("dev".equals(active)) {
|
|
|
+ securityCode = "SB";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == securityCode) {
|
|
|
+ System.out.println("securityCode is null");
|
|
|
+ throw new ExamCloudRuntimeException("securityCode is not specified");
|
|
|
+ } else {
|
|
|
+ System.out.println("securityCode=" + securityCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(host)) {
|
|
|
+ throw new ExamCloudRuntimeException("host is not specified");
|
|
|
+ }
|
|
|
+
|
|
|
+ String url = "http://" + host + ":" + port + "/properties/" + appSimpleName + "/" + active;
|
|
|
+ Map<String, String> pairs = getProperties(url, securityCode);
|
|
|
+
|
|
|
+ SecurityUtil.decrypt(pairs, securityCode);
|
|
|
+
|
|
|
+ if (null != args) {
|
|
|
+ for (String arg : args) {
|
|
|
+ arg = arg.trim();
|
|
|
+ if (arg.startsWith("--")) {
|
|
|
+ String key = arg.substring(2, arg.indexOf("="));
|
|
|
+ String value = arg.substring(arg.indexOf("=") + 1);
|
|
|
+ pairs.put(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ setSystemProperties(pairs);
|
|
|
+
|
|
|
+ Set<String> argSet = Sets.newLinkedHashSet();
|
|
|
+ for (Entry<String, String> p : pairs.entrySet()) {
|
|
|
+ PropertiesUtil.setProperty(p.getKey(), p.getValue());
|
|
|
+ String arg = "--" + p.getKey() + "=" + p.getValue();
|
|
|
+ argSet.add(arg);
|
|
|
+ }
|
|
|
+
|
|
|
+ BootSecurityManager.getInstance().setActive(active);
|
|
|
+
|
|
|
+ String[] newArgs = argSet.toArray(new String[argSet.size()]);
|
|
|
+
|
|
|
+ String sendStartupStatusUrl = "http://" + host + ":" + port + "/startupStatus/"
|
|
|
+ + appSimpleName + "/" + active;
|
|
|
+ try {
|
|
|
+ ConfigurableApplicationContext context = SpringApplication.run(source, newArgs);
|
|
|
+ sendStartupStatus(sendStartupStatusUrl, securityCode, "success");
|
|
|
+
|
|
|
+ return context;
|
|
|
+ } catch (Exception e) {
|
|
|
+ sendStartupStatus(sendStartupStatusUrl, securityCode,
|
|
|
+ "failure\n" + Util.getStackTrace(e));
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置系统属性
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param pairs
|
|
|
+ */
|
|
|
+ private static void setSystemProperties(Map<String, String> pairs) {
|
|
|
+ for (Entry<String, String> p : pairs.entrySet()) {
|
|
|
+ String key = p.getKey();
|
|
|
+ String value = p.getValue();
|
|
|
+ if (key.endsWith("$log.level.default")) {
|
|
|
+ System.setProperty("logLevel", value);
|
|
|
+ } else if (key.endsWith("$log.rootPath")) {
|
|
|
+ System.setProperty("logRootPath", value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * POST 表单请求
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static Map<String, String> getProperties(String url, String securityCode) {
|
|
|
+ Map<String, String> headers = Maps.newHashMap();
|
|
|
+ headers.put("securityCode", securityCode);
|
|
|
+ CloseableHttpResponse response = null;
|
|
|
+ String respBody = null;
|
|
|
+ try {
|
|
|
+ response = post(url, headers, null);
|
|
|
+ respBody = EntityUtils.toString(response.getEntity(), "UTF-8");
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ExamCloudRuntimeException(e);
|
|
|
+ } finally {
|
|
|
+ HttpClientUtil.close(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (org.apache.http.HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
|
|
|
+ System.out.println("fail to get properties from config server");
|
|
|
+ throw new ExamCloudRuntimeException("fail to get properties from config server");
|
|
|
+ }
|
|
|
+
|
|
|
+ respBody = SecurityUtil.decrypt(respBody, securityCode);
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, String> map = JsonUtil.fromJson(respBody, Map.class);
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送启动状态
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param url
|
|
|
+ * @param securityCode
|
|
|
+ * @param body
|
|
|
+ */
|
|
|
+ private static void sendStartupStatus(String url, String securityCode, String body) {
|
|
|
+ Map<String, String> headers = Maps.newHashMap();
|
|
|
+ headers.put("securityCode", securityCode);
|
|
|
+ CloseableHttpResponse response = null;
|
|
|
+ try {
|
|
|
+ response = post(url, headers, body);
|
|
|
+ EntityUtils.toString(response.getEntity(), "UTF-8");
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ExamCloudRuntimeException(e);
|
|
|
+ } finally {
|
|
|
+ HttpClientUtil.close(response);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * POST
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @param url
|
|
|
+ * @param headers
|
|
|
+ * @param body
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static CloseableHttpResponse post(String url, Map<String, String> headers,
|
|
|
+ String body) {
|
|
|
+
|
|
|
+ CloseableHttpClient httpclient = HttpClientPool.getHttpClient();
|
|
|
+ HttpPost post = new HttpPost(url);
|
|
|
+ post.setConfig(RequestConfig.custom().setConnectTimeout(10000).build());
|
|
|
+ post.setConfig(RequestConfig.custom().setConnectionRequestTimeout(1000 * 60 * 2).build());
|
|
|
+
|
|
|
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
|
|
|
+ post.addHeader(entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (null != body) {
|
|
|
+ post.setEntity(new StringEntity(body, "UTF-8"));
|
|
|
+ }
|
|
|
+ CloseableHttpResponse response = httpclient.execute(post);
|
|
|
+ return response;
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ExamCloudRuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|