martin 3 年 前
コミット
7f71a38710
57 ファイル変更2668 行追加0 行削除
  1. 44 0
      api-common/pom.xml
  2. 35 0
      api-common/src/main/java/api/common/pojo/common/CommonPO.java
  3. 17 0
      api-common/src/main/java/api/common/pojo/common/PageVO.java
  4. 68 0
      api-common/src/main/java/api/common/pojo/common/ResponseBodyVO.java
  5. 16 0
      api-common/src/main/java/api/common/pojo/common/SimulationTokenVO.java
  6. 26 0
      api-common/src/main/java/api/common/pojo/po/UserPO.java
  7. 78 0
      api-common/src/main/java/api/common/util/CollectionUtil.java
  8. 46 0
      api-common/src/main/java/api/common/util/EncryptUtil.java
  9. 194 0
      api-common/src/main/java/api/common/util/HttpUtil.java
  10. 156 0
      api-common/src/main/java/api/common/util/JsonUtil.java
  11. 205 0
      pom.xml
  12. 41 0
      simulation-gateway/pom.xml
  13. 13 0
      simulation-gateway/src/main/java/com/css/simulation/gateway/SimulationGatewayApplication.java
  14. 28 0
      simulation-gateway/src/main/java/com/css/simulation/gateway/configuration/MyCorsConfiguration.java
  15. 30 0
      simulation-gateway/src/main/resources/bootstrap.yml
  16. 14 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/SimulationOauthClientApplication.java
  17. 30 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/http/HttpConfiguration.java
  18. 28 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/oauth/OauthParameter.java
  19. 15 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SignInController.java
  20. 138 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SingleSignOnController.java
  21. 138 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/TestSingleSignOnController.java
  22. 50 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/mapper/UserMapper.java
  23. 17 0
      simulation-oauth-client/src/main/resources/bootstrap.yaml
  24. 99 0
      simulation-oauth-server/pom.xml
  25. 16 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/SimulationOauthServerApplication.java
  26. 21 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyCodeService.java
  27. 37 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyTokenService.java
  28. 31 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyTokenStore.java
  29. 98 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/OauthAuthorizationServerConfiguration.java
  30. 84 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/redis/RedisTemplateConfiguration.java
  31. 19 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyPasswordEncoder.java
  32. 55 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyUserDetails.java
  33. 26 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyUserDetailsService.java
  34. 23 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/SecurityConfiguration.java
  35. 30 0
      simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/mapper/UserMapper.java
  36. 15 0
      simulation-oauth-server/src/main/resources/bootstrap.yaml
  37. 97 0
      simulation-resource-scheduler/pom.xml
  38. 16 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/SimulationResourceSchedulerApplication.java
  39. 24 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/PodController.java
  40. 26 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/TaskController.java
  41. 28 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/JobMapper.java
  42. 23 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/TaskMapper.java
  43. 25 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/CameraDTO.java
  44. 11 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/DynamicsDTO.java
  45. 16 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/InfoDTO.java
  46. 11 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/ModelDTO.java
  47. 29 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/OgtDTO.java
  48. 14 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/ScenarioDTO.java
  49. 15 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/SensorsDTO.java
  50. 124 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/TaskDTO.java
  51. 16 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/VehicleDTO.java
  52. 25 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/JobPO.java
  53. 19 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/TaskPO.java
  54. 81 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/scheduler/JobScheduler.java
  55. 15 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/PodService.java
  56. 17 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/TaskService.java
  57. 55 0
      simulation-resource-scheduler/src/main/resources/bootstrap.yml

+ 44 - 0
api-common/pom.xml

@@ -0,0 +1,44 @@
+<?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">
+    <parent>
+        <artifactId>simulation-cloud</artifactId>
+        <groupId>com.css</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>api-common</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- http 客户端 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+        <!-- lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <!-- web 服务 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 35 - 0
api-common/src/main/java/api/common/pojo/common/CommonPO.java

@@ -0,0 +1,35 @@
+package api.common.pojo.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.sql.Timestamp;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CommonPO {
+
+    /**
+     * 记录创建时间
+     */
+    public Timestamp createTime;
+    /**
+     * 记录最后更新时间(包括删除)
+     */
+    public Timestamp modifyTime;
+    /**
+     * 记录创建人(用户id)
+     */
+    public String createUserId;
+    /**
+     * 记录最后更新人(包括删除)(用户id)
+     */
+    public String modifyUserId;
+    /**
+     * 是否已删除
+     */
+    public String isDeleted;
+
+}

+ 17 - 0
api-common/src/main/java/api/common/pojo/common/PageVO.java

@@ -0,0 +1,17 @@
+package api.common.pojo.common;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class PageVO {
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer pageNum;
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer pageSize;
+
+}

+ 68 - 0
api-common/src/main/java/api/common/pojo/common/ResponseBodyVO.java

@@ -0,0 +1,68 @@
+package api.common.pojo.common;
+
+import lombok.*;
+
+/**
+ * @author martin
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ResponseBodyVO<T> {
+
+    // -------------------------------- Comment --------------------------------
+
+    private boolean status;
+    private int code;
+    private String message;
+    private T info;
+
+    // -------------------------------- Comment --------------------------------
+
+    public ResponseBodyVO(Response response) {
+        this.status = response.isStatus();
+        this.code = response.getCode();
+        this.message = response.getMessage();
+    }
+
+    public ResponseBodyVO(Response response, String message) {
+        this.status = response.isStatus();
+        this.code = response.getCode();
+        this.message = message;
+    }
+
+    public ResponseBodyVO(Response response, T info) {
+        this.status = response.isStatus();
+        this.code = response.getCode();
+        this.message = response.getMessage();
+        this.info = info;
+    }
+
+    public ResponseBodyVO(Response response, String message, T info) {
+        this.status = response.isStatus();
+        this.code = response.getCode();
+        this.message = message;
+        this.info = info;
+    }
+
+    /**
+     * 响应信息常量类
+     *
+     * @author martin
+     */
+    @ToString
+    @AllArgsConstructor(access = AccessLevel.PRIVATE)   // 枚举的构造方法默认就是 private,可以省略 access 属性。
+    @Getter
+    public enum Response {
+
+        SUCCESS(true, 200, "请求成功!"),
+        CLIENT_FAILURE(false, 400, "请求参数错误!"),
+        SERVER_FAILURE(false, 500, "服务器错误!");
+
+        private final boolean status;       // 成功或失败
+        private final int code;             // 状态码
+        private final String message;       // 信息
+
+    }
+
+}

+ 16 - 0
api-common/src/main/java/api/common/pojo/common/SimulationTokenVO.java

@@ -0,0 +1,16 @@
+package api.common.pojo.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SimulationTokenVO {
+    private String access_token;
+    private String token_type;
+    private String refresh_token;
+    private String expires_in;
+    private String scope;
+}

+ 26 - 0
api-common/src/main/java/api/common/pojo/po/UserPO.java

@@ -0,0 +1,26 @@
+package api.common.pojo.po;
+
+import api.common.pojo.common.CommonPO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 用户。
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserPO extends CommonPO implements Serializable {
+
+    private String id;              // 用户主键(唯一)
+    private String username;        // 登录用户名
+    private String nickname;        // 用户昵称,用于显示
+    private String password;        // 密码(加密)
+    private String isDeleted = "0";
+
+}

+ 78 - 0
api-common/src/main/java/api/common/util/CollectionUtil.java

@@ -0,0 +1,78 @@
+package api.common.util;
+
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class CollectionUtil {
+
+    // -------------------------------- A --------------------------------
+    public static <T> List<T> arrayToList(T[] array) {
+        return Arrays.asList(array);
+    }
+
+    // -------------------------------- B --------------------------------
+    // -------------------------------- C --------------------------------
+    @SafeVarargs
+    public static <T> ArrayList<T> createArrayList(T... elements) {
+        return new ArrayList<>(Arrays.asList(elements));
+    }
+
+    // -------------------------------- D --------------------------------
+    // -------------------------------- F --------------------------------
+
+    /**
+     * 根据过滤条件来过滤列表
+     *
+     * @param arrayList 原始列表
+     * @param predicate 过滤条件的 lambda 表达式,a-> a.getColor().equals("red") && a.getWeight() > 300
+     * @param <T>       声明为泛型方法
+     * @return 结果列表
+     */
+    public static <T> List<T> filterList(List<T> arrayList, Predicate<? super T> predicate) {
+        return arrayList.stream().filter(predicate).collect(Collectors.toList());
+    }
+
+    // -------------------------------- G --------------------------------
+    // -------------------------------- H --------------------------------
+    // -------------------------------- I --------------------------------
+    public static boolean isEmpty(Collection<?> collection) {
+        return collection == null || collection.isEmpty();
+    }
+
+    public static boolean isEmpty(Map<?, ?> map) {
+        return map == null || map.isEmpty();
+    }
+
+    public static boolean isNotEmpty(Collection<?> collection) {
+        return !isEmpty(collection);
+    }
+
+    public static boolean isNotOne(Collection<?> collection) {
+        return isEmpty(collection) || collection.size() > 1;
+    }
+
+    public static boolean isNotEmpty(Map<?, ?> map) {
+        return !isEmpty(map);
+    }
+
+    // -------------------------------- J --------------------------------
+    // -------------------------------- K --------------------------------
+    // -------------------------------- L --------------------------------
+    // -------------------------------- M --------------------------------
+    // -------------------------------- N --------------------------------
+    // -------------------------------- O --------------------------------
+    // -------------------------------- P --------------------------------
+    // -------------------------------- Q --------------------------------
+    // -------------------------------- R --------------------------------
+    // -------------------------------- S --------------------------------
+    // -------------------------------- T --------------------------------
+    // -------------------------------- U --------------------------------
+    // -------------------------------- V --------------------------------
+    // -------------------------------- W --------------------------------
+    // -------------------------------- X --------------------------------
+    // -------------------------------- Y --------------------------------
+    // -------------------------------- Z --------------------------------
+
+
+}

+ 46 - 0
api-common/src/main/java/api/common/util/EncryptUtil.java

@@ -0,0 +1,46 @@
+package api.common.util;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class EncryptUtil {
+
+    /**
+     * 获得MD5加密字符串(32位大写)
+     */
+    public static String getUpperMD5(String plainText) throws NoSuchAlgorithmException {
+        byte[] hash;
+        //创建一个MD5算法对象,并获得MD5字节数组,16*8=128位
+        hash = MessageDigest.getInstance("MD5").digest(plainText.getBytes(StandardCharsets.UTF_8));
+
+        //转换为十六进制字符串
+        StringBuilder hex = new StringBuilder(hash.length * 2);
+        for (byte b : hash) {
+            if ((b & 0xFF) < 0x10) {
+                hex.append("0");
+            }
+            hex.append(Integer.toHexString(b & 0xFF));
+        }
+        return hex.toString().toUpperCase();
+    }
+
+    /**
+     * 获得MD5加密字符串(32位小写)
+     */
+    public static String getLowerMD5(String plainText) throws NoSuchAlgorithmException {
+        byte[] hash;
+        //创建一个MD5算法对象,并获得MD5字节数组,16*8=128位
+        hash = MessageDigest.getInstance("MD5").digest(plainText.getBytes(StandardCharsets.UTF_8));
+
+        //转换为十六进制字符串
+        StringBuilder hex = new StringBuilder(hash.length * 2);
+        for (byte b : hash) {
+            if ((b & 0xFF) < 0x10) {
+                hex.append("0");
+            }
+            hex.append(Integer.toHexString(b & 0xFF));
+        }
+        return hex.toString().toLowerCase();
+    }
+}

+ 194 - 0
api-common/src/main/java/api/common/util/HttpUtil.java

@@ -0,0 +1,194 @@
+package api.common.util;
+
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.springframework.boot.configurationprocessor.json.JSONException;
+import org.springframework.boot.configurationprocessor.json.JSONObject;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * <dependency>
+ * <groupId>org.apache.httpcomponents</groupId>
+ * <artifactId>httpclient</artifactId>
+ * <version>${http.client.version}</version>
+ * </dependency>
+ *
+ * @author martin
+ */
+public class HttpUtil {
+
+//    private static final CloseableHttpClient httpClient;
+//    private static final RequestConfig requestConfig = RequestConfig.custom()
+//            .setSocketTimeout(5000)
+//            .setConnectTimeout(5000)
+//            .setConnectionRequestTimeout(5000)
+//            .setRedirectsEnabled(false)
+//            .setExpectContinueEnabled(false)
+//            .build();
+//
+//    static {
+//        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
+//        pool.setMaxTotal(300);
+//        pool.setDefaultMaxPerRoute(300);
+//        httpClient = HttpClients.custom().setConnectionManager(pool).build();
+//    }
+
+    /**
+     * get 请求的参数在 url 里
+     */
+    public static JSONObject get(CloseableHttpClient httpClient, RequestConfig requestConfig, String url, Map<String, String> headers) throws Exception {
+        //1 创建 post 请求
+        HttpGet get = new HttpGet(url);
+        //2 设置请求默认配置
+        get.setConfig(requestConfig);
+        //3 设置请求头 post.setHeader("Content-type", "application/json; charset=utf-8");
+        if (!CollectionUtil.isEmpty(headers)) {
+            headers.forEach(get::setHeader);
+        }
+        //4 发送请求
+        CloseableHttpResponse response = httpClient.execute(get);
+        //5 处理返回结果,
+        //5-1 如果状态码为200,就是正常返回
+        if (response.getStatusLine().getStatusCode() == 200) {
+            String result = EntityUtils.toString(response.getEntity());
+            return new JSONObject(result);
+            //如果是下载文件,可以用response.getEntity().getContent()返回InputStream
+        } else {
+            throw new Exception("服务器错误!");
+        }
+    }
+
+    /**
+     * 通过 get 请求下载文件到本地
+     * 发送 get 请求,get 请求的参数在 url 里
+     *
+     * @param url           请求地址
+     * @param headers       请求头,可为 null
+     * @param localFilePath 本地保存的文件路径
+     * @throws IOException   异常
+     * @throws JSONException 异常
+     */
+    public static InputStream get(CloseableHttpClient httpClient, RequestConfig requestConfig,String url, Map<String, String> headers, String localFilePath) throws IOException, JSONException {
+        //1 创建 post 请求
+        HttpGet get = new HttpGet(url);
+        //2 设置请求默认配置
+        get.setConfig(requestConfig);
+        //3 设置请求头 post.setHeader("Content-type", "application/json; charset=utf-8");
+        if (!CollectionUtil.isEmpty(headers)) {
+            headers.forEach(get::setHeader);
+        }
+        //4 发送请求
+        CloseableHttpResponse response = httpClient.execute(get);
+        //5 处理返回结果,
+        //5-1 如果状态码为200,就是正常返回
+        if (response.getStatusLine().getStatusCode() == 200) {
+            //如果是下载文件,可以用response.getEntity().getContent()返回InputStream
+            return response.getEntity().getContent();
+        } else {
+            throw new RuntimeException("服务器错误!");
+        }
+    }
+
+    /**
+     * 发送 post 请求
+     */
+    public static JSONObject post(CloseableHttpClient httpClient, RequestConfig requestConfig,String url, Map<String, String> headers, Map<String, String> params) throws Exception {
+        //1 创建 post 请求
+        HttpPost post = new HttpPost(url);
+        //2 设置请求默认配置
+        post.setConfig(requestConfig);
+        //3 设置请求头 post.setHeader("Content-type", "application/json; charset=utf-8");
+        if (!CollectionUtil.isEmpty(headers)) {
+            headers.forEach(post::setHeader);
+        }
+        //4 设置请求体
+        if (!CollectionUtil.isEmpty(params)) {
+            params.forEach(post::setHeader);
+        }
+        //5 发送请求
+        CloseableHttpResponse response = httpClient.execute(post);
+        //6 处理返回结果,
+        //6-1 如果状态码为200,就是正常返回
+        if (response.getStatusLine().getStatusCode() == 200) {
+            String result = EntityUtils.toString(response.getEntity());
+            return new JSONObject(result);
+            //如果是下载文件,可以用response.getEntity().getContent()返回InputStream
+        } else {
+            throw new Exception("服务器错误!");
+        }
+    }
+
+    /**
+     * 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
+     * <p>
+     * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
+     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
+     * <p>
+     * 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
+     * 192.168.1.100
+     * <p>
+     * 用户真实IP为: 192.168.1.110
+     */
+    public static String getIpAddress(HttpServletRequest request) {
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+        return ip;
+    }
+
+
+    public static void setResponseForError(HttpServletResponse response) {
+        response.setContentType("application/json");
+    }
+
+    /**
+     * 读取上传的文件流到 String
+     */
+    public static String getUploadFileString(MultipartFile multipartFile) throws IOException {
+        // 读取流文件
+        InputStream inputStream = multipartFile.getInputStream();
+        // 防止路径乱码   如果utf-8 乱码  改GBK     eclipse里创建的txt  用UTF-8,在电脑上自己创建的txt  用GBK
+        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
+        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+
+        // 设置一个接收的String
+        StringBuilder stringBuffer = new StringBuilder();
+        String line;
+        while ((line = bufferedReader.readLine()) != null) {
+            stringBuffer.append(line);
+        }
+        String str = stringBuffer.toString();
+        bufferedReader.close();
+        inputStreamReader.close();
+        inputStream.close();
+        return str;
+    }
+
+
+}

+ 156 - 0
api-common/src/main/java/api/common/util/JsonUtil.java

@@ -0,0 +1,156 @@
+package api.common.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.boot.configurationprocessor.json.JSONArray;
+import org.springframework.boot.configurationprocessor.json.JSONException;
+import org.springframework.boot.configurationprocessor.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JsonUtil {
+
+    // -------------------------------- A --------------------------------
+    // -------------------------------- B --------------------------------
+
+    /**
+     * bean 转成 json
+     *
+     * @param bean bean 对象
+     * @param <T>  声明为泛型方法
+     * @return json 字符串
+     * @throws JsonProcessingException 异常
+     */
+    public static <T> String beanToJson(T bean) throws JsonProcessingException {
+        return new ObjectMapper().writeValueAsString(bean);
+    }
+    // -------------------------------- C --------------------------------
+    // -------------------------------- D --------------------------------
+    // -------------------------------- F --------------------------------
+    // -------------------------------- G --------------------------------
+    // -------------------------------- H --------------------------------
+    // -------------------------------- I --------------------------------
+    // -------------------------------- J --------------------------------
+
+    /**
+     * json 转成 JSONObject
+     *
+     * @param json json 字符串
+     * @return JSONObject 对象
+     * @throws JSONException 异常
+     */
+    public static JSONObject jsonToJSONObject(String json) throws JSONException {
+        return new JSONObject(json);
+    }
+
+    /**
+     * json 转成 bean
+     *
+     * @param json   json 字符串
+     * @param tClass 返回值类型
+     * @param <T>    声明为泛型方法
+     * @return bean 对象
+     * @throws JsonProcessingException 异常
+     */
+    public static <T> T jsonToBean(String json, Class<T> tClass) throws JsonProcessingException {
+        return new ObjectMapper().readValue(json, tClass);
+    }
+
+    /**
+     * JSONObject 转成 bean
+     *
+     * @param jsonObject   jsonObject 对象
+     * @param tClass 返回值类型
+     * @param <T>    声明为泛型方法
+     * @return bean 对象
+     */
+    public static <T> T jsonObjectToBean(JSONObject jsonObject, Class<T> tClass) throws JsonProcessingException {
+        return new ObjectMapper().readValue(jsonObject.toString(), tClass);
+    }
+
+    /**
+     * json 转成 list
+     *
+     * @param arrayJson    json 数组字符串
+     * @param elementClass 列表元素类型
+     * @param <E>          声明为泛型方法
+     * @return 结果列表
+     * @throws JsonProcessingException 异常
+     */
+    public static <E> List<E> jsonToList(String arrayJson, Class<E> elementClass) throws JsonProcessingException, JSONException {
+        List<E> resultList = new ArrayList<>();
+        JSONArray jsonArray = new JSONArray(arrayJson);
+        for (int i = 0; i < jsonArray.length(); i++) {
+            JSONObject jsonObject = jsonArray.getJSONObject(i);
+            String beanJson = jsonObject.toString();
+            E element = jsonToBean(beanJson, elementClass);
+            resultList.add(element);
+        }
+        return resultList;
+    }
+
+//    /**
+//     * json 字符串转成 info 为 list 的 result
+//     *
+//     * @param json         json 字符串
+//     * @param elementClass 列表元素类型
+//     * @param <E>          声明为泛型方法
+//     * @return result 对象
+//     * @throws JsonProcessingException 异常
+//     */
+//    public static <E> Result<List<E>> jsonToResultWithListInfo(String json, Class<E> elementClass) throws JsonProcessingException, JSONException {
+//        Result<?> temporaryResult = jsonToBean(json, Result.class);
+//        String infoJson = beanToJson(temporaryResult.getInfo());
+//        List<E> infoList = jsonToList(infoJson, elementClass);
+//        Result<List<E>> finalResult = new Result<>();
+//        finalResult.setCode(temporaryResult.getCode());
+//        finalResult.setMessage(temporaryResult.getMessage());
+//        finalResult.setInfo(infoList);
+//        return finalResult;
+//    }
+//
+//    /**
+//     * json 字符串转成 info 为 list 的 result
+//     *
+//     * @param jsonObject   JSONObject 对象
+//     * @param elementClass 列表元素类型
+//     * @param <E>          声明为泛型方法
+//     * @return result 对象
+//     * @throws JsonProcessingException 异常
+//     */
+//    public static <E> Result<List<E>> jsonObjectToResultWithListInfo(JSONObject jsonObject, Class<E> elementClass) throws JsonProcessingException, JSONException {
+//        String json = jsonObject.toString();
+//        return jsonToResultWithListInfo(json, elementClass);
+//    }
+    // -------------------------------- K --------------------------------
+    // -------------------------------- L --------------------------------
+
+    /**
+     * bean 转成 json
+     *
+     * @param list 列表对象
+     * @param <T>  声明为泛型方法
+     * @return json 字符串
+     * @throws JsonProcessingException 异常
+     */
+    public static <T> String listToJson(T list) throws JsonProcessingException {
+        return new ObjectMapper().writeValueAsString(list);
+    }
+
+    // -------------------------------- M --------------------------------
+    // -------------------------------- N --------------------------------
+    // -------------------------------- O --------------------------------
+    // -------------------------------- P --------------------------------
+    // -------------------------------- Q --------------------------------
+    // -------------------------------- R --------------------------------
+    // -------------------------------- S --------------------------------
+    // -------------------------------- T --------------------------------
+    // -------------------------------- U --------------------------------
+    // -------------------------------- V --------------------------------
+    // -------------------------------- W --------------------------------
+    // -------------------------------- X --------------------------------
+    // -------------------------------- Y --------------------------------
+    // -------------------------------- Z --------------------------------
+
+}

+ 205 - 0
pom.xml

@@ -0,0 +1,205 @@
+<?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.css</groupId>
+    <artifactId>simulation-cloud</artifactId>
+    <version>1.0</version>
+    <!-- 设置打包方式为 pom,而非默认的 jar -->
+    <packaging>pom</packaging>
+
+    <!-- 子模块 -->
+    <modules>
+        <module>simulation-auth</module>
+        <module>simulation-gateway</module>
+        <module>simulation-oauth-server</module>
+        <module>simulation-oauth-client</module>
+        <module>simulation-resource-scheduler</module>
+        <module>api-common</module>
+    </modules>
+
+
+    <!-- 统一版本 -->
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <!-- 基础 -->
+        <spring-cloud.version>2020.0.1</spring-cloud.version>
+        <spring-boot.version>2.4.2</spring-boot.version>
+        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
+        <!-- 权限认证 -->
+        <spring-cloud-starter-security.version>2.2.5.RELEASE</spring-cloud-starter-security.version>
+        <spring-cloud-starter-oauth2.version>2.2.5.RELEASE</spring-cloud-starter-oauth2.version>
+        <!-- 数据库 -->
+        <pagehelper-starter.version>1.4.1</pagehelper-starter.version>
+        <mybatis-spring-boot-starter.version>2.2.1</mybatis-spring-boot-starter.version>
+        <druid-spring-boot-starter.version>1.2.8</druid-spring-boot-starter.version>
+        <mysql-connector-java.version>5.1.49</mysql-connector-java.version>
+        <!-- 消息队列 -->
+        <kafka-clients.version>3.1.0</kafka-clients.version>
+        <!-- 其他 -->
+        <japidocs.version>1.4.4</japidocs.version>
+        <junit.version>4.12</junit.version>
+        <log4j.version>1.2.17</log4j.version>
+        <lombok.version>1.18.22</lombok.version>
+        <logback-classic.version>1.2.10</logback-classic.version>
+        <jjwt.version>0.9.1</jjwt.version>
+        <httpclient.version>4.5.13</httpclient.version>
+        <commons-pool2.version>2.11.1</commons-pool2.version>
+    </properties>
+
+
+    <!--子模块继承之后,提供作用:锁定版本+子module不用谢groupId和version-->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- 解决依赖冲突 -->
+            <dependency>
+                <groupId>ch.qos.logback</groupId>
+                <artifactId>logback-classic</artifactId>
+                <version>${logback-classic.version}</version>
+            </dependency>
+
+            <!-- 缓存 - 开始 -->
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-pool2</artifactId>
+                <version>${commons-pool2.version}</version>
+            </dependency>
+            <!-- 缓存 - 结束 -->
+
+            <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
+            <dependency>
+                <groupId>org.apache.kafka</groupId>
+                <artifactId>kafka-clients</artifactId>
+                <version>${kafka-clients.version}</version>
+            </dependency>
+
+            <!-- http 客户端 -->
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>${httpclient.version}</version>
+            </dependency>
+
+            <!-- 权限认证 - 开始 -->
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-security</artifactId>
+                <version>${spring-cloud-starter-security.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-oauth2</artifactId>
+                <version>${spring-cloud-starter-oauth2.version}</version>
+            </dependency>
+            <!-- 权限认证 - 结束 -->
+
+
+            <!-- api 文档 -->
+            <dependency>
+                <groupId>io.github.yedaxia</groupId>
+                <artifactId>japidocs</artifactId>
+                <version>${japidocs.version}</version>
+            </dependency>
+
+            <!-- 数据库 - 开始 -->
+            <!-- page helper -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper-starter.version}</version>
+            </dependency>
+            <!-- mybatis-starter -->
+            <dependency>
+                <groupId>org.mybatis.spring.boot</groupId>
+                <artifactId>mybatis-spring-boot-starter</artifactId>
+                <version>${mybatis-spring-boot-starter.version}</version>
+            </dependency>
+
+            <!-- druid 数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid-spring-boot-starter.version}</version>
+            </dependency>
+
+            <!-- mysql 驱动 -->
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql-connector-java.version}</version>
+            </dependency>
+            <!-- 数据库 - 结束 -->
+
+
+            <!-- 其他 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>${spring-cloud-alibaba.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+
+
+            <!-- lombok -->
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+            <!-- junit -->
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>${junit.version}</version>
+            </dependency>
+            <!-- log4j -->
+            <dependency>
+                <groupId>log4j</groupId>
+                <artifactId>log4j</artifactId>
+                <version>${log4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>3.0.0</version>
+                <type>maven-plugin</type>
+            </dependency>
+
+        </dependencies>
+
+    </dependencyManagement>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <fork>true</fork>
+                    <addResources>true</addResources>
+                </configuration>
+                <version>${spring-boot.version}</version>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 41 - 0
simulation-gateway/pom.xml

@@ -0,0 +1,41 @@
+<?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">
+    <parent>
+        <groupId>com.css</groupId>
+        <artifactId>simulation-cloud</artifactId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>simulation-gateway</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- gateway -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-gateway</artifactId>
+        </dependency>
+        <!-- nacos - 开始 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <!-- nacos - 结束 -->
+    </dependencies>
+
+</project>

+ 13 - 0
simulation-gateway/src/main/java/com/css/simulation/gateway/SimulationGatewayApplication.java

@@ -0,0 +1,13 @@
+package com.css.simulation.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SimulationGatewayApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SimulationGatewayApplication.class, args);
+    }
+
+}

+ 28 - 0
simulation-gateway/src/main/java/com/css/simulation/gateway/configuration/MyCorsConfiguration.java

@@ -0,0 +1,28 @@
+package com.css.simulation.gateway.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.reactive.CorsWebFilter;
+import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
+import org.springframework.web.util.pattern.PathPatternParser;
+
+@Configuration
+public class MyCorsConfiguration {
+
+    /**
+     * 解决跨域问题
+     *
+     * @return 过滤器
+     */
+    @Bean
+    public CorsWebFilter getCorsWebFilter() {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        corsConfiguration.addAllowedMethod("*");
+        corsConfiguration.addAllowedOrigin("*");
+        corsConfiguration.addAllowedHeader("*");
+        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(new PathPatternParser());
+        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
+        return new CorsWebFilter(urlBasedCorsConfigurationSource);
+    }
+}

+ 30 - 0
simulation-gateway/src/main/resources/bootstrap.yml

@@ -0,0 +1,30 @@
+#* -------------------------------- 服务器端口 --------------------------------
+server:
+  port: 8888
+
+spring:
+  application:
+    name: simulation-gateway
+  #* -------------------------------- profile 环境 --------------------------------
+  profiles:
+    active: dev
+  #* -------------------------------- cloud 微服务 --------------------------------
+  cloud:
+    #* -------------------------------- 注册中心 --------------------------------
+    nacos:
+      discovery:
+        server-addr: localhost:8841                     # 将配置中心注册进注册中心
+      config: # ${prefix}- ${spring.profiles.active}.${file-extension}
+        server-addr: localhost:8841                     # 从注册中心的微服务列表读取配置
+        namespace: 40cc3b1a-33b1-488a-98dc-4ae0570992ee # 配置命名空间 id,命名空间一般为项目名
+        file-extension: yaml                            # 读取 yaml 类型的文件
+    #* -------------------------------- gateway 网关 --------------------------------
+    gateway:
+      discovery:
+        locator:
+          enabled: true                 # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
+      routes:
+        - id: route_project_auth                      # 权限认证路由
+          uri: lb://scheduler        # 匹配后提供服务的路由地址,lb 代表负载均衡
+          predicates:
+            - Path=/login          # 断言,路径相匹配的进行路由,其他条件见官网。

+ 14 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/SimulationOauthClientApplication.java

@@ -0,0 +1,14 @@
+package com.css.simulation.oauth.client;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+
+@SpringBootApplication
+public class SimulationOauthClientApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SimulationOauthClientApplication.class, args);
+    }
+
+}

+ 30 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/http/HttpConfiguration.java

@@ -0,0 +1,30 @@
+package com.css.simulation.oauth.client.configuration.http;
+
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class HttpConfiguration {
+    @Bean
+    public CloseableHttpClient closeableHttpClient() {
+        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
+        pool.setMaxTotal(300);
+        pool.setDefaultMaxPerRoute(300);
+        return HttpClients.custom().setConnectionManager(pool).build();
+    }
+
+    @Bean
+    public RequestConfig requestConfig() {
+        return RequestConfig.custom()
+                .setSocketTimeout(5000)
+                .setConnectTimeout(5000)
+                .setConnectionRequestTimeout(5000)
+                .setRedirectsEnabled(false)
+                .setExpectContinueEnabled(false)
+                .build();
+    }
+}

+ 28 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/oauth/OauthParameter.java

@@ -0,0 +1,28 @@
+package com.css.simulation.oauth.client.configuration.oauth;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "oauth")
+public class OauthParameter {
+
+    private String zoogooyAppid;
+    private String zoogooyAppSecret;
+    private String zoogooyAuthorizeUri;
+    private String zoogooyRedirectUri;
+    private String zoogooyTokenUri;
+    private String zoogooyUserUri;
+    /**
+     * 一期之后
+     * 默认密码、令牌刷新时间等,改成可配置,从字典缓存里读
+     * 项目启动时直接把字典从 mysql 读到 redis 缓存中
+     */
+    private String simulationDefaultPassword;
+    private String simulationClientId;
+    private String simulationClientSecret;
+    private String simulationTokenUri;
+
+}

+ 15 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SignInController.java

@@ -0,0 +1,15 @@
+package com.css.simulation.oauth.client.controller;
+
+import api.common.pojo.common.ResponseBodyVO;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class SignInController {
+
+
+    @RequestMapping("/signIn")
+    public ResponseBodyVO<String> signIn(){
+        return null;
+    }
+}

+ 138 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SingleSignOnController.java

@@ -0,0 +1,138 @@
+package com.css.simulation.oauth.client.controller;
+
+import api.common.pojo.common.ResponseBodyVO;
+import api.common.pojo.common.SimulationTokenVO;
+import api.common.pojo.po.UserPO;
+import api.common.util.EncryptUtil;
+import api.common.util.HttpUtil;
+import api.common.util.JsonUtil;
+import com.css.simulation.oauth.client.configuration.oauth.OauthParameter;
+import com.css.simulation.oauth.client.mapper.UserMapper;
+import lombok.SneakyThrows;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.springframework.boot.configurationprocessor.json.JSONObject;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.annotation.Resource;
+
+@Controller
+@RequestMapping("/sso")
+public class SingleSignOnController {
+
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private CloseableHttpClient closeableHttpClient;
+    @Resource
+    private RequestConfig requestConfig;
+    @Resource
+    private OauthParameter oauthParameter;
+
+    /**
+     * http://localhost:7001/simulation/sso/entry?ticket=1001
+     */
+    @RequestMapping("/entry")
+    public String entry(@RequestParam("ticket") String ticket) {
+        System.out.println(oauthParameter);
+        String zoogooyAuthorizeUrl = oauthParameter.getZoogooyAuthorizeUri() +
+                "?appid=" + oauthParameter.getZoogooyAppid() +
+                "&redirect_uri=" + oauthParameter.getZoogooyRedirectUri() +
+                "&ticket=" + ticket +
+                "&response_type=code" +
+                "&scope=snsapi_userinfo";
+        return "redirect:" +zoogooyAuthorizeUrl;
+    }
+
+    /**
+     * 登录接口首页,将 code 返回给前端
+     *
+     * @return token 信息
+     */
+    @RequestMapping("/home")
+    @SneakyThrows
+    @ResponseBody
+    public ResponseBodyVO<SimulationTokenVO> home(@RequestParam("code") String code, @RequestParam("ticket") String ticket) {
+        //1 根据统一凭条 code 获取统一平台 access_token
+        /*
+        响应体
+        {
+          "access_token":"{ACCESS_TOKEN}",
+          "expires_in_sec":30,
+          "openid":"{OPENID}",
+          "scope":"{SCOPE}",
+          "appid":"{APPID}"
+        }
+         */
+        JSONObject zoogooyToken = HttpUtil.post(closeableHttpClient, requestConfig,
+                oauthParameter.getZoogooyTokenUri() + "?appid=" + oauthParameter.getZoogooyAppid() +
+                        "&secret=" + oauthParameter.getZoogooyAppSecret() +
+                        "&code=" + code +
+                        "&grant_type=authorization_code",
+                null, null);
+        String accessToken = zoogooyToken.optString("access_token");
+        String openid = zoogooyToken.optString("openid");
+        System.out.println("------- 统一平台令牌信息为:" + zoogooyToken);
+
+        //2 根据统一平台 access_token、openid、ticket 获取统一平台用户信息
+        /*
+        {
+          "openid":"{OPENID}",
+          "nickname": "{NICKNAME}",
+          "photoId":"2016091919310100025281cb87dcbdc74a09be41",
+          "role":["ROLE1" "ROLE2"],
+          "unionid": "{UNIONID}"
+        }
+         */
+        String zoogooyUserUrl = oauthParameter.getZoogooyUserUri() +
+                "?access_token=" + accessToken +
+                "&openid=" + openid +
+                "&ticket=" + ticket;
+        JSONObject userInfo = HttpUtil.post(closeableHttpClient, requestConfig, zoogooyUserUrl, null, null);
+
+        String unionid = userInfo.optString("unionid");
+        String nickname = userInfo.optString("nickname");
+        System.out.println("------- 统一平台用户信息为:" + userInfo);
+
+        //3 使用 union_id 查询数据库,是否已在仿真平台存在该用户
+        String username;
+        String password;
+        UserPO oldUser = userMapper.selectByIdIgnoreDelete(unionid);
+        System.out.println(oldUser);
+        if (oldUser == null) {   //3-1 仿真平台不存在用户,直接创建新的
+            password = EncryptUtil.getLowerMD5(oauthParameter.getSimulationDefaultPassword());
+            UserPO newUser = new UserPO();
+            newUser.setId(unionid);
+            username = openid;  // 将 openid 作为登录名
+            newUser.setUsername(username);
+            newUser.setNickname(nickname);
+            newUser.setPassword(password);
+            userMapper.insert(newUser);
+        } else {
+            if ("1".equals(oldUser.getIsDeleted())) { //3-2 仿真平台存在删除状态用户,改为未删除
+                userMapper.updateIsDeleted(unionid, "0");
+            }
+            //3-3 仿真平台用户存在未删除用户,放行
+            username = oldUser.getUsername();
+            password = oldUser.getPassword();
+        }
+
+
+        //4 根据仿真平台用户名密码颁发仿真平台 token,返回给前端
+        String simulationTokenUrl = oauthParameter.getSimulationTokenUri() +
+                "?grant_type=password" +
+                "&client_id=" + oauthParameter.getSimulationClientId() +
+                "&client_secret=" + oauthParameter.getSimulationClientSecret() +
+                "&username=" + username +
+                "&password=" + password;
+        SimulationTokenVO simulationToken = JsonUtil.jsonObjectToBean(HttpUtil.post(closeableHttpClient, requestConfig, simulationTokenUrl, null, null), SimulationTokenVO.class);
+        System.out.println("------- 仿真平台令牌信息为:"+simulationToken);
+
+
+        return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS, "请求成功!", simulationToken);
+    }
+
+}

+ 138 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/TestSingleSignOnController.java

@@ -0,0 +1,138 @@
+package com.css.simulation.oauth.client.controller;
+
+import api.common.pojo.common.ResponseBodyVO;
+import api.common.pojo.common.SimulationTokenVO;
+import api.common.pojo.po.UserPO;
+import api.common.util.EncryptUtil;
+import api.common.util.HttpUtil;
+import api.common.util.JsonUtil;
+import com.css.simulation.oauth.client.configuration.oauth.OauthParameter;
+import com.css.simulation.oauth.client.mapper.UserMapper;
+import lombok.SneakyThrows;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.springframework.boot.configurationprocessor.json.JSONObject;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.annotation.Resource;
+
+@Controller
+@RequestMapping("/test")
+public class TestSingleSignOnController {
+
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private CloseableHttpClient closeableHttpClient;
+    @Resource
+    private RequestConfig requestConfig;
+    @Resource
+    private OauthParameter oauthParameter;
+
+    /**
+     * http://localhost:7001/simulation/test/entry?ticket=1001
+     */
+    @RequestMapping("/entry")
+    public String entry(@RequestParam("ticket") String ticket) {
+        System.out.println(oauthParameter);
+        String zoogooyAuthorizeUrl = oauthParameter.getZoogooyAuthorizeUri() +
+                "?appid=" + oauthParameter.getZoogooyAppid() +
+                "&redirect_uri=" + oauthParameter.getZoogooyRedirectUri() +
+                "&ticket=" + ticket +
+                "&response_type=code" +
+                "&scope=snsapi_userinfo";
+        return "redirect:" +zoogooyAuthorizeUrl;
+    }
+
+    /**
+     * 登录接口首页,将 code 返回给前端
+     *
+     * @return token 信息
+     */
+    @RequestMapping("/home")
+    @SneakyThrows
+    @ResponseBody
+    public ResponseBodyVO<SimulationTokenVO> home(@RequestParam("code") String code, @RequestParam("ticket") String ticket) {
+        //1 根据统一凭条 code 获取统一平台 access_token
+        /*
+        响应体
+        {
+          "access_token":"{ACCESS_TOKEN}",
+          "expires_in_sec":30,
+          "openid":"{OPENID}",
+          "scope":"{SCOPE}",
+          "appid":"{APPID}"
+        }
+         */
+        JSONObject zoogooyToken = HttpUtil.post(closeableHttpClient, requestConfig,
+                oauthParameter.getZoogooyTokenUri() + "?appid=" + oauthParameter.getZoogooyAppid() +
+                        "&secret=" + oauthParameter.getZoogooyAppSecret() +
+                        "&code=" + code +
+                        "&grant_type=authorization_code",
+                null, null);
+        String accessToken = zoogooyToken.optString("access_token");
+        String openid = zoogooyToken.optString("openid");
+        System.out.println("------- 统一平台令牌信息为:" + zoogooyToken);
+
+        //2 根据统一平台 access_token、openid、ticket 获取统一平台用户信息
+        /*
+        {
+          "openid":"{OPENID}",
+          "nickname": "{NICKNAME}",
+          "photoId":"2016091919310100025281cb87dcbdc74a09be41",
+          "role":["ROLE1" "ROLE2"],
+          "unionid": "{UNIONID}"
+        }
+         */
+        String zoogooyUserUrl = oauthParameter.getZoogooyUserUri() +
+                "?access_token=" + accessToken +
+                "&openid=" + openid +
+                "&ticket=" + ticket;
+        JSONObject userInfo = HttpUtil.post(closeableHttpClient, requestConfig, zoogooyUserUrl, null, null);
+
+        String unionid = userInfo.optString("unionid");
+        String nickname = userInfo.optString("nickname");
+        System.out.println("------- 统一平台用户信息为:" + userInfo);
+
+        //3 使用 union_id 查询数据库,是否已在仿真平台存在该用户
+        String username;
+        String password;
+        UserPO oldUser = userMapper.selectByIdIgnoreDelete(unionid);
+        System.out.println(oldUser);
+        if (oldUser == null) {   //3-1 仿真平台不存在用户,直接创建新的
+            password = EncryptUtil.getLowerMD5(oauthParameter.getSimulationDefaultPassword());
+            UserPO newUser = new UserPO();
+            newUser.setId(unionid);
+            username = openid;  // 将 openid 作为登录名
+            newUser.setUsername(username);
+            newUser.setNickname(nickname);
+            newUser.setPassword(password);
+            userMapper.insert(newUser);
+        } else {
+            if ("1".equals(oldUser.getIsDeleted())) { //3-2 仿真平台存在删除状态用户,改为未删除
+                userMapper.updateIsDeleted(unionid, "0");
+            }
+            //3-3 仿真平台用户存在未删除用户,放行
+            username = oldUser.getUsername();
+            password = oldUser.getPassword();
+        }
+
+
+        //4 根据仿真平台用户名密码颁发仿真平台 token,返回给前端
+        String simulationTokenUrl = oauthParameter.getSimulationTokenUri() +
+                "?grant_type=password" +
+                "&client_id=" + oauthParameter.getSimulationClientId() +
+                "&client_secret=" + oauthParameter.getSimulationClientSecret() +
+                "&username=" + username +
+                "&password=" + password;
+        SimulationTokenVO simulationToken = JsonUtil.jsonObjectToBean(HttpUtil.post(closeableHttpClient, requestConfig, simulationTokenUrl, null, null), SimulationTokenVO.class);
+        System.out.println("------- 仿真平台令牌信息为:"+simulationToken);
+
+
+        return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS, "请求成功!", simulationToken);
+    }
+
+}

+ 50 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/mapper/UserMapper.java

@@ -0,0 +1,50 @@
+package com.css.simulation.oauth.client.mapper;
+
+
+import api.common.pojo.po.UserPO;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.type.JdbcType;
+
+@Mapper
+public interface UserMapper {
+
+    @Results(id = "user", value = {
+            @Result(property = "id", column = "id", jdbcType = JdbcType.VARCHAR),
+            @Result(property = "username", column = "username", jdbcType = JdbcType.VARCHAR),
+            @Result(property = "password", column = "password", jdbcType = JdbcType.VARCHAR),
+            @Result(property = "isDeleted", column = "is_deleted", jdbcType = JdbcType.VARCHAR)
+    })
+    @Select("select id,\n" +
+            "       username,\n" +
+            "       password,\n" +
+            "       is_deleted\n" +
+            "from system_user\n" +
+            "where id = #{id}")
+    UserPO selectByIdIgnoreDelete(@Param("id") String id);
+
+    @Select("update system_user\n" +
+            "set is_delete = #{isDeleted}\n" +
+            "   where id = #{id}")
+    void updateIsDeleted(@Param("id") String id,@Param("isDeleted") String isDeleted);
+
+
+
+
+    //* -------------------------------- insert --------------------------------
+    @Insert("insert into system_user(" +
+            "   id, " +
+            "   username," +
+            "   nickname," +
+            "   password, " +
+            "   is_deleted" +
+            ")values (" +
+            "   #{id}," +
+            "   #{username}," +
+            "   #{nickname}," +
+            "   #{password}," +
+            "   #{isDeleted}" +
+            ")")
+    void insert(UserPO userPO);
+
+
+}

+ 17 - 0
simulation-oauth-client/src/main/resources/bootstrap.yaml

@@ -0,0 +1,17 @@
+spring:
+  application:
+    name: simulation-oauth-client
+  #* -------------------------------- 环境配置 --------------------------------
+  profiles:
+    active: windowstest
+  #* -------------------------------- 微服务配置 --------------------------------
+  cloud:
+    nacos:
+      discovery:
+        server-addr: 10.15.12.70:8848                     # 将配置中心注册进注册中心
+      config:                                           # ${prefix}- ${spring.profiles.active}.${file-extension}
+        server-addr: 10.15.12.70:8848                     # 从注册中心的微服务列表读取配置
+        namespace: 3698bfc2-a612-487a-b2a2-aaad16cd9d9d # 配置命名空间 id,命名空间一般为项目名
+        file-extension: yaml                            # 读取 yaml 类型的文件
+
+

+ 99 - 0
simulation-oauth-server/pom.xml

@@ -0,0 +1,99 @@
+<?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">
+    <parent>
+        <artifactId>simulation-cloud</artifactId>
+        <groupId>com.css</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>simulation-oauth-server</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+
+        <!-- 权限认证 - 开始 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+        </dependency>
+        <!-- 权限认证 - 结束 -->
+
+        <!-- 缓存 - 开始-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <!-- 缓存 - 结束-->
+
+        <!-- 数据库 - 开始 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <!-- 数据库 - 结束 -->
+
+        <!-- nacos - 开始 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <!-- nacos - 结束 -->
+        <!-- api-common -->
+        <dependency>
+            <groupId>com.css</groupId>
+            <artifactId>api-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- 基础 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

+ 16 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/SimulationOauthServerApplication.java

@@ -0,0 +1,16 @@
+package com.css.simulation.oauth.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+
+
+@SpringBootApplication
+@EnableAuthorizationServer
+public class SimulationOauthServerApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SimulationOauthServerApplication.class, args);
+    }
+
+}

+ 21 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyCodeService.java

@@ -0,0 +1,21 @@
+package com.css.simulation.oauth.server.cofiguration.oauth;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
+import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
+
+@Configuration
+public class MyCodeService {
+
+    /**
+     * 授权码存储
+     * 设置授权码模式的授权码如何存储。
+     */
+    @Bean
+    public AuthorizationCodeServices authorizationCodeServices() {
+        // 基于内存的授权码存储
+        // 还有 JdbcAuthorizationCodeServices、RandomValueAuthorizationCodeServices
+        return new InMemoryAuthorizationCodeServices();
+    }
+}

+ 37 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyTokenService.java

@@ -0,0 +1,37 @@
+package com.css.simulation.oauth.server.cofiguration.oauth;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.ClientDetailsService;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class MyTokenService {
+
+    @Resource
+    private ClientDetailsService clientDetailsService;  // 客户端详情服务
+
+
+    @Resource
+    private TokenStore tokenStore;  // 客户端详情服务
+
+
+    /**
+     * 令牌管理策略
+     */
+    @Bean
+    public AuthorizationServerTokenServices authorizationServerTokenServices() {
+        DefaultTokenServices services = new DefaultTokenServices();
+        services.setClientDetailsService(clientDetailsService);     // 客户端详情服务,获取 ClientDetailsServiceConfigurer 中配置的客户端
+        services.setSupportRefreshToken(true);      // 允许令牌自动刷新
+        services.setTokenStore(tokenStore);         // 令牌存储策略
+        services.setAccessTokenValiditySeconds(7200);   // 令牌默认有效期 2 小时
+        services.setRefreshTokenValiditySeconds(259200);    // 刷新令牌默认有效期 3 天。
+        return services;
+    }
+
+}

+ 31 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/MyTokenStore.java

@@ -0,0 +1,31 @@
+package com.css.simulation.oauth.server.cofiguration.oauth;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class MyTokenStore {
+
+    @Resource
+    private RedisConnectionFactory redisConnectionFactory;  // 客户端详情服务
+
+    /**
+     * 令牌存储
+     * <p>
+     * (推荐)new RedisTokenStore():基于 redis
+     * (推荐)new JwtTokenStore(accessTokenConverter()):基于 Jwt
+     * new InMemoryTokenStore():基于内存
+     * new JwkTokenStore():基于 Jwk
+     * new JdbcTokenStore():基于 Jdbc
+     */
+    @Bean
+    public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory) {
+        return new RedisTokenStore(redisConnectionFactory);
+    }
+
+}

+ 98 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/oauth/OauthAuthorizationServerConfiguration.java

@@ -0,0 +1,98 @@
+package com.css.simulation.oauth.server.cofiguration.oauth;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
+import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+import javax.annotation.Resource;
+
+
+/**
+ *
+ */
+@Configuration
+@Slf4j
+public class OauthAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
+
+
+    @Resource
+    private AuthenticationManager authenticationManager;        // 认证管理器,来自 Spring Security
+    @Resource
+    private UserDetailsService userDetailsService;        // 用户信息验证服务,来自 Spring Security
+    @Resource
+    private AuthorizationCodeServices authorizationCodeServices;    // 授权码管理服务
+    @Resource
+    private TokenStore tokenStore;  // 令牌管理服务
+    @Resource
+    private AuthorizationServerTokenServices authorizationServerTokenServices;  // 令牌管理服务
+
+    /**
+     * 配置 ClientDetailsService,客户端详情信息在这里进行初始化。
+     * 可以把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
+     */
+    @Override
+    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
+        // 通过内存方式配置客户端
+        clients.inMemory()  // 内存方式
+                .withClient("simulation-oauth-client")       // 客户端 id
+                .secret("hPT7zVteEXvRzS41NhJXoQYqtGmai3W0")   // 客户端密钥
+                .resourceIds("simulation-resource-scheduler")  // 客户端拥有的资源列表
+                .authorizedGrantTypes("password", "refresh_token") // 允许的授权方式
+                .scopes("all")    // 授权范围划分
+                .autoApprove(false); // 是否自动通过,即是否跳过 scope 选择界面,跳过的话代表将所有 scope 授权范围赋予该 client
+    }
+
+    /**
+     * 配置授权类型
+     */
+    @Override
+    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
+        DefaultWebResponseExceptionTranslator defaultWebResponseExceptionTranslator = new DefaultWebResponseExceptionTranslator() {
+            @Override
+            public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
+                log.error("生成token异常", e);
+                ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
+                HttpHeaders headers = new HttpHeaders();
+                headers.setAll(responseEntity.getHeaders().toSingleValueMap());
+                OAuth2Exception excBody = responseEntity.getBody();
+                return new ResponseEntity<>(excBody, headers, responseEntity.getStatusCode());
+            }
+        };
+
+        endpoints.authenticationManager(authenticationManager)      // 认证管理器(密码模式)
+                .userDetailsService(userDetailsService)           // 用户信息管理(密码模式)
+                .authorizationCodeServices(authorizationCodeServices)   // 授权码服务(授权码模式)
+                .tokenStore(tokenStore)   // 令牌存储
+                .tokenServices(authorizationServerTokenServices)    // 令牌管理服务
+                .exceptionTranslator(defaultWebResponseExceptionTranslator)
+                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
+    }
+
+    /**
+     * 用来配置令牌端点的安全约束
+     * 公开 /oauth/check_token
+     * 公开 /oauth/token_key
+     */
+    @Override
+    public void configure(AuthorizationServerSecurityConfigurer security) {
+        security.tokenKeyAccess("permitAll()")      // oauth/token_key 公开
+                .checkTokenAccess("permitAll()")    // oauth/check_token 公开
+                .allowFormAuthenticationForClients();   // 表单认证,申请令牌
+    }
+
+
+}

+ 84 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/redis/RedisTemplateConfiguration.java

@@ -0,0 +1,84 @@
+package com.css.simulation.oauth.server.cofiguration.redis;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+@EnableCaching
+public class RedisTemplateConfiguration {
+
+    @Bean
+    public RedisSerializer<Object> jackson2JsonRedisSerializer() {
+        // 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值。
+        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        ObjectMapper mapper = new ObjectMapper();
+        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        // 指定序列化输入的类型,类必须是非 final 修饰的,final修饰的类,比如 String, Integer 等会跑出异常
+        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
+        serializer.setObjectMapper(mapper);
+        return serializer;
+    }
+
+    @Bean
+    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
+        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
+        configuration = configuration
+                // 设置 key 为 string 序列化
+                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
+                // 设置 value 为 json 序列化
+                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
+                // 不缓存空值
+                .disableCachingNullValues()
+                // 设置缓存默认过期时间(30 分钟)
+                .entryTtl(Duration.ofMinutes(30L))
+        ;
+        // 特殊缓存空间应用不同的配置
+        Map<String, RedisCacheConfiguration> map = new HashMap<>();
+        map.put("miFirst", configuration.entryTtl(Duration.ofMinutes(30L)));
+        map.put("miSecond", configuration.entryTtl(Duration.ofHours(1L)));
+
+        return RedisCacheManager.builder(connectionFactory)
+                .cacheDefaults(configuration)           // 默认配置
+                .withInitialCacheConfigurations(map)    // 特殊缓存
+                .transactionAware()                     // 事务
+                .build();
+    }
+
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        // key 采用 String 的序列化方式
+        template.setKeySerializer(stringRedisSerializer);
+        // hash 的 key 采用 String 的序列化方式
+        template.setHashKeySerializer(stringRedisSerializer);
+        // value 采用 jackson 的序列化方式
+        template.setValueSerializer(jackson2JsonRedisSerializer());
+        // hash 的 value 采用 jackson 的序列化方式
+        template.setHashValueSerializer(jackson2JsonRedisSerializer());
+        template.afterPropertiesSet();
+        return template;
+    }
+
+
+}

+ 19 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyPasswordEncoder.java

@@ -0,0 +1,19 @@
+package com.css.simulation.oauth.server.cofiguration.security;
+
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MyPasswordEncoder implements PasswordEncoder {
+
+    @Override
+    public String encode(CharSequence charSequence) {
+        return charSequence.toString();
+    }
+
+
+    @Override
+    public boolean matches(CharSequence rawPassword, String encodePassword) {
+        return encodePassword.equals(rawPassword.toString());
+    }
+}

+ 55 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyUserDetails.java

@@ -0,0 +1,55 @@
+package com.css.simulation.oauth.server.cofiguration.security;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class MyUserDetails implements UserDetails {
+
+    private String username;
+    private String password;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
+
+    /**
+     * 默认 false 是将用户账号过期,需改成 true 不过期
+     */
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    /**
+     * 默认 false 是将用户上锁,需改成 true 不上锁
+     */
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    /**
+     * 默认 false 是用户凭证国汽,需改成 true 不过期
+     */
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    /**
+     * 默认 false 是将用户失效,需改成 true 不失效
+     */
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+}

+ 26 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/MyUserDetailsService.java

@@ -0,0 +1,26 @@
+package com.css.simulation.oauth.server.cofiguration.security;
+
+
+import api.common.pojo.po.UserPO;
+import com.css.simulation.oauth.server.mapper.UserMapper;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+@Service
+public class MyUserDetailsService implements UserDetailsService {
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        UserPO userPO = userMapper.selectByUsername(username);
+        return new MyUserDetails(userPO.getUsername(), userPO.getPassword());
+    }
+
+
+}

+ 23 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/cofiguration/security/SecurityConfiguration.java

@@ -0,0 +1,23 @@
+package com.css.simulation.oauth.server.cofiguration.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+
+    /**
+     * 认证管理器
+     */
+    @Bean
+    public AuthenticationManager authenticationManager() throws Exception {
+        return super.authenticationManager();
+    }
+
+
+}

+ 30 - 0
simulation-oauth-server/src/main/java/com/css/simulation/oauth/server/mapper/UserMapper.java

@@ -0,0 +1,30 @@
+package com.css.simulation.oauth.server.mapper;
+
+
+import api.common.pojo.po.UserPO;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.type.JdbcType;
+
+/**
+ * 将查询接口放到第一个,用于写 @Results注解
+ */
+@Mapper
+public interface UserMapper {
+
+    //* -------------------------------- select --------------------------------
+
+    @Results(id = "user", value = {
+            @Result(property = "id", column = "id", jdbcType = JdbcType.VARCHAR),
+            @Result(property = "username", column = "username", jdbcType = JdbcType.VARCHAR),
+            @Result(property = "password", column = "password", jdbcType = JdbcType.VARCHAR)
+    })
+    @Select("select id,\n" +
+            "       username,\n" +
+            "       password\n" +
+            "from system_user\n" +
+            "where is_deleted = '0'" +
+            "   and username = #{username}")
+    UserPO selectByUsername(@Param("username") String username);
+
+
+}

+ 15 - 0
simulation-oauth-server/src/main/resources/bootstrap.yaml

@@ -0,0 +1,15 @@
+spring:
+  application:
+    name: simulation-oauth-server
+  #* -------------------------------- 环境配置 --------------------------------
+  profiles:
+    active: windowstest
+  #* -------------------------------- 微服务配置 --------------------------------
+  cloud:
+    nacos:
+      discovery:
+        server-addr: 10.15.12.70:8848                     # 将配置中心注册进注册中心
+      config:                                           # ${prefix}- ${spring.profiles.active}.${file-extension}
+        server-addr: 10.15.12.70:8848                     # 从注册中心的微服务列表读取配置
+        namespace: 3698bfc2-a612-487a-b2a2-aaad16cd9d9d # 配置命名空间 id,命名空间一般为项目名
+        file-extension: yaml                            # 读取 yaml 类型的文件

+ 97 - 0
simulation-resource-scheduler/pom.xml

@@ -0,0 +1,97 @@
+<?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">
+    <parent>
+        <artifactId>simulation-cloud</artifactId>
+        <groupId>com.css</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>simulation-resource-scheduler</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+
+        <!-- apache kafka - 开始 -->
+        <dependency>
+            <groupId>org.apache.kafka</groupId>
+            <artifactId>kafka-clients</artifactId>
+            <version>${kafka-clients.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+        <!-- apache kafka - 结束 -->
+
+        <!-- 数据库 - 开始 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <!-- 数据库 - 结束 -->
+
+        <!-- nacos - 开始 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <!-- nacos - 结束 -->
+
+        <!-- web 服务 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!-- 参数校验 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <!-- lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <!-- redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!-- api-common -->
+        <dependency>
+            <groupId>com.css</groupId>
+            <artifactId>api-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 16 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/SimulationResourceSchedulerApplication.java

@@ -0,0 +1,16 @@
+package com.css.simulation.resource.scheduler;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+
+@SpringBootApplication
+@EnableScheduling
+public class SimulationResourceSchedulerApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SimulationResourceSchedulerApplication.class, args);
+    }
+
+}

+ 24 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/PodController.java

@@ -0,0 +1,24 @@
+package com.css.simulation.resource.scheduler.controller;
+
+import com.css.simulation.job.service.PodService;
+import api.common.pojo.common.ResponseBodyVO;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+public class PodController {
+
+    @Resource
+    private PodService podService;
+
+    /**
+     * Pod 的心跳接口
+     */
+    @PostMapping("/pod/tick/{taskId}")
+    public ResponseBodyVO<String> tickTaskPod(@PathVariable("taskId") String taskId) {
+        return podService.tickTaskPod(taskId);
+    }
+}

+ 26 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/TaskController.java

@@ -0,0 +1,26 @@
+package com.css.simulation.resource.scheduler.controller;
+
+
+import api.common.pojo.common.ResponseBodyVO;
+import com.css.simulation.resource.scheduler.service.TaskService;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+public class TaskController {
+
+    @Resource
+    private TaskService taskService;
+
+    /**
+     * 修改任务状态
+     */
+    @PostMapping("/task/{taskId}/state/{taskState}")
+    public ResponseBodyVO<String> modifyTaskState(@PathVariable("taskId") String taskId, @PathVariable("taskState") String taskState) {
+        return taskService.modifyTaskState(taskId, taskState);
+    }
+
+}

+ 28 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/JobMapper.java

@@ -0,0 +1,28 @@
+package com.css.simulation.resource.scheduler.mapper;
+
+
+import com.css.simulation.resource.scheduler.pojo.po.JobPO;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.type.JdbcType;
+
+@Mapper
+public interface JobMapper {
+
+
+    @Results(id = "job", value = {
+            @Result(property = "id", column = "id", jdbcType = JdbcType.VARCHAR)
+    })
+    @Select("select id\n" +
+            "from simulation_job\n" +
+            "where is_deleted = '0'\n" +
+            "  and state = '1'\n" +
+            "order by create_time\n" +
+            "limit 0,1\n")
+    JobPO selectWaitingJob();
+
+
+    @Update("update simulation_job\n" +
+            "set state = #{state}\n" +
+            "where id = #{id}")
+    void updateJobState(@Param("id") String id,@Param("state") String state);
+}

+ 23 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/TaskMapper.java

@@ -0,0 +1,23 @@
+package com.css.simulation.resource.scheduler.mapper;
+
+import com.css.simulation.resource.scheduler.pojo.po.TaskPO;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.type.JdbcType;
+
+import java.util.List;
+
+@Mapper
+public interface TaskMapper {
+
+    @Results(id = "task", value = {
+            @Result(property = "id", column = "id", jdbcType = JdbcType.VARCHAR)
+    })
+    @Select("")
+    List<TaskPO> selectByJobId(@Param("jobId") String jobId);
+
+
+    @Update("update simulation_job\n" +
+            "set state = #{state}\n" +
+            "where id = #{id}")
+    void updateJobState(@Param("id") String id, @Param("state") String state);
+}

+ 25 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/CameraDTO.java

@@ -0,0 +1,25 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CameraDTO {
+    private String sensor_name;
+    private Integer sensor_fovH;
+    private Integer sensor_fovV;
+    private Integer sensor_near;
+    private Integer sensor_far;
+    private String sensor_resolution;
+    private Integer sensor_frameRate;
+    private Integer sensor_x;
+    private Integer sensor_y;
+    private Integer sensor_z;
+    private Integer sensor_h;
+    private Integer sensor_p;
+    private Integer sensor_r;
+}

+ 11 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/DynamicsDTO.java

@@ -0,0 +1,11 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DynamicsDTO {
+}

+ 16 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/InfoDTO.java

@@ -0,0 +1,16 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class InfoDTO {
+
+    private String project_id;
+    private String task_id;
+    private String task_path;
+    private String default_time;
+}

+ 11 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/ModelDTO.java

@@ -0,0 +1,11 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ModelDTO {
+}

+ 29 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/OgtDTO.java

@@ -0,0 +1,29 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class OgtDTO {
+    private String sensor_name;
+    private Integer sensor_fovH;
+    private Integer sensor_fovV;
+    private Integer sensor_near;
+    private Integer sensor_far;
+    private Integer sensor_x;
+    private Integer sensor_y;
+    private Integer sensor_z;
+    private Integer sensor_h;
+    private Integer sensor_p;
+    private Integer sensor_r;
+    private List<Integer> sensor_filter;
+    private boolean sensor_display;
+    private Integer sensor_maxObjects;
+    private Integer sensor_port;
+
+}

+ 14 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/ScenarioDTO.java

@@ -0,0 +1,14 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ScenarioDTO {
+    private String scenario_osc;
+    private String scenario_odr;
+    private String scenario_osgb;
+}

+ 15 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/SensorsDTO.java

@@ -0,0 +1,15 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SensorsDTO {
+    private List<CameraDTO> camera;
+    private List<OgtDTO> OGT;
+}

+ 124 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/TaskDTO.java

@@ -0,0 +1,124 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * {
+ *     "info": {
+ *         "project_id": 766,
+ *         "task_id": 2789,
+ *         "task_path": "jobs/RT_EY%402022-01-25_13%3A57%3A30_1643090250/SharingVan_20220125_0",
+ *         "default_time": 30
+ *     },
+ *     "scenario": {
+ *         "scenario_osc": "scenarios/SharingVAN_20220125/SharingVAN.xml",
+ *         "scenario_odr": "scenarios/SharingVAN_20220125/Road_DFMC.xodr",
+ *         "scenario_osgb": "scenarios/SharingVAN_20220125/Road_DFMC.opt.osgb"
+ *     },
+ *     "vehicle":{
+ * 		"model": {
+ * 			"model_label": "AudiA6_10"
+ *                },
+ * 		"dynamics": {
+ * 			"dynamics_maxspeed": 67,
+ * 			"dynamics_enginepower": 150000,
+ * 			"dynamics_maxdecel": 9.5,
+ * 			"dynamics_maxsteering": 0.48,
+ * 			"dynamics_mass": 1700,
+ * 			"dynamics_frontsurfaceeffective": 2.2,
+ * 			"dynamics_airdragcoefficient": 0.31,
+ * 			"dynamics_rollingresistance": 0,
+ * 			"dynamics_wheeldiameter": 0.684,
+ * 			"dynamics_wheeldrive": "wheel_drive_front",
+ * 			"dynamics_overallefficiency": 0.75,
+ * 			"dynamics_distfront": 3.838,
+ * 			"dynamics_distrear": 1.086,
+ * 			"dynamics_distleft": 0.94,
+ * 			"dynamics_distright": 0.94,
+ * 			"dynamics_distheight": 1.444,
+ * 			"dynamics_wheelbase": 2.91
+ *        },
+ * 		"sensors": {
+ * 			"camera": [
+ *                {
+ * 					"sensor_name": "following_view_camera",
+ * 					"sensor_fovH": 45,
+ * 					"sensor_fovV": 27,
+ * 					"sensor_near": 1,
+ * 					"sensor_far": 1500,
+ * 					"sensor_resolution": "800x600",
+ * 					"sensor_frameRate": 60,
+ * 					"sensor_x": -15,
+ * 					"sensor_y": 0,
+ * 					"sensor_z": 5,
+ * 					"sensor_h": 0,
+ * 					"sensor_p": 10,
+ * 					"sensor_r": 0
+ *                },
+ *                {
+ * 					"sensor_name": "plan_view_camera",
+ * 					"sensor_fovH": 45,
+ * 					"sensor_fovV": 27,
+ * 					"sensor_near": 1,
+ * 					"sensor_far": 1500,
+ * 					"sensor_resolution": "800x600",
+ * 					"sensor_frameRate": 60,
+ * 					"sensor_x": 35,
+ * 					"sensor_y": 0,
+ * 					"sensor_z": 200,
+ * 					"sensor_h": 0,
+ * 					"sensor_p": 90,
+ * 					"sensor_r": 0
+ *                }
+ * 			],
+ * 			"OGT": [
+ *                {
+ * 					"sensor_name": "360_perfect_sensor",
+ * 					"sensor_fovH": 360,
+ * 					"sensor_fovV": 20,
+ * 					"sensor_near": 0,
+ * 					"sensor_far": 100,
+ * 					"sensor_x": 0,
+ * 					"sensor_y": 0,
+ * 					"sensor_z": 1.7,
+ * 					"sensor_h": 0,
+ * 					"sensor_p": 0,
+ * 					"sensor_r": 0,
+ * 					"sensor_filter": [0,1,5],
+ * 					"sensor_display": true,
+ * 					"sensor_maxObjects": 10,
+ * 					"sensor_port": 10
+ *                },
+ *                {
+ * 					"sensor_name": "120_perfect_sensor",
+ * 					"sensor_fovH": 120,
+ * 					"sensor_fovV": 20,
+ * 					"sensor_near": 0,
+ * 					"sensor_far": 100,
+ * 					"sensor_x": 0,
+ * 					"sensor_y": 0,
+ * 					"sensor_z": 1.7,
+ * 					"sensor_h": 0,
+ * 					"sensor_p": 0,
+ * 					"sensor_r": 0,
+ * 					"sensor_filter": [0,1,5],
+ * 					"sensor_display": true,
+ * 					"sensor_maxObjects": 10,
+ * 					"sensor_port": 10
+ *                }
+ * 			]
+ *        }* 	}
+ * }
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TaskDTO {
+
+    private InfoDTO info;
+    private ScenarioDTO scenario;
+    private VehicleDTO vehicle;
+
+}

+ 16 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/dto/task/VehicleDTO.java

@@ -0,0 +1,16 @@
+package com.css.simulation.resource.scheduler.pojo.dto.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class VehicleDTO {
+
+    private ModelDTO model;
+    private DynamicsDTO dynamics;
+    private SensorsDTO sensors;
+
+}

+ 25 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/JobPO.java

@@ -0,0 +1,25 @@
+package com.css.simulation.resource.scheduler.pojo.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class JobPO {
+    /**
+     * 工作 id 编号
+     */
+    private String id;
+
+    /**
+     * 最大时间
+     */
+    private String defaultTime;
+
+    /**
+     * 并行度
+     */
+    private String parallelism;
+}

+ 19 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/TaskPO.java

@@ -0,0 +1,19 @@
+package com.css.simulation.resource.scheduler.pojo.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TaskPO {
+    private String id;
+    private String algorithm;
+    private String model;
+    private String scene;
+    /**
+     * 结果保存路径(MinIO形式)
+     */
+    private String resultPath;
+}

+ 81 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/scheduler/JobScheduler.java

@@ -0,0 +1,81 @@
+package com.css.simulation.resource.scheduler.scheduler;
+
+
+import api.common.util.JsonUtil;
+import com.css.simulation.resource.scheduler.mapper.JobMapper;
+import com.css.simulation.resource.scheduler.mapper.TaskMapper;
+import com.css.simulation.resource.scheduler.pojo.dto.task.*;
+import com.css.simulation.resource.scheduler.pojo.po.JobPO;
+import com.css.simulation.resource.scheduler.pojo.po.TaskPO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class JobScheduler {
+
+    @Resource
+    JobMapper jobMapper;
+    @Resource
+    TaskMapper taskMapper;
+    @Resource
+    private KafkaTemplate<String, String> kafkaTemplate;
+
+    @Scheduled(cron = "*/5 * * * *")
+    public void parseJob() throws JsonProcessingException {
+        //1 读取 mysql 获取待执行的且创建时间最早的 job 信息
+        JobPO jobPO = jobMapper.selectWaitingJob();
+        String jobId = jobPO.getId();                   // 工作id
+        String defaultTime = jobPO.getDefaultTime();    // 任务执行时间,一个工作里的所有任务公用
+        String parallelism = jobPO.getParallelism();    // 并行度,创建 pod 时使用
+        //2 修改该 job 的状态为执行中,防止下一个定时读取到
+        jobMapper.updateJobState(jobId, "2");
+        //3 根据 job 信息获取 task 信息。task 信息包括算法、模型等
+        List<TaskPO> taskPOList = taskMapper.selectByJobId(jobId);
+        //4 组装 task 消息
+        for (TaskPO taskPO : taskPOList) {
+            String taskId = taskPO.getId();
+            //4-1 初始化所有对象
+            TaskDTO taskDTO = new TaskDTO();
+
+            InfoDTO infoDTO = new InfoDTO();
+            ScenarioDTO scenarioDTO = new ScenarioDTO();
+
+            VehicleDTO vehicleDTO = new VehicleDTO();
+            ModelDTO modelDTO = new ModelDTO();
+            DynamicsDTO dynamicsDTO = new DynamicsDTO();
+            SensorsDTO sensorsDTO = new SensorsDTO();
+
+            List<CameraDTO> cameraDTOList = new ArrayList<>();
+            List<OgtDTO> ogtDTOList = new ArrayList<>();
+
+            //4-2 将所有初始化对象赋值
+
+            //4-3 组装
+            sensorsDTO.setCamera(cameraDTOList);
+            sensorsDTO.setOGT(ogtDTOList);
+
+            vehicleDTO.setModel(modelDTO);
+            vehicleDTO.setDynamics(dynamicsDTO);
+            vehicleDTO.setSensors(sensorsDTO);
+
+            taskDTO.setInfo(infoDTO);
+            taskDTO.setScenario(scenarioDTO);
+            taskDTO.setVehicle(vehicleDTO);
+
+            //4-4 将对象转成 json
+            String taskJson = JsonUtil.beanToJson(taskDTO);
+
+            //4-5 发送到 kafka
+            kafkaTemplate.send(jobId, 0, taskId, taskJson);
+
+        }
+        //3 将 job 名称作为 topic 名称,发送 task 信息到 kafka
+        //4 创建 pod 开始执行。
+    }
+}

+ 15 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/PodService.java

@@ -0,0 +1,15 @@
+package com.css.simulation.resource.scheduler.service;
+
+import api.common.pojo.common.ResponseBodyVO;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PodService {
+
+    /**
+     * Pod 的心跳接口
+     */
+    public ResponseBodyVO<String> tickTaskPod(String taskId) {
+        return null;
+    }
+}

+ 17 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/TaskService.java

@@ -0,0 +1,17 @@
+package com.css.simulation.resource.scheduler.service;
+
+import api.common.pojo.common.ResponseBodyVO;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TaskService {
+
+    /**
+     * 修改任务状态
+     */
+    public ResponseBodyVO<String> modifyTaskState( String taskId,  String taskState) {
+        //1 根据 taskId 修改任务状态 taskState。
+        //2 如果 taskState 为完成状态,调用打分算法对该任务进行打分。
+        return null;
+    }
+}

+ 55 - 0
simulation-resource-scheduler/src/main/resources/bootstrap.yml

@@ -0,0 +1,55 @@
+server:
+  port: 8001
+
+spring:
+  application:
+    name: project-service-a
+  #* -------------------------------- 环境配置 --------------------------------
+  profiles:
+    active: dev
+  #* -------------------------------- 微服务配置 --------------------------------
+  cloud:
+    nacos:
+      discovery:
+        server-addr: localhost:8841                     # 将配置中心注册进注册中心
+      config:                                           # ${prefix}- ${spring.profiles.active}.${file-extension}
+        server-addr: localhost:8841                     # 从注册中心的微服务列表读取配置
+        namespace: 40cc3b1a-33b1-488a-98dc-4ae0570992ee # 配置命名空间 id,命名空间一般为项目名
+        file-extension: yaml                            # 读取 yaml 类型的文件
+  #* -------------------------------- 数据源配置 --------------------------------
+  datasource:   # server-3_182.92.242.20_root_BMsATnte8uxs6Fr9
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://182.92.242.20:3306/simulation?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
+    username: root
+    password: BMsATnte8uxs6Fr9
+    dbcp2:
+      min-idle: 5         #数据库连接池的最小维持连接数
+      initial-size: 5     #初始化提供的连接数
+      max-total: 5          #最大的连接数
+      max-wait-millis: 200        #等待连接获取的最大超时时间
+  #* -------------------------------- kafka 消息队列 --------------------------------
+  kafka:
+    bootstrap-servers: 39.105.213.61:9091,39.105.213.61:9092,39.105.213.61:9093    # 指定连接的 kafka 集群。
+    listener:
+      missing-topics-fatal: false   # 消费端监听的topic不存在时,项目启动会报错(关掉)
+    producer: # 生产者配置
+      retries: 3                          # 重试次数。
+      acks: 1                             # 指定 ack 应答级别。0,1,-1
+      batch-size: 16384                   # 批次大小
+      buffer-memory: 33554432             # 缓冲区大小
+      key-serializer: org.apache.kafka.common.serialization.StringSerializer
+      value-serializer: org.apache.kafka.common.serialization.StringSerializer
+      properties:
+        linger:
+          ms: 0 # linger.ms为0表示每接收到一条消息就提交给kafka,这时候batch-size其实就没用了
+
+#  # -------------------------------- 缓存配置 --------------------------------
+#  cache:
+#    type: redis
+#  redis:
+#    host: localhost               # Redis 服务器地址
+#    port: 6379                    # Redis 服务器端口
+#    password: menglingxin0826     # Redis 服务器连接密码
+#    connect-timeout: 10000        # Redis 服务器连接超时时间
+#    timeout: 10000                # Redis 服务器读取数据超时时间