reghao 4 лет назад
Родитель
Сommit
da93ae86a3
17 измененных файлов с 73 добавлено и 344 удалено
  1. 1 1
      common/src/main/java/cn/reghao/autodop/common/log/MqttAppender.java
  2. 1 1
      common/src/main/java/cn/reghao/autodop/common/mqtt/DefaultMqttClient.java
  3. 2 8
      common/src/main/java/cn/reghao/autodop/common/msg/Message.java
  4. 2 2
      common/src/main/java/cn/reghao/autodop/common/msg/MsgQueue.java
  5. 1 1
      dagent/src/main/java/cn/reghao/autodop/dagent/machine/NodeClazzPubImpl.java
  6. 2 4
      dagent/src/main/java/cn/reghao/autodop/dagent/rpc/RpcListener.java
  7. 0 16
      dmaster/src/main/java/cn/reghao/autodop/dmaster/DmasterApplication.java
  8. 0 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/config/AppConfigController.java
  9. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/bd/AppDeployer.java
  10. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/monitor/service/MonitorScheduler.java
  11. 5 8
      dmaster/src/main/java/cn/reghao/autodop/dmaster/mqttsub/MessageListener.java
  12. 0 52
      dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/BeforeAppShutdown.java
  13. 1 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/DmasterLifecycle.java
  14. 0 115
      dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/SpringBootUtil.java
  15. 0 5
      dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/config/CacheConfig.java
  16. 32 60
      dmaster/src/main/resources/templates/app/config/app/add.html
  17. 24 66
      dmaster/src/main/resources/templates/app/config/app/detail.html

+ 1 - 1
common/src/main/java/cn/reghao/autodop/common/log/MqttAppender.java

@@ -42,7 +42,7 @@ public class MqttAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
         NodeLogDTO nodeLogDTO = nodeLogDTO(event);
         NodeLogDTO nodeLogDTO = nodeLogDTO(event);
         String jsonPayload = JsonConverter.objectToJson(nodeLogDTO);
         String jsonPayload = JsonConverter.objectToJson(nodeLogDTO);
         PubMsg pubMsg = PubMsg.pubMsg(NodePubClazz.class.getSimpleName(), NodePubClazz.log.name(), jsonPayload);
         PubMsg pubMsg = PubMsg.pubMsg(NodePubClazz.class.getSimpleName(), NodePubClazz.log.name(), jsonPayload);
-        Message message = Message.pubMessage("", "", pubMsg);
+        Message message = Message.pubMessage(pubMsg);
         try {
         try {
             mqttClient.pub(topic, 1, JsonConverter.objectToJson(message));
             mqttClient.pub(topic, 1, JsonConverter.objectToJson(message));
         } catch (MqttException e) {
         } catch (MqttException e) {

+ 1 - 1
common/src/main/java/cn/reghao/autodop/common/mqtt/DefaultMqttClient.java

@@ -75,7 +75,7 @@ public class DefaultMqttClient implements AutoCloseable {
     /**
     /**
      * 确保能订阅到离线消息的设置:
      * 确保能订阅到离线消息的设置:
      * - qos=1
      * - qos=1
-     * - clientId 确定,不能使用随机的 UUID
+     * - clientId 确定且唯一,不能使用随机的 UUID
      * - CleanSession=false
      * - CleanSession=false
      *
      *
      * @param
      * @param

+ 2 - 8
common/src/main/java/cn/reghao/autodop/common/msg/Message.java

@@ -15,27 +15,21 @@ public class Message implements Serializable {
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     private String msgType;
     private String msgType;
-    private String destination;
-    private String originator;
     private PubMsg pubMsg;
     private PubMsg pubMsg;
     private RpcMsg rpcMsg;
     private RpcMsg rpcMsg;
     private long sendTime;
     private long sendTime;
 
 
-    public static Message pubMessage(String destination, String originator, PubMsg pubMsg) {
+    public static Message pubMessage(PubMsg pubMsg) {
         Message message = new Message();
         Message message = new Message();
         message.setMsgType(MsgType.pub.name());
         message.setMsgType(MsgType.pub.name());
-        message.setDestination(destination);
-        message.setOriginator(originator);
         message.setPubMsg(pubMsg);
         message.setPubMsg(pubMsg);
         message.setSendTime(System.currentTimeMillis());
         message.setSendTime(System.currentTimeMillis());
         return message;
         return message;
     }
     }
 
 
-    public static Message rpcMessage(String destination, String originator, RpcMsg rpcMsg) {
+    public static Message rpcMessage(RpcMsg rpcMsg) {
         Message message = new Message();
         Message message = new Message();
         message.setMsgType(MsgType.rpc.name());
         message.setMsgType(MsgType.rpc.name());
-        message.setDestination(destination);
-        message.setOriginator(originator);
         message.setRpcMsg(rpcMsg);
         message.setRpcMsg(rpcMsg);
         message.setSendTime(System.currentTimeMillis());
         message.setSendTime(System.currentTimeMillis());
         return message;
         return message;

+ 2 - 2
common/src/main/java/cn/reghao/autodop/common/msg/MsgQueue.java

@@ -11,7 +11,7 @@ public class MsgQueue {
         return String.format("sub.%s", AppId.dmaster.name());
         return String.format("sub.%s", AppId.dmaster.name());
     }
     }
 
 
-    public static String dagentTopic(String appId) {
-        return String.format("rpc.%s.%s", appId, AppId.dagent.name());
+    public static String dagentTopic(String nodeId) {
+        return String.format("rpc.%s.%s", nodeId, AppId.dagent.name());
     }
     }
 }
 }

+ 1 - 1
dagent/src/main/java/cn/reghao/autodop/dagent/machine/NodeClazzPubImpl.java

@@ -59,7 +59,7 @@ public class NodeClazzPubImpl {
     }
     }
     
     
     private void pub(PubMsg pubMsg) {
     private void pub(PubMsg pubMsg) {
-        Message message = Message.pubMessage("", "", pubMsg);
+        Message message = Message.pubMessage(pubMsg);
         try {
         try {
             mqttClient.pub(topic, 1, JsonConverter.objectToJson(message));
             mqttClient.pub(topic, 1, JsonConverter.objectToJson(message));
         } catch (MqttException e) {
         } catch (MqttException e) {

+ 2 - 4
dagent/src/main/java/cn/reghao/autodop/dagent/rpc/RpcListener.java

@@ -21,7 +21,7 @@ import org.springframework.stereotype.Component;
 import java.lang.management.ManagementFactory;
 import java.lang.management.ManagementFactory;
 
 
 /**
 /**
- * 分发 dmaster 发送的消息
+ * 处理 sub.{nodeId}.dagent topic 中的消息
  *
  *
  * @author reghao
  * @author reghao
  * @date 2021-05-24 09:24:03
  * @date 2021-05-24 09:24:03
@@ -49,8 +49,6 @@ public class RpcListener implements MqttCallback {
         try {
         try {
             String msg = message.toString();
             String msg = message.toString();
             Message callMessage = JsonConverter.jsonToObject(msg, Message.class);
             Message callMessage = JsonConverter.jsonToObject(msg, Message.class);
-            String originator = callMessage.getOriginator();
-            String destination = callMessage.getDestination();
             RpcMsg callMsg = callMessage.getRpcMsg();
             RpcMsg callMsg = callMessage.getRpcMsg();
 
 
             RpcPayload rpcPayload = callMsg.getRpcPayload();
             RpcPayload rpcPayload = callMsg.getRpcPayload();
@@ -72,7 +70,7 @@ public class RpcListener implements MqttCallback {
             }
             }
 
 
             RpcMsg resultMsg = RpcMsg.resultMsg(callMsg, rpcResult);
             RpcMsg resultMsg = RpcMsg.resultMsg(callMsg, rpcResult);
-            Message message1 = Message.rpcMessage(originator, destination, resultMsg);
+            Message message1 = Message.rpcMessage(resultMsg);
             rpcReply(message1);
             rpcReply(message1);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("MQTT message exception -> {}", e.getMessage());
             log.error("MQTT message exception -> {}", e.getMessage());

+ 0 - 16
dmaster/src/main/java/cn/reghao/autodop/dmaster/DmasterApplication.java

@@ -1,12 +1,8 @@
 package cn.reghao.autodop.dmaster;
 package cn.reghao.autodop.dmaster;
 
 
-import cn.reghao.autodop.dmaster.spring.BeforeAppShutdown;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
-import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
-import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 
 
@@ -15,18 +11,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 @EntityScan({"cn.reghao.autodop.dmaster"})
 @EntityScan({"cn.reghao.autodop.dmaster"})
 @ComponentScan({"cn.reghao.autodop.dmaster", "cn.reghao.autodop.common"})
 @ComponentScan({"cn.reghao.autodop.dmaster", "cn.reghao.autodop.common"})
 public class DmasterApplication {
 public class DmasterApplication {
-	@Bean
-	public BeforeAppShutdown shutdownGracefully() {
-		return new BeforeAppShutdown(30);
-	}
-
-	@Bean
-	public ConfigurableServletWebServerFactory webServerFactory(final BeforeAppShutdown beforeAppShutdown) {
-		TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
-		factory.addConnectorCustomizers(beforeAppShutdown);
-		return factory;
-	}
-
 	public static void main(String[] args) {
 	public static void main(String[] args) {
 		SpringApplication.run(DmasterApplication.class, args);
 		SpringApplication.run(DmasterApplication.class, args);
 	}
 	}

+ 0 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/config/AppConfigController.java

@@ -42,7 +42,6 @@ public class AppConfigController {
         Integer id = app.getId();
         Integer id = app.getId();
         Result result;
         Result result;
         if (id == null) {
         if (id == null) {
-            // TODO app 属于 proj 时,提交的数据中 proj 是 null
             result = appConfigService.add(app);
             result = appConfigService.add(app);
         } else {
         } else {
             result = appConfigService.modify(app);
             result = appConfigService.modify(app);

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/bd/AppDeployer.java

@@ -51,7 +51,7 @@ public class AppDeployer {
             RpcPayload rpcPayload = RpcPayload.rpcPayload(AppRpcClazz.class.getSimpleName(), AppRpcClazz.deploy.name(),
             RpcPayload rpcPayload = RpcPayload.rpcPayload(AppRpcClazz.class.getSimpleName(), AppRpcClazz.deploy.name(),
                     JsonConverter.objectToJson(deployParam));
                     JsonConverter.objectToJson(deployParam));
             RpcMsg rpcMsg = RpcMsg.callMsg(rpcPayload);
             RpcMsg rpcMsg = RpcMsg.callMsg(rpcPayload);
-            Message message = Message.rpcMessage("", "", rpcMsg);
+            Message message = Message.rpcMessage(rpcMsg);
 
 
             // TODO 对于需要返回值的 pub,需要做一个记录,pub 和 sub 一一对应
             // TODO 对于需要返回值的 pub,需要做一个记录,pub 和 sub 一一对应
             String topic = MsgQueue.dagentTopic(MachineId.id());
             String topic = MsgQueue.dagentTopic(MachineId.id());

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/monitor/service/MonitorScheduler.java

@@ -42,7 +42,7 @@ public class MonitorScheduler {
      * @return
      * @return
      * @date 2021-06-24 上午10:22
      * @date 2021-06-24 上午10:22
      */
      */
-    @PostConstruct
+    //@PostConstruct
     public void startScheduler() throws SchedulerException, IOException {
     public void startScheduler() throws SchedulerException, IOException {
         //startAllJobs();
         //startAllJobs();
         //scheduler.start();
         //scheduler.start();

+ 5 - 8
dmaster/src/main/java/cn/reghao/autodop/dmaster/mqttsub/MessageListener.java

@@ -20,7 +20,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
 /**
 /**
- * 分发 dagent 发送的消息
+ * 处理 sub.dmaster topic 中的消息
  *
  *
  * @author reghao
  * @author reghao
  * @date 2021-05-24 09:24:03
  * @date 2021-05-24 09:24:03
@@ -33,10 +33,8 @@ public class MessageListener implements MqttCallback {
     private final AppRpcClazzResult appRpcClazzResult;
     private final AppRpcClazzResult appRpcClazzResult;
     private final DockerRpcClazzResult dockerRpcClazzResult;
     private final DockerRpcClazzResult dockerRpcClazzResult;
 
 
-    public MessageListener(NodeClazzPubResult nodeClazzPubResult,
-                           MachineRpcClazzResult machineRpcClazzResult,
-                           AppRpcClazzResult appRpcClazzResult,
-                           DockerRpcClazzResult dockerRpcClazzResult) {
+    public MessageListener(NodeClazzPubResult nodeClazzPubResult, MachineRpcClazzResult machineRpcClazzResult,
+                           AppRpcClazzResult appRpcClazzResult, DockerRpcClazzResult dockerRpcClazzResult) {
         this.nodeClazzPubResult = nodeClazzPubResult;
         this.nodeClazzPubResult = nodeClazzPubResult;
         this.machineRpcClazzResult = machineRpcClazzResult;
         this.machineRpcClazzResult = machineRpcClazzResult;
         this.appRpcClazzResult = appRpcClazzResult;
         this.appRpcClazzResult = appRpcClazzResult;
@@ -58,7 +56,7 @@ public class MessageListener implements MqttCallback {
                     processPubMsg(message1.getPubMsg());
                     processPubMsg(message1.getPubMsg());
                     break;
                     break;
                 case rpc:
                 case rpc:
-                    processRpcMsg(message1.getRpcMsg());
+                    processRpcResult(message1.getRpcMsg());
                     break;
                     break;
                 default:
                 default:
             }
             }
@@ -80,7 +78,7 @@ public class MessageListener implements MqttCallback {
         }
         }
     }
     }
 
 
-    private void processRpcMsg(RpcMsg rpcMsg) {
+    private void processRpcResult(RpcMsg rpcMsg) {
         String msgId = rpcMsg.getMsgId();
         String msgId = rpcMsg.getMsgId();
         RpcPayload rpcPayload = rpcMsg.getRpcPayload();
         RpcPayload rpcPayload = rpcMsg.getRpcPayload();
         String clazz = rpcPayload.getClazz();
         String clazz = rpcPayload.getClazz();
@@ -103,7 +101,6 @@ public class MessageListener implements MqttCallback {
 
 
     @Override
     @Override
     public void deliveryComplete(IMqttDeliveryToken token) {
     public void deliveryComplete(IMqttDeliveryToken token) {
-        log.info("token -> {}", token);
     }
     }
 
 
     @Override
     @Override

+ 0 - 52
dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/BeforeAppShutdown.java

@@ -1,52 +0,0 @@
-package cn.reghao.autodop.dmaster.spring;
-
-import lombok.extern.slf4j.Slf4j;
-import org.apache.catalina.connector.Connector;
-import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextClosedEvent;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 应用进程结束前执行,优雅关闭
- * TODO 考虑应用停止的多种情况
- *
- * @author reghao
- * @date 2019-09-06 13:31:16
- */
-@Deprecated
-@Slf4j
-public class BeforeAppShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
-    private volatile Connector connector;
-    private long timeout;
-
-    public BeforeAppShutdown(long timeout) {
-        this.timeout = timeout;
-    }
-
-    @Override
-    public void customize(Connector connector) {
-        this.connector = connector;
-    }
-
-    @Override
-    public void onApplicationEvent(ContextClosedEvent event) {
-        connector.pause();
-        Executor executor = connector.getProtocolHandler().getExecutor();
-        if (executor instanceof ThreadPoolExecutor) {
-            ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
-            threadPoolExecutor.shutdown();
-            try {
-                if (!threadPoolExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) {
-                    log.warn("应用未在 30s 内优雅关闭,强制关闭应用");
-                }
-                log.warn("优雅关闭应用");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-}

+ 1 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/DmasterLifecycle.java

@@ -28,14 +28,12 @@ import java.util.List;
 @Slf4j
 @Slf4j
 @Component
 @Component
 public class DmasterLifecycle implements ApplicationRunner, DisposableBean {
 public class DmasterLifecycle implements ApplicationRunner, DisposableBean {
-    private final String topic;
     private final MessageListener messageListener;
     private final MessageListener messageListener;
     private final DefaultMqttClient mqttClient;
     private final DefaultMqttClient mqttClient;
     private final BuildDirService buildDirService;
     private final BuildDirService buildDirService;
 
 
     public DmasterLifecycle(NodeLogCrud nodeLogCrud, MessageListener messageListener,
     public DmasterLifecycle(NodeLogCrud nodeLogCrud, MessageListener messageListener,
                             BuildDirService buildDirService, DefaultMqttClient mqttClient) {
                             BuildDirService buildDirService, DefaultMqttClient mqttClient) {
-        this.topic = MsgQueue.dmasterTopic();
         this.messageListener = messageListener;
         this.messageListener = messageListener;
         this.mqttClient = mqttClient;
         this.mqttClient = mqttClient;
         this.buildDirService = buildDirService;
         this.buildDirService = buildDirService;
@@ -61,6 +59,7 @@ public class DmasterLifecycle implements ApplicationRunner, DisposableBean {
     }
     }
 
 
     private void subTopic() throws MqttException {
     private void subTopic() throws MqttException {
+        String topic = MsgQueue.dmasterTopic();
         mqttClient.sub(topic, messageListener);
         mqttClient.sub(topic, messageListener);
     }
     }
 
 

+ 0 - 115
dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/SpringBootUtil.java

@@ -1,115 +0,0 @@
-package cn.reghao.autodop.dmaster.spring;
-
-import cn.reghao.autodop.common.util.FileOps;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * @author reghao
- * @date 2019-08-30 13:58:48
- */
-@Slf4j
-@Component
-public class SpringBootUtil implements ApplicationContextAware {
-    private static ApplicationContext context;
-
-    /**
-     * 应用所在的目录
-     *
-     * @param
-     * @return
-     * @date 2019-08-30 下午2:04
-     */
-    public static String runningDir() {
-        return FileOps.dirPath(System.getProperty("java.class.path"));
-    }
-
-    /**
-     * 保存文件到指定目录
-     *
-     * @param
-     * @return
-     * @date 2019-08-28 下午10:01
-     */
-    public static String saveFile(MultipartFile file, String path) {
-        if (file.isEmpty()) {
-            return null;
-        } else {
-            String filePath = path + File.separator + file.getOriginalFilename();
-            File file2 = new File(filePath);
-            // 文件存在则删除
-            if (file2.exists() && !file2.delete()) {
-                return null;
-            }
-
-            try {
-                file.transferTo(file2);
-            } catch (IOException e) {
-                e.printStackTrace();
-                return null;
-            }
-
-            return filePath;
-        }
-    }
-
-    /**
-     * 重启 java 应用
-     *
-     * @param
-     * @return
-     * @date 2019-09-06 上午11:38
-     */
-    public static void restart(String filePath) {
-        /*String app = filePath.split(FileUtil.dirPath(filePath))[1].split("/")[1];
-        String stop = "jps|grep "+ app +"|cut -d \" \" -f1|xargs kill -15";
-        String start = "chmod +x " + filePath + " && " + filePath + " ./deployer-test.json";
-        String restart = stop + " && " + start;
-
-        try {
-            log.info("重启应用");
-            new ProcessBuilder("sh", "-c", restart).start();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }*/
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
-        context = ctx;
-    }
-
-    public static String getEnv() {
-        // TODO 潜在 bug,数组有多个元素的情况
-        return context.getEnvironment().getActiveProfiles()[0];
-    }
-
-    public static String getEnvDetail() {
-        String env = context.getEnvironment().getActiveProfiles()[0];
-        if ("dev".equals(env)) {
-            return "开发环境";
-        } else if ("test".equals(env)) {
-            return "测试环境";
-        } else if ("prod".equals(env)) {
-            return "生产环境";
-        } else {
-            return  "未知环境";
-        }
-    }
-
-    public static String getRunningDir() {
-        String env = getEnv();
-        if (env.equals("dev")) {
-            return FileOps.dirPath(System.getProperty("java.class.path").split(":")[0]);
-        } else {
-            return FileOps.dirPath(System.getProperty("java.class.path"));
-        }
-    }
-}

+ 0 - 5
dmaster/src/main/java/cn/reghao/autodop/dmaster/spring/config/CacheConfig.java

@@ -37,9 +37,4 @@ public class CacheConfig {
                 .expireAfterAccess(60, TimeUnit.SECONDS)
                 .expireAfterAccess(60, TimeUnit.SECONDS)
                 .build();
                 .build();
     }
     }
-
-    @Bean("projKeyGenerator")
-    public KeyGenerator projKeyGenerator() {
-        return (target, method, params) -> "proj" + "-" + params[0];
-    }
 }
 }

+ 32 - 60
dmaster/src/main/resources/templates/app/config/app/add.html

@@ -9,32 +9,6 @@
         <div class="timo-detail-title">基本信息</div>
         <div class="timo-detail-title">基本信息</div>
         <table class="layui-table timo-detail-table">
         <table class="layui-table timo-detail-table">
             <tbody>
             <tbody>
-            <span th:if="${app} == null">
-                <th>项目</th>
-                    <td>
-                        <div class="layui-form-item">
-                            <div class="layui-input-inline">
-                                <select name="app.proj.projId">
-                                    <option th:each="item:${projs}" th:value="${item.key}" >[[${item.value}]]</option>
-                                </select>
-                            </div>
-                        </div>
-                    </td>
-            </span>
-            <span th:if="${app?.proj} != null">
-                <tr>
-                    <th>项目</th>
-                    <td>
-                        <div class="layui-form-item">
-                            <div class="layui-input-inline">
-                                <select name="app.proj.projId">
-                                    <option th:each="item:${projs}" th:value="${item.key}" th:selected="${app.proj.projId} eq ${item.key}">[[${item.value}]]</option>
-                                </select>
-                            </div>
-                        </div>
-                    </td>
-                </tr>
-            </span>
             <tr>
             <tr>
                 <th>应用 ID</th>
                 <th>应用 ID</th>
                 <td>
                 <td>
@@ -138,40 +112,38 @@
                 </td>
                 </td>
             </tr>
             </tr>
             <!-- TODO 若选择了项目,则仓库、编译和打包配置不用选择 -->
             <!-- TODO 若选择了项目,则仓库、编译和打包配置不用选择 -->
-            <span th:if="${app?.proj} == null">
-                <tr>
-                    <th>仓库认证(若选择了项目则不必选择)</th>
-                    <td>
-                        <div class="layui-form-item">
-                            <div class="layui-input-inline">
-                                <select name="repoAuthConfig.name">
-                                    <option th:each="item : ${repoAuths}" th:value="${item.key}" th:selected="${app?.repoAuthConfig?.name} eq ${item.key}">[[${item.value}]]</option>
-                                </select>
-                            </div>
-                        </div>
-                    </td>
-                    <th>编译器(若选择了项目则不必选择)</th>
-                    <td>
-                        <div class="layui-form-item">
-                            <div class="layui-input-inline">
-                                <select name="compilerConfig.name">
-                                    <option th:each="item : ${compilers}" th:value="${item.key}" th:selected="${app?.compilerConfig?.name} eq ${item.key}">[[${item.value}]]</option>
-                                </select>
-                            </div>
-                        </div>
-                    </td>
-                    <th>打包工具(若选择了项目则不必选择)</th>
-                    <td>
-                        <div class="layui-form-item">
-                            <div class="layui-input-inline">
-                                <select name="packerConfig.name">
-                                    <option th:each="item : ${packers}" th:value="${item.key}" th:selected="${app?.packerConfig?.name} eq ${item.key}">[[${item.value}]]</option>
-                                </select>
-                            </div>
-                        </div>
-                    </td>
-                </tr>
-            </span>
+            <tr>
+                <th>仓库认证(若选择了项目则不必选择)</th>
+                <td>
+                    <div class="layui-form-item">
+                        <div class="layui-input-inline">
+                            <select name="repoAuthConfig.name">
+                                <option th:each="item : ${repoAuths}" th:value="${item.key}" th:selected="${app?.repoAuthConfig?.name} eq ${item.key}">[[${item.value}]]</option>
+                            </select>
+                        </div>
+                    </div>
+                </td>
+                <th>编译器(若选择了项目则不必选择)</th>
+                <td>
+                    <div class="layui-form-item">
+                        <div class="layui-input-inline">
+                            <select name="compilerConfig.name">
+                                <option th:each="item : ${compilers}" th:value="${item.key}" th:selected="${app?.compilerConfig?.name} eq ${item.key}">[[${item.value}]]</option>
+                            </select>
+                        </div>
+                    </div>
+                </td>
+                <th>打包工具(若选择了项目则不必选择)</th>
+                <td>
+                    <div class="layui-form-item">
+                        <div class="layui-input-inline">
+                            <select name="packerConfig.name">
+                                <option th:each="item : ${packers}" th:value="${item.key}" th:selected="${app?.packerConfig?.name} eq ${item.key}">[[${item.value}]]</option>
+                            </select>
+                        </div>
+                    </div>
+                </td>
+            </tr>
             <tr>
             <tr>
                 <th>Dockerfile</th>
                 <th>Dockerfile</th>
                 <td>
                 <td>

+ 24 - 66
dmaster/src/main/resources/templates/app/config/app/detail.html

@@ -6,12 +6,6 @@
         <div class="timo-detail-title">基本信息</div>
         <div class="timo-detail-title">基本信息</div>
         <table class="layui-table timo-detail-table">
         <table class="layui-table timo-detail-table">
             <tbody>
             <tbody>
-            <span th:if="${app?.proj} != null">
-                <tr>
-                    <th>所属项目</th>
-                    <td th:text="${app.proj.projName}"></td>
-                </tr>
-            </span>
             <tr>
             <tr>
                 <th>应用 ID</th>
                 <th>应用 ID</th>
                 <td th:text="${app.appId}"></td>
                 <td th:text="${app.appId}"></td>
@@ -64,66 +58,30 @@
                     <textarea class="layui-textarea" readonly="readonly" th:text="${app.packScript}"></textarea>
                     <textarea class="layui-textarea" readonly="readonly" th:text="${app.packScript}"></textarea>
                 </td>
                 </td>
             </tr>
             </tr>
-            <span th:if="${app.proj} != null">
-                <tr>
-                    <th>项目名字</th>
-                    <td th:text="${app.proj.projName}"></td>
-                    <th>项目仓库</th>
-                    <td th:text="${app.proj.projRepo}"></td>
-                    <th>仓库分支</th>
-                    <td th:text="${app.proj.repoBranch}"></td>
-                </tr>
-                <tr>
-                    <th>仓库类型</th>
-                    <td th:text="${app.proj.repoAuthConfig.type}"></td>
-                    <th>仓库认证名字</th>
-                    <td th:text="${app.proj.repoAuthConfig.name}"></td>
-                    <th>认证类型</th>
-                    <td th:text="${app.proj.repoAuthConfig.authType}"></td>
-                </tr>
-                <tr>
-                    <th>编译器类型</th>
-                    <td th:text="${app.proj.compilerConfig.type}"></td>
-                    <th>编译器名字</th>
-                    <td th:text="${app.proj.compilerConfig.name}"></td>
-                    <th>编译命令</th>
-                    <td th:text="${app.proj.compilerConfig.compileCmd}"></td>
-                </tr>
-                <tr>
-                    <th>打包类型</th>
-                    <td th:text="${app.proj.packerConfig.type}"></td>
-                    <th>打包名字</th>
-                    <td th:text="${app.proj.packerConfig.name}"></td>
-                    <th>打包路径</th>
-                    <td th:text="${app.proj.packerConfig.targetPath}"></td>
-                </tr>
-            </span>
-            <span th:if="${app.proj} == null">
-                <tr>
-                    <th>仓库类型</th>
-                    <td th:text="${app.repoAuthConfig.type}"></td>
-                    <th>仓库认证名字</th>
-                    <td th:text="${app.repoAuthConfig.name}"></td>
-                    <th>认证类型</th>
-                    <td th:text="${app.repoAuthConfig.authType}"></td>
-                </tr>
-                <tr>
-                    <th>编译器类型</th>
-                    <td th:text="${app.compilerConfig.type}"></td>
-                    <th>编译器名字</th>
-                    <td th:text="${app.compilerConfig.name}"></td>
-                    <th>编译命令</th>
-                    <td th:text="${app.compilerConfig.compileCmd}"></td>
-                </tr>
-                <tr>
-                    <th>打包类型</th>
-                    <td th:text="${app.packerConfig.type}"></td>
-                    <th>打包名字</th>
-                    <td th:text="${app.packerConfig.name}"></td>
-                    <th>打包路径</th>
-                    <td th:text="${app.packerConfig.targetPath}"></td>
-                </tr>
-                </span>
+            <tr>
+                <th>仓库类型</th>
+                <td th:text="${app.repoAuthConfig.type}"></td>
+                <th>仓库认证名字</th>
+                <td th:text="${app.repoAuthConfig.name}"></td>
+                <th>认证类型</th>
+                <td th:text="${app.repoAuthConfig.authType}"></td>
+            </tr>
+            <tr>
+                <th>编译器类型</th>
+                <td th:text="${app.compilerConfig.type}"></td>
+                <th>编译器名字</th>
+                <td th:text="${app.compilerConfig.name}"></td>
+                <th>编译命令</th>
+                <td th:text="${app.compilerConfig.compileCmd}"></td>
+            </tr>
+            <tr>
+                <th>打包类型</th>
+                <td th:text="${app.packerConfig.type}"></td>
+                <th>打包名字</th>
+                <td th:text="${app.packerConfig.name}"></td>
+                <th>打包路径</th>
+                <td th:text="${app.packerConfig.targetPath}"></td>
+            </tr>
             </tbody>
             </tbody>
         </table>
         </table>
         <div class="timo-detail-title">部署配置</div>
         <div class="timo-detail-title">部署配置</div>