Browse Source

代码重构

01495251 2 months ago
commit
ca4a5180c1
35 changed files with 3745 additions and 0 deletions
  1. BIN
      lib/beautyeye_lnf.jar
  2. 159 0
      pom.xml
  3. BIN
      src/images/photo.jpg
  4. 3 0
      src/main/META-INF/MANIFEST.MF
  5. 33 0
      src/main/java/com/sg/answer/App.java
  6. 41 0
      src/main/java/com/sg/answer/core/HttpEntityType.java
  7. 358 0
      src/main/java/com/sg/answer/core/HttpRequestConfig.java
  8. 73 0
      src/main/java/com/sg/answer/core/HttpRequestMethod.java
  9. 113 0
      src/main/java/com/sg/answer/core/HttpRequestResult.java
  10. 64 0
      src/main/java/com/sg/answer/core/SgEntity.java
  11. 30 0
      src/main/java/com/sg/answer/core/UserInfoEntity.java
  12. 268 0
      src/main/java/com/sg/answer/core/YtoHttpClientBuilder.java
  13. 48 0
      src/main/java/com/sg/answer/entity/JobEnum.java
  14. 31 0
      src/main/java/com/sg/answer/entity/JobTypeEntity.java
  15. 321 0
      src/main/java/com/sg/answer/panel/PlaceComponents.java
  16. 84 0
      src/main/java/com/sg/answer/service/AnswerService.java
  17. 142 0
      src/main/java/com/sg/answer/service/UserInfoService.java
  18. 131 0
      src/main/java/com/sg/answer/sg/API.java
  19. 22 0
      src/main/java/com/sg/answer/sg/ApiEndpoints.java
  20. 170 0
      src/main/java/com/sg/answer/sg/Constant.java
  21. 42 0
      src/main/java/com/sg/answer/sg/ErrorCode.java
  22. 346 0
      src/main/java/com/sg/answer/sg/FrameManager.java
  23. 48 0
      src/main/java/com/sg/answer/sg/JTextFieldHintListener.java
  24. 143 0
      src/main/java/com/sg/answer/sg/SgController.java
  25. 27 0
      src/main/java/com/sg/answer/sg/SgException.java
  26. 18 0
      src/main/java/com/sg/answer/sg/answer.java
  27. 187 0
      src/main/java/com/sg/answer/utils/GetNetworkTime.java
  28. 318 0
      src/main/java/com/sg/answer/utils/HttpClientUtils.java
  29. 38 0
      src/main/java/com/sg/answer/utils/LocalMac.java
  30. 42 0
      src/main/java/com/sg/answer/utils/Md5Utils.java
  31. 48 0
      src/main/java/com/sg/answer/utils/ObjectUtils.java
  32. 26 0
      src/main/java/com/sg/answer/utils/SgUtils.java
  33. 84 0
      src/main/resource/logback.xml
  34. 20 0
      src/test/java/com/sg/answer/AppTest.java
  35. 267 0
      src/test/java/com/sg/answer/test.java

BIN
lib/beautyeye_lnf.jar


+ 159 - 0
pom.xml

@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>com.sg.answer</groupId>
+  <artifactId>sg-answer6.0.2</artifactId>
+  <version>6.0.2SNAPSHOT</version>
+
+  <name>sg-answer6.0.2</name>
+  <url>http://www.example.com</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+    <slf4j-api.version>1.7.25</slf4j-api.version>
+    <logback.version>1.1.7</logback.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+        <version>4.5.13</version>
+    </dependency>
+    <dependency>
+      <groupId>net.oschina.bilbodai.common.beanutil</groupId>
+      <artifactId>beanutil</artifactId>
+      <version>3.1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <version>3.7</version>
+    </dependency>
+    <dependency>
+      <groupId>org.projectlombok</groupId>
+      <artifactId>lombok</artifactId>
+      <version>1.16.10</version>
+    </dependency>
+    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
+    <dependency>
+      <groupId>com.alibaba</groupId>
+      <artifactId>fastjson</artifactId>
+      <version>1.2.58</version>
+    </dependency>
+    <!--mvn install:install-file -DgroupId=com.yto -DartifactId=beautyeye_lnf -Dversion=3.0 -Dpackaging=jar -Dfile=D:\ideaWorkSpace\sg-answer6.xx\lib\beautyeye_lnf.jar-->
+    <dependency>
+      <groupId>com.yto</groupId>
+      <artifactId>beautyeye_lnf</artifactId>
+      <version>3.0</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+
+    <!-- log start -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j-api.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <version>${logback.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-access</artifactId>
+      <version>${logback.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>${logback.version}</version>
+    </dependency>
+    <!-- log end -->
+  </dependencies>
+
+  <build>
+    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
+      <plugins>
+        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
+        <plugin>
+          <artifactId>maven-clean-plugin</artifactId>
+          <version>3.1.0</version>
+        </plugin>
+        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
+        <plugin>
+          <artifactId>maven-resources-plugin</artifactId>
+          <version>3.0.2</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.8.0</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.22.1</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>3.0.2</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-install-plugin</artifactId>
+          <version>2.5.2</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>2.8.2</version>
+        </plugin>
+        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
+        <plugin>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>3.7.1</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>3.3.0</version> <!-- 你可以根据需要调整版本 -->
+        <configuration>
+          <archive>
+            <manifestEntries>
+              <Main-Class>com.sg.answer.App</Main-Class> <!-- 替换为你的主类 -->
+            </manifestEntries>
+          </archive>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>3.2.1</version> <!-- 选择合适版本 -->
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

BIN
src/images/photo.jpg


+ 3 - 0
src/main/META-INF/MANIFEST.MF

@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: com.sg.answer.App
+

+ 33 - 0
src/main/java/com/sg/answer/App.java

@@ -0,0 +1,33 @@
+package com.sg.answer;
+
+import com.sg.answer.sg.FrameManager;
+import com.sg.answer.sg.SgController;
+import org.apache.http.util.Asserts;
+import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;
+
+import javax.swing.*;
+import java.io.File;
+import java.net.URL;
+
+/**
+ * Hello world!
+ *
+ */
+public class App
+{
+     public static void main(String[] args) {
+         try {
+//             URL url= new URL("http://pic1.win4000.com/pic/9/75/1a9b924550.jpg");
+//             System.out.println(url.getFile().substring(url.getFile().lastIndexOf(".")));
+            BeautyEyeLNFHelper.launchBeautyEyeLNF();
+             UIManager.put("RootPane.setupButtonVisible", false);
+         } catch (Exception e) {
+             e.printStackTrace();
+         }
+         Asserts.check(SgController.auth(),"授权时间已过期");
+         FrameManager frameManager = new FrameManager();
+         frameManager.init();
+         JOptionPane.showMessageDialog(frameManager.panel, "有效期授权时间截止到 2025-06-05 00:00:00" ,"提示", JOptionPane.WARNING_MESSAGE);
+    }
+
+}

+ 41 - 0
src/main/java/com/sg/answer/core/HttpEntityType.java

@@ -0,0 +1,41 @@
+package com.sg.answer.core;
+
+/**
+ * <pre>
+ * 名称: HttpEntityType
+ * 描述: TODO
+ * </pre>
+ *
+ * @author Ryan Chen
+ * @since 1.0.0
+ */
+public enum HttpEntityType {
+
+    //ENTITY_FILE("FileEntity"),
+
+    BYTE_ARRAY("BYTE_ARRAY"),
+
+    // ENTITY_INPUT_STREAM("ENTITY_INPUT_STREAM"),
+
+    //ENTITY_SERIALIZABLE("SerializableEntity"),
+
+    // ENTITY_MULTIPART("MultipartEntity"),
+
+    URL_ENCODED_FORM("URL_ENCODED_FORM"),
+
+    APPLICATION_XML("application/xml"),
+
+    APPLICATION_JSON("application/json"),
+
+    TEXT_PLAIN("text/plain");
+
+    private String contentType;
+
+    private HttpEntityType(String contentType) {
+        this.contentType = contentType;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+}

+ 358 - 0
src/main/java/com/sg/answer/core/HttpRequestConfig.java

@@ -0,0 +1,358 @@
+package com.sg.answer.core;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * <pre>
+ * 名称: HttpRequestConfig
+ * 描述: TODO
+ * </pre>
+ *
+ * @author Ryan Chen
+ * @since 1.0.0
+ */
+public class HttpRequestConfig {
+
+
+    /**
+     * 请求url ,解决多线程处理时,url被覆盖问题
+     */
+    private static final ThreadLocal<String> URLS = new ThreadLocal<String>();
+    /**
+     * 解决多线程下载时,strean被close的问题
+     */
+    private static final ThreadLocal<OutputStream> OUTS = new ThreadLocal<OutputStream>();
+    /**
+     * httpClient 对象
+     */
+    private CloseableHttpClient httpClient;
+
+    /**
+     * requestMethod 请求方法类型
+     */
+    private HttpRequestMethod requestMethod;
+
+    /**
+     * 用于cookie操作
+     */
+    private HttpContext context;
+
+    /**
+     * 实体类型
+     */
+    private HttpEntityType httpEntityType = HttpEntityType.URL_ENCODED_FORM;
+
+    /**
+     * 请求参数
+     */
+    private Map<String, Object> paramMap = new LinkedHashMap<>();
+
+    /**
+     * 请求 header
+     */
+    private Map<String, Header> headerMap = new LinkedHashMap<>();
+
+    /**
+     * body
+     */
+    private String body;
+
+    /**
+     * 字节数组方式作为输入参数
+     */
+    private byte[] bytes;
+
+    /**
+     * 使用ssl
+     */
+    private boolean useSSL = false;
+
+    /**
+     * 请求编码类型
+     */
+    private String requestCharset = "UTF-8";
+
+    /**
+     * 响应编码类型
+     */
+    private String responseCharset = "UTF-8";
+
+    private HttpRequestConfig() {
+
+    }
+
+    public static HttpRequestConfig create() {
+        return new HttpRequestConfig();
+    }
+
+    public static String getUrl() {
+        return URLS.get();
+    }
+
+    public static OutputStream getOut() {
+        return OUTS.get();
+    }
+
+    /**
+     * @param httpClient HttpClient对象
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig client(CloseableHttpClient httpClient) {
+        this.httpClient = httpClient;
+        return this;
+    }
+
+    /**
+     * @param url 资源url
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig url(String url) {
+        URLS.set(url);
+        return this;
+    }
+
+    /**
+     * @param out 输出流对象
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig out(OutputStream out) {
+        OUTS.set(out);
+        return this;
+    }
+
+    /**
+     * @param headerMap Header头信息
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig headers(Map<String, Header> headerMap) {
+        this.headerMap = headerMap;
+        return this;
+    }
+
+    /**
+     * 添加单个header
+     *
+     * @param name
+     * @param value
+     * @return
+     */
+    public HttpRequestConfig addHeader(String name, String value) {
+        this.headerMap.put(name, new BasicHeader(name, value));
+        return this;
+    }
+
+    /**
+     * @param requestMethod 请求方法
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig requestMethod(HttpRequestMethod requestMethod) {
+        this.requestMethod = requestMethod;
+        return this;
+    }
+
+    /**
+     * @param context cookie操作相关
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig context(HttpContext context) {
+        this.context = context;
+        return this;
+    }
+
+    /**
+     * @param httpEntityType httpEntity 类型
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig httpEntityType(HttpEntityType httpEntityType) {
+        this.httpEntityType = httpEntityType;
+        return this;
+    }
+
+    /**
+     * @param paramMap 传递参数
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig paramMap(Map<String, Object> paramMap) {
+        if (this.paramMap == null || paramMap == null) {
+            this.paramMap = paramMap;
+        } else {
+            this.paramMap.putAll(paramMap);
+        }
+        return this;
+    }
+
+    /**
+     * 设置单个参数
+     *
+     * @param name
+     * @param value
+     * @return
+     */
+    public HttpRequestConfig addParam(String name, Object value) {
+        this.paramMap.put(name, value);
+        return this;
+    }
+
+    /**
+     * @param json 以json格式字符串作为参数
+     * @return 返回当前对象
+     */
+    public HttpRequestConfig json(String json) {
+        this.httpEntityType(HttpEntityType.APPLICATION_JSON);
+        return body(json);
+    }
+
+    public HttpRequestConfig xml(String xml) {
+        this.httpEntityType(HttpEntityType.APPLICATION_XML);
+        return body(xml);
+    }
+
+    public HttpRequestConfig body(String body) {
+        this.body = body;
+        paramMap = new HashMap<>();
+        return this;
+    }
+
+    /**
+     * @param bytes 字节数组作为参数
+     * @return
+     */
+    public HttpRequestConfig bytes(byte[] bytes) {
+        this.bytes = bytes;
+        paramMap = new HashMap<>();
+        return this;
+    }
+
+    /**
+     * 使用 ssl,默认关闭
+     *
+     * @return
+     */
+    public HttpRequestConfig useSSL() {
+        this.useSSL = true;
+        return this;
+    }
+
+    /**
+     * 请求编码
+     *
+     * @param requestCharset
+     * @return
+     */
+    public HttpRequestConfig requestCharset(String requestCharset) {
+        this.requestCharset = requestCharset;
+        return this;
+    }
+
+    /**
+     * 响应编码
+     *
+     * @param responseCharset
+     * @return
+     */
+    public HttpRequestConfig responseCharset(String responseCharset) {
+        this.responseCharset = responseCharset;
+        return this;
+    }
+
+    public HttpClient getHttpClient() {
+        return httpClient;
+    }
+
+    public HttpRequestMethod getRequestMethod() {
+        return requestMethod;
+    }
+
+    public HttpContext getContext() {
+        return context;
+    }
+
+    public HttpEntityType getHttpEntityType() {
+        return httpEntityType;
+    }
+
+    public Map<String, Object> getParamMap() {
+        return paramMap;
+    }
+
+    public Map<String, Header> getHeaderMap() {
+        return headerMap;
+    }
+
+    public Header[] getHeaders() {
+        return headerMap.values().toArray(new Header[headerMap.size()]);
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public byte[] getBytes() {
+        return bytes;
+    }
+
+    public boolean isUseSSL() {
+        return useSSL;
+    }
+
+    public String getRequestCharset() {
+        return requestCharset;
+    }
+
+    public String getResponseCharset() {
+        return responseCharset;
+    }
+
+    public HttpEntity getEntity() {
+        HttpEntity entity;
+        switch (this.httpEntityType) {
+            case BYTE_ARRAY:
+                entity = new ByteArrayEntity(getBytes());
+                break;
+            case URL_ENCODED_FORM:
+                List<NameValuePair> pairList = new ArrayList<>(paramMap.size());
+                for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
+                    NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry
+                            .getValue().toString());
+                    pairList.add(pair);
+                }
+                entity = new UrlEncodedFormEntity(pairList, Charset.forName(getRequestCharset()));
+                break;
+            default:
+                entity = new StringEntity(this.getBody(), ContentType.create(this.httpEntityType.getContentType(), this.getRequestCharset()));
+                break;
+
+        }
+        return entity;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("HttpRequestConfig{");
+        sb.append("httpClient=").append(httpClient);
+        sb.append(", requestMethod=").append(requestMethod);
+        sb.append(", paramMap=").append(paramMap);
+        sb.append(", headerMap=").append(headerMap);
+        sb.append(", body='").append(body).append('\'');
+        sb.append(", useSSL=").append(useSSL);
+        sb.append(", requestCharset='").append(requestCharset).append('\'');
+        sb.append(", responseCharset='").append(responseCharset).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+}

+ 73 - 0
src/main/java/com/sg/answer/core/HttpRequestMethod.java

@@ -0,0 +1,73 @@
+package com.sg.answer.core;
+
+/**
+ * <pre>
+ * 名称: HttpRequestMethod
+ * 描述: TODO
+ * </pre>
+ *
+ * @author Ryan Chen
+ * @since 1.0.0
+ */
+public enum HttpRequestMethod {
+
+    /**
+     * 求获取Request-URI所标识的资源
+     */
+    GET(0, "GET"),
+
+    /**
+     * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
+     * POST请求可能会导致新的资源的建立和/或已有资源的修改
+     */
+    POST(1, "POST"),
+
+    /**
+     * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。
+     * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息
+     * 只获取响应信息报头
+     */
+    HEAD(2, "HEAD"),
+
+    /**
+     * 向指定资源位置上传其最新内容(全部更新,操作幂等)
+     */
+    PUT(3, "PUT"),
+
+    /**
+     * 请求服务器删除Request-URI所标识的资源
+     */
+    DELETE(4, "DELETE"),
+
+    /**
+     * 请求服务器回送收到的请求信息,主要用于测试或诊断
+     */
+    TRACE(5, "TRACE"),
+
+    /**
+     * 向指定资源位置上传其最新内容(部分更新,非幂等)
+     */
+    PATCH(6, "PATCH"),
+
+    /**
+     * 返回服务器针对特定资源所支持的HTTP请求方法。
+     * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性
+     */
+    OPTIONS(7, "OPTIONS");
+
+    private int code;
+    private String name;
+
+    private HttpRequestMethod(int code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}

+ 113 - 0
src/main/java/com/sg/answer/core/HttpRequestResult.java

@@ -0,0 +1,113 @@
+package com.sg.answer.core;
+
+import org.apache.http.Header;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * <pre>
+ * 名称: HttpRequestResult
+ * 描述: TODO
+ * </pre>
+ *
+ * @author Ryan Chen
+ * @since 1.0.0
+ */
+public class HttpRequestResult {
+
+    private int code;
+    private String responseText;
+    private String contentType;
+    private String contentEncoding;
+
+    private Map<String, Header> headersMap;
+
+    public HttpRequestResult(int code) {
+        this(code, null, null, null, null);
+    }
+
+    public HttpRequestResult(int code, Header[] headers) {
+        this(code, null, null, null, headers);
+    }
+
+
+    public HttpRequestResult(int code, String responseText, String contentType
+            , String contentEncoding, Header[] headers) {
+        this.code = code;
+        this.responseText = getNotNullString(responseText);
+        this.contentType = getNotNullString(contentType);
+        this.contentEncoding = getNotNullString(contentEncoding);
+        headersMap = new LinkedHashMap<>();
+        addHeaders(headers);
+    }
+
+    private void addHeaders(Header[] headers) {
+        if (null != headers) {
+            for (Header header : headers) {
+                headersMap.put(header.getName(), header);
+            }
+        }
+    }
+
+    private String getNotNullString(String str) {
+        return null == str ? "" : str;
+    }
+
+    private Header[] getNotNullHeaders(Header[] headers) {
+        return null == headers ? new Header[0] : headers;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getResponseText() {
+        return responseText;
+    }
+
+    public void setResponseText(String responseText) {
+        this.responseText = getNotNullString(responseText);
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    public void setContentType(String contentType) {
+        this.contentType = getNotNullString(contentType);
+    }
+
+    public String getContentEncoding() {
+        return contentEncoding;
+    }
+
+    public void setContentEncoding(String contentEncoding) {
+        this.contentEncoding = getNotNullString(contentEncoding);
+    }
+
+    public Header getHeader(String name) {
+        return headersMap.get(name);
+    }
+
+    public Header[] getAllHeaders() {
+        return headersMap.values().toArray(new Header[headersMap.size()]);
+    }
+
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("HttpRequestResult{");
+        sb.append("code=").append(code);
+        sb.append(", responseText='").append(responseText).append('\'');
+        sb.append(", contentType='").append(contentType).append('\'');
+        sb.append(", contentEncoding='").append(contentEncoding).append('\'');
+        sb.append(", headersMap=").append(headersMap);
+        sb.append('}');
+        return sb.toString();
+    }
+}

+ 64 - 0
src/main/java/com/sg/answer/core/SgEntity.java

@@ -0,0 +1,64 @@
+package com.sg.answer.core;
+
+import lombok.Data;
+
+import javax.swing.*;
+
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className SgEntity
+ * @description TODO
+ * @date 2020/3/19 13:19
+ */
+@Data
+public class SgEntity {
+
+    /**答题关卡进度,随答题时间而变动*/
+    private  JLabel gkText=new JLabel("默认为第一关");
+    /**工种id*/
+    private  Integer gz;
+    /**关卡id(经难度关卡进度计算后最终id)*/
+    private  Integer id;
+    /**结束答题标记*/
+    private  Boolean flag=true;
+    /**当前刷分小计标签*/
+    private  JLabel xjText = new JLabel("0");
+    /**当前刷分目标*/
+    private JLabel mbText = new JLabel("∞");
+    /**自动刷分输入文本域*/
+    private  JTextField coustomText= new JTextField();
+    private  JTextArea textArea = new JTextArea(5, 10);
+    /**总分*/
+    private double total;
+    /**自定义分数*/
+    private  double coustomScore;
+    /**难度id(1,2,3)*/
+    private  Integer type;
+    /**答题难度*/
+    private  String difficulty;
+   /**当前用户答题剩余时间,满时间为180分钟*/
+    private  JLabel timeLabel=new JLabel();
+    /**头像*/
+    private  JLabel image;
+    /**工号*/
+    private  JTextField userText =new JTextField("34110210",20);
+    /**密码*/
+    private JPasswordField passwordText = new JPasswordField("pengyu@0215",20);
+    /**工种选择下拉框*/
+    private JComboBox comboBox;
+    /**难度选择下拉框*/
+    private JComboBox typeBox;
+
+    public SgEntity(){
+
+    }
+    public void apppendLogs(String msg){
+        this.getTextArea().append(msg);
+        this.getTextArea().paintImmediately( this.getTextArea().getBounds());
+    }
+
+
+    
+}

+ 30 - 0
src/main/java/com/sg/answer/core/UserInfoEntity.java

@@ -0,0 +1,30 @@
+package com.sg.answer.core;
+
+import lombok.Data;
+
+import javax.swing.*;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className UserInfoEntity
+ * @description TODO
+ * @date 2020/3/19 14:08
+ */
+@Data
+public class UserInfoEntity {
+    /**姓名*/
+    private JLabel userNameData = new JLabel("");
+    /**工号*/
+    private  JLabel jobNoData = new JLabel("");
+    /**工种*/
+    private  JLabel jobTypeData= new JLabel("");
+    /**积分*/
+    private  JLabel integralDate = new JLabel("0");
+    /**金币*/
+    private  JLabel goldCoinData = new JLabel("0");
+    /**钻石*/
+    private  JLabel diamondData= new JLabel("0");
+    /**头像*/
+    private  JLabel image;
+}

+ 268 - 0
src/main/java/com/sg/answer/core/YtoHttpClientBuilder.java

@@ -0,0 +1,268 @@
+package com.sg.answer.core;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.NoHttpResponseException;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContexts;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * <pre>
+ * 名称: HttpRequestConfig
+ * 描述: TODO
+ * </pre>
+ *
+ * @author Ryan Chen
+ * @since 1.0.0
+ */
+@Slf4j
+public class YtoHttpClientBuilder extends HttpClientBuilder {
+
+    private YtoHttpClientBuilder() {
+
+    }
+
+    public static YtoHttpClientBuilder custom() {
+        return new YtoHttpClientBuilder();
+    }
+
+    /**
+     * create SSLConnectionSocketFactory to trust all
+     *
+     * @return
+     */
+    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
+        try {
+            SSLContext sslcontext = SSLContexts.custom()
+                    .loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true)
+                    .build();
+            return new SSLConnectionSocketFactory(sslcontext,
+                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
+        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 设置超时
+     *
+     * @param connectTimeout           连接超时时间
+     * @param socketTimeout            等待响应超时
+     * @param connectionRequestTimeout 从连接池获取连接超时时间
+     * @return
+     */
+    public YtoHttpClientBuilder timeout(int connectTimeout, int socketTimeout, int connectionRequestTimeout) {
+
+        RequestConfig requestConfig = RequestConfig.custom()
+                //从连接池中获取连接的超时时间
+                .setConnectionRequestTimeout(connectionRequestTimeout)
+                //建立连接超时
+                .setConnectTimeout(connectTimeout)
+                //等待响应超时(读取数据超时)
+                .setSocketTimeout(socketTimeout)
+                .build();
+        return (YtoHttpClientBuilder) this.setDefaultRequestConfig(requestConfig);
+    }
+
+    /**
+     * 设置超时
+     *
+     * @param timeout
+     * @return
+     */
+    public YtoHttpClientBuilder timeout(int timeout) {
+        RequestConfig requestConfig = RequestConfig.custom()
+                //从连接池中获取连接的超时时间
+                .setConnectionRequestTimeout(timeout)
+                //建立连接超时
+                .setConnectTimeout(timeout)
+                //等待响应超时(读取数据超时)
+                .setSocketTimeout(timeout)
+                .build();
+        return (YtoHttpClientBuilder) this.setDefaultRequestConfig(requestConfig);
+    }
+
+    /**
+     * 设置连接池
+     *
+     * @param maxTotal    最大连接数
+     * @param maxPerRoute 每个路由的最大连接数
+     * @param maxRoute    最大路由数据
+     * @param hostname    主机
+     * @param port        端口
+     * @return
+     */
+    public YtoHttpClientBuilder pool(int maxTotal, int maxPerRoute, int maxRoute, String hostname, int port) {
+        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
+                .getSocketFactory();
+        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
+                .getSocketFactory();
+        Registry<ConnectionSocketFactory> registry = RegistryBuilder
+                .<ConnectionSocketFactory>create().register("http", plainsf)
+                .register("https", sslsf).build();
+        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
+                registry);
+        //每隔 2 秒才检查连接的有效性
+        cm.setValidateAfterInactivity(2000);
+        // 将最大连接数增加
+        cm.setMaxTotal(maxTotal);
+        // 将每个路由基础的连接增加
+        cm.setDefaultMaxPerRoute(maxPerRoute);
+        HttpHost httpHost = new HttpHost(hostname, port);
+        // 将目标主机的最大连接数增加
+        cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
+        return (YtoHttpClientBuilder) this.setConnectionManager(cm);
+    }
+
+    /**
+     * 设置连接池
+     *
+     * @param maxTotal    最大连接数
+     * @param maxPerRoute 每个路由的最大连接数
+     * @return
+     */
+    public YtoHttpClientBuilder pool(int maxTotal, int maxPerRoute) {
+        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
+                .getSocketFactory();
+        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
+                .getSocketFactory();
+        Registry<ConnectionSocketFactory> registry = RegistryBuilder
+                .<ConnectionSocketFactory>create().register("http", plainsf)
+                .register("https", sslsf).build();
+        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
+                registry);
+        // 将最大连接数增加
+        cm.setMaxTotal(maxTotal);
+        // 将每个路由基础的连接增加
+        cm.setDefaultMaxPerRoute(maxPerRoute);
+
+        return (YtoHttpClientBuilder) this.setConnectionManager(cm);
+    }
+
+    /**
+     * 重试(如果请求是幂等的,就再次尝试)
+     *
+     * @param tryTimes               重试次数
+     * @param retryWhenInterruptedIO 连接拒绝时,是否重试
+     * @return 返回当前对象
+     */
+    public YtoHttpClientBuilder retry(final int tryTimes, final boolean retryWhenInterruptedIO) {
+        // 请求重试处理
+        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
+
+            @SneakyThrows
+            @Override
+            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
+                // 如果已经重试了n次,就放弃
+                if (executionCount > tryTimes) {
+                    log.error("已重试{}次,放弃本次请求",executionCount);
+                    return false;
+                }
+                // 如果服务器丢掉了连接,那么就重试
+                if (exception instanceof NoHttpResponseException) {
+                    return true;
+                }
+                // 不要重试SSL握手异常
+                if (exception instanceof SSLHandshakeException) {
+                    return false;
+                }
+                // 超时重连
+                if (exception instanceof InterruptedIOException) {
+                    log.error("连接超时,开始第{}次重连……",executionCount);
+                    Thread.sleep(3000);
+                    return retryWhenInterruptedIO;
+                }
+                // 目标服务器不可达
+                if (exception instanceof UnknownHostException) {
+                    log.error("目标服务器不可达");
+                    return true;
+                }
+                // 连接被拒绝
+                if (exception instanceof ConnectTimeoutException) {
+                    return false;
+                }
+                // SSL握手异常
+                if (exception instanceof SSLException) {
+                    return false;
+                }
+                //连接被重置
+                if (exception instanceof SocketException) {
+                    log.error("连接被重置,开始第{}次重连……",executionCount);
+                    Thread.sleep(10000);
+                    return retryWhenInterruptedIO;
+                }
+                HttpClientContext clientContext = HttpClientContext.adapt(context);
+                HttpRequest request = clientContext.getRequest();
+                // 如果请求是幂等的,就再次尝试
+                if (!(request instanceof HttpEntityEnclosingRequest)) {
+                    return true;
+                }
+                return false;
+            }
+        };
+        return (YtoHttpClientBuilder) this.setRetryHandler(httpRequestRetryHandler);
+    }
+
+    /**
+     * 重试
+     *
+     * @param tryTimes 重试次数
+     * @return
+     */
+    public YtoHttpClientBuilder retry(final int tryTimes) {
+        return retry(tryTimes, false);
+    }
+
+    /**
+     * 设置代理
+     *
+     * @param hostOrIP 代理host或者ip
+     * @param port     代理端口
+     * @return 返回当前对象
+     */
+    public YtoHttpClientBuilder proxy(String hostOrIP, int port) {
+        // 依次是代理地址,代理端口号,协议类型
+        HttpHost proxy = new HttpHost(hostOrIP, port, "http");
+        DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
+        return (YtoHttpClientBuilder) this.setRoutePlanner(routePlanner);
+    }
+
+    /**
+     * 设置ssl安全链接
+     *
+     * @return 返回当前对象
+     */
+    public YtoHttpClientBuilder ssl() {
+        return (YtoHttpClientBuilder) this.setSSLSocketFactory(createSSLConnSocketFactory());
+    }
+}

+ 48 - 0
src/main/java/com/sg/answer/entity/JobEnum.java

@@ -0,0 +1,48 @@
+package com.sg.answer.entity;
+
+import lombok.Data;
+
+/**
+ * @author 王玉鹏
+ */
+
+public enum JobEnum {
+
+    DIANGONG("电工", 2,30),
+    QIANGONG("钳工", 6,150);
+
+    JobEnum(String jobTypeNname, int typeId, int GkId) {
+        this.jobTypeNname=jobTypeNname;
+        this.typeId=typeId;
+        this.GkId=GkId;
+    }
+
+    private String jobTypeNname;
+    private int typeId;
+    private int GkId;
+
+
+    public String getJobTypeNname() {
+        return jobTypeNname;
+    }
+
+    public void setJobTypeNname(String jobTypeNname) {
+        this.jobTypeNname = jobTypeNname;
+    }
+
+    public int getTypeId() {
+        return typeId;
+    }
+
+    public void setTypeId(int typeId) {
+        this.typeId = typeId;
+    }
+
+    public int getGkId() {
+        return GkId;
+    }
+
+    public void setGkId(int gkId) {
+        GkId = gkId;
+    }
+}

+ 31 - 0
src/main/java/com/sg/answer/entity/JobTypeEntity.java

@@ -0,0 +1,31 @@
+package com.sg.answer.entity;
+
+import lombok.Data;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className JobTypeEntity
+ * @description TODO
+ * @date 2020/12/10 14:12
+ */
+@Data
+public class JobTypeEntity {
+    //工种名称
+    private String jobTypeNname;
+    //工种id
+    private int typeId;
+    //关卡初始id
+    private int gkId;
+
+    public JobTypeEntity(String jobTypeNname, int typeId, int gkId) {
+        this.jobTypeNname = jobTypeNname;
+        this.typeId = typeId;
+        this.gkId = gkId;
+    }
+
+    @Override
+    public String toString() {
+        return jobTypeNname;
+    }
+}

+ 321 - 0
src/main/java/com/sg/answer/panel/PlaceComponents.java

@@ -0,0 +1,321 @@
+package com.sg.answer.panel;
+
+import com.sg.answer.core.SgEntity;
+import com.sg.answer.core.UserInfoEntity;
+import com.sg.answer.sg.Constant;
+import com.sg.answer.sg.FrameManager;
+import com.sg.answer.entity.JobTypeEntity;
+import com.sg.answer.utils.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.sg.answer.sg.API.reset;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className PlaceComponents
+ * @description TODO
+ * @date 2020/3/19 13:03
+ */
+@Slf4j
+public class PlaceComponents {
+
+
+    private  AtomicBoolean status = new AtomicBoolean(true);
+
+    protected AtomicBoolean pause = new AtomicBoolean(false);
+
+    private static final Object lock = new Object();
+
+    public  JPanel placeComponents() {
+        JPanel panel = new JPanel();
+        panel.setLayout(null);
+
+        // 创建 当前关卡JLabel
+        JLabel gkLabel = new JLabel("当前关卡:");
+        gkLabel.setBounds(10,10,80,25);
+        panel.add(gkLabel);
+        SgEntity sgEntity = new SgEntity();
+        sgEntity.getGkText().setForeground(Color.RED);
+        sgEntity.getGkText().setBounds(100,10,165,25);
+        panel.add(sgEntity.getGkText());
+
+        // 创建 JLabel
+        JLabel userLabel = new JLabel("用户:");
+        /* 这个方法定义了组件的位置。
+         * setBounds(x, y, width, height)
+         * x 和 y 指定左上角的新位置,由 width 和 height 指定新的大小。
+         */
+        userLabel.setBounds(10,40,80,25);
+        panel.add(userLabel);
+
+        sgEntity.getUserText().setBounds(100,40,165,25);
+        panel.add( sgEntity.getUserText());
+
+        // 输入密码的文本域
+        JLabel passwordLabel = new JLabel("密码:");
+        passwordLabel.setBounds(10,70,80,25);
+        panel.add(passwordLabel);
+
+        sgEntity.getPasswordText().setBounds(100,70,165,25);
+        panel.add(sgEntity.getPasswordText());
+
+        // 工种的文本域
+        JLabel gzLabel = new JLabel("工种:");
+        gzLabel.setBounds(10,100,80,25);
+        panel.add(gzLabel);
+
+        JComboBox comboBox=new JComboBox();
+        for (JobTypeEntity jobTypeEntity : Constant.jobTypeList) {
+            comboBox.addItem(jobTypeEntity);
+        }
+/*        for (String JobTypeName:Constant.jobTypeId.keySet()) {
+            comboBox.addItem(JobTypeName);
+        }*/
+        sgEntity.setComboBox(comboBox);
+        comboBox.setBounds(100,100,165,25);
+        panel.add(comboBox);
+
+        //难度
+        JLabel typeLabel = new JLabel("难度选择:");
+        typeLabel.setBounds(10,130,80,25);
+        panel.add(typeLabel);
+
+        JComboBox typeBox=new JComboBox();
+        for (String name : Constant.level.keySet()) {
+            typeBox.addItem(name);
+        }
+        typeBox.setBounds(100,130,165,25);
+        sgEntity.setTypeBox(typeBox);
+        panel.add(typeBox);
+
+        //统计
+        JLabel xjLabel = new JLabel("当前刷分小计:");
+        xjLabel.setBounds(320,10,100,25);
+        panel.add(xjLabel);
+
+        sgEntity.getXjText().setBounds(410,10,50,25);
+        sgEntity.getXjText().setForeground(Color.green);
+        panel.add(sgEntity.getXjText());
+
+
+        //目标显示
+        JLabel mbLabel = new JLabel("目标:");
+        mbLabel.setBounds(460,10,100,25);
+        panel.add(mbLabel);
+
+        sgEntity.getMbText().setBounds(500,10,50,25);
+        sgEntity.getMbText().setForeground(Color.red);
+        panel.add(sgEntity.getMbText());
+
+        //倒计时
+        sgEntity.getTimeLabel().setForeground(Color.MAGENTA);
+        sgEntity.getTimeLabel().setBounds(530,10,150,20);
+        panel.add(sgEntity.getTimeLabel());
+
+        // 自定义刷分
+
+        //目标显示
+        JLabel zdyLabel = new JLabel("自定义刷分:");
+        zdyLabel.setBounds(10,160,100,25);
+        panel.add(zdyLabel);
+
+        sgEntity.getCoustomText().setBounds(100,160,100,25);
+        panel.add( sgEntity.getCoustomText());
+
+        JButton coustomButton = new JButton("刷分");
+        coustomButton.setBounds(210, 160, 55, 25);
+        panel.add(coustomButton);
+
+        // 创建登录按钮
+        JButton loginButton = new JButton("登陆答题");
+        loginButton.setBounds(10, 190, 110, 25);
+        panel.add(loginButton);
+
+        // 创建停止按钮
+        JButton stopButton = new JButton("结束刷题");
+        stopButton.setBounds(160, 190, 110, 25);
+        panel.add(stopButton);
+
+        //日志
+        sgEntity.getTextArea().setBounds(10, 260, 770, 150);
+        // 设置自动换行
+        sgEntity.getTextArea().setLineWrap(true);
+        // 添加到内容面板
+        sgEntity.getTextArea().setText("日志");
+        sgEntity.getTextArea().setForeground(Color.green);
+        sgEntity.getTextArea().setBackground(Color.black);
+        sgEntity.getTextArea().setFocusable(false);
+        panel.add( sgEntity.getTextArea());
+        //日志滚动面板
+        JScrollPane scrollpane=new JScrollPane();
+        scrollpane.setBounds(10, 260, 700, 180);
+        scrollpane.setViewportView( sgEntity.getTextArea());
+        panel.add(scrollpane);
+
+        // tip
+        JLabel bqLabel = new JLabel("本软件由彭宇制作,如有疑问请加微信:pengyu20100613联系本人");
+        bqLabel.setForeground(Color.RED);
+        bqLabel.setBounds(10,420,400,20);
+        panel.add(bqLabel);
+
+        /*******************************个人信息面板*********************************/
+
+        UserInfoEntity userInfoEntity = new UserInfoEntity();
+
+        // 姓名
+        JLabel userName = new JLabel("姓名:");
+        userName.setBounds(320,40,80,25);
+        panel.add(userName);
+
+        userInfoEntity.setUserNameData( new JLabel());
+        userInfoEntity.getUserNameData().setBounds(360,40,80,25);
+        userInfoEntity.getUserNameData().setForeground(Color.blue);
+
+        userInfoEntity.getUserNameData().addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e){
+                if (e.getButton() == MouseEvent.BUTTON3){
+                    StringSelection selection = new StringSelection(userInfoEntity.getUserNameData().getText());
+                    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
+                    JOptionPane.showMessageDialog(panel, "姓名已复制到剪贴板了" ," tip", JOptionPane.WARNING_MESSAGE);
+                }
+            }
+        });
+
+        panel.add( userInfoEntity.getUserNameData());
+
+
+        // 工号
+        JLabel jobNo = new JLabel("工号:");
+        jobNo.setBounds(320,75,80,25);
+        panel.add(jobNo);
+
+        userInfoEntity.getJobNoData().setBounds(360,75,80,25);
+        userInfoEntity.getJobNoData().setForeground(Color.blue);
+        panel.add(userInfoEntity.getJobNoData());
+
+        // 工种
+        JLabel jobType = new JLabel("工种:");
+        jobType.setBounds(320,105,80,25);
+        panel.add(jobType);
+
+        userInfoEntity.getJobTypeData().setBounds(360,105,80,25);
+        userInfoEntity.getJobTypeData().setForeground(Color.blue);
+        panel.add(userInfoEntity.getJobTypeData());
+
+        // 积分
+        JLabel integral = new JLabel("总积分:");
+        integral.setBounds(30,220,80,25);
+        integral.setFont(new Font (Font.DIALOG, Font.BOLD, 15));
+        integral.setForeground(Color.BLUE);
+        panel.add(integral);
+
+        userInfoEntity.getIntegralDate().setBounds(100,220,80,25);
+        userInfoEntity.getIntegralDate().setFont(new Font (Font.DIALOG, Font.BOLD, 15));
+        userInfoEntity.getIntegralDate().setForeground(Color.red);
+        panel.add(userInfoEntity.getIntegralDate());
+
+
+        // 金币
+        JLabel goldCoin = new JLabel("金币:");
+        goldCoin.setBounds(320,135,80,25);
+        panel.add(goldCoin);
+
+        userInfoEntity.getGoldCoinData().setBounds(360,135,80,25);
+        userInfoEntity.getGoldCoinData().setForeground(Color.blue);
+        panel.add(userInfoEntity.getGoldCoinData());
+
+
+        // 钻石
+        JLabel diamond = new JLabel("钻石:");
+        diamond.setBounds(320,165,80,25);
+        panel.add(diamond);
+
+        // 暂停
+        JButton parseButton = new JButton("暂停答题");
+        parseButton.setBounds(350, 190, 80, 25);
+        panel.add(parseButton);
+
+        userInfoEntity.getDiamondData().setBounds(360,165,80,25);
+        userInfoEntity.getDiamondData().setForeground(Color.blue);
+        panel.add( userInfoEntity.getDiamondData());
+
+        JLabel initLabel = new JLabel("本次答题初始分数:");
+        initLabel.setBounds(200,220,140,25);
+        initLabel.setFont(new Font (Font.DIALOG, Font.BOLD, 15));
+        initLabel.setForeground(Color.BLUE);
+        panel.add(initLabel);
+
+        JLabel statrScore = new JLabel("0");
+        statrScore.setBounds(355,220,80,25);
+        statrScore.setFont(new Font (Font.DIALOG, Font.BOLD, 15));
+        statrScore.setForeground(Color.red);
+        panel.add(statrScore);
+
+
+        // 头像
+        try {
+            URL url= new URL("http://pic1.win4000.com/pic/9/75/1a9b924550.jpg");
+            ImageIcon imageIcon = new ImageIcon(url);
+            imageIcon.setImage(imageIcon.getImage().getScaledInstance(195,290,Image.SCALE_DEFAULT));
+            sgEntity.setImage(new JLabel(imageIcon));
+            sgEntity.getImage().setBounds(480,30,200,300);
+            panel.add(sgEntity.getImage());
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+
+
+        //自定义监听时间
+        coustomButton.addActionListener(e -> {
+            if (StringUtils.isEmpty(sgEntity.getCoustomText().getText()) || !ObjectUtils.isNumeric(sgEntity.getCoustomText().getText())) {
+                JOptionPane.showMessageDialog(panel, "请输入正确得分数", " stop", JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+            sgEntity.setCoustomScore(Double.parseDouble(sgEntity.getCoustomText().getText()));
+            sgEntity.getMbText().setText(sgEntity.getCoustomText().getText());
+        });
+        //结束答题时间
+        stopButton.addActionListener(e -> {
+             status.set(false);
+             JOptionPane.showMessageDialog(panel, "本次答题已结束,如需要重写开始请继续" ," stop", JOptionPane.ERROR_MESSAGE);
+            reset(loginButton,sgEntity,"已结束本次答题");
+        });
+        //登录时间
+        loginButton.addActionListener((ActionEvent e) -> {
+            status.set(true);
+            try {
+                new FrameManager().start(loginButton,sgEntity,userInfoEntity,statrScore,status,pause,lock);
+            } catch (Exception e1) {
+                e1.printStackTrace();
+            }
+        });
+        parseButton.addActionListener(e ->{
+            loginButton.setEnabled(false);
+            parseButton.setText(parseButton.getText().equals("暂停答题")?"继续答题":"暂停答题");
+            pause.set(!pause.get());
+
+            if (!pause.get()){
+                synchronized (lock){
+                    sgEntity.apppendLogs(" 已恢复当前答题 ");
+                    log.info("以恢复当前等待线程,开始继续答题");
+                    lock.notify();
+                }
+            }
+        });
+
+
+        return  panel;
+
+    }
+}

+ 84 - 0
src/main/java/com/sg/answer/service/AnswerService.java

@@ -0,0 +1,84 @@
+package com.sg.answer.service;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.sg.answer.core.HttpRequestConfig;
+import com.sg.answer.core.HttpRequestResult;
+import com.sg.answer.core.SgEntity;
+import com.sg.answer.sg.ApiEndpoints;
+import com.sg.answer.sg.ErrorCode;
+import com.sg.answer.sg.SgException;
+import com.sg.answer.utils.HttpClientUtils;
+import com.sg.answer.utils.SgUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.HttpClient;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+
+import static com.sg.answer.sg.Constant.answerNum;
+
+@Slf4j
+public class AnswerService {
+
+    private final CookieStore cookieStore;
+
+    public AnswerService(CookieStore cookieStore) {
+        this.cookieStore = cookieStore;
+    }
+
+    private void openAnswerHtml(int num) throws Exception {
+        String openAnswerUrl = ApiEndpoints.START_LEVEL + "?id=" + num + "&matchid=0";
+        log.info("闯关页面请求地址:{}", openAnswerUrl);
+        String openResult = SgUtils.executeRemotePostRequest(cookieStore, openAnswerUrl);
+        if (StringUtils.isEmpty(openResult)) {
+            log.error("请求返回结果集为空");
+            throw new SgException(ErrorCode.RESULT_EMPTY.getCode(), ErrorCode.RESULT_EMPTY.getName());
+        }
+        if (openResult.contains("今天的闯关时间已用尽")) {
+            log.error("今天的闯关时间已用尽");
+            throw new SgException(ErrorCode.TIME_Limit.getCode(), ErrorCode.TIME_Limit.getName());
+        }
+        if (openResult.contains("未解锁")) {
+            log.error("当前关卡未解锁");
+            throw new SgException(ErrorCode.LEVEL_NOT_UNLOCKED.getCode(), ErrorCode.LEVEL_NOT_UNLOCKED.getName());
+        }
+    }
+
+    public JSONObject autoAnswer(List<String> stemList, String num) throws Exception {
+        String answerResult;
+        int index = new Random().nextInt(50);
+        String stem = stemList.get(index);
+        log.info("随机选题:序号={},题干={}", index, stem);
+        String dtUrl = ApiEndpoints.SUBMIT_ANSWER + "?passid=" + num + "&" + stem;
+        try {
+            answerResult = SgUtils.executeRemotePostRequest(cookieStore, dtUrl);
+        } catch (Exception e) {
+            log.error("请求超时,10秒后重试...");
+            Thread.sleep(10000);
+            answerResult = SgUtils.executeRemotePostRequest(cookieStore, dtUrl);
+        }
+        return handleAnswerResult(answerResult, dtUrl);
+    }
+
+    public JSONObject handleAnswerResult(String res,String dtUrl) throws Exception {
+        JSONObject jb;
+        try {
+            jb = JSONObject.parseObject(res);
+//          log.info("当前答题数量:{}",jb.get("isright"));
+        } catch (JSONException exception) {
+            log.error("json解析异常{}", exception.getMessage());
+            if (exception.getMessage().contains("重新登录")) {
+                throw new SgException(ErrorCode.LOGOUT.getCode(), ErrorCode.LOGOUT.getName());
+            }
+            Thread.sleep(10000);
+            String tryResult = SgUtils.executeRemotePostRequest(cookieStore, dtUrl);
+            jb = JSONObject.parseObject(tryResult);
+        }
+        return jb;
+    }
+}

+ 142 - 0
src/main/java/com/sg/answer/service/UserInfoService.java

@@ -0,0 +1,142 @@
+package com.sg.answer.service;
+
+import com.sg.answer.core.SgEntity;
+import com.sg.answer.core.UserInfoEntity;
+import com.sg.answer.sg.ApiEndpoints;
+import com.sg.answer.sg.Constant;
+import com.sg.answer.sg.ErrorCode;
+import com.sg.answer.sg.SgException;
+import com.sg.answer.utils.SgUtils;
+import org.apache.http.client.CookieStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.sg.answer.sg.Constant.*;
+
+public class UserInfoService {
+    private static final Logger log = LoggerFactory.getLogger(UserInfoService.class);
+
+    public static void getPersonalInfo(CookieStore cookie, SgEntity sgEntity,
+                                       UserInfoEntity userInfo) throws Exception {
+        try {
+            String htmlContent = SgUtils.executeRemotePostRequest(cookie, ApiEndpoints.USER_DATA);
+            parseAndUpdateUserInfo(htmlContent, sgEntity, userInfo);
+            loadUserAvatar(htmlContent, sgEntity);
+        } catch (IOException e) {
+            log.error("网络请求失败", e);
+            throw new SgException(ErrorCode.REQUEST_ERROR.getCode(), ErrorCode.REQUEST_ERROR.getName());
+        } catch (RuntimeException e) {
+            log.error("系统解析异常", e);
+            throw new SgException(ErrorCode.PARSE_ERROR.getCode(), ErrorCode.PARSE_ERROR.getName());
+        }
+    }
+
+    public static int getGKInfo(CookieStore cookie, SgEntity sgEntity) throws Exception {
+        try {
+            String htmlContent = SgUtils.executeRemotePostRequest(cookie, ApiEndpoints.USER_GK + "?id=" + sgEntity.getId() + "&passtype=" + sgEntity.getType());
+            processCountdown(htmlContent, sgEntity);
+            return getCurrentGk(htmlContent);
+        } catch (IOException e) {
+            log.error("网络请求失败", e);
+            throw new SgException(ErrorCode.REQUEST_ERROR.getCode(), ErrorCode.REQUEST_ERROR.getName());
+        } catch (RuntimeException e) {
+            log.error("系统解析异常", e);
+            throw new SgException(ErrorCode.PARSE_ERROR.getCode(), ErrorCode.PARSE_ERROR.getName());
+        }
+    }
+
+    private static void parseAndUpdateUserInfo(String html, SgEntity sgEntity,
+                                               UserInfoEntity userInfo) {
+        // 姓名
+        extractValue(USER_NAME_PATTERN, html, 1).ifPresent(value ->
+                updateUI(() -> userInfo.getUserNameData().setText(cleanHtml(value)))
+        );
+        //职务
+        extractValue(JOB_PATTERN, html, 1).ifPresent(value ->
+                updateUI(() -> userInfo.getJobTypeData().setText(cleanHtml(value)))
+        );
+        // 更新工号
+        updateUI(() -> userInfo.getJobNoData().setText(
+                sgEntity.getUserText().getText()
+        ));
+        //积分、砖石、金币
+        List<String> financials = extractAllMatches(INFO_PATTERN, html);
+        if (financials.size() >= 3) {
+            updateUI(() -> {
+                userInfo.getIntegralDate().setText(financials.get(0));
+                userInfo.getGoldCoinData().setText(financials.get(1));
+                userInfo.getDiamondData().setText(financials.get(2));
+            });
+        }
+    }
+
+    private static void loadUserAvatar(String html, SgEntity sgEntity) {
+        extractValue(AVATAR_PATTERN, html, 1).ifPresent(avatarPath -> {
+            try {
+                URL imageUrl = new URL(Constant.SERVER_IP + avatarPath);
+                ImageIcon icon = new ImageIcon(imageUrl);
+                updateUI(() -> sgEntity.getImage().setIcon(icon));
+            } catch (MalformedURLException e) {
+                log.warn("头像URL格式错误: {}", avatarPath, e);
+            }
+        });
+    }
+
+    private static int getCurrentGk(String html) throws NumberFormatException {
+        Optional<String> gkHtml = extractValue(PASS_PATTERN, html, 1);
+        if (gkHtml.isPresent()) {
+            return Integer.parseInt(cleanHtml(gkHtml.get()));
+        } else {
+            throw new NumberFormatException("获取关卡数据异常");
+        }
+    }
+
+    private static void processCountdown(String html, SgEntity sgEntity) {
+        extractValue(TIME_PATTERN, html, 0).ifPresent(timeHtml -> {
+            updateUI(() -> sgEntity.getTimeLabel().setText(cleanHtml(timeHtml)));
+        });
+    }
+
+
+
+    // 通用正则提取方法
+    private static Optional<String> extractValue(Pattern pattern, String input, int group) {
+        Matcher matcher = pattern.matcher(input);
+        return matcher.find() ? Optional.of(matcher.group(group).trim()) : Optional.empty();
+    }
+
+    // 多值提取
+    private static List<String> extractAllMatches(Pattern pattern, String input) {
+        List<String> matches = new ArrayList<>(3);
+        Matcher matcher = pattern.matcher(input);
+        while (matcher.find()) {
+            matches.add(matcher.group(1));
+        }
+        return matches;
+    }
+
+    // 线程安全的UI更新
+    private static void updateUI(Runnable action) {
+        if (SwingUtilities.isEventDispatchThread()) {
+            action.run();
+        } else {
+            SwingUtilities.invokeLater(action);
+        }
+    }
+
+    // 清理HTML标签
+    private static String cleanHtml(String input) {
+        return input.replaceAll("<[^>]+>", "").trim();
+    }
+
+}

+ 131 - 0
src/main/java/com/sg/answer/sg/API.java

@@ -0,0 +1,131 @@
+package com.sg.answer.sg;
+
+import com.sg.answer.core.HttpRequestConfig;
+import com.sg.answer.core.HttpRequestResult;
+import com.sg.answer.core.SgEntity;
+import com.sg.answer.core.UserInfoEntity;
+import com.sg.answer.utils.HttpClientUtils;
+import com.sg.answer.utils.Md5Utils;
+import com.sg.answer.utils.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.protocol.HttpContext;
+
+import javax.swing.*;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+
+import static com.sg.answer.sg.Constant.*;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className API
+ * @description TODO
+ * @date 2020/3/19 13:07
+ */
+@Slf4j
+public class API {
+    //登陆
+    public  static CookieStore login(String username, String password) throws Exception {
+        Map<String, String> map = new HashMap<>();
+        map.put("username",username);
+        map.put("password", Md5Utils.encryptPassword(username,password));
+        CookieStore cookie = SgController.doPost(API+"users/chklogin", map, "UTF-8");
+        if (ObjectUtils.isEmpty(cookie)|| cookie.getCookies().size()<=1){
+            log.info("cookie为空,登陆失败");
+            throw new SgException(ErrorCode.PASSWORD_ERROR.getCode(),ErrorCode.PASSWORD_ERROR.getName());
+        }
+        return cookie;
+    }
+    //获取个人信息
+/*    public  static  void getPersonalInfo(CookieStore cookie, SgEntity sgEntity, UserInfoEntity userInfoEntity) throws Exception {
+
+        HttpContext httpContext = new HttpClientContext();
+        ((HttpClientContext) httpContext).setCookieStore(cookie);
+        HttpRequestConfig config = HttpRequestConfig.create().url(API+"/personal").context(httpContext);
+        HttpRequestResult result = HttpClientUtils.post(config);
+        String data=result.getResponseText();
+
+        Matcher m = userNamePattern.matcher(data);
+
+        Matcher n = jobPattern.matcher(data);
+        while(m.find()) {
+            userInfoEntity .getUserNameData().setText(m.group().replaceAll("<li>","").replaceAll("</li>","").replaceAll("姓名:","").replaceAll("<span>","").replaceAll("</span>","").trim());
+        }
+        while(n.find()) {
+            userInfoEntity.getJobTypeData().setText(n.group().replaceAll("<li>","").replaceAll("</li>","").replaceAll("职务:","").replaceAll("<span>","").replaceAll("</span>","").trim());
+        }
+        userInfoEntity.getJobNoData().setText(sgEntity.getUserText().getText());
+
+        Matcher m2=userInfoPattern.matcher(data);
+        int a = 0;
+        while(m2.find()) {
+            if (a==0){
+                //积分
+                userInfoEntity.getIntegralDate().setText(m2.group().replaceAll("<strong>","").replaceAll("</strong>","").trim());
+            }
+            if (a==1){
+                //金币
+                userInfoEntity.getGoldCoinData().setText(m2.group().replaceAll("<strong>","").replaceAll("</strong>","").trim());
+            }
+            if (a==2){
+                //钻石
+                userInfoEntity.getDiamondData().setText(m2.group().replaceAll("<strong>","").replaceAll("</strong>","").trim());
+            }
+            a++;
+        }
+
+        //获取用户头像
+        Matcher m3=imagePattern.matcher(data);
+        String src="";
+        while(m3.find()) {
+            src=m3.group(2);
+            log.info("当前用户头像:{}",src);
+        }
+        URL url = new URL(Constant.SERVER_IP+src);
+        sgEntity.getImage().setIcon(new ImageIcon(url));
+    }
+
+    public  static int getCurrentLevel(CookieStore cookie, SgEntity sgEntity) throws Exception {
+        HttpContext httpContext = new HttpClientContext();
+        ((HttpClientContext) httpContext).setCookieStore(cookie);
+
+        HttpRequestConfig config = HttpRequestConfig.create().url(API+"/cglb/gk?id="+sgEntity.getId()+"&passtype="+sgEntity.getType()).context(httpContext);
+//        http://117.39.28.234:8023/index/cglb/gk?id=1&passtype=3
+        HttpRequestResult result = HttpClientUtils.post(config);
+
+        String scjl=result.getResponseText();
+        Matcher m=passPattern.matcher(scjl);
+        String bq="";
+        while(m.find()) {
+            bq=m.group(1);
+        }
+        Matcher m2=countDownPattern.matcher(scjl);
+        while(m2.find()) {
+            sgEntity.getTimeLabel().setText(m2.group().replaceAll("<p>","").replaceAll("</p>","").trim());
+        }
+        //当前用户答题关数
+        int gs =1;
+        for (int i = 0; i < bq.split("<i>").length; i++) {
+            if (i==1){
+                gs= Integer.valueOf(bq.split("<i>")[i].replaceAll("[^0-9]", ""));
+            }
+        }
+        return gs;
+    }*/
+
+    public  static void reset(JButton loginButton,SgEntity sgEntity,String msg){
+        sgEntity.getTextArea().setText(msg+"\t");
+        sgEntity.getTextArea().paintImmediately( sgEntity.getTextArea().getBounds());
+        loginButton.setEnabled(true);
+        loginButton.setText("登陆答题");
+        sgEntity.setCoustomScore(0.0);
+        sgEntity.getCoustomText().setText("自定义刷分");
+        sgEntity.getXjText().setText("0");
+        sgEntity.getMbText().setText("∞");
+    }
+}

+ 22 - 0
src/main/java/com/sg/answer/sg/ApiEndpoints.java

@@ -0,0 +1,22 @@
+package com.sg.answer.sg;
+
+public final  class ApiEndpoints {
+    // 基础API路径
+    public static final String BASE_API = "http://117.39.28.234:8023/index/";
+
+    // 登录相关
+    public static final String LOGIN = BASE_API + "auth/login";
+    public static final String USER_INFO = BASE_API + "user/profile";
+
+    // 答题相关
+    public static final String START_LEVEL = BASE_API + "cglb/dt";
+    public static final String SUBMIT_ANSWER = BASE_API + "cglb/ajaxdt";
+    public static final String LEVEL_RESULT = BASE_API + "cglb/passresult";
+
+    // 进度相关
+    public static final String CURRENT_PROGRESS = BASE_API + "progress/current";
+
+    //用戶相关
+    public static final String USER_DATA = BASE_API + "personal";
+    public static final String USER_GK = BASE_API + "cglb/gk";
+}

+ 170 - 0
src/main/java/com/sg/answer/sg/Constant.java

@@ -0,0 +1,170 @@
+package com.sg.answer.sg;
+
+import com.sg.answer.entity.JobTypeEntity;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Created by Administrator on 2020/3/14.
+ */
+public class Constant {
+    /**答题系统服务地址*/
+//    public final static String API = "http://1.85.1.34:8023/index";
+    public final static String API = "http://117.39.28.234:8023/index/";
+//    public final static String MOBILE_API_URL = "http://117.39.28.234:8023/mobile/";
+    public final static String SERVER_IP = "http://117.39.28.234:8023/";
+    /**所有关数*/
+    public static Map<Integer,Object> gkNum = new HashMap<>(20);
+    /**1-10关对应的题干数量*/
+    public static Map<Integer,Integer> answerNum = new HashMap<>(20);
+    /**难度*/
+    public static Map<String,Integer> level = new LinkedHashMap<>(20);
+    /**题干以及答案*/
+    public static List<String> stemList = new ArrayList<>();
+    /**工种集合*/
+    public static List<JobTypeEntity> jobTypeList = new ArrayList<>();
+    /*******************************正则表达式**********************************************************************************************/
+    public static final Pattern USER_NAME_PATTERN =
+            Pattern.compile("<li>姓名:(.*?)</li>", Pattern.DOTALL);
+    public static final Pattern JOB_PATTERN =
+            Pattern.compile("<li>职务:(.*?)</li>", Pattern.DOTALL);
+    /**积分、砖石、金币*/
+    public static final Pattern INFO_PATTERN =
+            Pattern.compile("<strong>(\\d+\\.?\\d*)</strong>");
+    /**头像地址*/
+    public static final Pattern AVATAR_PATTERN =
+            Pattern.compile("<img[^>]*src=[\"']([^\"']*?avatar[^\"']*?)[\"']", Pattern.CASE_INSENSITIVE);
+    /**当前闯关记录关卡*/
+    public static final Pattern PASS_PATTERN =
+            Pattern.compile("<li[^>]*class=\"bg_brown\"[^>]*>(<a[^>]*>(<i[^>]*>.*?</i>|.)*?</a>|.)*?</li>");
+    public static final Pattern TIME_PATTERN =
+            Pattern.compile("<p>[今][日][剩][余][时][间].*?</p>");
+
+    static {
+        jobTypeList.add(new JobTypeEntity("产品质量检查工",1,0));
+        jobTypeList.add(new JobTypeEntity("电工",2,30));
+        jobTypeList.add(new JobTypeEntity("电焊工",3,60));
+        jobTypeList.add(new JobTypeEntity("精整工",4,90));
+        jobTypeList.add(new JobTypeEntity("连铸工",5,120));
+        jobTypeList.add(new JobTypeEntity("钳工",6,150));
+        jobTypeList.add(new JobTypeEntity("天车工",7,180));
+        jobTypeList.add(new JobTypeEntity("自动化控制",9,240));
+        jobTypeList.add(new JobTypeEntity("轧钢工",10,270));
+        jobTypeList.add(new JobTypeEntity("质量知识题库",11,300));
+        jobTypeList.add(new JobTypeEntity("转炉炼钢工",12,330));
+        jobTypeList.add(new JobTypeEntity("党史",13,360));
+        jobTypeList.add(new JobTypeEntity("高炉工长",14,390));
+        jobTypeList.add(new JobTypeEntity("高炉炼铁工",15,420));
+        jobTypeList.add(new JobTypeEntity("高炉炉前工",16,450));
+        jobTypeList.add(new JobTypeEntity("烧结工",17,480));
+        jobTypeList.add(new JobTypeEntity("烧结原料工",18,510));
+        jobTypeList.add(new JobTypeEntity("安全",19,540));
+    }
+    static {
+        gkNum.put(1,"一");
+        gkNum.put(2,"二");
+        gkNum.put(3,"三");
+        gkNum.put(4,"四");
+        gkNum.put(5,"五");
+        gkNum.put(6,"六");
+        gkNum.put(7,"七");
+        gkNum.put(8,"八");
+        gkNum.put(9,"九");
+        gkNum.put(10,"十");
+        gkNum.put(11,"十一");
+        gkNum.put(12,"十二");
+        gkNum.put(13,"十三");
+    }
+    static {
+        answerNum.put(1,10);
+        answerNum.put(2,20);
+        answerNum.put(3,30);
+        answerNum.put(4,40);
+        answerNum.put(5,50);
+        answerNum.put(6,60);
+        answerNum.put(7,70);
+        answerNum.put(8,80);
+        answerNum.put(9,90);
+        answerNum.put(10,100);
+        answerNum.put(11,80);
+        answerNum.put(12,90);
+        answerNum.put(13,100);
+    }
+
+    static {
+        level.put("险中求胜",3);
+        level.put("争分夺秒",2);
+        level.put("风云初动",1);
+    }
+
+    static {
+        stemList.add("id=41572&answer=%E5%AF%B9");
+        stemList.add("id=78311&answer=%E9%94%99");
+        stemList.add("id=53461&answer=%E5%AF%B9");
+        stemList.add("id=52275&answer=ABCD");
+        stemList.add("id=52481&answer=ABC");
+        stemList.add("id=53092&answer=%E9%94%99");
+        stemList.add("id=52481&answer=ABC");
+        stemList.add("id=90847&answer=B");
+        stemList.add("id=90846&answer=C");
+        stemList.add("id=90845&answer=D");
+        stemList.add("id=81730&answer=ABD");
+        stemList.add("id=81729&answer=ABCD");
+        stemList.add("id=81712&answer=BCD");
+        stemList.add("id=86316&answer=%E5%AF%B9");
+        stemList.add("id=86311&answer=%E9%94%99");
+        stemList.add("id=117498&answer=A");
+        stemList.add("id=117494&answer=C");
+        stemList.add("id=119028&answer=AB");
+        stemList.add("id=119027&answer=BCD");
+        stemList.add("id=119026&answer=ABC");
+        stemList.add("id=119025&answer=ABCD");
+        stemList.add("id=119015&answer=ABC");
+        stemList.add("id=119013&answer=ABC");
+        stemList.add("id=119009&answer=AB");
+        stemList.add("id=97626&answer=%E5%AF%B9");
+        stemList.add("id=97625&answer=%E9%94%99");
+        stemList.add("id=97621&answer=%E9%94%99");
+        stemList.add("id=97620&answer=%E5%AF%B9");
+        stemList.add("id=97619&answer=%E5%AF%B9");
+        stemList.add("id=97617&answer=%E5%AF%B9");
+        stemList.add("id=97614&answer=%E5%AF%B9");
+        stemList.add("id=97611&answer=%E5%AF%B9");
+        //党史
+        stemList.add("id=58826&answer=D");
+        stemList.add("id=58825&answer=C");
+        stemList.add("id=58824&answer=A");
+        stemList.add("id=58823&answer=C");
+        stemList.add("id=58822&answer=B");
+        stemList.add("id=58821&answer=B");
+        stemList.add("id=58809&answer=B");
+        stemList.add("id=58808&answer=D");
+        //轧钢工
+        stemList.add("id=142813&answer=AD");
+        stemList.add("id=142812&answer=ABC");
+        stemList.add("id=142811&answer=ABC");
+        stemList.add("id=142809&answer=ABCD");
+        stemList.add("id=142804&answer=BC");
+        stemList.add("id=142803&answer=ABC");
+        stemList.add("id=142802&answer=ABCD");
+        stemList.add("id=142798&answer=AB");
+        stemList.add("id=142797&answer=BCD");
+        stemList.add("id=142794&answer=ABC");
+
+        stemList.add("id=58826&answer=A");
+        stemList.add("id=58826&answer=A");
+        stemList.add("id=58826&answer=B");
+        stemList.add("id=58826&answer=B");
+        stemList.add("id=58826&answer=C");
+        stemList.add("id=58826&answer=C");
+        stemList.add("id=58809&answer=A");
+        stemList.add("id=58809&answer=A");
+        stemList.add("id=58809&answer=C");
+        stemList.add("id=58809&answer=B");
+
+
+
+    }
+
+}

+ 42 - 0
src/main/java/com/sg/answer/sg/ErrorCode.java

@@ -0,0 +1,42 @@
+package com.sg.answer.sg;
+
+
+/**
+ * Created by Administrator on 2020/3/29.
+ */
+public enum ErrorCode {
+
+    TIME_Limit(10001,"答题时间已用尽"),
+    RESULT_EMPTY(10002,"结果为空"),
+    SORCE_LIMT(10003,"已到达自定义分数上上限"),
+    LEVEL_NOT_UNLOCKED(10004,"当前管卡未解锁"),
+    STOP_ANSWER(10005,"结束刷题"),
+    PASSWORD_ERROR(10006,"账号密码错误"),
+    LOGOUT(10007,"账号已在其他设备登录,请重新登录"),
+    REQUEST_ERROR(10008,"用户数据请求失败"),
+    PARSE_ERROR(10009,"数据解析错误"),
+    ;
+    private int  code;
+    private String  name;
+
+    ErrorCode(int code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 346 - 0
src/main/java/com/sg/answer/sg/FrameManager.java

@@ -0,0 +1,346 @@
+package com.sg.answer.sg;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.sg.answer.core.HttpRequestConfig;
+import com.sg.answer.core.HttpRequestResult;
+import com.sg.answer.core.SgEntity;
+import com.sg.answer.core.UserInfoEntity;
+import com.sg.answer.entity.JobTypeEntity;
+import com.sg.answer.panel.PlaceComponents;
+import com.sg.answer.service.UserInfoService;
+import com.sg.answer.utils.HttpClientUtils;
+import com.sg.answer.utils.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.protocol.HttpContext;
+
+import javax.swing.*;
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.sg.answer.sg.API.*;
+import static com.sg.answer.sg.Constant.*;
+import static com.sg.answer.sg.Constant.gkNum;
+import static com.sg.answer.sg.Constant.answerNum;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className FrameManager
+ * @description TODO
+ * @date 2020/3/19 13:14
+ */
+@Slf4j
+public class FrameManager {
+
+    // 线程池配置
+    private static final ThreadPoolExecutor WORKER_POOL = new ThreadPoolExecutor(
+            10, 20, 30L, TimeUnit.SECONDS,
+            new LinkedBlockingQueue<>(100),
+            new ThreadFactoryBuilder().setNameFormat("AnswerWorker-%d").build(),
+            new ThreadPoolExecutor.CallerRunsPolicy());
+
+    public JPanel panel = new JPanel();
+    private CookieStore cookie;
+    static Set<String> sets = new HashSet<>();
+
+    public void init() {
+        // 创建 JFrame 实例
+        JFrame frame = new JFrame("全自动答题系统6.0.2 By 彭宇");
+        frame.setBounds(500, 250, 770, 550);
+        frame.setSize(770, 550);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        //初始化界面
+        PlaceComponents pl = new PlaceComponents();
+        panel = pl.placeComponents();
+        frame.add(panel);
+        // 设置界面可见
+        frame.setVisible(true);
+    }
+
+    /**
+     * @param loginButton,   userText, passwordText, comboBox, typeBox]
+     * @param userInfoEntity
+     * @param statrScore
+     * @param status
+     * @param pause
+     * @param lock
+     * @return void
+     * @author wangyupeng
+     * @description 登陆并开始刷题
+     * @date 2019/7/5 15:30
+     */
+    public void start(JButton loginButton, SgEntity sgEntity, UserInfoEntity userInfoEntity, JLabel statrScore, AtomicBoolean status, AtomicBoolean pause, Object lock) throws Exception {
+        if (!validateCredentials(sgEntity)){
+            return;
+        }
+        initializeSession(sgEntity);
+        updateUIComponents(loginButton, true, "努力答题中……");
+
+        log.info("当前活动线程数量:{}", Thread.activeCount());
+
+        WORKER_POOL.execute(() -> {
+            try {
+                if (status.get()) {
+                    cookie = login(sgEntity.getUserText().getText(), String.valueOf(sgEntity.getPasswordText().getPassword()));
+                    UserInfoService.getPersonalInfo(cookie, sgEntity, userInfoEntity);
+                    final String startScore = userInfoEntity.getIntegralDate().getText();
+                    statrScore.setText(startScore);
+                    anwser(cookie, sgEntity, userInfoEntity, statrScore, status, pause, lock);
+                } else {
+                    log.info("答题已结束");
+                }
+            } catch (SgException sg) {
+                log.error("答题结束:", sg);
+                JOptionPane.showMessageDialog(panel, sg.getMessage(), " stop", JOptionPane.ERROR_MESSAGE);
+                reset(loginButton, sgEntity, sg.getMessage());
+            } catch (Exception e) {
+                log.info("未知异常:", e);
+            }
+        });
+    }
+
+    public static void anwser(CookieStore cookie, SgEntity sgEntity, UserInfoEntity userInfoEntity, JLabel statrScore, AtomicBoolean status, AtomicBoolean pause, Object lock) throws Exception {
+        //当前工种选项
+        JobTypeEntity currentJobType = (JobTypeEntity) sgEntity.getComboBox().getSelectedItem();
+        if (!status.get()) {
+            return;
+        }
+        HttpClientContext httpContext = new HttpClientContext();
+        httpContext.setCookieStore(cookie);
+        //获取当前答题进度关卡
+        int gs = UserInfoService.getGKInfo(cookie, sgEntity);
+        //外层循环控制1到10关,内存循环控制对应关数多少题数
+        for (int i = 1; i <= 10; i++) {
+            if (!status.get()) {
+                log.info("结束本次刷题");
+                break;
+            }
+            sgEntity.getGkText().setText("第" + gs + "关" + "(" + sgEntity.getDifficulty() + ")");
+            sgEntity.getTextArea().setText("开始第" + gs + "关答题:");
+
+            /**获取用户历史答题关卡id*/
+            int num;
+            if (gs == 11) {
+                num = 8 + sgEntity.getGz();
+            } else if (gs == 12) {
+                num = 9 + sgEntity.getGz();
+            } else if (gs == 13) {
+                num = 10 + sgEntity.getGz();
+            } else {
+                num = gs + sgEntity.getGz();
+            }
+            log.info("当前工种:{},开始第{}关答题,答题页面id:{}", currentJobType.getJobTypeNname(), gs, num);
+            sets.add(currentJobType.getJobTypeNname().trim());
+
+            /**打开当前闯关页面(开始答题计时)*/
+            openAnswerHtml(httpContext, num);
+            //开始进行本官答题
+            for (int j = 1; j <= answerNum.get(gs) + 10; j++) {
+                if (!status.get()) {
+                    log.info("已结束本次刷题");
+                    break;
+                }
+                while (pause.get()) {
+                    sgEntity.apppendLogs(" 已暂停当前答题 ");
+                    onPause(lock, pause);
+                }
+                sgEntity.getTextArea().append(currentJobType.getJobTypeNname() + ":第" + j + "题,");
+                sgEntity.getTextArea().setCaretPosition(sgEntity.getTextArea().getText().length());
+                sgEntity.getTextArea().paintImmediately(sgEntity.getTextArea().getBounds());
+                log.info("{}====================>第{}题", currentJobType.getJobTypeNname(), j);
+
+                HttpRequestResult answeresult1;
+                int ram = new Random().nextInt(50);
+                String stem = stemList.get(ram);
+                log.info("当前随机选择数字为:{},题干为:【{}】", ram, stem);
+                /**循环答题(每2秒一次 )*/
+                HttpRequestConfig answerConfig = HttpRequestConfig.create().url(API + "cglb/ajaxdt?passid=" + num + "&" + stem).context(httpContext);
+                try {
+                    answeresult1 = HttpClientUtils.post(answerConfig);
+                } catch (IOException e) {
+                    log.error("答题超时{},重新发起请求", e);
+                    Thread.sleep(10000);
+                    answeresult1 = HttpClientUtils.post(answerConfig);
+                    log.info("重新连接成功:{}", cookie);
+                }
+                JSONObject jb;
+                try {
+                    jb = JSONObject.parseObject(answeresult1.getResponseText());
+//                    log.info("当前答题数量:{}",jb.get("isright"));
+                } catch (JSONException exception) {
+                    log.error("json解析异常{}", exception.getMessage());
+                    if (exception.getMessage().contains("重新登录")) {
+                        throw new SgException(ErrorCode.LOGOUT.getCode(), ErrorCode.LOGOUT.getName());
+                    }
+                    Thread.sleep(10000);
+                    answeresult1 = HttpClientUtils.post(answerConfig);
+                    jb = JSONObject.parseObject(answeresult1.getResponseText());
+                }
+
+                if (Integer.valueOf(jb.get("isright").toString()) == -1) {
+                    sgEntity.getTextArea().append("答题速度过快,直接进行下一题答题");
+                    continue;
+                }
+                if (Integer.valueOf(jb.get("right_num").toString()) >= answerNum.get(gs)) {
+                    log.info("当前关已答题{}道", Integer.valueOf(jb.get("right_num").toString()));
+                    break;
+                }
+                Thread.sleep(2000);
+            }
+            if (!sgEntity.getFlag()) {
+                break;
+            }
+            //进行本本关结算
+            sgEntity.getTextArea().append("开始第" + gkNum.get(gs) + "关结算");
+            sgEntity.getTextArea().paintImmediately(sgEntity.getTextArea().getBounds());
+            log.info("{} 开始第" + gkNum.get(gs) + "关结算," + "当前答题页面id:" + num + "闯关页面id:{}", currentJobType.getJobTypeNname(), sgEntity.getId());
+            log.info("当前答题工种数量:{},当前答题工种为:{}:", sets.size(), StringUtils.join(sets.toArray(), ","));
+            if (!status.get()) {
+                log.info("结束本次刷题,停止当前结算");
+                break;
+            }
+            /**对当前关卡进行结算*/
+            HttpRequestConfig answerConfig = HttpRequestConfig.create().url(API + "/cglb/passresult?passid=" + num + "&matchid=0").context(httpContext);
+            HttpRequestResult answeresult1 = HttpClientUtils.post(answerConfig);
+
+            if (StringUtils.isEmpty(answeresult1.getResponseText())) {
+                log.error("结算异常,再次发起结算请求……");
+                answeresult1 = HttpClientUtils.post(answerConfig);
+            }
+            if (answeresult1.getResponseText().contains("只差一点点")) {
+                log.error("错误题目过多,闯关失败……");
+            }
+            /**结算完成刷新个人信息答题成绩*/
+            UserInfoService.getPersonalInfo(cookie, sgEntity, userInfoEntity);
+
+            DecimalFormat df = new DecimalFormat("######0.00");
+            Double xj = Double.parseDouble(userInfoEntity.getIntegralDate().getText()) - Double.parseDouble(statrScore.getText());
+            log.info("增长分数:{}", xj);
+            sgEntity.getXjText().setText(df.format(xj));
+            sgEntity.getXjText().paintImmediately(sgEntity.getXjText().getBounds());
+//          userInfoEntity.getIntegralDate().setText(Double.parseDouble(userInfoEntity.getIntegralDate().getText())+score+"");
+            if (!ObjectUtils.isEmpty(sgEntity.getCoustomScore()) && xj >= sgEntity.getCoustomScore() && sgEntity.getCoustomScore() != 0.0) {
+                status.set(false);
+                log.info("已完成{}分刷分,如需继续请重新开始", sgEntity.getCoustomScore());
+                throw new SgException(ErrorCode.SORCE_LIMT.getCode(), ErrorCode.SORCE_LIMT.getName());
+            }
+            if (!status.get()) {
+                log.info("结束本次刷题,停止当前结算");
+                break;
+            }
+            gs++;
+            if (gs > 10) {
+                log.info("一轮答题结束");
+                break;
+            }
+        }
+        //一轮答题10关结束后,开始从第一关开始
+        if (status.get()) {
+            anwser(cookie, sgEntity, userInfoEntity, statrScore, status, pause, lock);
+        }
+    }
+
+    private static void openAnswerHtml(HttpContext httpContext, int num) throws Exception {
+        String openAnswerUrl = ApiEndpoints.START_LEVEL + "?id=" + num + "&matchid=0";
+        log.info("闯关页面请求地址:{}", openAnswerUrl);
+        HttpRequestConfig openConfig = HttpRequestConfig.create().url(openAnswerUrl).context(httpContext);
+        HttpRequestResult openResult = HttpClientUtils.post(openConfig);
+        if (StringUtils.isEmpty(openResult.getResponseText())) {
+            log.error("请求返回结果集为空");
+            throw new SgException(ErrorCode.RESULT_EMPTY.getCode(), ErrorCode.RESULT_EMPTY.getName());
+        }
+        if (openResult.getResponseText().contains("今天的闯关时间已用尽")) {
+            log.error("今天的闯关时间已用尽");
+            throw new SgException(ErrorCode.TIME_Limit.getCode(), ErrorCode.TIME_Limit.getName());
+        }
+        if (openResult.getResponseText().contains("未解锁")) {
+            log.error("当前关卡未解锁");
+            throw new SgException(ErrorCode.LEVEL_NOT_UNLOCKED.getCode(), ErrorCode.LEVEL_NOT_UNLOCKED.getName());
+        }
+    }
+
+    private static void onPause(Object lock, AtomicBoolean pause) {
+        synchronized (lock) {
+            try {
+                log.info("已暂停答题,等待线程唤醒");
+                lock.wait();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // 验证凭证方法
+    private boolean validateCredentials(SgEntity sgEntity) throws SgException {
+        String uname = Optional.ofNullable(sgEntity.getUserText())
+                .map(JTextField::getText)
+                .orElse("");
+        String pwd = Optional.ofNullable(sgEntity.getPasswordText())
+                .map(p -> new String(p.getPassword()))
+                .orElse("");
+        if (uname.isEmpty() || pwd.isEmpty()) {
+            SwingUtilities.invokeLater(() ->
+                    JOptionPane.showMessageDialog(panel, "账号密码不能为空", "错误", JOptionPane.ERROR_MESSAGE));
+           return false;
+        }
+        return true;
+    }
+
+
+    // 初始化管卡数据
+    private void initializeSession(SgEntity sgEntity) {
+        sgEntity.setFlag(true);
+        //当前工种选项
+        JobTypeEntity currentJobType = (JobTypeEntity) sgEntity.getComboBox().getSelectedItem();
+        //获取当前当前选择工种第一关关卡id
+        sgEntity.setGz(currentJobType.getGkId());
+
+        //获取当前选择难度id
+        sgEntity.setType(level.get(sgEntity.getTypeBox().getSelectedItem().toString()));
+        sgEntity.setDifficulty(sgEntity.getTypeBox().getSelectedItem().toString());
+
+        //获取当前工种id(为自动获取当前答题关卡进度做准备)
+        sgEntity.setId(currentJobType.getTypeId());
+        log.info("当前选择工种为:{},【{}】第一关id为:【{}】", currentJobType.getJobTypeNname(), sgEntity.getTypeBox().getSelectedItem().toString(), currentJobType.getGkId());
+
+        //根据难度选择计算关卡id变化
+        switch (sgEntity.getType()) {
+            case 1:
+                break;
+            case 2:
+                sgEntity.setGz(sgEntity.getGz() + 10);
+                break;
+            case 3:
+                sgEntity.setGz(sgEntity.getGz() + 20);
+                break;
+            default:
+                break;
+        }
+    }
+
+    // UI组件更新方法
+    private void updateUIComponents(JComponent component, boolean enabled, String text) {
+        SwingUtilities.invokeLater(() -> {
+            if (component instanceof AbstractButton) {
+                component.setEnabled(enabled);
+            }
+            if (component instanceof JLabel) {
+                ((JLabel) component).setText(text);
+            } else if (component instanceof JButton) {
+                ((JButton) component).setText(text);
+            }
+        });
+      }
+
+    }

+ 48 - 0
src/main/java/com/sg/answer/sg/JTextFieldHintListener.java

@@ -0,0 +1,48 @@
+package com.sg.answer.sg;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className JTextFieldHintListener
+ * @description TODO
+ * @date 2019/7/3 19:18
+ */
+public class JTextFieldHintListener  implements FocusListener {
+    private String hintText;
+    private JTextField textField;
+    public JTextFieldHintListener(JTextField jTextField,String hintText) {
+        this.textField = jTextField;
+        this.hintText = hintText;
+        //默认直接显示
+        jTextField.setText(hintText);
+        jTextField.setForeground(Color.GRAY);
+    }
+
+    @Override
+    public void focusGained(FocusEvent e) {
+        //获取焦点时,清空提示内容
+        String temp = textField.getText();
+        if(temp.equals(hintText)) {
+            textField.setText("");
+            textField.setForeground(Color.BLACK);
+        }
+
+    }
+
+    @Override
+    public void focusLost(FocusEvent e) {
+        //失去焦点时,没有输入内容,显示提示内容
+        String temp = textField.getText();
+        if (temp.equals("")) {
+            textField.setForeground(Color.GRAY);
+            textField.setText(hintText);
+        }
+
+    }
+
+}

+ 143 - 0
src/main/java/com/sg/answer/sg/SgController.java

@@ -0,0 +1,143 @@
+package com.sg.answer.sg;
+
+import com.sg.answer.utils.GetNetworkTime;
+import com.sg.answer.utils.LocalMac;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+
+import javax.swing.*;
+import java.net.InetAddress;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className SgController
+ * @description TODO
+ * @date 2019/6/28 10:43
+ */
+public class SgController {
+
+
+    /**
+     * @author wangyupeng
+     * @description 登陆
+     * @date  2019/7/5 15:40
+     * @param url, map, charset]
+     * @return org.apache.http.client.CookieStore
+     */
+    public static CookieStore doPost(String url, Map<String, String> map, String charset) {
+        CloseableHttpClient httpClient = null;
+        HttpPost httpPost = null;
+        String result = null;
+        CookieStore cookieStore = new BasicCookieStore();
+        try {
+            httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
+            httpPost = new HttpPost(url);
+            httpPost.setHeader(
+                    "User-Agent",
+                    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36");
+            List<NameValuePair> list = new ArrayList<>();
+            Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry<String, String> elem = iterator.next();
+                list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
+            }
+            if (list.size() > 0) {
+                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);
+                httpPost.setEntity(entity);
+            }
+            httpClient.execute(httpPost);
+            String HyGHnOvkdQZ0y = null;
+            String safetycode = null;
+            List<Cookie> cookies = cookieStore.getCookies();
+            for (int i = 0; i < cookies.size(); i++) {
+                if (cookies.get(i).getName().equals("BJ83T0U0lFrKq1")) {
+                    HyGHnOvkdQZ0y = cookies.get(i).getValue();
+                }
+                if (cookies.get(i).getName().equals("safetycode1")) {
+                    safetycode = cookies.get(i).getValue();
+                }
+            }
+            if (HyGHnOvkdQZ0y != null) {
+                result = "BJ83T0U0lFrKq1="+HyGHnOvkdQZ0y+";safetycode1="+safetycode;
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return cookieStore;
+    }
+    /**
+     * @author wangyupeng
+     * @description 授权认证
+     * @date  2019/7/5 15:31
+     * @return java.lang.Boolean
+     */
+    public static Boolean  auth(){
+        String mac="";
+        Boolean fac=false;
+/*        List<String> macs = new ArrayList<>();
+        macs.add("8C-EC-4B-7D-ED-1F");
+        macs.add("00-E0-4C-2F-63-44");
+        macs.add("9C-DA-3E-98-FF-49");
+        macs.add("14-DD-A9-E0-F8-16");
+        macs.add("60-EE-5C-C2-BC-7A");
+        macs.add("00-50-56-C0-00-01");
+        macs.add("8C-EC-4B-7D-ED-1F");
+        //新笔记本电脑MAC
+        macs.add("98-2C-BC-75-28-D0");
+        try {
+            InetAddress ia = InetAddress.getLocalHost();
+            mac= LocalMac.getLocalMac(ia);
+            System.out.println(ia);
+        } catch (Exception e) {
+            JOptionPane.showMessageDialog(null, "网络繁忙" ," 网络繁忙", JOptionPane.ERROR_MESSAGE);
+            e.printStackTrace();
+        }
+        System.out.println(mac);
+        if (!macs.contains(mac)){
+            JOptionPane.showMessageDialog(null, "未授权" ," 授权", JOptionPane.ERROR_MESSAGE);
+            return false;
+        }else {
+            fac=true;
+        }*/
+        try {
+            Long currentNetTime=GetNetworkTime.getWebsiteDatetimeActiveLong("http://www.taobao.com");
+            Long expireTime= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2025-06-05 00:00:00").getTime();
+            long  dayTime=360L*24L*60L*60L*1000L;
+            if (currentNetTime<=expireTime+dayTime){
+                fac=true;
+            }else {
+                fac=false;
+                JOptionPane.showMessageDialog(null, "授权时间已过期" ," 授权", JOptionPane.ERROR_MESSAGE);
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+
+        return fac;
+    }
+
+    public void setLoglevel(){
+        // 设置默认工厂类
+        System.setProperty("org.apache.commons.logging.LogFactory", "org.apache.commons.logging.impl.LogFactoryImpl");
+        // 设置日志打印类
+        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
+        //设置默认日志级别
+        LogFactory.getFactory().setAttribute("org.apache.commons.logging.simplelog.defaultlog", "error");
+        LogFactory.getFactory().setAttribute("org.apache.http.headers", "error");
+        LogFactory.getFactory().setAttribute("rg.apache.http.wire", "error");
+    }
+
+}
+

+ 27 - 0
src/main/java/com/sg/answer/sg/SgException.java

@@ -0,0 +1,27 @@
+package com.sg.answer.sg;
+
+import lombok.Data;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className SgException
+ * @description TODO
+ * @date 2019/7/5 15:52
+ */
+@Data
+public class SgException extends Exception {
+
+    private int code;
+
+    public SgException(String msg) {
+        super(msg);
+    }
+    public SgException(int code,String msg) {
+        super(msg);
+        this.code=code;
+    }
+    public SgException() {
+        super();
+    }
+}

+ 18 - 0
src/main/java/com/sg/answer/sg/answer.java

@@ -0,0 +1,18 @@
+package com.sg.answer.sg;
+
+import lombok.Data;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className answer
+ * @description TODO
+ * @date 2019/7/1 16:01
+ */
+@Data
+public class answer {
+
+   private String workName;
+
+   private String workId;
+}

+ 187 - 0
src/main/java/com/sg/answer/utils/GetNetworkTime.java

@@ -0,0 +1,187 @@
+package com.sg.answer.utils;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className GetNetworkTime
+ * @description TODO
+ * @date 2019/7/1 17:49
+ */
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * 读取网络时间
+ *
+ * @author SHANHY(365384722@QQ.COM)
+ * @date   2015年11月27日
+ */
+public class GetNetworkTime {
+
+//  public static String webUrl1 = "http://www.bjtime.cn";//bjTime
+//  public static String webUrl2 = "http://www.baidu.com";//百度
+//  public static String webUrl3 = "http://www.taobao.com";//淘宝
+//  public static String webUrl4 = "http://www.ntsc.ac.cn";//中国科学院国家授时中心
+//  public static String webUrl5 = "http://www.360.cn";//360
+//  public static String webUrl6 = "http://www.beijing-time.org";//beijing-time
+
+    public static List<String> webUrlList = new ArrayList<>();
+    static{
+        webUrlList.add("http://www.bjtime.cn");
+        webUrlList.add("http://www.baidu.com");
+        webUrlList.add("http://www.taobao.com");
+        webUrlList.add("http://www.ntsc.ac.cn");
+        webUrlList.add("http://www.360.cn");
+        webUrlList.add("http://www.beijing-time.org");
+    }
+    public static void main(String[] args) {
+        System.out.println(getWebsiteDatetime(webUrlList.get(0)) + " [bjtime]");
+        System.out.println(getWebsiteDatetime(webUrlList.get(1)) + " [百度]");
+        System.out.println(getWebsiteDatetime(webUrlList.get(2)) + " [淘宝]");
+        System.out.println(getWebsiteDatetime(webUrlList.get(3)) + " [中国科学院国家授时中心]");
+        System.out.println(getWebsiteDatetime(webUrlList.get(4)) + " [360安全卫士]");
+        System.out.println(getWebsiteDatetime(webUrlList.get(5)) + " [beijing-time]");
+        System.out.println(getWebsiteDatetimeActiveTimeStamp() + " [TimeStamp]");
+        System.out.println(getWebsiteDatetimeActiveString() + " [String]");
+        System.out.println(getWebsiteDatetimeActiveLong(webUrlList.get(5)) + " [Long]");
+        System.out.println(getWebsiteDatetimeActiveDate() + " [Date]");
+    }
+
+    /**
+     * 获取指定网站的日期时间
+     *
+     * @param webUrl
+     * @return
+     * @author SHANHY
+     * @date   2015年11月27日
+     */
+    private static String getWebsiteDatetime(String webUrl){
+        try {
+            URL url = new URL(webUrl);// 取得资源对象
+            URLConnection uc = url.openConnection();// 生成连接对象
+            uc.connect();// 发出连接
+            long ld = uc.getDate();// 读取网站日期时间
+            Date date = new Date(ld);// 转换为标准时间对象
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);// 输出北京时间
+            return sdf.format(date);
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取指定网站的日期时间
+     *
+     * @param webUrl
+     * @return  返回日期字符串
+     * @author HWJ(本人:372170989@QQ.COM,欢迎同行来一起交流努力)
+     * @date   2017年7月7日
+     */
+    public static String getWebsiteDatetimeActiveString(){
+        for (int i = 0; i < webUrlList.size(); i++) {
+            try {
+                URL url = new URL(webUrlList.get(i));// 取得资源对象
+                URLConnection uc = url.openConnection();// 生成连接对象
+                uc.connect();// 发出连接
+                long ld = uc.getDate();// 读取网站日期时间
+                Date date = new Date(ld);// 转换为标准时间对象
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);// 输出北京时间
+                return sdf.format(date);
+            } catch (MalformedURLException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取指定网站的日期时间
+     *
+     * @param webUrl
+     * @return  返回java.util.Date;
+     * @author HWJ
+     * @date   2017年7月7日
+     */
+    public static Date getWebsiteDatetimeActiveDate(){
+        for (int i = 0; i < webUrlList.size(); i++) {
+            try {
+                URL url = new URL(webUrlList.get(i));// 取得资源对象
+                URLConnection uc = url.openConnection();// 生成连接对象
+                uc.connect();// 发出连接
+                long ld = uc.getDate();// 读取网站日期时间
+                Date date = new Date(ld);// 转换为标准时间对象
+                return date;
+            } catch (MalformedURLException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取指定网站的日期时间
+     *
+     * @param webUrl
+     * @return  返回日期long类型
+     * @author HWJ
+     * @date   2017年7月7日
+     */
+    public static long getWebsiteDatetimeActiveLong(String webUrl){
+        long ld=0;
+        try {
+                URL url = new URL(webUrl);// 取得资源对象
+                URLConnection uc = url.openConnection();// 生成连接对象
+                uc.connect();// 发出连接
+                ld = uc.getDate();// 读取网站日期时间
+                return ld;
+            } catch (MalformedURLException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        return ld;
+    }
+
+
+    /**
+     * 获取指定网站的日期时间
+     *
+     * @param webUrl
+     * @return  返回日期Timestamp类型
+     * @author HWJ
+     * @date   2017年7月7日
+     */
+    public static Timestamp getWebsiteDatetimeActiveTimeStamp(){
+        for (int i = 0; i < webUrlList.size(); i++) {
+            try {
+                URL url = new URL(webUrlList.get(i));// 取得资源对象
+                URLConnection uc = url.openConnection();// 生成连接对象
+                uc.connect();// 发出连接
+                long ld = uc.getDate();// 读取网站日期时间
+                Timestamp ts = new Timestamp(ld);
+                return ts;
+            } catch (MalformedURLException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+}

+ 318 - 0
src/main/java/com/sg/answer/utils/HttpClientUtils.java

@@ -0,0 +1,318 @@
+package com.sg.answer.utils;
+
+
+import com.sg.answer.core.HttpRequestConfig;
+import com.sg.answer.core.HttpRequestMethod;
+import com.sg.answer.core.HttpRequestResult;
+import com.sg.answer.core.YtoHttpClientBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.*;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * <pre>
+ * 名称: HttpClientUtils
+ * 描述: TODO
+ * </pre>
+ *
+ * @author
+ * @since 1.0.0
+ */
+public class HttpClientUtils {
+
+    private final static Object syncLock = new Object();
+    private static final int CONNECT_TIMEOUT = 60000;
+    private static final int SOCKET_TIMEOUT = 60000;
+    private static final int CONNECT_REQUEST_TIMEOUT = 10000;
+    private static final int MAX_TOTAL = 1000;
+    private static final int MAX_PER_ROUTE = 100;
+    private static final int RETRY_TIMES = 3;
+    /**
+     * 默认采用的http协议的HttpClient对象
+     */
+    private static CloseableHttpClient httpClient;
+    /**
+     * 默认采用的https协议的HttpClient对象
+     */
+    private static CloseableHttpClient httpsClient;
+
+    /**
+     * 初始化 httpCient
+     *
+     * @param httpRequestConfig
+     */
+    private static void setHttpClinet(HttpRequestConfig httpRequestConfig) {
+
+        if (httpRequestConfig.getHttpClient() == null) {
+            if (httpRequestConfig.isUseSSL()) {
+                if (httpsClient == null) {
+                    synchronized (syncLock) {
+                        if (httpsClient == null) {
+                            httpsClient = YtoHttpClientBuilder.custom()
+                                    .ssl()
+                                    .timeout(CONNECT_TIMEOUT, SOCKET_TIMEOUT, CONNECT_REQUEST_TIMEOUT)
+                                    .pool(MAX_TOTAL, MAX_PER_ROUTE)
+                                    .retry(RETRY_TIMES, true).build();
+
+                        }
+                    }
+                }
+                httpRequestConfig.client(httpsClient);
+            } else {
+                if (httpClient == null) {
+                    synchronized (syncLock) {
+                        if (httpClient == null) {
+                            httpClient = YtoHttpClientBuilder.custom()
+                                    .timeout(CONNECT_TIMEOUT, SOCKET_TIMEOUT, CONNECT_REQUEST_TIMEOUT)
+                                    .pool(MAX_TOTAL, MAX_PER_ROUTE)
+                                    .retry(RETRY_TIMES, true).build();
+
+                        }
+                    }
+                }
+                httpRequestConfig.client(httpClient);
+            }
+        }
+    }
+
+    /**
+     * GET 请求
+     *
+     * @param httpRequestConfig 请求配置类
+     * @return 请求结果
+     * @throws IOException
+     */
+    public static HttpRequestResult get(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.GET)), httpRequestConfig);
+    }
+
+    /**
+     * POST 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult post(HttpRequestConfig httpRequestConfig) throws Exception {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.POST)), httpRequestConfig);
+    }
+
+    /**
+     * PUT 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult put(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.PUT)), httpRequestConfig);
+    }
+
+    /**
+     * HEADER 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult header(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.HEAD)), httpRequestConfig);
+    }
+
+    /**
+     * PATCH 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult patch(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.PATCH)), httpRequestConfig);
+    }
+
+    /**
+     * DELETE 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult delete(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.DELETE)), httpRequestConfig);
+    }
+
+
+    /**
+     * TRACE 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult trace(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.TRACE)), httpRequestConfig);
+    }
+
+    /**
+     * OPTIONS 请求
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static HttpRequestResult options(HttpRequestConfig httpRequestConfig) throws IOException {
+        return transformHttpRequestResult(execute(httpRequestConfig.requestMethod(HttpRequestMethod.OPTIONS)), httpRequestConfig);
+    }
+
+    /**
+     * 下载
+     *
+     * @param httpRequestConfig
+     * @return
+     * @throws IOException
+     */
+    public static OutputStream down(HttpRequestConfig httpRequestConfig) throws IOException {
+        HttpResponse response = execute(httpRequestConfig.requestMethod(HttpRequestMethod.GET));
+        response.getEntity().writeTo(HttpRequestConfig.getOut());
+        close(response);
+        return HttpRequestConfig.getOut();
+    }
+
+
+    /**
+     * 请求资源或服务
+     *
+     * @param config 请求参数配置
+     * @return 返回HttpResponse对象
+     */
+    private static HttpResponse execute(HttpRequestConfig config) throws IOException {
+
+        if (config.getRequestMethod() == null) {
+            throw new NullPointerException("request method is null!");
+        }
+
+        //设置httpClient
+        setHttpClinet(config);
+
+        //创建请求对象
+        HttpRequestBase request = getRequest(HttpRequestConfig.getUrl(), config.getRequestMethod());
+
+        //设置header信息
+        request.setHeaders(config.getHeaders());
+
+        //判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持)
+        if (HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())) {
+            //装填参数
+            HttpEntity entity = config.getEntity();
+            //设置参数到请求对象中
+            ((HttpEntityEnclosingRequestBase) request).setEntity(entity);
+
+            if (config.getParamMap().size() > 0) {
+          //      log.debug("请求参数:{}", config.getParamMap());
+            }
+
+            if (StringUtils.isNotBlank(config.getBody())) {
+             //   log.debug("请求参数:{}", config.getBody());
+            }
+
+        } else {
+            int index = HttpRequestConfig.getUrl().indexOf("?");
+            if (index > 0) {
+              //  log.debug("请求参数:{}", HttpRequestConfig.getUrl().substring(index + 1));
+            }
+        }
+        //执行请求操作,并拿到结果(同步阻塞)
+        if (config.getContext() == null) {
+            return config.getHttpClient().execute(request);
+        } else {
+            return config.getHttpClient().execute(request, config.getContext());
+        }
+
+
+    }
+
+    private static HttpRequestResult transformHttpRequestResult(HttpResponse response, HttpRequestConfig config) throws IOException {
+        //获取结果实体
+        HttpRequestResult result = new HttpRequestResult(response.getStatusLine().getStatusCode(), response.getAllHeaders());
+        if (response.getEntity() != null) {
+            //content 编码
+            String charset = (response.getEntity().getContentEncoding() == null) ? config.getResponseCharset() : response.getEntity().getContentEncoding().getValue();
+            result.setContentEncoding(charset);
+            //content 类型
+            String contentType = (response.getEntity().getContentType() == null) ? "" : response.getEntity().getContentType().getValue();
+            result.setContentType(contentType);
+            result.setResponseText(EntityUtils.toString(response.getEntity(), config.getResponseCharset()));
+        } else {//有可能是head请求
+            result.setResponseText(response.getStatusLine().toString());
+        }
+
+        close(response);
+        return result;
+    }
+
+    /**
+     * 尝试关闭
+     *
+     * @param response
+     */
+    private static void close(HttpResponse response) {
+        try {
+            EntityUtils.consume(response.getEntity());
+            if (response != null) {
+                //如果CloseableHttpResponse 是resp的父类,则支持关闭
+                if (CloseableHttpResponse.class.isAssignableFrom(response.getClass())) {
+                    ((CloseableHttpResponse) response).close();
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 根据请求方法名,获取request对象
+     *
+     * @param url    资源地址
+     * @param method 请求方式
+     * @return 返回Http处理request基类
+     */
+    private static HttpRequestBase getRequest(String url, HttpRequestMethod method) {
+        HttpRequestBase request = null;
+        switch (method.getCode()) {
+            case 0:
+                request = new HttpGet(url);
+                break;
+            case 1:
+                request = new HttpPost(url);
+                break;
+            case 2:
+                request = new HttpHead(url);
+                break;
+            case 3:
+                request = new HttpPut(url);
+                break;
+            case 4:
+                request = new HttpDelete(url);
+                break;
+            case 5:
+                request = new HttpTrace(url);
+                break;
+            case 6:
+                request = new HttpPatch(url);
+                break;
+            case 7:
+                request = new HttpOptions(url);
+                break;
+            default:
+                request = new HttpPost(url);
+                break;
+        }
+        return request;
+    }
+}

+ 38 - 0
src/main/java/com/sg/answer/utils/LocalMac.java

@@ -0,0 +1,38 @@
+package com.sg.answer.utils;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className LocalMac
+ * @description TODO
+ * @date 2019/7/1 14:33
+ */
+public class LocalMac {
+
+    public static String getLocalMac(InetAddress ia) throws SocketException {
+        //获取网卡,获取地址
+        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
+       // System.out.println("mac数组长度:"+mac.length);
+        StringBuffer sb = new StringBuffer("");
+        for(int i=0; i<mac.length; i++) {
+            if(i!=0) {
+                sb.append("-");
+            }
+            //字节转换为整数
+            int temp = mac[i]&0xff;
+            String str = Integer.toHexString(temp);
+           // System.out.println("每8位:"+str);
+            if(str.length()==1) {
+                sb.append("0"+str);
+            }else {
+                sb.append(str);
+            }
+        }
+        System.out.println("本机MAC地址:"+sb.toString().toUpperCase());
+        return sb.toString().toUpperCase();
+    }
+}

+ 42 - 0
src/main/java/com/sg/answer/utils/Md5Utils.java

@@ -0,0 +1,42 @@
+package com.sg.answer.utils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class Md5Utils {
+    public static String encryptPassword(String username, String password) {
+
+        try {
+            // 第一次MD5加密
+            MessageDigest md1 = MessageDigest.getInstance("MD5");
+            md1.update(password.getBytes());
+            byte[] digest1 = md1.digest();
+            StringBuilder sb = new StringBuilder();
+            for (byte b : digest1) {
+                sb.append(String.format("%02x", b & 0xff));
+            }
+            String md5Password1 = sb.toString();
+
+            // 拼接用户名、第一次MD5加密结果和固定字符串
+            String concatenatedString = username + md5Password1 + "BJJX@&(@LONGGANG$^#*@&#";
+
+            // 第二次MD5加密
+            MessageDigest md2 = MessageDigest.getInstance("MD5");
+            md2.update(concatenatedString.getBytes());
+            byte[] digest2 = md2.digest();
+            sb.setLength(0);
+            for (byte b : digest2) {
+                sb.append(String.format("%02x", b & 0xff));
+            }
+            String md5Password2 = sb.toString();
+
+            // 返回最终的加密结果
+            return md5Password2;
+
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+
+        return null; // 加密失败返回null
+    }
+}

+ 48 - 0
src/main/java/com/sg/answer/utils/ObjectUtils.java

@@ -0,0 +1,48 @@
+package com.sg.answer.utils;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author 王玉鹏
+ * @version 1.0
+ * @className ObjectUtils
+ * @description TODO
+ * @date 2019/6/29 9:43
+ */
+public class ObjectUtils {
+
+    public static boolean isEmpty(Object obj) {
+        if (obj == null) {
+            return true;
+        }
+
+        if (obj instanceof CharSequence) {
+            return ((CharSequence) obj).length() == 0;
+        }
+        if (obj.getClass().isArray()) {
+            return Array.getLength(obj) == 0;
+        }
+        if (obj instanceof Collection) {
+            return ((Collection) obj).isEmpty();
+        }
+        if (obj instanceof Map) {
+            return ((Map) obj).isEmpty();
+        }
+
+        // else
+        return false;
+    }
+
+    public static boolean isNumeric(String str){
+        Pattern pattern = Pattern.compile("[0-9]*");
+        Matcher isNum = pattern.matcher(str);
+        if( !isNum.matches() ){
+            return false;
+        }
+        return true;
+    }
+}

+ 26 - 0
src/main/java/com/sg/answer/utils/SgUtils.java

@@ -0,0 +1,26 @@
+package com.sg.answer.utils;
+
+import com.sg.answer.core.HttpRequestConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.protocol.HttpContext;
+
+@Slf4j
+public class SgUtils {
+    public static String executeRemotePostRequest(CookieStore cookie, String url) throws Exception {
+        log.info("请求url:{}", url);
+        HttpContext context = createHttpContext(cookie);
+        HttpRequestConfig config = HttpRequestConfig.create()
+                .url(url)
+                .context(context);
+
+        return HttpClientUtils.post(config).getResponseText();
+    }
+
+    private static HttpContext createHttpContext(CookieStore cookieStore) {
+        HttpClientContext context = new HttpClientContext();
+        context.setCookieStore(cookieStore);
+        return context;
+    }
+}

+ 84 - 0
src/main/resource/logback.xml

@@ -0,0 +1,84 @@
+<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
+<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
+<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
+<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
+<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
+<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 子节点<property> :用来定义变量值,它有两个属性name和value,通过<property>定义的值会被插入到logger上下文中,可以使“${}”来使用变量。-->
+    <property name="LOG_HOME" value="${user.dir}/logs/answer" />
+
+    <!--子节点<appender>:负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名-->
+    <!-- ConsoleAppender 控制台输出日志 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <!-- 设置日志输出格式 -->
+            <pattern>[%d{yyyy/MM/dd HH:mm:ss.SSS}][%thread][%p][%logger{0}:%L] %m%n</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+
+
+    <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:-->
+    <!--      <file>:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。-->
+    <!--      <append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。-->
+    <!--      <rollingPolicy>:当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类-->
+    <!--      class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy": 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。有以下子节点:-->
+    <!--        <fileNamePattern>:必要节点,包含文件名及“%d”转换符,“%d”可以包含一个java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。-->
+    <!--如果直接使用 %d,默认格式是 yyyy-MM-dd。RollingFileAppender的file字节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file指定的文件(活动文件),活动文件的名字不会改变;-->
+    <!--如果没设置file,活动文件的名字会根据fileNamePattern 的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。-->
+    <!--        <maxHistory>:-->
+    <!--可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,且<maxHistory>是6,则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。-->
+
+    <!--      class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy": 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动。只有一个节点:-->
+    <!--        <maxFileSize>:这是活动文件的大小,默认值是10MB。-->
+    <!--        <prudent>:当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空。-->
+
+    <!--      <triggeringPolicy >: 告知 RollingFileAppender 合适激活滚动。-->
+    <!--      class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy" 根据固定窗口算法重命名文件的滚动策略。有以下子节点:-->
+    <!--        <minIndex>:窗口索引最小值-->
+    <!--        <maxIndex>:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。-->
+    <!--        <fileNamePattern>:必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如,mylog%i.log.gz 或者 没有log%i.log.zip-->
+    <appender name="LogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/answer.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/answer.log.%d{yyyy-MM-dd}</fileNamePattern>
+        </rollingPolicy>
+        <!-- <encoder>:对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。-->
+        <!-- PatternLayoutEncoder 是唯一有用的且默认的encoder ,有一个<pattern>节点,用来设置日志的输入格式。使用“%”加“转换符”方式,如果要输出“%”,则必须用“\”对“\%”进行转义。-->
+        <encoder>
+            <pattern>%p %d{yyyy-MM-dd HH:mm:ss} {%thread} %logger - %m%n</pattern>
+        </encoder>
+    </appender>
+
+<!--    <appender name="PokerMqListenerLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/mq/poker-mq.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/mq/poker-mq.log.%d{yyyy-MM-dd}</fileNamePattern>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%p %d{yyyy-MM-dd HH:mm:ss} %logger - %m%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="com.jd.station.soa.message.listener.PokerActivityInfoMqListener" level="INFO" additivity="false">
+        <appender-ref ref="PokerMqListenerLogFile"/>
+    </logger>-->
+
+    <logger name="jdbc.sqltiming" level="info"/>
+    <logger name="com.ibatis" level="info" />
+    <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="info" />
+    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="info" />
+    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="info" />
+    <logger name="java.sql.Connection" level="info" />
+    <logger name="java.sql.Statement" level="info" />
+    <logger name="java.sql.PreparedStatement" level="info" />
+    <logger name="java.sql.ResultSet" level="info" />
+
+    <root level="INFO">
+        <appender-ref ref="console" />
+        <appender-ref ref="LogFile" />
+    </root>
+
+</configuration>

+ 20 - 0
src/test/java/com/sg/answer/AppTest.java

@@ -0,0 +1,20 @@
+package com.sg.answer;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Unit test1 1for simple App.
+ */
+public class AppTest 
+{
+    /**
+     * Rigorous Test :-)
+     */
+    @Test
+    public void shouldAnswerWithTrue()
+    {
+        assertTrue( true );
+    }
+}

+ 267 - 0
src/test/java/com/sg/answer/test.java

@@ -0,0 +1,267 @@
+package com.sg.answer;
+
+import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class test extends JFrame {
+
+	private JPanel contentPane;
+	private JTextField textField;
+	private JTextField textField_1;
+	private JTextField textField_2;
+
+	/**
+	 * Launch the application.
+	 */
+	public static void main(String[] args) {
+
+		try {
+			BeautyEyeLNFHelper.launchBeautyEyeLNF();
+			UIManager.put("RootPane.setupButtonVisible", false);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		EventQueue.invokeLater(new Runnable() {
+			public void run() {
+				try {
+					test frame = new test();
+					frame.setVisible(true);
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		});
+	}
+
+	/**
+	 * Create the frame.
+	 */
+	public test() throws MalformedURLException {
+		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		setBounds(100, 100, 803, 639);
+		contentPane = new JPanel();
+		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+		setContentPane(contentPane);
+		
+		JButton btnNewButton = new JButton("结束");
+		
+		JLabel lblNewLabel = new JLabel("用户名");
+		
+		JTextArea textArea = new JTextArea();
+		textArea.setText("日志");
+		textArea.setBackground(Color.BLACK);
+		textArea.setForeground(Color.GREEN);
+		
+		textField = new JTextField();
+		textField.setColumns(10);
+		
+		textField_1 = new JTextField();
+		textField_1.setColumns(10);
+		
+		JLabel label = new JLabel("密码");
+		
+		JButton button = new JButton("登陆");
+		
+		JLabel label_1 = new JLabel("工种");
+		
+		JComboBox comboBox = new JComboBox();
+		
+		JLabel label_2 = new JLabel("难度");
+		
+		JComboBox comboBox_1 = new JComboBox();
+		
+		JLabel label_3 = new JLabel("当前关卡:");
+		
+		JLabel label_4 = new JLabel("默认为第一关");
+		label_4.setForeground(Color.RED);
+		
+		JLabel label_5 = new JLabel("当前刷分小计:");
+		
+		JLabel label_6 = new JLabel("0");
+		label_6.setForeground(Color.GREEN);
+		
+		JLabel label_7 = new JLabel("姓名:");
+		
+		JLabel label_8 = new JLabel("工种:");
+		
+		JLabel label_9 = new JLabel("工号:");
+		
+		JLabel label_10 = new JLabel("积分:");
+		
+		JLabel label_11 = new JLabel("金币:");
+		
+		JLabel lblNewLabel_1 = new JLabel("py");
+		
+		JLabel label_12 = new JLabel("001");
+		
+		JLabel label_13 = new JLabel("001");
+		
+		JLabel label_14 = new JLabel("0");
+		
+		JLabel label_15 = new JLabel("0");
+		
+		JLabel label_16 = new JLabel("自定义分数:");
+		
+		textField_2 = new JTextField();
+		textField_2.setColumns(10);
+		
+		JButton button_1 = new JButton("开始");
+		
+		JLabel label_17 = new JLabel("本次刷分初始分数:");
+		
+		JLabel label_18 = new JLabel("25000");
+		
+		JLabel lblNewLabel_2 = new JLabel("本次刷分总增长分数:");
+		
+		JLabel label_19 = new JLabel("500");
+		URL url= new URL("http://pic1.win4000.com/pic/9/75/1a9b924550.jpg");
+		ImageIcon imageIcon = new ImageIcon(url);
+		JLabel lblNewLabel_3 = new JLabel();
+
+		imageIcon.setImage(imageIcon.getImage().getScaledInstance(220,90,Image.SCALE_DEFAULT));
+		lblNewLabel_3.setIcon(imageIcon);
+		GroupLayout gl_contentPane = new GroupLayout(contentPane);
+		gl_contentPane.setHorizontalGroup(
+				gl_contentPane.createParallelGroup(Alignment.LEADING)
+						.addGroup(gl_contentPane.createSequentialGroup()
+								.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+										.addGroup(gl_contentPane.createSequentialGroup()
+												.addGap(35)
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING, false)
+														.addComponent(textArea, GroupLayout.PREFERRED_SIZE, 697, GroupLayout.PREFERRED_SIZE)
+														.addGroup(gl_contentPane.createSequentialGroup()
+																.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+																		.addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 94, GroupLayout.PREFERRED_SIZE)
+																		.addComponent(label)
+																		.addComponent(label_1)
+																		.addComponent(label_2)
+																		.addComponent(label_3))
+																.addPreferredGap(ComponentPlacement.RELATED)
+																.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+																		.addComponent(label_4)
+																		.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+																		.addComponent(textField_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+																		.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+																		.addComponent(comboBox_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+																.addGap(70)
+																.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_11)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_15))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_10)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_14))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_9)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_13))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_5)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_6))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_8)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(label_12))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_7)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(lblNewLabel_1)))
+																.addGap(31)
+																.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING, false)
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addComponent(label_16)
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addComponent(textField_2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+																				.addGap(18)
+																				.addComponent(button_1))
+																		.addGroup(gl_contentPane.createSequentialGroup()
+																				.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+																						.addComponent(label_17)
+																						.addComponent(lblNewLabel_2))
+																				.addPreferredGap(ComponentPlacement.RELATED)
+																				.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+																						.addComponent(label_19)
+																						.addComponent(label_18)))
+																		.addComponent(lblNewLabel_3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+										.addGroup(gl_contentPane.createSequentialGroup()
+												.addGap(53)
+												.addComponent(button)
+												.addGap(18)
+												.addComponent(btnNewButton)))
+								.addContainerGap(45, Short.MAX_VALUE))
+		);
+		gl_contentPane.setVerticalGroup(
+				gl_contentPane.createParallelGroup(Alignment.LEADING)
+						.addGroup(gl_contentPane.createSequentialGroup()
+								.addGap(62)
+								.addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING)
+										.addGroup(gl_contentPane.createSequentialGroup()
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+														.addComponent(label_3)
+														.addComponent(label_4)
+														.addComponent(label_5)
+														.addComponent(label_6))
+												.addGap(18)
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+														.addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 31, GroupLayout.PREFERRED_SIZE)
+														.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+														.addComponent(label_7)
+														.addComponent(lblNewLabel_1))
+												.addPreferredGap(ComponentPlacement.UNRELATED)
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+														.addComponent(textField_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+														.addComponent(label)
+														.addComponent(label_8)
+														.addComponent(label_12))
+												.addPreferredGap(ComponentPlacement.UNRELATED)
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+														.addComponent(label_1)
+														.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+														.addComponent(label_9)
+														.addComponent(label_13))
+												.addGap(9))
+										.addGroup(gl_contentPane.createSequentialGroup()
+												.addComponent(lblNewLabel_3, GroupLayout.DEFAULT_SIZE, 92, Short.MAX_VALUE)
+												.addGap(18)
+												.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+														.addComponent(lblNewLabel_2)
+														.addComponent(label_19))
+												.addPreferredGap(ComponentPlacement.UNRELATED)))
+								.addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING)
+										.addComponent(label_2)
+										.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+												.addComponent(comboBox_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+												.addComponent(label_10)
+												.addComponent(label_14)
+												.addComponent(label_17)
+												.addComponent(label_18)))
+								.addGap(18)
+								.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
+										.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+												.addComponent(button)
+												.addComponent(btnNewButton))
+										.addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE)
+												.addComponent(label_15)
+												.addComponent(label_16)
+												.addComponent(textField_2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+												.addComponent(button_1)
+												.addComponent(label_11)))
+								.addGap(18)
+								.addComponent(textArea, GroupLayout.PREFERRED_SIZE, 214, GroupLayout.PREFERRED_SIZE)
+								.addContainerGap(99, Short.MAX_VALUE))
+		);
+		contentPane.setLayout(gl_contentPane);
+	}
+}