martin 3 年 前
コミット
847bb498ab
22 ファイル変更914 行追加640 行削除
  1. 5 2
      api-common/src/main/java/api/common/pojo/po/UserPO.java
  2. 0 12
      api-common/src/main/java/api/common/util/EncodeUtil.java
  3. 161 99
      api-common/src/main/java/api/common/util/HttpUtil.java
  4. 7 0
      api-common/src/main/java/api/common/util/TimeUtil.java
  5. 34 2
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/http/HttpConfiguration.java
  6. 88 47
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SignController.java
  7. 27 18
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/mapper/UserMapper.java
  8. 13 0
      simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/util/EncodeUtil.java
  9. 16 0
      simulation-resource-common/src/main/java/com/css/simulation/resource/common/util/MinioUtil.java
  10. 23 0
      simulation-resource-scheduler/pom.xml
  11. 24 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/configuration/minio/MinioConfiguration.java
  12. 84 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/configuration/redis/RedisTemplateConfiguration.java
  13. 248 236
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/consumer/ManualProjectConsumer.java
  14. 26 27
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/TestConsumerController.java
  15. 0 55
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/CommonService.java
  16. 0 49
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/DemoController.java
  17. 0 58
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/fallback/CommonServiceFallback.java
  18. 3 8
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/IndexTemplateMapper.java
  19. 2 1
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/IndexTemplatePO.java
  20. 3 4
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/scheduler/TickScheduler.java
  21. 18 22
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/TaskService.java
  22. 132 0
      simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/util/MinioUtil.java

+ 5 - 2
api-common/src/main/java/api/common/pojo/po/UserPO.java

@@ -1,7 +1,9 @@
 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;
@@ -9,13 +11,15 @@ import java.io.Serializable;
 /**
  * 用户。
  */
+@EqualsAndHashCode(callSuper = true)
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class UserPO implements Serializable {
+public class UserPO extends CommonPO implements Serializable {
 
     private String id;              // 用户主键(唯一)
     private String username;        // 登录用户名
+    private String openid;          // 众工业平台的 openid
     private String nickname;        // 用户昵称,用于显示
     private String password;        // 密码(加密)
     private String phone;
@@ -23,6 +27,5 @@ public class UserPO implements Serializable {
     private String isSub;
     private String parentId;
     private String role;
-    private String isDeleted = "0";
 
 }

+ 0 - 12
api-common/src/main/java/api/common/util/EncodeUtil.java

@@ -1,12 +0,0 @@
-package api.common.util;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-
-public class EncodeUtil {
-
-    public static String utf8(String string) throws UnsupportedEncodingException {
-        return URLEncoder.encode(string, "utf-8");
-    }
-
-}

+ 161 - 99
api-common/src/main/java/api/common/util/HttpUtil.java

@@ -4,17 +4,22 @@ 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.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
 import org.apache.http.util.EntityUtils;
-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.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
 import java.util.Map;
 
 /**
@@ -23,45 +28,74 @@ import java.util.Map;
  * <artifactId>httpclient</artifactId>
  * <version>${http.client.version}</version>
  * </dependency>
- *
- * @author martin
  */
 public class HttpUtil {
 
+    public static CloseableHttpClient getHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+
+        PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
+        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
+                SSLContextBuilder.create().loadTrustMaterial(null, (x509Certificates, s) -> true).build(), // 全部信任 不做身份鉴定
+                new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"},
+                null,
+                NoopHostnameVerifier.INSTANCE);
+        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+                .register("http", plainConnectionSocketFactory)
+                .register("https", sslConnectionSocketFactory)
+                .build();
+        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(registry);
+        pool.setMaxTotal(300);
+        pool.setDefaultMaxPerRoute(300);
+        return HttpClients.custom().setConnectionManager(pool).build();
+    }
+
+    public static RequestConfig getRequestConfig() {
+        return RequestConfig.custom()
+                .setSocketTimeout(5000)
+                .setConnectTimeout(5000)
+                .setConnectionRequestTimeout(5000)
+                .setRedirectsEnabled(false)
+                .setExpectContinueEnabled(false)
+                .build();
+    }
+
+
     /**
-     * get 请求的参数在 url 里
+     * 普通 get 请求
+     *
+     * @param closeableHttpClient http 客户端
+     * @param requestConfig       请求配置
+     * @param url                 请求路径带参数
+     * @return 请求结果
+     * @throws IOException IO异常
      */
-    public static String get(CloseableHttpClient httpClient, RequestConfig requestConfig, String url, Map<String, String> headers) throws Exception {
+    public static String get(CloseableHttpClient closeableHttpClient, RequestConfig requestConfig, String url) throws IOException {
         //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) {
+        //2 发送请求
+        CloseableHttpResponse response = closeableHttpClient.execute(get);
+        //3 处理返回结果,如果状态码为200,就是正常返回
+        int statusCode = response.getStatusLine().getStatusCode();
+        if (statusCode == 200) {
             return EntityUtils.toString(response.getEntity());
-            //如果是下载文件,可以用response.getEntity().getContent()返回InputStream
         } else {
-            throw new Exception("服务器错误!");
+            throw new RuntimeException("------- 请求错误:" + statusCode);
         }
     }
 
     /**
-     * 通过 get 请求下载文件到本地
-     * 发送 get 请求,get 请求的参数在 url 里
+     * 带请求头的 get 请求
      *
-     * @param url           请求地址
-     * @param headers       请求头,可为 null
-     * @param localFilePath 本地保存的文件路径
-     * @throws IOException   异常
+     * @param closeableHttpClient http 客户端
+     * @param requestConfig       请求配置
+     * @param url                 请求路径带参数
+     * @param headers             请求头
+     * @return 请求结果
+     * @throws IOException IO异常
      */
-    public static InputStream get(CloseableHttpClient httpClient, RequestConfig requestConfig,String url, Map<String, String> headers, String localFilePath) throws IOException {
+    public static String get(CloseableHttpClient closeableHttpClient, RequestConfig requestConfig, String url,
+                             Map<String, String> headers) throws IOException {
         //1 创建 post 请求
         HttpGet get = new HttpGet(url);
         //2 设置请求默认配置
@@ -71,21 +105,27 @@ public class HttpUtil {
             headers.forEach(get::setHeader);
         }
         //4 发送请求
-        CloseableHttpResponse response = httpClient.execute(get);
+        CloseableHttpResponse response = closeableHttpClient.execute(get);
         //5 处理返回结果,
         //5-1 如果状态码为200,就是正常返回
-        if (response.getStatusLine().getStatusCode() == 200) {
-            //如果是下载文件,可以用response.getEntity().getContent()返回InputStream
-            return response.getEntity().getContent();
+        int statusCode = response.getStatusLine().getStatusCode();
+        if (statusCode == 200) {
+            return EntityUtils.toString(response.getEntity());
         } else {
-            throw new RuntimeException("服务器错误!");
+            throw new RuntimeException("------- 请求错误:" + statusCode);
         }
     }
 
     /**
      * 发送 post 请求
      */
-    public static String post(CloseableHttpClient httpClient, RequestConfig requestConfig,String url, Map<String, String> headers, Map<String, String> params) throws Exception {
+    public static String post(
+            CloseableHttpClient closeableHttpClient,
+            RequestConfig requestConfig,
+            String url,
+            Map<String, String> headers,
+            Map<String, String> params
+    ) throws Exception {
         //1 创建 post 请求
         HttpPost post = new HttpPost(url);
         //2 设置请求默认配置
@@ -99,75 +139,97 @@ public class HttpUtil {
             params.forEach(post::setHeader);
         }
         //5 发送请求
-        CloseableHttpResponse response = httpClient.execute(post);
+        CloseableHttpResponse response = closeableHttpClient.execute(post);
         //6 处理返回结果,
         //6-1 如果状态码为200,就是正常返回
-        if (response.getStatusLine().getStatusCode() == 200) {
+        int statusCode = response.getStatusLine().getStatusCode();
+        if (statusCode == 200) {
             return EntityUtils.toString(response.getEntity());
-            //如果是下载文件,可以用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);
+            throw new RuntimeException("------- 请求错误:" + statusCode);
         }
-        String str = stringBuffer.toString();
-        bufferedReader.close();
-        inputStreamReader.close();
-        inputStream.close();
-        return str;
     }
 
+//
+//    /**
+//     * 通过 get 请求下载文件
+//     * 发送 get 请求,get 请求的参数在 url 里
+//     *
+//     * @param url     请求地址
+//     * @param headers 请求头,可为 null
+//     * @return 文件流
+//     * @throws IOException 异常
+//     */
+//    public static InputStream getDownload(String url, Map<String, String> headers) throws IOException {
+//        //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,就是正常返回
+//        int statusCode = response.getStatusLine().getStatusCode();
+//        if (statusCode == 200) {
+//            return response.getEntity().getContent();
+//        } else {
+//            throw new RuntimeException("------- 请求错误:" + statusCode);
+//        }
+//    }
+//
+//
+//    /**
+//     * 发送 post 请求
+//     */
+//    public static InputStream postUpload(String url) throws IOException {
+//        //1 创建 post 请求
+//        HttpPost post = new HttpPost(url);
+//        //2 设置请求默认配置
+//        post.setConfig(requestConfig);
+//        //3 设置请求头 post.setHeader("Content-type", "application/json; charset=utf-8");
+//        post.setHeader("Content-type", "multipart/form-data");
+//        //5 发送请求
+//        CloseableHttpResponse response = httpClient.execute(post);
+//        //6 处理返回结果,
+//        //6-1 如果状态码为 200,就是正常返回
+//        int statusCode = response.getStatusLine().getStatusCode();
+//        if (statusCode == 200) {
+//            return response.getEntity().getContent();
+//        } else {
+//            throw new RuntimeException("------- 请求错误:" + statusCode);
+//        }
+//    }
+//
+//    /**
+//     * 发送 post 请求
+//     */
+//    public static InputStream postDownload(String url, Map<String, String> headers, Map<String, String> params) throws IOException {
+//        //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,就是正常返回
+//        int statusCode = response.getStatusLine().getStatusCode();
+//        if (statusCode == 200) {
+//            return response.getEntity().getContent();
+//        } else {
+//            throw new RuntimeException("------- 请求错误:" + statusCode);
+//        }
+//    }
 
 }

+ 7 - 0
api-common/src/main/java/api/common/util/TimeUtil.java

@@ -12,6 +12,13 @@ public class TimeUtil {
     public static long getNow() {
         return System.currentTimeMillis();
     }
+    public static long getNowLong() {
+        return System.currentTimeMillis();
+    }
+
+    public static String getNowString() {
+        return System.currentTimeMillis()+"";
+    }
 
     public static Timestamp getNowForMysql() {
         return new Timestamp(System.currentTimeMillis());

+ 34 - 2
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/configuration/http/HttpConfiguration.java

@@ -1,22 +1,54 @@
 package com.css.simulation.oauth.client.configuration.http;
 
 import org.apache.http.client.config.RequestConfig;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 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;
 
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+
 @Configuration
 public class HttpConfiguration {
     @Bean
-    public CloseableHttpClient closeableHttpClient() {
+    public CloseableHttpClient closeableHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        X509TrustManager x509TrustManager = new X509TrustManager() {
+            @Override
+            public X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+
+            @Override
+            public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
+            }
+
+            @Override
+            public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
+            }
+        };
+        sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
+        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
         PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
         pool.setMaxTotal(300);
         pool.setDefaultMaxPerRoute(300);
-        return HttpClients.custom().setConnectionManager(pool).build();
+        return HttpClients.custom()
+                .setConnectionManager(pool)
+                .setSSLSocketFactory(sslConnectionSocketFactory)
+                .build();
     }
 
+
     @Bean
     public RequestConfig requestConfig() {
         return RequestConfig.custom()

+ 88 - 47
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/controller/SignController.java

@@ -5,18 +5,17 @@ import api.common.pojo.param.SignSingleParameter;
 import api.common.pojo.param.SignUsernameParameter;
 import api.common.pojo.po.UserPO;
 import api.common.pojo.vo.SimulationTokenVO;
-import api.common.util.EncodeUtil;
-import api.common.util.EncryptUtil;
-import api.common.util.HttpUtil;
-import api.common.util.JsonUtil;
+import api.common.util.*;
 import com.css.simulation.oauth.client.configuration.oauth.OauthParameter;
 import com.css.simulation.oauth.client.mapper.UserMapper;
+import com.css.simulation.oauth.client.util.EncodeUtil;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -31,30 +30,23 @@ import javax.annotation.Resource;
 @Slf4j
 public class SignController {
 
+    static final String USER_ID = "simulation-oauth-client";
+
     @Resource
-    private UserMapper userMapper;
-    @Resource
-    private CloseableHttpClient closeableHttpClient;
+    UserMapper userMapper;
+    @Autowired
+    CloseableHttpClient closeableHttpClient;
     @Resource
-    private RequestConfig requestConfig;
+    RequestConfig requestConfig;
     @Resource
-    private OauthParameter oauthParameter;
+    OauthParameter oauthParameter;
 
-    /**
-     * http://localhost:6001/simulation/oauth/client/sign/hello
-     * http://localhost:7001/simulation/oauth/client/sign/hello
-     */
     @RequestMapping("/hello")
     @ResponseBody
     public String hello() {
         return "hello clent!";
     }
 
-
-    /**
-     * http://localhost:6001/simulation/oauth/client/entry?ticket=1001
-     * http://localhost:7001/simulation/oauth/client/entry?ticket=1001
-     */
     @RequestMapping("/entry")
     @SneakyThrows
     public String entry(@RequestParam("ticket") String ticket) {
@@ -77,6 +69,7 @@ public class SignController {
 
     /**
      * 单点登录
+     * 众工业平台:http://icvdc.china-icv.cn/
      *
      * @return token 信息
      */
@@ -90,60 +83,107 @@ public class SignController {
         String ticket = signSingleParameter.getTicket();
         String encodeTicket = EncodeUtil.utf8(ticket);
         log.info("------- /single 接收到的 code 为:" + code);
-        log.info("------- /single code 编码之后为:" + code);
+        log.info("------- /single code 编码之后为:" + encodeCode);
         log.info("------- /single 接收到的 ticket 为:" + ticket);
-        log.info("------- /single ticket 编码之后为:" + ticket);
-        //1 根据统一凭条 code 获取统一平台 access_token
-
-        String zoogooyTokenUrl = oauthParameter.getZoogooyTokenUri() + "?appid=" + oauthParameter.getZoogooyAppid() +
+        log.info("------- /single ticket 编码之后为:" + encodeTicket);
+        String zoogooyTokenUrl = oauthParameter.getZoogooyTokenUri() +
+                "?appid=" + oauthParameter.getZoogooyAppid() +
                 "&secret=" + oauthParameter.getZoogooyAppSecret() +
                 "&code=" + encodeCode +
                 "&grant_type=authorization_code";
-
-
-        String zoogooyTokenJson = HttpUtil.post(closeableHttpClient, requestConfig, zoogooyTokenUrl, null, null);
+        log.info("------- /single 根据编码之后的 code 获取众工业平台 access_token:" + zoogooyTokenUrl);
+        String zoogooyTokenJson = HttpUtil.get(closeableHttpClient, requestConfig, zoogooyTokenUrl);
         ObjectMapper objectMapper1 = new ObjectMapper();
         JsonNode tokenRoot = objectMapper1.readTree(zoogooyTokenJson);
-        String accessToken = tokenRoot.path("access_token").asText();
-        String openid = tokenRoot.path("openid").asText();
-        log.info("------- 统一平台令牌信息为:" + accessToken);
+        if (!tokenRoot.path("success").asBoolean()) {
+            throw new RuntimeException(tokenRoot.path("message").asText());
+        }
+        log.info("------- /single 众工业平台 token 信息为:" + zoogooyTokenJson);
+        /*
+        {
+          "data" : {
+            "scope" : "snsapi_userinfo",
+            "expires_in_sec" : 60,
+            "access_token" : "30b26a0824a1456f96bfc151b7bb5356",
+            "openid" : "6c7a11cebMkd0qvhpskKX1nRzAicfH9xePJ945DOG+7j9KOB/9M=",
+            "appid" : "2af6f44d98104dc5adcbfb49809ff9d5",
+            "create_time" : "2022-03-25 17:50:49",
+            "unionid" : "E2c47RsObMkd0qvhpskKX1nRzAicfH9xePJ945DOG+7j9KOB/9M="
+          },
+          "success" : true,
+          "message" : "ok",
+          "code" : 1,
+          "nowTime" : "2022-03-25 17:50:52"
+        }
+         */
 
-        //2 根据统一平台 access_token、openid、ticket 获取统一平台用户信息
+        String accessToken = tokenRoot.path("data").path("access_token").asText();
+        String encodeAccessToken = EncodeUtil.utf8(accessToken);
+        String openid = tokenRoot.path("data").path("openid").asText();
+        String encodeOpenid = EncodeUtil.utf8(openid);
 
+        log.info("------- /single 众工业平台 access_token 为:" + accessToken);
+        log.info("------- /single 众工业平台 access_token 编码之后为:" + encodeAccessToken);
+        log.info("------- /single 众工业平台 openid 为:" + openid);
+        log.info("------- /single 众工业平台 openid 编码之后为:" + encodeOpenid);
         String zoogooyUserUrl = oauthParameter.getZoogooyUserUri() +
-                "?access_token=" + accessToken +
-                "&openid=" + openid +
+                "?access_token=" + encodeAccessToken +
+                "&openid=" + encodeOpenid +
                 "&ticket=" + encodeTicket;
-        String zoogooyUserJson = HttpUtil.post(closeableHttpClient, requestConfig, zoogooyUserUrl, null, null);
+        log.info("------- /single 根据编码之后的 access_token、openid、ticket 获取众工业平台用户信息:" + zoogooyUserUrl);
+        /*
+        {
+          "data" : {
+            "loginName" : "13389957835",
+            "photoId" : "1648195226865/908fa0ec08fa513d7e3510cd40c346f1b3fbd9ba.jpeg",
+            "userType" : "personal",
+            "nickname" : "尼卡",
+            "openid" : "6c7a11cebMkd0qvhpskKX1nRzAicfH9xePJ945DOG+7j9KOB/9M="
+          },
+          "success" : true,
+          "message" : "ok",
+          "code" : 1,
+          "nowTime" : "2022-03-28 11:11:09"
+        }
+         */
+        String zoogooyUserJson = HttpUtil.get(closeableHttpClient, requestConfig, zoogooyUserUrl);
         ObjectMapper objectMapper2 = new ObjectMapper();
         JsonNode userRoot = objectMapper2.readTree(zoogooyUserJson);
+        if (!userRoot.path("success").asBoolean()) {
+            throw new RuntimeException("------- /single 获取众工业平台用户信息出错:" + zoogooyUserJson);
+        }
+        log.info("------- /single 众工业平台用户信息为:" + zoogooyUserJson);
 
-        String unionid = userRoot.path("unionid").asText();
-        String nickname = userRoot.path("nickname").asText();
-        log.info("------- 统一平台用户信息为:" + unionid);
+        String username = userRoot.path("data").path("loginName").asText();
+        String nickname = userRoot.path("data").path("nickname").asText();
+        String password = EncryptUtil.getLowerMD5(oauthParameter.getSimulationDefaultPassword());
 
         //3 使用 union_id 查询数据库,是否已在仿真平台存在该用户
-        String username;
-        String password;
-        UserPO oldUser = userMapper.selectByIdIgnoreDelete(unionid);
+        UserPO oldUser = userMapper.selectByOpenIdIgnoreDelete(openid);
         if (oldUser == null) {   //3-1 仿真平台不存在用户,直接创建新的
-            password = EncryptUtil.getLowerMD5(oauthParameter.getSimulationDefaultPassword());
             UserPO newUser = new UserPO();
-            newUser.setId(unionid);
-            username = openid;  // 将 openid 作为登录名
+            newUser.setId(StringUtil.getRandomUUID());
             newUser.setUsername(username);
             newUser.setNickname(nickname);
+            newUser.setOpenid(openid);
             newUser.setPassword(password);
+            newUser.setCreateUserId(USER_ID);
+            newUser.setModifyUserId(USER_ID);
+            newUser.setCreateTime(TimeUtil.getNowForMysql());
+            newUser.setModifyTime(TimeUtil.getNowForMysql());
+            newUser.setIsDeleted("0");
             userMapper.insert(newUser);
+            log.info("------- /single 成功插入新用户信息:" + newUser);
         } else {
             if ("1".equals(oldUser.getIsDeleted())) { //3-2 仿真平台存在删除状态用户,改为未删除
-                userMapper.updateIsDeleted(unionid, "0");
+                userMapper.updateIsDeleted(openid, "0");
             }
-            //3-3 仿真平台用户存在未删除用户,放行
+            //3-3 仿真平台用户存在未删除用户,放行。不会每次都更新,防止在仿真云平台更新的信息被众工业覆盖
             username = oldUser.getUsername();
             password = oldUser.getPassword();
         }
 
+        // -------------------------------- 这里需要用到前面创建的用户信息,所以不使用事务 --------------------------------
         //4 根据仿真平台用户名密码颁发仿真平台 token,返回给前端
         String simulationTokenUrl = oauthParameter.getSimulationTokenUri() +
                 "?grant_type=password" +
@@ -151,8 +191,9 @@ public class SignController {
                 "&client_secret=" + oauthParameter.getSimulationClientSecret() +
                 "&username=" + username +
                 "&password=" + password;
-        String simulationToken = HttpUtil.post(closeableHttpClient, requestConfig, simulationTokenUrl, null, null).toString();
-        System.out.println("------- 仿真平台令牌信息为:" + simulationToken);
+        log.info("------- /single 获取仿真云平台 token 信息:" + simulationTokenUrl);
+        String simulationToken = HttpUtil.get(closeableHttpClient, requestConfig, simulationTokenUrl);
+        log.info("------- /single 仿真云平台 token 信息为:" + simulationToken);
         SimulationTokenVO simulationTokenVO = JsonUtil.jsonToBean(simulationToken, SimulationTokenVO.class);
         return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS, simulationTokenVO);
     }
@@ -188,7 +229,7 @@ public class SignController {
                 "&client_secret=" + oauthParameter.getSimulationClientSecret() +
                 "&username=" + username +
                 "&password=" + password;
-        String simulationToken = HttpUtil.post(closeableHttpClient, requestConfig, simulationTokenUrl, null, null);
+        String simulationToken = HttpUtil.get(closeableHttpClient, requestConfig, simulationTokenUrl);
         System.out.println("------- 仿真平台令牌信息为:" + simulationToken);
         SimulationTokenVO simulationTokenVO = JsonUtil.jsonToBean(simulationToken, SimulationTokenVO.class);
         return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS, simulationTokenVO);

+ 27 - 18
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/mapper/UserMapper.java

@@ -19,8 +19,8 @@ public interface UserMapper {
             "       password,\n" +
             "       is_deleted\n" +
             "from system_user\n" +
-            "where id = #{id}")
-    UserPO selectByIdIgnoreDelete(@Param("id") String id);
+            "where openid = #{openid}")
+    UserPO selectByOpenIdIgnoreDelete(@Param("openid") String openid);
 
 
     @ResultMap("user")
@@ -35,27 +35,36 @@ public interface UserMapper {
 
     @Update("update system_user\n" +
             "set is_delete = #{isDeleted}\n" +
-            "   where id = #{id}")
-    void updateIsDeleted(@Param("id") String id,@Param("isDeleted") String isDeleted);
+            "   where openid = #{openid}")
+    void updateIsDeleted(@Param("openid") String openid,@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);
+    @Insert("insert into system_user(id,\n" +
+            "                        username,\n" +
+            "                        nickname,\n" +
+            "                        openid,\n" +
+            "                        password,\n" +
+            "                        create_time,\n" +
+            "                        modify_time,\n" +
+            "                        create_user_id,\n" +
+            "                        modify_user_id,\n" +
+            "                        is_deleted)\n" +
+            "values (\n" +
+            "           #{user.id},\n" +
+            "           #{user.username},\n" +
+            "           #{user.nickname},\n" +
+            "           #{user.openid},\n" +
+            "           #{user.password},\n" +
+            "           #{user.createTime},\n" +
+            "           #{user.modifyTime},\n" +
+            "           #{user.createUserId},\n" +
+            "           #{user.modifyUserId},\n" +
+            "           #{user.isDeleted}\n" +
+            "       )")
+    void insert(@Param("user") UserPO userPO);
 
 
 }

+ 13 - 0
simulation-oauth-client/src/main/java/com/css/simulation/oauth/client/util/EncodeUtil.java

@@ -0,0 +1,13 @@
+package com.css.simulation.oauth.client.util;
+
+import org.springframework.web.util.UriUtils;
+
+import java.io.UnsupportedEncodingException;
+
+public class EncodeUtil {
+
+    public static String utf8(String string) {
+        return UriUtils.encode(string, "utf-8");
+    }
+
+}

+ 16 - 0
simulation-resource-common/src/main/java/com/css/simulation/resource/common/util/MinioUtil.java

@@ -32,6 +32,22 @@ public class MinioUtil {
         }
     }
 
+
+    /**
+     * 获取预览路径
+     *
+     * @return 预览路径
+     */
+    public static String getFileList(MinioClient minioClient, Method method, String bucket, String object) throws io.minio.errors.ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, io.minio.errors.InternalException {
+
+
+        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
+                .method(method)
+                .bucket(bucket)
+                .object(object)
+                .build());
+    }
+
     /**
      * 获取预览路径
      *

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

@@ -18,6 +18,29 @@
 
     <dependencies>
 
+
+        <!-- minio - 开始 -->
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+        </dependency>
+        <!-- minio - 结束 -->
+
+        <!-- 缓存 - 开始-->
+        <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>
+        <!-- 缓存 - 结束-->
+
         <!-- docker 客户端 -->
         <dependency>
             <groupId>com.github.docker-java</groupId>

+ 24 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/configuration/minio/MinioConfiguration.java

@@ -0,0 +1,24 @@
+package com.css.simulation.resource.scheduler.configuration.minio;
+
+import io.minio.MinioClient;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "minio")
+public class MinioConfiguration {
+    private String endpoint;
+    private String accessKey;
+    private String secretKey;
+
+    @Bean
+    public MinioClient minioClient() {
+        return MinioClient.builder()
+                .endpoint(endpoint)
+                .credentials(accessKey, secretKey)
+                .build();
+    }
+}

+ 84 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/configuration/redis/RedisTemplateConfiguration.java

@@ -0,0 +1,84 @@
+package com.css.simulation.resource.scheduler.configuration.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;
+    }
+
+
+}

+ 248 - 236
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/consumer/ManualProjectConsumer.java

@@ -3,31 +3,30 @@ package com.css.simulation.resource.scheduler.consumer;
 
 import api.common.pojo.constants.DictConstants;
 import api.common.pojo.dto.ProjectMessageDTO;
-import api.common.pojo.param.KafkaParameter;
-import api.common.pojo.param.MinioParameter;
-import api.common.pojo.param.RedisParameter;
-import api.common.util.*;
-import com.css.simulation.resource.scheduler.feign.CommonService;
+import api.common.util.JsonUtil;
+import api.common.util.LinuxUtil;
+import api.common.util.StringUtil;
+import api.common.util.TimeUtil;
 import com.css.simulation.resource.scheduler.mapper.*;
-import com.css.simulation.resource.scheduler.pojo.to.*;
 import com.css.simulation.resource.scheduler.pojo.po.*;
-import feign.Response;
+import com.css.simulation.resource.scheduler.pojo.to.*;
+import com.css.simulation.resource.scheduler.util.MinioUtil;
 import io.kubernetes.client.openapi.ApiClient;
-import io.kubernetes.client.openapi.ApiException;
 import io.kubernetes.client.openapi.apis.BatchV1Api;
-import io.kubernetes.client.openapi.models.*;
+import io.kubernetes.client.openapi.models.V1Job;
 import io.kubernetes.client.util.Yaml;
+import io.minio.MinioClient;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.core.KafkaTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ResourceUtils;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -37,7 +36,14 @@ import java.util.List;
 public class ManualProjectConsumer {
 
     private static final String USER_ID = "simulation-resource-scheduler";
-
+    @Autowired
+    MinioClient minioClient;
+    @Value("${minio.bucket-name}")
+    String bucketName;
+    @Autowired
+    KafkaTemplate<String, String> kafkaTemplate;
+    @Autowired
+    StringRedisTemplate redisTemplate;
     @Autowired
     ProjectMapper projectMapper;
     @Autowired
@@ -53,8 +59,6 @@ public class ManualProjectConsumer {
     @Autowired
     SensorOgtMapper sensorOgtMapper;
     @Autowired
-    CommonService commonService;
-    @Autowired
     AlgorithmMapper algorithmMapper;
     @Autowired
     ApiClient apiClient;
@@ -153,7 +157,7 @@ public class ManualProjectConsumer {
             taskPO.setIsDeleted("0");
             taskMapper.insert(taskPO);
             // 心跳信息存在緩存中
-            commonService.set(new RedisParameter(manualProjectTopic + ":" + projectId + ":" + taskId, TimeUtil.getNow() + "", 0));
+            redisTemplate.opsForValue().set(manualProjectTopic + ":" + projectId + ":" + taskId, TimeUtil.getNowString());
             // 组装 task 消息
             TaskTO taskTO = TaskTO.builder()
                     .info(InfoTO.builder()
@@ -199,198 +203,20 @@ public class ManualProjectConsumer {
             //4-4 将对象转成 json
             String taskJson = JsonUtil.beanToJson(taskTO);
             //4-5 将 projectId 作为 topic 名称,发送 task 信息到 kafka
-            commonService.send(new KafkaParameter(projectId, taskJson));
+            kafkaTemplate.send(projectId, taskJson).addCallback(success -> {
+                // 消息发送到的topic
+                String topic = success.getRecordMetadata().topic();
+                // 消息发送到的分区
+                int partition = success.getRecordMetadata().partition();
+                // 消息在分区内的offset
+                long offset = success.getRecordMetadata().offset();
+                log.info("发送消息成功:" + topic + "-" + partition + "-" + offset);
+            }, failure -> {
+                log.error("发送消息失败:" + failure.getMessage());
+            });
         }
 
         // -------------------------------- 4 算法导入(一期按单机版做) --------------------------------
-//        // 私有仓库导入算法镜像(搭建私有仓库)
-//        String algorithmId = projectMessageDTO.getAlgorithmId();    // 算法 id
-//        //4-1 根据算法 id 获取算法文件地址、是否已导入成镜像。
-//        AlgorithmPO algorithmPO = algorithmMapper.selectById(algorithmId);
-//        String minioPath = algorithmPO.getMinioPath();
-//        String dockerImage;
-//        if ("0".equals(algorithmPO.getDockerImport())) {
-//            dockerImage = "algorithm_" + algorithmId + ":latest";
-//            String algorithmTarLinuxTempPath = linuxTempPath + minioPath;
-//            // 下载算法文件到本地( 2 到仓库服务器)
-//            Response response = commonService.download(new MinioParameter(minioPath));
-//            InputStream inputStream = response.body().asInputStream();
-//            FileUtil.writeInputStreamToLocalFile(inputStream, algorithmTarLinuxTempPath);
-//            //4-2 本地执行 docker load 算法文件成镜像(集群版可改成用 docker-java 操作仓库)
-//            LinuxUtil.execute("docker import " + algorithmTarLinuxTempPath + " " + dockerImage);
-//        } else if ("1".equals(algorithmPO.getDockerImport()) && StringUtil.isNotEmpty(algorithmPO.getDockerImage())) {
-//            dockerImage = algorithmPO.getDockerImage();
-//        } else {
-//            throw new RuntimeException("算法 " + algorithmId + "的 mysql 数据有误!");
-//        }
-        // -------------------------------- 5 创建 pod 开始执行 --------------------------------
-        int completions = sceneList.size();     // 结束标
-        int parallelism = projectMessageDTO.getParallelism();    // 并行度
-        BatchV1Api batchV1Api = new BatchV1Api(apiClient);
-//        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-template.yaml"));
-        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-test.yaml"));
-        //1 apiVersion
-        //2 kind
-        //3 metadata
-        V1ObjectMeta metadata = yaml.getMetadata();
-        metadata.setName("project_" + projectId);
-        yaml.setMetadata(metadata);
-        //4 job
-        V1JobSpec job = yaml.getSpec();
-        job.setCompletions(completions); // 这个标准是什么?
-        job.setParallelism(parallelism);
-        //5 pod
-        V1PodSpec v1PodSpec = job.getTemplate().getSpec();
-        //6 container
-        List<V1Container> containers = v1PodSpec.getContainers();
-        for (V1Container container : containers) {
-            String name = container.getName();
-            if ("vtd".equals(name)) {
-                container.setName("vtd_" + projectId);
-            }
-            if ("algorithm".equals(name)) {
-                container.setName("algorithm_" + projectId);
-//                container.setImage(dockerImage);
-            }
-        }
-        //4-4 创建
-        yaml.setSpec(job);
-        batchV1Api.createNamespacedJob("simulation-cloud", yaml, null, null, null);
-    }
-
-
-    //    public void testParseProject(ConsumerRecord<String, String> projectRecord) throws IOException, ApiException {
-    public void testParseProject(String projectJson) throws IOException, ApiException {
-//        System.out.println("------- 接收到消息为:" + projectRecord);
-        System.out.println("------- 接收到消息为:" + projectJson);
-        //1 读取 kafka 的 project 信息
-        /*
-            {
-                "projectId": "sadfasdfs",	// 项目 id
-                "algorithmId": "sadfasdfs",	// 算法 id
-                "vehicleConfigId": "sadfasdfs",	// 车辆 id
-                "scenePackageId": "sadfasdfs",	// 场景包 id
-                "maxSimulationTime": 11111,	// 最大仿真时间
-                "parallelism": 30		// 并行度
-            }
-         */
-//        String projectJson = projectRecord.value();
-        ProjectMessageDTO projectMessageDTO = JsonUtil.jsonToBean(projectJson, ProjectMessageDTO.class);
-        String projectId = projectMessageDTO.getProjectId();    // 项目 id
-        projectMapper.updateProjectState(projectId, "20");   // 修改该 project 的状态为执行中
-
-
-        // -------------------------------- 1 场景 --------------------------------
-        // 根据 packageId,拿到场景 id,然后获取每个场景的文件地址。
-        String packageId = projectMessageDTO.getScenePackageId();
-        List<IndexTemplatePO> leafIndexList = indexTemplateMapper.selectLeafIndexByPackageId(packageId);
-        List<String> naturalIdList = new ArrayList<>();
-        List<String> standardIdList = new ArrayList<>();
-        List<String> accidentIdList = new ArrayList<>();
-        for (IndexTemplatePO indexTemplatePO : leafIndexList) {
-            String naturalIds = indexTemplatePO.getSceneNaturalIds();
-            String standardIds = indexTemplatePO.getSceneStatueIds();
-            String accidentIds = indexTemplatePO.getSceneTrafficIds();
-            if (StringUtil.isNotEmpty(naturalIds)) {
-                String[] naturalIdArray = naturalIds.split(",");
-                naturalIdList.addAll(Arrays.asList(naturalIdArray));
-            }
-            if (StringUtil.isNotEmpty(standardIds)) {
-                String[] standardArray = standardIds.split(",");
-                standardIdList.addAll(Arrays.asList(standardArray));
-            }
-            if (StringUtil.isNotEmpty(accidentIds)) {
-                String[] accidentIdArray = accidentIds.split(",");
-                accidentIdList.addAll(Arrays.asList(accidentIdArray));
-            }
-        }
-        List<ScenePO> sceneList = new ArrayList<>();
-        sceneList.addAll(sceneMapper.selectNaturalByIdList(naturalIdList));
-        sceneList.addAll(sceneMapper.selectStandardByIdList(standardIdList));
-        sceneList.addAll(sceneMapper.selectAccidentByIdList(accidentIdList));
-        projectMapper.updateTaskNumber(projectId, sceneList.size()); // 有多少场景就有多少任务
-        // -------------------------------- 2 模型 --------------------------------
-        // 根据车辆配置id vehicleConfigId, 获取 模型信息和传感器信息
-        String vehicleConfigId = projectMessageDTO.getVehicleConfigId();// 模型配置 id
-        VehiclePO vehiclePO = vehicleMapper.selectByVehicleConfigId(vehicleConfigId);   // 模型
-        List<CameraPO> cameraPOList = sensorCameraMapper.selectCameraByVehicleConfigId(vehicleConfigId);    // 摄像头
-        List<OgtPO> ogtPOList = sensorOgtMapper.selectOgtByVehicleId(vehicleConfigId); // 完美传感器
-
-        // -------------------------------- 3 任务消息 --------------------------------
-        // 根据场景创建任务,组装 task 消息
-        int maxSimulationTime = projectMessageDTO.getMaxSimulationTime();
-
-        for (ScenePO scenePO : sceneList) {
-            String taskId = StringUtil.getRandomUUID();
-            String resultPath = linuxTempPath + projectId + "/" + taskId;
-            // 保存任务信息
-            TaskPO taskPO = TaskPO.builder() // run_start_time 和 run_end_time 不填
-                    .id(taskId)
-                    .pId(projectId)
-                    .sceneId(scenePO.getId())
-                    .sceneName(scenePO.getName())
-                    .sceneType(scenePO.getType())
-                    .runState(DictConstants.TASK_PENDING)
-                    .runResult(resultPath)
-                    .build();
-            taskPO.setCreateTime(TimeUtil.getNowForMysql());
-            taskPO.setCreateUserId(USER_ID);
-            taskPO.setModifyTime(TimeUtil.getNowForMysql());
-            taskPO.setModifyUserId(USER_ID);
-            taskPO.setModifyTime(TimeUtil.getNowForMysql());
-            taskPO.setIsDeleted("0");
-            taskMapper.insert(taskPO);
-            // 心跳信息存在緩存中
-            commonService.set(new RedisParameter(manualProjectTopic + ":" + projectId + ":" + taskId, TimeUtil.getNow() + "", 0));
-            // 组装 task 消息
-            TaskTO taskTO = TaskTO.builder()
-                    .info(InfoTO.builder()
-                            .project_id(projectId)
-                            .task_id(taskId)
-                            .task_path(resultPath)
-                            .default_time(maxSimulationTime)
-                            .build())
-                    .scenario(ScenarioTO.builder()
-                            .scenario_osc(scenePO.getScenarioOsc())
-                            .scenario_odr(scenePO.getScenarioOdr())
-                            .scenario_osgb(scenePO.getScenarioOsgb())
-                            .build())
-                    .vehicle(VehicleTO.builder()
-                            .model(ModelTO.builder()
-                                    .model_label(vehiclePO.getModelLabel())
-                                    .build())
-                            .dynamics(DynamicsTO.builder()
-                                    .dynamics_maxspeed(vehiclePO.getMaxSpeed())
-                                    .dynamics_enginepower(vehiclePO.getEnginePower())
-                                    .dynamics_maxdecel(vehiclePO.getMaxDeceleration())
-                                    .dynamics_maxsteering(vehiclePO.getMaxSteeringAngle())
-                                    .dynamics_mass(vehiclePO.getMass())
-                                    .dynamics_frontsurfaceeffective(vehiclePO.getFrontSurfaceEffective())
-                                    .dynamics_airdragcoefficient(vehiclePO.getAirDragCoefficient())
-                                    .dynamics_rollingresistance(vehiclePO.getRollingResistanceCoefficient())
-                                    .dynamics_wheeldiameter(vehiclePO.getWheelDiameter())
-                                    .dynamics_wheeldrive(vehiclePO.getWheelDrive())
-                                    .dynamics_overallefficiency(vehiclePO.getOverallEfficiency())
-                                    .dynamics_distfront(vehiclePO.getFrontDistance())
-                                    .dynamics_distrear(vehiclePO.getRearDistance())
-                                    .dynamics_distleft(vehiclePO.getLeftDistance())
-                                    .dynamics_distright(vehiclePO.getRightDistance())
-                                    .dynamics_distheight(vehiclePO.getHeightDistance())
-                                    .dynamics_wheelbase(vehiclePO.getWheelbase())
-                                    .build())
-                            .sensors(SensorsTO.builder()   // 根据 vehicleId 查询绑定的传感器列表
-                                    .camera(cameraPOList)
-                                    .OGT(ogtPOList)
-                                    .build())
-                            .build())
-                    .build();
-            //4-4 将对象转成 json
-            String taskJson = JsonUtil.beanToJson(taskTO);
-            //4-5 将 projectId 作为 topic 名称,发送 task 信息到 kafka
-            commonService.send(new KafkaParameter(projectId, taskJson));
-        }
-
-        // -------------------------------- 4 算法(一期按单机版做) --------------------------------
         // 私有仓库导入算法镜像(搭建私有仓库)
         String algorithmId = projectMessageDTO.getAlgorithmId();    // 算法 id
         //4-1 根据算法 id 获取算法文件地址、是否已导入成镜像。
@@ -401,9 +227,7 @@ public class ManualProjectConsumer {
             dockerImage = "algorithm_" + algorithmId + ":latest";
             String algorithmTarLinuxTempPath = linuxTempPath + minioPath;
             // 下载算法文件到本地( 2 到仓库服务器)
-            Response response = commonService.download(new MinioParameter(minioPath));
-            InputStream inputStream = response.body().asInputStream();
-            FileUtil.writeInputStreamToLocalFile(inputStream, algorithmTarLinuxTempPath);
+            MinioUtil.downloadToFile(minioClient, bucketName, minioPath, algorithmTarLinuxTempPath);
             //4-2 本地执行 docker load 算法文件成镜像(集群版可改成用 docker-java 操作仓库)
             LinuxUtil.execute("docker import " + algorithmTarLinuxTempPath + " " + dockerImage);
         } else if ("1".equals(algorithmPO.getDockerImport()) && StringUtil.isNotEmpty(algorithmPO.getDockerImage())) {
@@ -415,36 +239,224 @@ public class ManualProjectConsumer {
         int completions = sceneList.size();     // 结束标
         int parallelism = projectMessageDTO.getParallelism();    // 并行度
         BatchV1Api batchV1Api = new BatchV1Api(apiClient);
-        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-template.yaml"));
-        //1 apiVersion
-        //2 kind
-        //3 metadata
-        V1ObjectMeta metadata = yaml.getMetadata();
-        metadata.setName("project_" + projectId);
-        yaml.setMetadata(metadata);
-        //4 job
-        V1JobSpec job = yaml.getSpec();
-        job.setCompletions(completions); // 这个标准是什么?
-        job.setParallelism(parallelism);
-        //5 pod
-        V1PodSpec v1PodSpec = job.getTemplate().getSpec();
-        //6 container
-        List<V1Container> containers = v1PodSpec.getContainers();
-        for (V1Container container : containers) {
-            String name = container.getName();
-            if ("vtd".equals(name)) {
-                container.setName("vtd_" + projectId);
-            }
-            if ("algorithm".equals(name)) {
-                container.setName("algorithm_" + projectId);
-                container.setImage(dockerImage);
-            }
-        }
-        //4-4 创建
-        yaml.setSpec(job);
-        batchV1Api.createNamespacedJob("simulation-task", yaml, null, null, null);
-
+//        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-template.yaml"));
+        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-test.yaml"));
+//        //1 apiVersion
+//        //2 kind
+//        //3 metadata
+//        V1ObjectMeta metadata = yaml.getMetadata();
+//        metadata.setName("project_" + projectId);
+//        yaml.setMetadata(metadata);
+//        //4 job
+//        V1JobSpec job = yaml.getSpec();
+//        job.setCompletions(completions); // 这个标准是什么?
+//        job.setParallelism(parallelism);
+//        //5 pod
+//        V1PodSpec v1PodSpec = job.getTemplate().getSpec();
+//        //6 container
+//        List<V1Container> containers = v1PodSpec.getContainers();
+//        for (V1Container container : containers) {
+//            String name = container.getName();
+//            if ("vtd".equals(name)) {
+//                container.setName("vtd_" + projectId);
+//            }
+//            if ("algorithm".equals(name)) {
+//                container.setName("algorithm_" + projectId);
+////                container.setImage(dockerImage);
+//            }
+//        }
+//        //4-4 创建
+//        yaml.setSpec(job);
+        batchV1Api.createNamespacedJob("simulation-cloud", yaml, null, null, null);
     }
 
 
+//    //    public void testParseProject(ConsumerRecord<String, String> projectRecord) throws IOException, ApiException {
+//    public void testParseProject(String projectJson) throws IOException, ApiException {
+////        System.out.println("------- 接收到消息为:" + projectRecord);
+//        System.out.println("------- 接收到消息为:" + projectJson);
+//        //1 读取 kafka 的 project 信息
+//        /*
+//            {
+//                "projectId": "sadfasdfs",	// 项目 id
+//                "algorithmId": "sadfasdfs",	// 算法 id
+//                "vehicleConfigId": "sadfasdfs",	// 车辆 id
+//                "scenePackageId": "sadfasdfs",	// 场景包 id
+//                "maxSimulationTime": 11111,	// 最大仿真时间
+//                "parallelism": 30		// 并行度
+//            }
+//         */
+////        String projectJson = projectRecord.value();
+//        ProjectMessageDTO projectMessageDTO = JsonUtil.jsonToBean(projectJson, ProjectMessageDTO.class);
+//        String projectId = projectMessageDTO.getProjectId();    // 项目 id
+//        projectMapper.updateProjectState(projectId, "20");   // 修改该 project 的状态为执行中
+//
+//
+//        // -------------------------------- 1 场景 --------------------------------
+//        // 根据 packageId,拿到场景 id,然后获取每个场景的文件地址。
+//        String packageId = projectMessageDTO.getScenePackageId();
+//        List<IndexTemplatePO> leafIndexList = indexTemplateMapper.selectLeafIndexByPackageId(packageId);
+//        List<String> naturalIdList = new ArrayList<>();
+//        List<String> standardIdList = new ArrayList<>();
+//        List<String> accidentIdList = new ArrayList<>();
+//        for (IndexTemplatePO indexTemplatePO : leafIndexList) {
+//            String naturalIds = indexTemplatePO.getSceneNaturalIds();
+//            String standardIds = indexTemplatePO.getSceneStatueIds();
+//            String accidentIds = indexTemplatePO.getSceneTrafficIds();
+//            if (StringUtil.isNotEmpty(naturalIds)) {
+//                String[] naturalIdArray = naturalIds.split(",");
+//                naturalIdList.addAll(Arrays.asList(naturalIdArray));
+//            }
+//            if (StringUtil.isNotEmpty(standardIds)) {
+//                String[] standardArray = standardIds.split(",");
+//                standardIdList.addAll(Arrays.asList(standardArray));
+//            }
+//            if (StringUtil.isNotEmpty(accidentIds)) {
+//                String[] accidentIdArray = accidentIds.split(",");
+//                accidentIdList.addAll(Arrays.asList(accidentIdArray));
+//            }
+//        }
+//        List<ScenePO> sceneList = new ArrayList<>();
+//        sceneList.addAll(sceneMapper.selectNaturalByIdList(naturalIdList));
+//        sceneList.addAll(sceneMapper.selectStandardByIdList(standardIdList));
+//        sceneList.addAll(sceneMapper.selectAccidentByIdList(accidentIdList));
+//        projectMapper.updateTaskNumber(projectId, sceneList.size()); // 有多少场景就有多少任务
+//        // -------------------------------- 2 模型 --------------------------------
+//        // 根据车辆配置id vehicleConfigId, 获取 模型信息和传感器信息
+//        String vehicleConfigId = projectMessageDTO.getVehicleConfigId();// 模型配置 id
+//        VehiclePO vehiclePO = vehicleMapper.selectByVehicleConfigId(vehicleConfigId);   // 模型
+//        List<CameraPO> cameraPOList = sensorCameraMapper.selectCameraByVehicleConfigId(vehicleConfigId);    // 摄像头
+//        List<OgtPO> ogtPOList = sensorOgtMapper.selectOgtByVehicleId(vehicleConfigId); // 完美传感器
+//
+//        // -------------------------------- 3 任务消息 --------------------------------
+//        // 根据场景创建任务,组装 task 消息
+//        int maxSimulationTime = projectMessageDTO.getMaxSimulationTime();
+//
+//        for (ScenePO scenePO : sceneList) {
+//            String taskId = StringUtil.getRandomUUID();
+//            String resultPath = linuxTempPath + projectId + "/" + taskId;
+//            // 保存任务信息
+//            TaskPO taskPO = TaskPO.builder() // run_start_time 和 run_end_time 不填
+//                    .id(taskId)
+//                    .pId(projectId)
+//                    .sceneId(scenePO.getId())
+//                    .sceneName(scenePO.getName())
+//                    .sceneType(scenePO.getType())
+//                    .runState(DictConstants.TASK_PENDING)
+//                    .runResult(resultPath)
+//                    .build();
+//            taskPO.setCreateTime(TimeUtil.getNowForMysql());
+//            taskPO.setCreateUserId(USER_ID);
+//            taskPO.setModifyTime(TimeUtil.getNowForMysql());
+//            taskPO.setModifyUserId(USER_ID);
+//            taskPO.setModifyTime(TimeUtil.getNowForMysql());
+//            taskPO.setIsDeleted("0");
+//            taskMapper.insert(taskPO);
+//            // 心跳信息存在緩存中
+//            commonService.set(new RedisParameter(manualProjectTopic + ":" + projectId + ":" + taskId, TimeUtil.getNow() + "", 0));
+//            // 组装 task 消息
+//            TaskTO taskTO = TaskTO.builder()
+//                    .info(InfoTO.builder()
+//                            .project_id(projectId)
+//                            .task_id(taskId)
+//                            .task_path(resultPath)
+//                            .default_time(maxSimulationTime)
+//                            .build())
+//                    .scenario(ScenarioTO.builder()
+//                            .scenario_osc(scenePO.getScenarioOsc())
+//                            .scenario_odr(scenePO.getScenarioOdr())
+//                            .scenario_osgb(scenePO.getScenarioOsgb())
+//                            .build())
+//                    .vehicle(VehicleTO.builder()
+//                            .model(ModelTO.builder()
+//                                    .model_label(vehiclePO.getModelLabel())
+//                                    .build())
+//                            .dynamics(DynamicsTO.builder()
+//                                    .dynamics_maxspeed(vehiclePO.getMaxSpeed())
+//                                    .dynamics_enginepower(vehiclePO.getEnginePower())
+//                                    .dynamics_maxdecel(vehiclePO.getMaxDeceleration())
+//                                    .dynamics_maxsteering(vehiclePO.getMaxSteeringAngle())
+//                                    .dynamics_mass(vehiclePO.getMass())
+//                                    .dynamics_frontsurfaceeffective(vehiclePO.getFrontSurfaceEffective())
+//                                    .dynamics_airdragcoefficient(vehiclePO.getAirDragCoefficient())
+//                                    .dynamics_rollingresistance(vehiclePO.getRollingResistanceCoefficient())
+//                                    .dynamics_wheeldiameter(vehiclePO.getWheelDiameter())
+//                                    .dynamics_wheeldrive(vehiclePO.getWheelDrive())
+//                                    .dynamics_overallefficiency(vehiclePO.getOverallEfficiency())
+//                                    .dynamics_distfront(vehiclePO.getFrontDistance())
+//                                    .dynamics_distrear(vehiclePO.getRearDistance())
+//                                    .dynamics_distleft(vehiclePO.getLeftDistance())
+//                                    .dynamics_distright(vehiclePO.getRightDistance())
+//                                    .dynamics_distheight(vehiclePO.getHeightDistance())
+//                                    .dynamics_wheelbase(vehiclePO.getWheelbase())
+//                                    .build())
+//                            .sensors(SensorsTO.builder()   // 根据 vehicleId 查询绑定的传感器列表
+//                                    .camera(cameraPOList)
+//                                    .OGT(ogtPOList)
+//                                    .build())
+//                            .build())
+//                    .build();
+//            //4-4 将对象转成 json
+//            String taskJson = JsonUtil.beanToJson(taskTO);
+//            //4-5 将 projectId 作为 topic 名称,发送 task 信息到 kafka
+//            commonService.send(new KafkaParameter(projectId, taskJson));
+//        }
+//
+//        // -------------------------------- 4 算法(一期按单机版做) --------------------------------
+//        // 私有仓库导入算法镜像(搭建私有仓库)
+//        String algorithmId = projectMessageDTO.getAlgorithmId();    // 算法 id
+//        //4-1 根据算法 id 获取算法文件地址、是否已导入成镜像。
+//        AlgorithmPO algorithmPO = algorithmMapper.selectById(algorithmId);
+//        String minioPath = algorithmPO.getMinioPath();
+//        String dockerImage;
+//        if ("0".equals(algorithmPO.getDockerImport())) {
+//            dockerImage = "algorithm_" + algorithmId + ":latest";
+//            String algorithmTarLinuxTempPath = linuxTempPath + minioPath;
+//            // 下载算法文件到本地( 2 到仓库服务器)
+//            Response response = commonService.download(new MinioParameter(minioPath));
+//            InputStream inputStream = response.body().asInputStream();
+//            FileUtil.writeInputStreamToLocalFile(inputStream, algorithmTarLinuxTempPath);
+//            //4-2 本地执行 docker load 算法文件成镜像(集群版可改成用 docker-java 操作仓库)
+//            LinuxUtil.execute("docker import " + algorithmTarLinuxTempPath + " " + dockerImage);
+//        } else if ("1".equals(algorithmPO.getDockerImport()) && StringUtil.isNotEmpty(algorithmPO.getDockerImage())) {
+//            dockerImage = algorithmPO.getDockerImage();
+//        } else {
+//            throw new RuntimeException("算法 " + algorithmId + "的 mysql 数据有误!");
+//        }
+//        // -------------------------------- 5 创建 pod 开始执行 --------------------------------
+//        int completions = sceneList.size();     // 结束标
+//        int parallelism = projectMessageDTO.getParallelism();    // 并行度
+//        BatchV1Api batchV1Api = new BatchV1Api(apiClient);
+//        V1Job yaml = (V1Job) Yaml.load(ResourceUtils.getFile("classpath:kubernetes/template/job-template.yaml"));
+//        //1 apiVersion
+//        //2 kind
+//        //3 metadata
+//        V1ObjectMeta metadata = yaml.getMetadata();
+//        metadata.setName("project_" + projectId);
+//        yaml.setMetadata(metadata);
+//        //4 job
+//        V1JobSpec job = yaml.getSpec();
+//        job.setCompletions(completions);
+//        job.setParallelism(parallelism);
+//        //5 pod
+//        V1PodSpec v1PodSpec = job.getTemplate().getSpec();
+//        //6 container
+//        List<V1Container> containers = v1PodSpec.getContainers();
+//        for (V1Container container : containers) {
+//            String name = container.getName();
+//            if ("vtd".equals(name)) {
+//                container.setName("vtd_" + projectId);
+//            }
+//            if ("algorithm".equals(name)) {
+//                container.setName("algorithm_" + projectId);
+//                container.setImage(dockerImage);
+//            }
+//        }
+//        //4-4 创建
+//        yaml.setSpec(job);
+//        batchV1Api.createNamespacedJob("simulation-task", yaml, null, null, null);
+//
+//    }
+
+
 }

+ 26 - 27
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/controller/TestConsumerController.java

@@ -1,27 +1,26 @@
-package com.css.simulation.resource.scheduler.controller;
-
-import api.common.pojo.dto.ProjectMessageDTO;
-import api.common.util.JsonUtil;
-import com.css.simulation.resource.scheduler.consumer.ManualProjectConsumer;
-import io.kubernetes.client.openapi.ApiException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.IOException;
-
-@RequestMapping("/test")
-@RestController
-public class TestConsumerController {
-
-    @Autowired
-    ManualProjectConsumer manualProjectConsumer;
-
-    @PostMapping("/consumer")
-    public void hello(@RequestBody ProjectMessageDTO projectMessageDTO) throws IOException, ApiException {
-
-        manualProjectConsumer.testParseProject(JsonUtil.beanToJson(projectMessageDTO));
-    }
-}
+//package com.css.simulation.resource.scheduler.controller;
+//
+//import api.common.pojo.dto.ProjectMessageDTO;
+//import api.common.util.JsonUtil;
+//import com.css.simulation.resource.scheduler.consumer.ManualProjectConsumer;
+//import io.kubernetes.client.openapi.ApiException;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.web.bind.annotation.PostMapping;
+//import org.springframework.web.bind.annotation.RequestBody;
+//import org.springframework.web.bind.annotation.RequestMapping;
+//import org.springframework.web.bind.annotation.RestController;
+//
+//import java.io.IOException;
+//
+//@RequestMapping("/test")
+//@RestController
+//public class TestConsumerController {
+//
+//    @Autowired
+//    ManualProjectConsumer manualProjectConsumer;
+//
+//    @PostMapping("/consumer")
+//    public void hello(@RequestBody ProjectMessageDTO projectMessageDTO) throws IOException, ApiException {
+//        manualProjectConsumer.testParseProject(JsonUtil.beanToJson(projectMessageDTO));
+//    }
+//}

+ 0 - 55
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/CommonService.java

@@ -1,55 +0,0 @@
-package com.css.simulation.resource.scheduler.feign;
-
-import api.common.pojo.common.ResponseBodyVO;
-import api.common.pojo.param.KafkaParameter;
-import api.common.pojo.param.MinioParameter;
-import api.common.pojo.param.RedisParameter;
-import com.css.simulation.resource.scheduler.configuration.feign.OpenFeignConfiguration;
-import com.css.simulation.resource.scheduler.feign.fallback.CommonServiceFallback;
-import feign.Response;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.multipart.MultipartFile;
-
-@Component
-@FeignClient(
-        value = "simulation-resource-common",
-        contextId = "common1",
-        path = "/simulation/resource/common",
-        fallback = CommonServiceFallback.class,
-        configuration = OpenFeignConfiguration.class
-)
-public interface CommonService {
-
-    @PostMapping(value = "/minio/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    ResponseBodyVO<String> upload(@RequestPart("file") MultipartFile file,
-                                  @RequestParam("objectName") String objectName);
-
-    @PostMapping("/minio/download")
-    Response download(@RequestBody @Validated MinioParameter minioParameter);
-
-
-    @PostMapping(value = "/kafka/send", consumes = MediaType.APPLICATION_JSON_VALUE)
-    ResponseBodyVO<String> send(@RequestBody @Validated KafkaParameter kafkaParameter);
-
-    @PostMapping("/redis/get")
-    ResponseBodyVO<String> get(@RequestBody @Validated RedisParameter redisParameter);
-
-    @PostMapping("/redis/set")
-    ResponseBodyVO<String> set(@RequestBody @Validated RedisParameter redisParameter);
-
-    @PostMapping("/redis/getExpire")
-    ResponseBodyVO<Long> getExpire(@RequestBody @Validated RedisParameter redisParameter);
-
-
-    @PostMapping("/redis/delete")
-    ResponseBodyVO<String> delete(@RequestBody @Validated RedisParameter redisParameter);
-
-
-}

+ 0 - 49
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/DemoController.java

@@ -1,49 +0,0 @@
-package com.css.simulation.resource.scheduler.feign;
-
-import api.common.pojo.common.ResponseBodyVO;
-import api.common.pojo.param.KafkaParameter;
-import api.common.pojo.param.MinioParameter;
-import api.common.util.FileUtil;
-import feign.Response;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-
-@RestController
-@RequestMapping("/demo")
-public class DemoController {
-
-    @Autowired
-    private CommonService commonService;
-
-    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    public ResponseBodyVO<String> upload(@RequestPart("file") MultipartFile file,
-                                         @RequestParam("objectName") String objectName) {
-
-        return commonService.upload(file, objectName);
-    }
-
-    @PostMapping("/download")
-    public void download(
-            @RequestBody @Validated MinioParameter minioParameter,
-            HttpServletResponse response
-    ) throws IOException {
-        Response download = commonService.download(minioParameter);
-        Response.Body body = download.body();
-        InputStream inputStream = body.asInputStream();
-        FileUtil.downloadForHttp(minioParameter.getObjectName(), inputStream, response, 1024);
-    }
-
-    // -------------------------------- 带回调函数的发送 --------------------------------
-    @PostMapping("/send")
-    public ResponseBodyVO<String> send(@RequestBody @Validated KafkaParameter kafkaParameter) {
-        return commonService.send(kafkaParameter);
-    }
-
-}

+ 0 - 58
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/feign/fallback/CommonServiceFallback.java

@@ -1,58 +0,0 @@
-package com.css.simulation.resource.scheduler.feign.fallback;
-
-import api.common.pojo.common.ResponseBodyVO;
-import api.common.pojo.param.KafkaParameter;
-import api.common.pojo.param.MinioParameter;
-import api.common.pojo.param.RedisParameter;
-import com.css.simulation.resource.scheduler.feign.CommonService;
-import feign.Response;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.multipart.MultipartFile;
-
-
-@Service
-@Slf4j
-public class CommonServiceFallback implements CommonService {
-
-    @Override
-    public ResponseBodyVO<String> upload(@RequestPart("file") MultipartFile file,
-                                         @RequestParam("objectName") String objectName) {
-        return new ResponseBodyVO<>(ResponseBodyVO.Response.SERVER_FAILURE);
-    }
-
-    @Override
-    public Response download(@RequestBody @Validated MinioParameter minioParameter) {
-        log.error("------- 下载错误:" + minioParameter.getObjectName());
-        return null;
-    }
-
-    @Override
-    public ResponseBodyVO<String> send(KafkaParameter kafkaParameter) {
-        return new ResponseBodyVO<>(ResponseBodyVO.Response.SERVER_FAILURE);
-    }
-
-    @Override
-    public ResponseBodyVO<String> get(RedisParameter redisParameter) {
-        return null;
-    }
-
-    @Override
-    public ResponseBodyVO<String> set(RedisParameter redisParameter) {
-        return null;
-    }
-
-    @Override
-    public ResponseBodyVO<Long> getExpire(RedisParameter redisParameter) {
-        return null;
-    }
-
-    @Override
-    public ResponseBodyVO<String> delete(RedisParameter redisParameter) {
-        return null;
-    }
-}

+ 3 - 8
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/mapper/IndexTemplateMapper.java

@@ -23,6 +23,7 @@ public interface IndexTemplateMapper {
             @Result(column = "scene_statue_ids", property = "sceneStatueIds", jdbcType = JdbcType.VARCHAR),
             @Result(column = "weight", property = "weight", jdbcType = JdbcType.VARCHAR),
             @Result(column = "parent_id", property = "parentId", jdbcType = JdbcType.VARCHAR),
+            @Result(column = "rule_name", property = "ruleName", jdbcType = JdbcType.VARCHAR),
             @Result(column = "rule_details", property = "ruleDetails", jdbcType = JdbcType.VARCHAR)
     })
     @Select("select scene_natural_ids,\n" +
@@ -40,10 +41,11 @@ public interface IndexTemplateMapper {
             "       sps.scene_statue_ids,\n" +
             "       sps.weight,\n" +
             "       sps.parent_id,\n" +
+            "       sr.rule_name,\n" +
             "       sr.rule_details\n" +
             "from scene_package_sublist sps\n" +
             "         left join scoring_rules sr on sps.package_and_rules = sr.rules_id\n" +
-            "where root_id = '#{packageId}'\n" +
+            "where root_id = #{packageId}\n" +
             "  and package_and_rules is not null\n" +
             "  and package_and_rules != ''")
     List<IndexTemplatePO> selectLeafIndexWithRuleDetailsByPackageId(@Param("packageId") String packageId);
@@ -66,11 +68,4 @@ public interface IndexTemplateMapper {
             "</if>\n" +
             "")
     List<IndexTemplatePO> selectByIdList(@Param("idList") List<String> idList);
-
-
-    @Insert("insert into ")
-    void insertLeafIndex(IndexTemplatePO indexTemplatePO);
-
-    
-    void insertTotalScore(TaskIndexPO totalTaskIndex);
 }

+ 2 - 1
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/pojo/po/IndexTemplatePO.java

@@ -17,8 +17,9 @@ public class IndexTemplatePO {
     private String sceneStatueIds;
     private String weight;  // 权重
     private String parentId;  // 父 id
+    private String ruleName; // 打分规则名称,例如 AEB_1-1
     private String ruleDetails; // 打分规则代码
-    private Double tempScore; // 打分规则代码
+    private Double tempScore;
 
 
 }

+ 3 - 4
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/scheduler/TickScheduler.java

@@ -1,13 +1,12 @@
 package com.css.simulation.resource.scheduler.scheduler;
 
 import api.common.pojo.constants.DictConstants;
-import api.common.pojo.param.RedisParameter;
 import api.common.util.TimeUtil;
-import com.css.simulation.resource.scheduler.feign.CommonService;
 import com.css.simulation.resource.scheduler.mapper.TaskMapper;
 import com.css.simulation.resource.scheduler.pojo.po.TaskPO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
@@ -19,7 +18,7 @@ public class TickScheduler {
     @Value("${scheduler.manual-project.topic}")
     private String manualProjectTopic;
     @Autowired
-    private CommonService commonService;
+    StringRedisTemplate redisTemplate;
 
     @Autowired
     private TaskMapper taskMapper;
@@ -33,7 +32,7 @@ public class TickScheduler {
             String taskId = task.getId();
             String projectId = task.getPId();
             Long maxSimulationTime = task.getMaxSimulationTime();
-            long tickTime = Long.parseLong(commonService.get(RedisParameter.builder().key(manualProjectTopic + ":" + projectId + ":" + taskId).build()).getInfo());
+            long tickTime = Long.parseLong(redisTemplate.opsForValue().get(manualProjectTopic + ":" + projectId + ":" + taskId));
             if (TimeUtil.getNow() - tickTime > maxSimulationTime) {
                 //3 判断如果心跳时间距离当前时间已经超时,则修改任务状态为失败,并销毁 pod
                 taskMapper.updateState(taskId, DictConstants.TASK_ABORTED);

+ 18 - 22
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/service/TaskService.java

@@ -1,10 +1,7 @@
 package com.css.simulation.resource.scheduler.service;
 
 import api.common.pojo.constants.DictConstants;
-import api.common.pojo.param.MinioParameter;
-import api.common.pojo.param.RedisParameter;
 import api.common.util.*;
-import com.css.simulation.resource.scheduler.feign.CommonService;
 import com.css.simulation.resource.scheduler.manager.TaskIndexManager;
 import com.css.simulation.resource.scheduler.manager.TaskManager;
 import com.css.simulation.resource.scheduler.mapper.IndexTemplateMapper;
@@ -16,16 +13,16 @@ import com.css.simulation.resource.scheduler.pojo.po.ProjectPO;
 import com.css.simulation.resource.scheduler.pojo.po.TaskIndexPO;
 import com.css.simulation.resource.scheduler.pojo.po.TaskPO;
 import com.css.simulation.resource.scheduler.pojo.to.ScoreTO;
-import feign.Response;
+import com.css.simulation.resource.scheduler.util.MinioUtil;
+import io.minio.MinioClient;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -34,9 +31,12 @@ import java.util.stream.Collectors;
 public class TaskService {
 
     private final String USER_ID = "simulation-resource-scheduler";
-
     @Autowired
-    CommonService commonService;
+    MinioClient minioClient;
+    @Value("${minio.bucket-name}")
+    String bucketName;
+    @Autowired
+    StringRedisTemplate redisTemplate;
     @Autowired
     ProjectMapper projectMapper;
     @Autowired
@@ -63,20 +63,17 @@ public class TaskService {
     String linuxTempPath;
 
     public void taskTick(String taskId) {
-        log.info("------- 接收到任务 " + taskId + "的心跳!");
+        log.info("------- /tick 接收到任务 " + taskId + "的心跳!");
         // 刷新 redis 心跳时间
         ProjectPO projectPO = projectMapper.selectById(taskId);
         String projectId = projectPO.getId();
-        commonService.set(RedisParameter.builder()
-                .key(manualProjectTopic + ":" + projectId + ":" + taskId)
-                .value(TimeUtil.getNow() + "")
-                .build());
+        redisTemplate.opsForValue().set(manualProjectTopic + ":" + projectId + ":" + taskId, TimeUtil.getNowString());
     }
 
     @Transactional
     @SneakyThrows
     public void taskState(String taskId, String state) {
-        log.info("------- 接收到任务 " + taskId + "的状态:" + state);
+        log.info("------- /state 接收到任务 " + taskId + "的状态:" + state);
         //1 根据 taskId 修改任务状态 taskState。
         taskMapper.updateState(taskId, state);
         //2 如果 taskState 为完成状态,校验一下项目的已完成数量。
@@ -95,8 +92,9 @@ public class TaskService {
         for (int i = 0; i < leafIndexTemplateList.size(); i++) {
             IndexTemplatePO indexTemplatePO = leafIndexTemplateList.get(i);
             // -------------------------------- 将叶子节点对应的打分规则保存到临时目录 --------------------------------
+            String ruleName = indexTemplatePO.getRuleName();    // 打分脚本名称,例如 AEB_1-1
             String ruleDetails = indexTemplatePO.getRuleDetails();    // 打分脚本内容
-            String ruleDetailsPath = linuxTempPath + "rule-script/" + projectId + "_" + i;
+            String ruleDetailsPath = pyPath + "script/" + projectId + "_" + i;
             FileUtil.writeInputStreamToLocalFile(IoUtil.stringToInputStream(ruleDetails), ruleDetailsPath);
             // -------------------------------- 查询每个叶子指标包括的场景 --------------------------------
             Set<String> sceneIdSet = new HashSet<>();
@@ -125,18 +123,16 @@ public class TaskService {
                         String runResultMinio = task2.getRunResult();
                         String runResultLinux = linuxTempPath + runResultMinio;
 //                        String command = "python3 " + pyPath + " " + runResultLinux + " " + task2.getSceneType();  // 默认使用场景名称找打分脚本
-                        String command = "python3 " + pyPath + " " + runResultLinux + " " + task2.getSceneType() + " " + ruleDetailsPath; // 指定打分脚本
+                        String command = "python3 " + pyPath + "main.py " + runResultLinux + " " + task2.getSceneType() + " " + ruleDetailsPath; // 指定打分脚本
+
                         try {
-                            Response download = commonService.download(MinioParameter.builder().objectName(runResultMinio).build());
-                            Response.Body body = download.body();
-                            InputStream inputStream = body.asInputStream();
-                            FileUtil.writeInputStreamToLocalFile(inputStream, runResultLinux);
+                            MinioUtil.downloadToFile(minioClient, bucketName, runResultMinio, runResultLinux);
                             log.info("------- 开始执行打分命令:" + command);
                             score = JsonUtil.jsonToBean(SshUtil.execute(hostname, username, password, command), ScoreTO.class);
                             log.info("------- 打分结束,结果为:" + score);
-                        } catch (IOException e) {
+                        } catch (Exception e) {
                             log.error("------- 打分出错,命令为:" + command);
-                            throw new RuntimeException();
+                            throw new RuntimeException(e.getMessage());
                         }
                         task2.setReturnSceneId(score.getUnit_scene_ID());
                         task2.setScore(score.getUnit_scene_score());

+ 132 - 0
simulation-resource-scheduler/src/main/java/com/css/simulation/resource/scheduler/util/MinioUtil.java

@@ -0,0 +1,132 @@
+package com.css.simulation.resource.scheduler.util;
+
+import io.minio.*;
+import io.minio.errors.ErrorResponseException;
+import io.minio.errors.InsufficientDataException;
+import io.minio.errors.InvalidResponseException;
+import io.minio.errors.XmlParserException;
+import io.minio.http.Method;
+import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public class MinioUtil {
+
+    /**
+     * 判断 bucket 是否存在
+     */
+    public static boolean isBucketExist(MinioClient minioClient, String bucketName) throws InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
+    }
+
+    /**
+     * 创建 bucket
+     */
+    public static void createBucket(MinioClient minioClient, String bucketName) throws InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        if (!isBucketExist(minioClient, bucketName)) {
+            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+        }
+    }
+
+    /**
+     * 获取预览路径
+     *
+     * @return 预览路径
+     */
+    public static String getPreviewUrl(MinioClient minioClient, Method method, String bucket, String object) throws io.minio.errors.ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, io.minio.errors.InternalException {
+        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
+                .method(method)
+                .bucket(bucket)
+                .object(object)
+                .build());
+    }
+
+    /**
+     * 通过文件路径上传文件上传文件
+     */
+    public static void uploadFromFile(
+            MinioClient minioClient,
+            String sourceFilePath,
+            String bucketName,
+            String objectName
+    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        minioClient.uploadObject(UploadObjectArgs.builder()
+                .filename(sourceFilePath)
+                .bucket(bucketName)
+                .object(objectName)
+                .build());
+    }
+
+    /**
+     * 通过文件路径上传文件上传文件
+     *
+     * @param partSize 分片最小 5MB
+     */
+    public static void uploadFromStream(
+            MinioClient minioClient,
+            InputStream inputStream,
+            long objectSize,
+            long partSize,
+            String bucketName,
+            String objectName
+    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        minioClient.putObject(PutObjectArgs.builder()
+                .stream(inputStream, objectSize, partSize)
+                .bucket(bucketName)
+                .object(objectName)
+                .build());
+    }
+
+    /**
+     * 通过文件路径上传文件上传文件
+     */
+    public static void uploadFromMultipartFile(
+            MinioClient minioClient,
+            MultipartFile multipartFile,
+            String bucketName,
+            String objectName
+    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        InputStream inputStream = multipartFile.getInputStream();
+        long objectSize = multipartFile.getSize();
+        long partSize = 5 * 1024 * 1024L; // 分片最小 5M
+        minioClient.putObject(PutObjectArgs.builder()
+                .stream(inputStream, objectSize, partSize)
+                .bucket(bucketName)
+                .object(objectName)
+                .build());
+    }
+
+    /**
+     * 下载文件
+     */
+    public static void downloadToFile(
+            MinioClient minioClient,
+            String bucketName,
+            String objectName,
+            String targetFilePath
+    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        minioClient.downloadObject(DownloadObjectArgs.builder()
+                .bucket(bucketName)
+                .object(objectName)
+                .filename(targetFilePath)
+                .build());
+    }
+
+    /**
+     * 下载文件
+     */
+    public static InputStream downloadToStream(
+            MinioClient minioClient,
+            String bucketName,
+            String objectName
+    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
+        return minioClient.getObject(GetObjectArgs.builder()
+                .bucket(bucketName)
+                .object(objectName)
+                .build());
+    }
+}