Browse Source

ui-server模块

yingp 7 years ago
parent
commit
6487d7b56e
27 changed files with 1063 additions and 25 deletions
  1. 2 2
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java
  2. 11 6
      applications/purchase/purchase-server/src/main/resources/application.yml
  3. 7 6
      base-servers/ui-server/pom.xml
  4. 2 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/UiApplication.java
  5. 32 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/ViewController.java
  6. 40 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/co/CoViewController.java
  7. 9 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/core/Const.java
  8. 79 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/Component.java
  9. 53 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/View.java
  10. 89 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoComponent.java
  11. 63 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoView.java
  12. 38 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ComponentRepository.java
  13. 27 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ViewRepository.java
  14. 32 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoComponentRepository.java
  15. 29 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoViewRepository.java
  16. 67 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ComponentService.java
  17. 51 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ViewService.java
  18. 71 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoComponentService.java
  19. 55 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoViewService.java
  20. 46 0
      base-servers/ui-server/src/main/resources/application.yml
  21. BIN
      base-servers/ui-server/src/main/resources/auth/pub.key
  22. 15 0
      base-servers/ui-server/src/main/resources/banner.txt
  23. 64 0
      base-servers/ui-server/src/main/resources/logback-spring.xml
  24. 148 0
      base-servers/ui-server/src/test/java/com/usoftchina/saas/ui/test/ViewServiceTest.java
  25. 18 0
      framework/core/src/main/java/com/usoftchina/saas/utils/StringUtils.java
  26. 12 0
      script/docker-base.yaml
  27. 3 11
      script/mysql/init/ui.sql

+ 2 - 2
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java

@@ -1,6 +1,6 @@
 package com.usoftchina.saas.purchase;
 
-import com.usoftchina.saas.auth.client.EnableAuthClient;
+//import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@@ -13,7 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @SpringBootApplication
 @EnableEurekaClient
 @EnableTransactionManagement
-@EnableAuthClient
+//@EnableAuthClient
 public class PurchaseApplication {
     public static void main(String[] args) {
         SpringApplication.run(PurchaseApplication.class, args);

+ 11 - 6
applications/purchase/purchase-server/src/main/resources/application.yml

@@ -6,11 +6,16 @@ spring:
       name: admin
       password: select111***
   datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://192.168.253.12:3306/saas_biz?characterEncoding=utf-8&useSSL=false
+    username: root
+    password: select111***
     hikari:
-      driver-class-name: com.mysql.cj.jdbc.Driver
-      jdbc-url: jdbc:mysql://192.168.253.12:3306/saas_biz?characterEncoding=utf-8&useSSL=false
-      username: root
-      password: select111***
+      minimum-idle: 5
+      maximum-pool-size: 50
+      idle-timeout: 30000
+      max-lifetime: 1800000
+      connection-timeout: 30000
   messages:
     basename: i18n/messages
 eureka:
@@ -24,9 +29,9 @@ eureka:
   client:
     registryFetchIntervalSeconds: 5
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8500/eureka/
 server:
-  port: 8580
+  port: 8800
   tomcat:
     uri-encoding: UTF-8
 info:

+ 7 - 6
base-servers/ui-server/pom.xml

@@ -31,12 +31,8 @@
         </dependency>
         <!-- db -->
         <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mybatis.spring.boot</groupId>
-            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
         </dependency>
         <!-- sleuth -->
         <dependency>
@@ -47,6 +43,11 @@
             <groupId>org.springframework.amqp</groupId>
             <artifactId>spring-rabbit</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>

+ 2 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/UiApplication.java

@@ -2,6 +2,7 @@ package com.usoftchina.saas.ui;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
@@ -12,6 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @SpringBootApplication
 @EnableEurekaClient
 @EnableTransactionManagement
+@EnableCaching
 public class UiApplication {
     public static void main(String[] args) {
         SpringApplication.run(UiApplication.class, args);

+ 32 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/ViewController.java

@@ -0,0 +1,32 @@
+package com.usoftchina.saas.ui.controller;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.ui.service.ViewService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RestController
+@RequestMapping("/api/ui/view")
+public class ViewController {
+
+    @Autowired
+    private ViewService viewService;
+
+    /**
+     * 获取通用视图配置
+     *
+     * @param name
+     * @return
+     */
+    @GetMapping("/config")
+    public Result<Object> getViewConfig(@RequestParam String name) {
+        return Result.success(viewService.getDeepConfig(name));
+    }
+}

+ 40 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/co/CoViewController.java

@@ -0,0 +1,40 @@
+package com.usoftchina.saas.ui.controller.co;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.ui.service.ViewService;
+import com.usoftchina.saas.ui.service.co.CoViewService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RestController
+@RequestMapping("/api/ui/co_view")
+public class CoViewController {
+    @Autowired
+    private CoViewService coViewService;
+
+    @Autowired
+    private ViewService viewService;
+
+    /**
+     * 获取企业视图配置
+     *
+     * @param name
+     * @return
+     */
+    @GetMapping("/config")
+    public Result<Object> getViewConfig(@RequestParam String name) {
+        Object config = coViewService.getDeepConfig(name);
+        if (null == config) {
+            // 企业配置不存在则取标准配置
+            config = viewService.getDeepConfig(name);
+        }
+        return Result.success(config);
+    }
+}

+ 9 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/core/Const.java

@@ -0,0 +1,9 @@
+package com.usoftchina.saas.ui.core;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+public class Const {
+    public static final String DEFAULT_CHILDREN_PROPERTY = "items";
+}

+ 79 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/Component.java

@@ -0,0 +1,79 @@
+package com.usoftchina.saas.ui.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_component")
+public class Component {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_component_view_index")
+    private String viewName;
+    @Indexed(name = "ui_component_pid_index")
+    private String parentId;
+    private String description;
+    private Integer orderNum;
+    private Object config;
+    private String childrenProperty;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getViewName() {
+        return viewName;
+    }
+
+    public void setViewName(String viewName) {
+        this.viewName = viewName;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+
+    public String getChildrenProperty() {
+        return childrenProperty;
+    }
+
+    public void setChildrenProperty(String childrenProperty) {
+        this.childrenProperty = childrenProperty;
+    }
+}

+ 53 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/View.java

@@ -0,0 +1,53 @@
+package com.usoftchina.saas.ui.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_view")
+public class View implements Serializable{
+    @Id
+    private String _id;
+    @Indexed(name = "ui_view_name_index", unique = true)
+    private String name;
+    private String description;
+    private Object config;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+}

+ 89 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoComponent.java

@@ -0,0 +1,89 @@
+package com.usoftchina.saas.ui.po.co;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_component_co")
+public class CoComponent {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_component_co_index")
+    private Long companyId;
+    @Indexed(name = "ui_component_view_index")
+    private String viewName;
+    @Indexed(name = "ui_component_pid_index")
+    private String parentId;
+    private String description;
+    private Integer orderNum;
+    private Object config;
+    private String childrenProperty;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getViewName() {
+        return viewName;
+    }
+
+    public void setViewName(String viewName) {
+        this.viewName = viewName;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+
+    public String getChildrenProperty() {
+        return childrenProperty;
+    }
+
+    public void setChildrenProperty(String childrenProperty) {
+        this.childrenProperty = childrenProperty;
+    }
+}

+ 63 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoView.java

@@ -0,0 +1,63 @@
+package com.usoftchina.saas.ui.po.co;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_view_co")
+public class CoView implements Serializable {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_view_co_index")
+    private Long companyId;
+    @Indexed(name = "ui_view_co_name_index", unique = true)
+    private String name;
+    private String description;
+    private Object config;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+}

+ 38 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ComponentRepository.java

@@ -0,0 +1,38 @@
+package com.usoftchina.saas.ui.repository;
+
+import com.usoftchina.saas.ui.po.Component;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface ComponentRepository extends MongoRepository<Component, String> {
+    /**
+     * 查找view下的组件
+     *
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    List<Component> findByViewNameAndParentIdOrderByOrderNum(String viewName, String parentId);
+
+    /**
+     * 查找view下的组件
+     *
+     * @param parentId
+     * @return
+     */
+    List<Component> findByParentIdOrderByOrderNum(String parentId);
+
+    /**
+     * 按view删除
+     *
+     * @param viewName
+     */
+    void deleteByViewName(String viewName);
+}

+ 27 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ViewRepository.java

@@ -0,0 +1,27 @@
+package com.usoftchina.saas.ui.repository;
+
+import com.usoftchina.saas.ui.po.View;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface ViewRepository extends MongoRepository<View, String> {
+    /**
+     * 按名称查找
+     *
+     * @param name
+     * @return
+     */
+    View findByName(String name);
+
+    /**
+     * 按名称删除
+     *
+     * @param name
+     */
+    void deleteByName(String name);
+}

+ 32 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoComponentRepository.java

@@ -0,0 +1,32 @@
+package com.usoftchina.saas.ui.repository.co;
+
+import com.usoftchina.saas.ui.po.co.CoComponent;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface CoComponentRepository extends MongoRepository<CoComponent, String> {
+    /**
+     * 查找view下的组件
+     *
+     * @param companyId
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    List<CoComponent> findByCompanyIdAndViewNameAndParentIdOrderByOrderNum(Long companyId, String viewName, String parentId);
+
+    /**
+     * 按view删除
+     *
+     * @param companyId
+     * @param viewName
+     */
+    void deleteByCompanyIdAndViewName(Long companyId, String viewName);
+}

+ 29 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoViewRepository.java

@@ -0,0 +1,29 @@
+package com.usoftchina.saas.ui.repository.co;
+
+import com.usoftchina.saas.ui.po.co.CoView;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface CoViewRepository extends MongoRepository<CoView, String> {
+    /**
+     * 按名称查找
+     *
+     * @param companyId
+     * @param name
+     * @return
+     */
+    CoView findByCompanyIdAndName(Long companyId, String name);
+
+    /**
+     * 按名称删除
+     *
+     * @param companyId
+     * @param name
+     */
+    void deleteByCompanyIdAndName(Long companyId, String name);
+}

+ 67 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ComponentService.java

@@ -0,0 +1,67 @@
+package com.usoftchina.saas.ui.service;
+
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.repository.ComponentRepository;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class ComponentService {
+
+    @Autowired
+    private ComponentRepository componentRepository;
+
+    @CacheEvict(value = "viewConfig", key = "#component.viewName")
+    public Component save(Component component) {
+        return componentRepository.save(component);
+    }
+
+    @CacheEvict(value = "viewConfig", key = "#viewName")
+    public void deleteByView(String viewName) {
+        componentRepository.deleteByViewName(viewName);
+    }
+
+    /**
+     * 按viewName深度查找config
+     *
+     * @param viewName
+     * @return
+     */
+    public List<Object> getDeepConfigsByView(String viewName) {
+        return getDeepConfigsByParent(viewName, null);
+    }
+
+    /**
+     * 按parentId深度查找config
+     *
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    private List<Object> getDeepConfigsByParent(String viewName, String parentId) {
+        List<Component> components = componentRepository.findByViewNameAndParentIdOrderByOrderNum(viewName, parentId);
+        if (!CollectionUtils.isEmpty(components)) {
+            return components.stream().map(cmp -> {
+                Map<String, Object> config = (Map<String, Object>) cmp.getConfig();
+                List<Object> childrenConfigs = getDeepConfigsByParent(viewName, cmp.get_id());
+                if (!CollectionUtils.isEmpty(childrenConfigs)) {
+                    config.put(StringUtils.nullIf(cmp.getChildrenProperty(), Const.DEFAULT_CHILDREN_PROPERTY), childrenConfigs);
+                }
+                return config;
+            }).collect(Collectors.toList());
+        }
+        return null;
+    }
+}

+ 51 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ViewService.java

@@ -0,0 +1,51 @@
+package com.usoftchina.saas.ui.service;
+
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.repository.ViewRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class ViewService {
+
+    @Autowired
+    private ViewRepository viewRepository;
+
+    @Autowired
+    private ComponentService componentService;
+
+    @CacheEvict(value = "viewConfig", key = "#view.name")
+    public View save(View view) {
+        return viewRepository.save(view);
+    }
+
+    @Cacheable(value = "viewConfig", key = "#name")
+    public Object getDeepConfig(String name) {
+        View view = viewRepository.findByName(name);
+        if (null != view && null != view.getConfig()) {
+            Map<String, Object> config = (Map<String, Object>) view.getConfig();
+            List<Object> items = componentService.getDeepConfigsByView(name);
+            if (!CollectionUtils.isEmpty(items)) {
+                config.put(Const.DEFAULT_CHILDREN_PROPERTY, items);
+            }
+            return config;
+        }
+        return null;
+    }
+
+    @CacheEvict(value = "viewConfig", key = "#name")
+    public void deleteView(String name) {
+        viewRepository.deleteByName(name);
+    }
+}

+ 71 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoComponentService.java

@@ -0,0 +1,71 @@
+package com.usoftchina.saas.ui.service.co;
+
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.po.co.CoComponent;
+import com.usoftchina.saas.ui.repository.co.CoComponentRepository;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class CoComponentService {
+
+    @Autowired
+    private CoComponentRepository componentRepository;
+
+    @CacheEvict(value = "coViewConfig", key = "#component.viewName")
+    public CoComponent save(CoComponent component) {
+        component.setCompanyId(BaseContextHolder.getCompanyId());
+        return componentRepository.save(component);
+    }
+
+    @CacheEvict(value = "coViewConfig", key = "#viewName")
+    public void deleteByView(String viewName) {
+        componentRepository.deleteByCompanyIdAndViewName(BaseContextHolder.getCompanyId(), viewName);
+    }
+
+    /**
+     * 按viewName深度查找config
+     *
+     * @param viewName
+     * @return
+     */
+    public List<Object> getDeepConfigsByView(String viewName) {
+        return getDeepConfigsByParent(BaseContextHolder.getCompanyId(), viewName, null);
+    }
+
+    /**
+     * 按parentId深度查找config
+     *
+     * @param companyId
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    private List<Object> getDeepConfigsByParent(Long companyId, String viewName, String parentId) {
+        List<CoComponent> components = componentRepository.findByCompanyIdAndViewNameAndParentIdOrderByOrderNum(companyId, viewName, parentId);
+        if (!CollectionUtils.isEmpty(components)) {
+            return components.stream().map(cmp -> {
+                Map<String, Object> config = (Map<String, Object>) cmp.getConfig();
+                List<Object> childrenConfigs = getDeepConfigsByParent(companyId, viewName, cmp.get_id());
+                if (!CollectionUtils.isEmpty(childrenConfigs)) {
+                    config.put(StringUtils.nullIf(cmp.getChildrenProperty(), Const.DEFAULT_CHILDREN_PROPERTY), childrenConfigs);
+                }
+                return config;
+            }).collect(Collectors.toList());
+        }
+        return null;
+    }
+}

+ 55 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoViewService.java

@@ -0,0 +1,55 @@
+package com.usoftchina.saas.ui.service.co;
+
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.po.co.CoView;
+import com.usoftchina.saas.ui.repository.ViewRepository;
+import com.usoftchina.saas.ui.repository.co.CoViewRepository;
+import com.usoftchina.saas.ui.service.ComponentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class CoViewService {
+    @Autowired
+    private CoViewRepository viewRepository;
+
+    @Autowired
+    private CoComponentService componentService;
+
+    @CacheEvict(value = "coViewConfig", key = "#view.name")
+    public CoView save(CoView view) {
+        view.setCompanyId(BaseContextHolder.getCompanyId());
+        return viewRepository.save(view);
+    }
+
+    @Cacheable(value = "coViewConfig", key = "#name")
+    public Object getDeepConfig(String name) {
+        CoView view = viewRepository.findByCompanyIdAndName(BaseContextHolder.getCompanyId(), name);
+        if (null != view && null != view.getConfig()) {
+            Map<String, Object> config = (Map<String, Object>) view.getConfig();
+            List<Object> items = componentService.getDeepConfigsByView(name);
+            if (!CollectionUtils.isEmpty(items)) {
+                config.put(Const.DEFAULT_CHILDREN_PROPERTY, items);
+            }
+            return config;
+        }
+        return null;
+    }
+
+    @CacheEvict(value = "coViewConfig", key = "#name")
+    public void deleteView(String name) {
+        viewRepository.deleteByCompanyIdAndName(BaseContextHolder.getCompanyId(), name);
+    }
+}

+ 46 - 0
base-servers/ui-server/src/main/resources/application.yml

@@ -0,0 +1,46 @@
+spring:
+  application:
+    name: ui-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  rabbitmq:
+    host: 192.168.0.176
+    port: 5672
+    password: guest
+    username: guest
+  zipkin:
+    sender:
+      type: rabbit
+  sleuth:
+    sampler:
+      percentage: 1.0
+  data:
+    mongodb:
+      uri: mongodb://192.168.253.12:27017/saas_ui
+server:
+  port: 8620
+  tomcat:
+    uri-encoding: UTF-8
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8500/eureka/
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+auth:
+  public-key: auth/pub.key

BIN
base-servers/ui-server/src/main/resources/auth/pub.key


+ 15 - 0
base-servers/ui-server/src/main/resources/banner.txt

@@ -0,0 +1,15 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+88        88   ad88888ba     ,ad8888ba,    88888888888  888888888888  ,ad8888ba,   88        88  88  888b      88         db
+88        88  d8"     "8b   d8"'    `"8b   88                88      d8"'    `"8b  88        88  88  8888b     88        d88b
+88        88  Y8,          d8'        `8b  88                88     d8'            88        88  88  88 `8b    88       d8'`8b
+88        88  `Y8aaaaa,    88          88  88aaaaa           88     88             88aaaaaaaa88  88  88  `8b   88      d8'  `8b
+88        88    `"""""8b,  88          88  88"""""           88     88             88""""""""88  88  88   `8b  88     d8YaaaaY8b
+88        88          `8b  Y8,        ,8P  88                88     Y8,            88        88  88  88    `8b 88    d8""""""""8b
+Y8a.    .a8P  Y8a     a8P   Y8a.    .a8P   88                88      Y8a.    .a8P  88        88  88  88     `8888   d8'        `8b
+ `"Y8888Y"'    "Y88888P"     `"Y8888Y"'    88                88       `"Y8888Y"'   88        88  88  88      `888  d8'          `8b
+
+
+Application Version: ${application.version}${application.formatted-version}
+Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
+${AnsiColor.DEFAULT}

+ 64 - 0
base-servers/ui-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
+    <jmxConfigurator/>
+
+    <!--
+    %m
+    输出代码中指定的消息
+    %p
+    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
+    %r
+    输出自应用启动到输出该log信息耗费的毫秒数
+    %c
+    输出所属的类目,通常就是所在类的全名
+    %t
+    输出产生该日志事件的线程名
+    %n
+    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
+    %d
+    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
+    输出类似:2002年10月18日 22:10:28,921
+    %l
+    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
+    -->
+
+    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/saas/ui-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="ui-server"/>
+    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
+    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
+    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
+
+    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
+
+
+    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${log.level.console}</level>
+        </filter>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/root.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 每天一归档 -->
+            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
+            <!-- 单个日志文件最多 100MB, 60天的日志周期,最大不能超过20GB -->
+            <maxFileSize>128MB</maxFileSize>
+            <maxHistory>60</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="${log.level.console}">
+        <appender-ref ref="CONSOLE_APPENDER"/>
+        <appender-ref ref="ROOT_APPENDER"/>
+    </root>
+
+</configuration>

+ 148 - 0
base-servers/ui-server/src/test/java/com/usoftchina/saas/ui/test/ViewServiceTest.java

@@ -0,0 +1,148 @@
+package com.usoftchina.saas.ui.test;
+
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.service.ComponentService;
+import com.usoftchina.saas.ui.service.ViewService;
+import com.usoftchina.saas.utils.JsonUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class ViewServiceTest {
+
+    @Autowired
+    private ViewService viewService;
+
+    @Autowired
+    private ComponentService componentService;
+
+    private String viewName = "test.form";
+
+    @Before
+    public void generateData() {
+        viewData();
+        part1Data();
+        part2Data();
+    }
+
+    private void viewData() {
+        View view = new View();
+        view.setName(viewName);
+        view.setDescription("测试表单");
+
+        Map<String, Object> config = new HashMap<>(2);
+        config.put("xtype", "container");
+        config.put("layout", "vbox");
+        view.setConfig(config);
+
+        view = viewService.save(view);
+
+        System.out.println(JsonUtils.toJsonString(view));
+    }
+
+    private void part1Data() {
+        Component part1 = new Component();
+        part1.setViewName(viewName);
+        part1.setOrderNum(1);
+        part1.setDescription("抬头Form");
+        Map<String, Object> part1Config = new HashMap<>(3);
+        part1Config.put("xtype", "form");
+        part1Config.put("height", 180);
+        part1Config.put("layout", "column");
+        part1.setConfig(part1Config);
+        part1 = componentService.save(part1);
+        System.out.println(JsonUtils.toJsonString(part1));
+
+        Component field1 = new Component();
+        field1.setViewName(viewName);
+        field1.setOrderNum(1);
+        field1.setDescription("编号");
+        field1.setParentId(part1.get_id());
+        Map<String, Object> field1Config = new HashMap<>(4);
+        field1Config.put("xtype", "textfield");
+        field1Config.put("name", "code");
+        field1Config.put("columnWidth", 0.25);
+        field1Config.put("fieldLabel", "编号");
+        field1.setConfig(field1Config);
+        componentService.save(field1);
+
+        Component field2 = new Component();
+        field2.setViewName(viewName);
+        field2.setOrderNum(2);
+        field2.setDescription("单据日期");
+        field2.setParentId(part1.get_id());
+        Map<String, Object> field2Config = new HashMap<>(3);
+        field2Config.put("xtype", "textfield");
+        field1Config.put("name", "docDate");
+        field2Config.put("columnWidth", 0.25);
+        field2Config.put("fieldLabel", "单据日期");
+        field2.setConfig(field2Config);
+        componentService.save(field2);
+    }
+
+    private void part2Data() {
+        Component part2 = new Component();
+        part2.setViewName(viewName);
+        part2.setOrderNum(2);
+        part2.setDescription("明细Grid");
+        part2.setChildrenProperty("columns");
+        Map<String, Object> part2Config = new HashMap<>(3);
+        part2Config.put("xtype", "grid");
+        part2Config.put("flex", 1);
+        part2Config.put("title", "商品清单");
+        part2.setConfig(part2Config);
+        part2 = componentService.save(part2);
+        System.out.println(JsonUtils.toJsonString(part2));
+
+        Component col1 = new Component();
+        col1.setViewName(viewName);
+        col1.setOrderNum(1);
+        col1.setDescription("商品编号");
+        col1.setParentId(part2.get_id());
+        Map<String, Object> col1Config = new HashMap<>(4);
+        col1Config.put("xtype", "triggercolumn");
+        col1Config.put("dataIndex", "pr_code");
+        col1Config.put("text", "商品编号");
+        col1.setConfig(col1Config);
+        componentService.save(col1);
+
+        Component col2 = new Component();
+        col2.setViewName(viewName);
+        col2.setOrderNum(2);
+        col2.setDescription("单位");
+        col2.setParentId(part2.get_id());
+        Map<String, Object> col2Config = new HashMap<>(3);
+        col2Config.put("xtype", "gridcolumn");
+        col2Config.put("dataIndex", "pr_unit");
+        col2Config.put("text", "单位");
+        col2.setConfig(col2Config);
+        componentService.save(col2);
+    }
+
+    @Test
+    public void getViewConfig() {
+        Object config = viewService.getDeepConfig(viewName);
+        System.out.println(JsonUtils.toJsonString(config));
+        // {"layout":"vbox","xtype":"container","items":[{"layout":"column","xtype":"form","height":180,"items":[{"name":"code","columnWidth":0.25,"xtype":"textfield","fieldLabel":"编号"},{"columnWidth":0.25,"xtype":"textfield","fieldLabel":"单据日期"}]},{"title":"商品清单","flex":1,"xtype":"grid","columns":[{"dataIndex":"pr_code","xtype":"triggercolumn","text":"商品编号"},{"dataIndex":"pr_unit","xtype":"gridcolumn","text":"单位"}]}]}
+    }
+
+    @After
+    public void deleteData() {
+        componentService.deleteByView(viewName);
+        viewService.deleteView(viewName);
+    }
+}

+ 18 - 0
framework/core/src/main/java/com/usoftchina/saas/utils/StringUtils.java

@@ -0,0 +1,18 @@
+package com.usoftchina.saas.utils;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+public class StringUtils {
+    /**
+     * 为空取值
+     *
+     * @param target
+     * @param nullValue
+     * @return
+     */
+    public static String nullIf(String target, String nullValue) {
+        return (null == target || target.isEmpty()) ? nullValue : target;
+    }
+}

+ 12 - 0
script/docker-base.yaml

@@ -12,6 +12,18 @@ services:
       - "25672:25672"
     networks:
       - saas
+  mongodb:
+    image: mongo
+    container_name: mongodb
+    ports:
+      - "27017:27017"
+    volumes:
+      - /data/mongodb:/data/db
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: root
+      MONGO_INITDB_ROOT_PASSWORD: select111***
+    networks:
+      - saas
 #  mysql:
 #    image: mysql:5.7
 #    container_name: mysql

+ 3 - 11
script/mysql/init/ui.sql

@@ -1,17 +1,9 @@
 CREATE DATABASE `saas_ui` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
 use `saas_ui`;
 
-create table `ui_page`(
+create table `ui_component`(
   id int unsigned primary key not null auto_increment,
+  parent_id varchar(100),
   description varchar(500) not null,
-  xtype varchar(50),
-  layout json
-);
-
-create table `ui_form`(
-  id int unsigned primary key not null auto_increment,
-  page_id varchar(100) not null,
-  field_name varchar(100) not null,
-  field_desc varchar(100) not null,
-  field_order int not null
+  config json not null
 );