sr hace 4 años
padre
commit
7c20c2c427
Se han modificado 33 ficheros con 3279 adiciones y 201 borrados
  1. 26 0
      boman-api/boman-domain/pom.xml
  2. 177 0
      boman-api/boman-domain/src/main/java/com.boman.domain/SysDictData.java
  3. 128 0
      boman-web-core/pom.xml
  4. 29 0
      boman-web-core/src/main/java/com/boman/web/core/BomanWebCoreApplication.java
  5. 19 0
      boman-web-core/src/main/java/com/boman/web/core/config/RestTemplateConfiguration.java
  6. 11 0
      boman-web-core/src/main/java/com/boman/web/core/constant/DictConstant.java
  7. 134 0
      boman-web-core/src/main/java/com/boman/web/core/constant/FormDataConstant.java
  8. 66 0
      boman-web-core/src/main/java/com/boman/web/core/constant/SubmitConstant.java
  9. 214 0
      boman-web-core/src/main/java/com/boman/web/core/controller/ObjController.java
  10. 70 0
      boman-web-core/src/main/java/com/boman/web/core/domain/BaseTableDTO.java
  11. 91 0
      boman-web-core/src/main/java/com/boman/web/core/domain/BaseTableSaveDTO.java
  12. 53 0
      boman-web-core/src/main/java/com/boman/web/core/domain/MainTableRecord.java
  13. 54 0
      boman-web-core/src/main/java/com/boman/web/core/domain/RowRecord.java
  14. 72 0
      boman-web-core/src/main/java/com/boman/web/core/domain/RowResult.java
  15. 185 0
      boman-web-core/src/main/java/com/boman/web/core/domain/TableServiceContext.java
  16. 30 0
      boman-web-core/src/main/java/com/boman/web/core/domain/TriggerActionConstant.java
  17. 662 0
      boman-web-core/src/main/java/com/boman/web/core/mapper/StandardlyMapper1.java
  18. 569 0
      boman-web-core/src/main/java/com/boman/web/core/service/TableServiceCmdService.java
  19. 67 0
      boman-web-core/src/main/java/com/boman/web/core/service/delete/BaseDeleteServiceImpl.java
  20. 46 0
      boman-web-core/src/main/java/com/boman/web/core/service/delete/IBaseDeleteService.java
  21. 69 0
      boman-web-core/src/main/java/com/boman/web/core/service/save/BaseSaveServiceImpl.java
  22. 29 0
      boman-web-core/src/main/java/com/boman/web/core/service/save/IBaseSaveService.java
  23. 97 0
      boman-web-core/src/main/java/com/boman/web/core/service/select/BaseSelectServiceImpl.java
  24. 59 0
      boman-web-core/src/main/java/com/boman/web/core/service/select/IBaseSelectService.java
  25. 38 0
      boman-web-core/src/main/java/com/boman/web/core/service/submit/BaseSubmitServiceImpl.java
  26. 21 0
      boman-web-core/src/main/java/com/boman/web/core/service/submit/IBaseSubmitService.java
  27. 75 0
      boman-web-core/src/main/java/com/boman/web/core/service/update/BaseUpdateServiceImpl.java
  28. 24 0
      boman-web-core/src/main/java/com/boman/web/core/service/update/IBaseUpdateService.java
  29. 57 0
      boman-web-core/src/main/java/com/boman/web/core/utils/IdUtils.java
  30. 17 0
      boman-web-core/src/main/resources/bootstrap.yml
  31. 74 0
      boman-web-core/src/main/resources/logback.xml
  32. 16 0
      boman-web-core/src/main/resources/rebel.xml
  33. 0 201
      ruoyi-ui/src/views/system/table/index.vue

+ 26 - 0
boman-api/boman-domain/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.boman</groupId>
+        <artifactId>boman-api</artifactId>
+        <version>2.5.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>boman-domain</artifactId>
+
+    <description>
+        boman-domain
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.4</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 177 - 0
boman-api/boman-domain/src/main/java/com.boman.domain/SysDictData.java

@@ -0,0 +1,177 @@
+package com.boman.system.api.domain;
+
+import com.boman.common.core.annotation.Excel;
+import com.boman.common.core.annotation.Excel.ColumnType;
+import com.boman.common.core.constant.UserConstants;
+import com.boman.common.core.web.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典数据表 sys_dict_data
+ * 
+ * @author ruoyi
+ */
+public class SysDictData extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 字典编码 */
+    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
+    private Long id;
+
+    /** 字典排序 */
+    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
+    private Long dictSort;
+
+    /** 字典标签 */
+    @Excel(name = "字典标签")
+    private String dictLabel;
+
+    /** 字典键值 */
+    @Excel(name = "字典键值")
+    private String dictValue;
+
+    /** 字典类型 */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /** 样式属性(其他样式扩展) */
+    private String cssClass;
+
+    /** 表格字典样式 */
+    private String listClass;
+
+    /** 是否默认(Y是 N否) */
+    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+    private String isDefault;
+
+    /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getDictSort()
+    {
+        return dictSort;
+    }
+
+    public void setDictSort(Long dictSort)
+    {
+        this.dictSort = dictSort;
+    }
+
+    @NotBlank(message = "字典标签不能为空")
+    @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
+    public String getDictLabel()
+    {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel)
+    {
+        this.dictLabel = dictLabel;
+    }
+
+    @NotBlank(message = "字典键值不能为空")
+    @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
+    public String getDictValue()
+    {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue)
+    {
+        this.dictValue = dictValue;
+    }
+
+    @NotBlank(message = "字典类型不能为空")
+    @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
+    public String getCssClass()
+    {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass)
+    {
+        this.cssClass = cssClass;
+    }
+
+    public String getListClass()
+    {
+        return listClass;
+    }
+
+    public void setListClass(String listClass)
+    {
+        this.listClass = listClass;
+    }
+
+    public boolean getDefault()
+    {
+        return UserConstants.YES.equals(this.isDefault) ? true : false;
+    }
+
+    public String getIsDefault()
+    {
+        return isDefault;
+    }
+
+    public void setIsDefault(String isDefault)
+    {
+        this.isDefault = isDefault;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("dictSort", getDictSort())
+            .append("dictLabel", getDictLabel())
+            .append("dictValue", getDictValue())
+            .append("dictType", getDictType())
+            .append("cssClass", getCssClass())
+            .append("listClass", getListClass())
+            .append("isDefault", getIsDefault())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}

+ 128 - 0
boman-web-core/pom.xml

@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.boman</groupId>
+        <artifactId>boman</artifactId>
+        <version>2.5.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>boman-web-core</artifactId>
+
+    <dependencies>
+
+        <!-- SpringCloud Ailibaba Nacos -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Ailibaba Nacos Config -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <!-- SpringCloud Ailibaba Sentinel -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+
+        <!-- SpringBoot Actuator -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!-- Swagger UI -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.fox.version}</version>
+        </dependency>
+
+        <!-- Mysql Connector -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- RuoYi Common DataSource -->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-common-datasource</artifactId>
+        </dependency>
+
+<!--         RuoYi Common DataScope-->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-common-datascope</artifactId>
+        </dependency>
+
+<!--         RuoYi Common Log-->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-common-log</artifactId>
+        </dependency>
+
+<!--         RuoYi Common Swagger-->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-common-swagger</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.9.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.4</version>
+        </dependency>
+
+        <!--        远程调用 gen-->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-api-gen</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+
+        <!--        远程调用 system-->
+        <dependency>
+            <groupId>com.boman</groupId>
+            <artifactId>boman-api-system</artifactId>
+            <version>2.5.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.boman</groupId>
+                    <artifactId>boman-modules-gen</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 29 - 0
boman-web-core/src/main/java/com/boman/web/core/BomanWebCoreApplication.java

@@ -0,0 +1,29 @@
+package com.boman.web.core;
+
+import com.boman.common.security.annotation.EnableCustomConfig;
+import com.boman.common.security.annotation.EnableRyFeignClients;
+import com.boman.common.swagger.annotation.EnableCustomSwagger2;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cloud.client.SpringCloudApplication;
+
+/**
+ * web-core
+ *
+ * @author shiqian
+ */
+@EnableCustomConfig
+@EnableCustomSwagger2
+@EnableRyFeignClients
+@SpringCloudApplication
+public class BomanWebCoreApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(BomanWebCoreApplication.class, args);
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+        System.out.println("---------------------------------------------- web-core 模块启动成功----------------------------------------------");
+    }
+}

+ 19 - 0
boman-web-core/src/main/java/com/boman/web/core/config/RestTemplateConfiguration.java

@@ -0,0 +1,19 @@
+package com.boman.web.core.config;
+
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author tjf
+ * @Date: 2021/04/01/18:20
+ */
+@Configuration
+public class RestTemplateConfiguration {
+    @Bean
+    @LoadBalanced
+    public RestTemplate getRestTemplate(){
+        return new RestTemplate();
+    }
+}

+ 11 - 0
boman-web-core/src/main/java/com/boman/web/core/constant/DictConstant.java

@@ -0,0 +1,11 @@
+package com.boman.web.core.constant;
+
+/**
+ * @author shiqian
+ * @date 2021年04月02日 14:52
+ **/
+public class DictConstant {
+
+    public static final String DICT_LABEL = "dictLabel";
+    public static final String DICT_VALUE = "dictValue";
+}

+ 134 - 0
boman-web-core/src/main/java/com/boman/web/core/constant/FormDataConstant.java

@@ -0,0 +1,134 @@
+package com.boman.web.core.constant;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * @author shiqian
+ * @date 2021年03月26日 09:47
+ **/
+public class FormDataConstant {
+
+    /**
+     * 删除数据时,需要删除的业务表的主键
+     */
+    public static final String ID_LIST = "idList";
+
+    /**
+     * id标识
+     */
+    public static final String ID = "id";
+
+    /**
+     * 查询的条件
+     */
+    public static final String CONDITION = "condition";
+
+    /**
+     * 查询后需要返回到前台的字段
+     */
+    public static final String SHOW_DATA = "showData";
+
+
+    /**
+     * equals
+     */
+    public static final String EQ = "EQ";
+
+    /**
+     * like
+     */
+    public static final String LIKE = "LIKE";
+
+    /**
+     * not equals
+     */
+    public static final String NE = "NE";
+
+    /**
+     * greater than
+     */
+    public static final String GT = "GT";
+
+    /**
+     * greater than or equal to
+     */
+    public static final String GTE = "GTE";
+
+    /**
+     * less than
+     */
+    public static final String LT = "LT";
+
+    /**
+     * less than or equal to
+     */
+    public static final String LTE = "LTE";
+
+    /**
+     * between and
+     */
+    public static final String BETWEEN = "BETWEEN";
+
+    /**
+     * 需要转义
+     */
+    public static final String VARCHAR = "varchar";
+
+    public static final String CHAR = "char";
+    public static final String DATETIME = "datetime";
+    public static final String TIMESTAMP = "timestamp";
+
+    /**  根据表名查询表单时,返回给前台的查询字段   */
+    public static final String QUERY_LIST = "queryList";
+
+    /**  根据表名查询表单时,返回给前台的按钮 (其实不是list而是 "AMDQSUE"的字符串 */
+    public static final String BUTTON_LIST = "buttonList";
+
+    /**  根据表名查询表单时,返回给前台列表展示的列*/
+    public static final String TABLE_HEAD_LIST = "tableHeadList";
+
+    /**  分页  总条数*/
+    public static final String PAGE_TOTAL = "total";
+
+    /**  分页 总记录*/
+    public static final String PAGE_ROWS = "rows";
+
+
+    /**  数据库字段创建人*/
+    public static final String UPDATE_BY = "UPDATE_BY";
+
+
+    /**  数据库字段创建时间*/
+    public static final String UPDATE_TIME = "UPDATE_TIME";
+
+    /**  数据库字段创建人*/
+    public static final String CREATE_BY = "create_by";
+
+    /**  数据库字段创建时间*/
+    public static final String CREATE_TIME = "create_time";
+
+
+    /**  状态 */
+    public static final String STATUS = "status";
+
+
+    /**  单选框 */
+    public static final String RADIO = "radio";
+
+
+    /**  复选框 */
+    public static final String CHECKBOX = "checkbox";
+
+
+    /**  下拉框 */
+    public static final String SELECT = "select";
+
+
+    /**  需要查字典表的框框 */
+    public static final List<String> NEED_QUERY_DICT_LIST = Lists.newArrayList(RADIO, CHECKBOX, SELECT);
+
+
+
+}

+ 66 - 0
boman-web-core/src/main/java/com/boman/web/core/constant/SubmitConstant.java

@@ -0,0 +1,66 @@
+package com.boman.web.core.constant;
+
+import lombok.Data;
+
+/**
+ * @author shiqian
+ * @date 2021年04月01日 13:56
+ **/
+@Data
+public class SubmitConstant {
+
+    /**
+     * 提交人
+     */
+    public static final String SUBMIT_USERID = "submit_userid";
+
+    /**
+     * 提交时间
+     */
+    public static final  String SUBMIT_TIME = "submit_time";
+
+    /**
+     * 提交备注
+     */
+    public static final  String REMARK = "remark";
+
+    /**
+     * 未提交
+     */
+    public static final String NOT_SUBMIT = "1";
+
+    /**
+     * 已经提交了
+     */
+    public static final String SUBMITTED = "2";
+
+    /**
+     * 驳回
+     */
+    public static final String REJECT = "3";
+
+    /**
+     * 审核中
+     */
+    public static final String CHECKING = "4";
+
+    /**
+     * 批量提交的时候,状态符合标识
+     */
+    public static final String SUBMIT_RESULT = "submitResult";
+
+    /**
+     * 批量提交的时候,状态符合标识,且成功
+     */
+    public static final String SUCCESS = "SUCCESS";
+
+    /**
+     * 批量提交的时候,状态符合, 但是不知道什么原因失败了
+     */
+    public static final String FAIL = "FAIL";
+
+    /**
+     * 批量提交的时候,状态压根就不符合
+     */
+    public static final String NOT_ALLOWED = "NOT_ALLOWED";
+}

+ 214 - 0
boman-web-core/src/main/java/com/boman/web/core/controller/ObjController.java

@@ -0,0 +1,214 @@
+package com.boman.web.core.controller;
+
+import com.boman.common.core.web.domain.AjaxResult;
+import com.boman.gen.controller.MyController;
+import com.boman.web.core.domain.BaseTableSaveDTO;
+import com.boman.web.core.service.TableServiceCmdService;
+import io.swagger.annotations.ApiOperation;
+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;
+
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 09:19
+ **/
+@RestController
+@RequestMapping("/p/cs")
+public class ObjController {
+
+    @Autowired
+    private TableServiceCmdService tableServiceCmdService;
+
+    /**
+     * 功能描述: 通用保存接口
+     *                {
+     *                    "objId": 1,
+     *                    "table": "sys_config",
+     *                    "fixedData": {
+     *                        "CONFIG_NAME": "测试config_name",
+     *                        "CONFIG_KEY": "测试config_key",
+     *                        "CONFIG_VALUE": "测试config_value",
+     *                        "CONFIG_TYPE": "Y",
+     *                        "REMARK": "测试remark"
+     *                    }
+     *                }
+     *
+     * @param baseTableSaveDTO 前台传过来的dto
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "单对象保存")
+    @PostMapping("/objectSave")
+    public AjaxResult objectSave(@RequestBody BaseTableSaveDTO baseTableSaveDTO) {
+        return tableServiceCmdService.objectSave(baseTableSaveDTO);
+    }
+
+    /**
+     * 功能描述: 通用删除接口 (真的删除)
+     *               eg:  {
+     *                         "table": "sys_config",
+     *                         "idList": [
+     *                             141,
+     *                             142
+     *                         ]
+     *                     }
+     *
+     *
+     *
+     * @param baseTableSaveDTO 前台传过来的dto
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "单对象删除")
+    @PostMapping("/objectDelete")
+    public AjaxResult objectDelete(@RequestBody BaseTableSaveDTO baseTableSaveDTO) {
+        return tableServiceCmdService.objectDelete(baseTableSaveDTO);
+    }
+
+    /**
+     * 功能描述: 通用删除接口 (逻辑删除)
+     *
+     *                    eg:{
+     *                           "table": "sys_config",
+     *                           "logicDelName": "CONFIG_KEY",
+     *                           "logicDelValue": "我被修改了吧",
+     *                           "idList": [
+     *                               141,
+     *                               142
+     *                           ]
+     *                       }
+     *
+     * @param baseTableSaveDTO 前台传过来的dto
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "单对象逻辑删除")
+    @PostMapping("/objectLogicDelete")
+    public AjaxResult objectLogicDelete(@RequestBody BaseTableSaveDTO baseTableSaveDTO) {
+        return tableServiceCmdService.objectLogicDelete(baseTableSaveDTO);
+    }
+
+    /**
+     * 功能描述: 获取单表单数据 默认查所有字段
+     *                    eg:{
+     *                          "table": "sys_config",
+     *                          "fixedData": {
+     *                              "id": 20
+     *                            }
+     *                        }
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "获取单表单数据")
+    @PostMapping("/getObject")
+    public AjaxResult getObject(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.getObject(condition);
+    }
+
+    /**
+     * 功能描述: 获取表单列表数据
+     *                    eg:{
+     *                          "table": "sys_config",
+     *                          "limit": 0,
+     *                          "offset": 10,
+     *                          "orderBy": "create_time asc",
+     *                          "fixedData": {
+     *                              "condition": {
+     *                                  "CONFIG_NAME": "主框架",
+     *                                  "CONFIG_VALUE": "skin-blue",
+     *                                  "CREATE_TIME": ["2017-01-01", "2019-02-02"]
+     *                              },
+     *                              "showData": [
+     *                                  "CONFIG_ID", "CONFIG_NAME", "CONFIG_VALUE"
+     *                              ]
+     *                            }
+     *                        }
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "获取表单列表数据")
+    @PostMapping("/queryList")
+    public AjaxResult queryList(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.queryList(condition);
+    }
+
+    /**
+     * 功能描述: 获取表单查询字段、按钮、表头
+     * 注意: 都是从redis中拿的,如果数据库和redis不一致,则需刷新一下redis
+     * 刷新的入口为 {@link MyController#loadTable(com.boman.gen.domain.GenTable)}
+     *
+     *                    eg:{
+     *                          "table": "sys_config"
+     *                        }
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "获取表单查询字段和按钮")
+    @PostMapping("/getTableQuery")
+    public AjaxResult getTableQuery(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.getTableQuery(condition);
+    }
+
+    /**
+     * 功能描述: 获取表单子表
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "获取表单子表")
+    @PostMapping("/objectTab")
+    public AjaxResult objectTab(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.objectTab(condition);
+    }
+
+    /**
+     * 功能描述: 表单提交接口, 更改的字段类型和字段值都是一致的
+     *              {
+     *                  "table": "sys_test",
+     *                  "commitData": [
+     *                      {
+     *                          "id": 1,
+     *                          "status": "2",
+     *                          "remark": "提交了吧"
+     *                      }
+     *                  ]
+     *              }
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "表单提交接口")
+    @PostMapping("/objectSubmit")
+    public AjaxResult objectSubmit(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.objectSubmit(condition, true);
+    }
+
+
+    /**
+     * 功能描述: 反提交接口, 更改的字段类型和字段值都是一致的
+     *                {
+     *                    "table": "sys_config",
+     *                    "fixedData": {
+     *                        "idList": [
+     *                            3
+     *                        ],
+     *                        "status": "1",
+     *                        "remark": "理由不够充分"
+     *                    }
+     *                }
+     *
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    @ApiOperation(value = "反提交接口")
+    @PostMapping("/objectUnSubmit")
+    public AjaxResult objectUnSubmit(@RequestBody BaseTableSaveDTO condition) {
+        return tableServiceCmdService.objectSubmit(condition, false);
+    }
+
+
+}

+ 70 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/BaseTableDTO.java

@@ -0,0 +1,70 @@
+package com.boman.web.core.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 09:53
+ **/
+public class BaseTableDTO {
+
+    @JSONField(name = "objId")
+    private Long objId;
+
+    @JSONField(name = "fixedData")
+    private JSONObject fixedData;
+
+    /**
+     * 前台传参中的表名
+     */
+    @JSONField(name = "table")
+    private String table;
+
+    @JSONField(name = "delMTable")
+    private Boolean delMTable;
+
+    @JSONField(name = "tabItem")
+    private JSONObject tabItem;
+
+    public Long getObjId() {
+        return objId;
+    }
+
+    public void setObjId(Long objId) {
+        this.objId = objId;
+    }
+
+    public JSONObject getFixedData() {
+        return fixedData;
+    }
+
+    public void setFixedData(JSONObject fixedData) {
+        this.fixedData = fixedData;
+    }
+
+    public String getTable() {
+        return table;
+    }
+
+    public void setTable(String table) {
+        this.table = table;
+    }
+
+    public Boolean getDelMTable() {
+        return delMTable;
+    }
+
+    public void setDelMTable(Boolean delMTable) {
+        this.delMTable = delMTable;
+    }
+
+    public JSONObject getTabItem() {
+        return tabItem;
+    }
+
+    public void setTabItem(JSONObject tabItem) {
+        this.tabItem = tabItem;
+    }
+}

+ 91 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/BaseTableSaveDTO.java

@@ -0,0 +1,91 @@
+package com.boman.web.core.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author:zc
+ * @since:2018/12/27
+ * @createat:2018/12/274:41 PM
+ */
+@Data
+@ToString
+@EqualsAndHashCode
+public class BaseTableSaveDTO implements Serializable {
+
+    private static final long serialVersionUID = -8653990707913725671L;
+    @JSONField(name = "objId")
+    private Long objId;
+
+    @JSONField(name = "fixedData")
+    private JSONObject fixedData;
+
+    @JSONField(name = "table")
+    private String table;
+
+    /**
+     * 逻辑删除,数据库对应的属性名称
+     */
+    @JSONField(name = "logicDelName")
+    private String logicDelName;
+
+    /**
+     * 逻辑删除,数据库对应的属性值
+     */
+    @JSONField(name = "logicDelValue")
+    private String logicDelValue;
+
+    /**
+     * 删除时,前台传过来需要删除的idList
+     */
+    @JSONField(name = "idList")
+    private List<Long> idList;
+
+    /**
+     * 批量提交时,提交到后台的数据
+     */
+    @JSONField(name = "commitData")
+    private List<JSONObject> commitData;
+
+    /**
+     * orderBy eg: order_by columnName desc
+     */
+    @JSONField(name = "orderBy")
+    private String orderBy;
+
+    /**
+     * 分页
+     */
+    @JSONField(name = "pageNo")
+    private Integer pageNo;
+
+    /**
+     * 分页
+     */
+    @JSONField(name = "pageSize")
+    private Integer pageSize;
+
+    /**
+     * 状态
+     */
+    @JSONField(name = "status")
+    private String status;
+
+
+    public int getLimit() {
+        return pageNo == 0 ? 0 : (pageNo - 1) * pageSize;
+    }
+
+    public int getOffset(){
+        return pageSize == 0 ? 10 : pageSize;
+    }
+
+}
+
+

+ 53 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/MainTableRecord.java

@@ -0,0 +1,53 @@
+package com.boman.web.core.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.gen.domain.GenTable;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 10:04
+ **/
+@Data
+public class MainTableRecord {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MainTableRecord.class);
+
+    private TableServiceContext context;
+    private RowRecord mainData;
+
+    @Setter
+    @Getter
+    private RowResult result;
+
+
+    public MainTableRecord(TableServiceContext context, GenTable genTable, Long id, JSONObject fixedData, JSONObject delTables) {
+        this.context = context;
+        this.mainData = new RowRecord(id, genTable, fixedData);
+    }
+
+    public Long getId() {
+        return mainData.getId();
+    }
+
+    public void setId(Long value) {
+        mainData.setId(value);
+    }
+
+    public GenTable getTable() {
+        return mainData.getGenTable();
+    }
+
+    public JSONObject getCommitData() {
+        return mainData.getCommitData();
+    }
+
+    public JSONObject getOriginalData() {
+        return mainData.getOriginalData();
+    }
+}

+ 54 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/RowRecord.java

@@ -0,0 +1,54 @@
+package com.boman.web.core.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.gen.domain.GenTable;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author zc
+ * @date 2019/02/19
+ */
+@Data
+@Slf4j
+public class RowRecord {
+
+    private GenTable genTable;
+
+    private Long id;
+
+    //提交过来的数据
+    private JSONObject postData = new JSONObject();
+
+    //原数据
+    private JSONObject originalData = new JSONObject();
+
+    //新数据
+    private JSONObject newData;
+
+    //将要提交到数据库中的数据
+    private JSONObject commitData = new JSONObject();
+
+    public RowRecord(Long id, GenTable genTable, JSONObject fixedData) {
+        this.id = id;
+        this.genTable = genTable;
+
+        if (fixedData == null) {
+            fixedData = new JSONObject();
+        }
+
+        fixedData.forEach((fieldName, fieldValue)->{
+            postData.put(fieldName.toUpperCase(), fieldValue);
+        });
+
+        for (String key : postData.keySet()) {
+            commitData.put(key, postData.get(key));
+        }
+
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("baseData", originalData);
+        jsonObject.put("data", commitData);
+        newData = new JSONObject(jsonObject);
+    }
+
+}

+ 72 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/RowResult.java

@@ -0,0 +1,72 @@
+package com.boman.web.core.domain;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 10:59
+ **/
+public class RowResult {
+
+    private Integer code;
+    private String message;
+    private Object data;
+
+    public RowResult() {
+    }
+
+    public boolean isOk() {
+        return this.code >= 0;
+    }
+
+    public static RowResult ok(String message) {
+        return create(0, message);
+    }
+
+    public static RowResult ok(String message, Object data) {
+        return create(0, message, data);
+    }
+
+    public static RowResult error(String message) {
+        return create(-1, message);
+    }
+
+    public static RowResult error(String message, Object data) {
+        return create(-1, message, data);
+    }
+
+    public static RowResult create(Integer errorCode, String message) {
+        return create(errorCode, message, (Object)null);
+    }
+
+    public static RowResult create(Integer errorCode, String message, Object data) {
+        RowResult result = new RowResult();
+        result.code = errorCode;
+        result.message = message;
+        result.data = data;
+        return result;
+    }
+
+    public Integer getCode() {
+        return this.code;
+    }
+
+    public String getMessage() {
+        return this.message;
+    }
+
+    public Object getData() {
+        return this.data;
+    }
+
+    public void setData(final Object data) {
+        this.data = data;
+    }
+
+    public static boolean checkSuccess(RowResult rowResult){
+        return null != rowResult && 0 == rowResult.getCode();
+    }
+
+    public static boolean checkFail(RowResult rowResult){
+        return !checkSuccess(rowResult);
+    }
+}

+ 185 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/TableServiceContext.java

@@ -0,0 +1,185 @@
+package com.boman.web.core.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.common.core.utils.SpringUtils;
+import com.boman.common.redis.RedisKey;
+import com.boman.common.redis.service.RedisService;
+import com.boman.gen.domain.GenTable;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.sql.Timestamp;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 09:58
+ **/
+@Service
+public class TableServiceContext {
+
+    private final static String PREFIX = "Controller:/event/do";
+
+    /**
+     * 当前表
+     */
+    private GenTable table;
+
+    /**
+     * 真实表名
+     */
+    private String realTableName;
+
+    /**
+     * 动作名(ADD,SAVE,SUBMIT,VOID,UNSUBMIT)
+     */
+    private String actionName;   //Controller:/event/doAdd
+
+    /**
+     * 业务发生的时间戳
+     */
+    private Timestamp currentTime;
+
+    /**
+     * 上行的数据
+     * 每个row对象对应到一条单据(如果存在事务,应该在这个级别上体现)
+     */
+    private List<MainTableRecord> rows;
+
+    /**
+     * 本次请求存放的临时数据
+     * !!慎用,最好不要在各个对象间传递
+     */
+    private Map<String, Object> values;
+
+    private boolean isDelMtable;
+
+    /**
+     * 是否批量新增
+     */
+    private boolean isInsertBacth = false;
+
+    private TableServiceContext() {
+        values = Maps.newHashMap();
+    }
+
+
+    @Resource
+    private RedisService redisService;
+
+    public static TableServiceContext createFrom(BaseTableDTO baseTableDTO) {
+        TableServiceContext result = new TableServiceContext();
+        String tableName = baseTableDTO.getTable();
+        if (StringUtils.isEmpty(tableName)) {
+            throw new IllegalArgumentException("表名参数不能为空");
+        }
+
+        //从redis中获取表信息
+        RedisService redisService = SpringUtils.getBean(RedisService.class);
+        result.table = redisService.getCacheObject(RedisKey.TABLE_INFO + tableName);
+
+        if (result.table == null) {
+            throw new IllegalArgumentException(tableName + "表信息不存在");
+        }
+
+        result.realTableName = result.table.getTableName();
+        if (Strings.isNullOrEmpty(result.realTableName)) {
+            throw new IllegalArgumentException(tableName + "表名不存在");
+        }
+
+        // 前台传过来的数据
+        JSONObject fixedData = baseTableDTO.getFixedData();
+        //删除
+        Boolean isdelmtable = baseTableDTO.getDelMTable();
+        JSONObject tabItem = baseTableDTO.getTabItem();
+        if (isdelmtable != null) {
+            result.isDelMtable = isdelmtable;
+        }
+
+        // 获取objid判断 新增或更新
+        Long objid = baseTableDTO.getObjId();
+        MainTableRecord mainRowData = new MainTableRecord(result, result.table, objid, fixedData, tabItem);
+        result.rows = Lists.newArrayList();
+        result.rows.add(mainRowData);
+
+        return result;
+    }
+
+    public GenTable getTable() {
+        return table;
+    }
+
+    public void setTable(GenTable table) {
+        this.table = table;
+    }
+
+    public String getRealTableName() {
+        return realTableName;
+    }
+
+    public void setRealTableName(String realTableName) {
+        this.realTableName = realTableName;
+    }
+
+    public String getActionName() {
+        return actionName;
+    }
+
+    public void setActionName(String actionName) {
+        this.actionName = actionName;
+    }
+
+    public Timestamp getCurrentTime() {
+        return currentTime;
+    }
+
+    public void setCurrentTime(Timestamp currentTime) {
+        this.currentTime = currentTime;
+    }
+
+    public List<MainTableRecord> getRows() {
+        return rows;
+    }
+
+    public void setRows(List<MainTableRecord> rows) {
+        this.rows = rows;
+    }
+
+    public Map<String, Object> getValues() {
+        return values;
+    }
+
+    public void setValues(Map<String, Object> values) {
+        this.values = values;
+    }
+
+    public boolean isDelMtable() {
+        return isDelMtable;
+    }
+
+    public void setDelMtable(boolean delMtable) {
+        isDelMtable = delMtable;
+    }
+
+    public boolean isInsertBacth() {
+        return isInsertBacth;
+    }
+
+    public void setInsertBacth(boolean insertBacth) {
+        isInsertBacth = insertBacth;
+    }
+//
+//    public Collection<Filter> getFilters() {
+//        return filters;
+//    }
+//
+//    public void setFilters(Collection<Filter> filters) {
+//        this.filters = filters;
+//    }
+}

+ 30 - 0
boman-web-core/src/main/java/com/boman/web/core/domain/TriggerActionConstant.java

@@ -0,0 +1,30 @@
+package com.boman.web.core.domain;
+
+/**
+ * @author tjf
+ * @Date: 2021/04/01/16:33
+ */
+public class TriggerActionConstant {
+
+    /**
+     * 新增
+     */
+    public static final String ACTION_CREATE = "trigger_create";
+
+    /**
+     * 查询
+     */
+    public static final String ACTION_RETRIEVE = "trigger_retrieve";
+    /**
+     * 修改
+     */
+    public static final String ACTION_UPDATE = "trigger_update";
+    /**
+     * 删除
+     */
+    public static final String ACTION_DELETE = "trigger_delete";
+    /**
+     * 提交
+     */
+    public static final String ACTION_SUBMIT = "trigger_submit";
+}

+ 662 - 0
boman-web-core/src/main/java/com/boman/web/core/mapper/StandardlyMapper1.java

@@ -0,0 +1,662 @@
+package com.boman.web.core.mapper;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.boman.common.core.utils.obj.ObjectUtils;
+import com.boman.web.core.constant.FormDataConstant;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.jdbc.SQL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.escapeStr;
+import static com.boman.web.core.constant.FormDataConstant.*;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 11:36
+ **/
+@Mapper
+@Component
+public interface StandardlyMapper1 {
+
+    Logger LOGGER = LoggerFactory.getLogger(StandardlyMapper1.class);
+
+    @UpdateProvider(
+            type = SqlProvider.class,
+            method = "update"
+    )
+    int updateById(@Param("tableName") String var1, @Param("model") JSONObject var2
+            , @Param("pkName") String pkName, @Param("ids") Long[] ids);
+
+    @UpdateProvider(
+            type = SqlProvider.class,
+            method = "update"
+    )
+    int newUpdateById(@Param("tableName") String var1, @Param("model") long var2);
+
+
+    @DeleteProvider(
+            type = SqlProvider.class,
+            method = "delete"
+    )
+    int deleteByIds(@Param("tableName") String var1, @Param("ids") Long[] var2, @Param("pkName") String pkName);
+
+    @Delete({"DELETE FROM ${tableName} where ID = #{id}"})
+    int deleteById(@Param("tableName") String tableName, @Param("pkName") String pkName, @Param("id") long var2);
+
+    @Select({"select * FROM ${tableName} where ID = #{id}"})
+    JSONObject getById(@Param("tableName") String var1, @Param("id") long var2);
+
+    @Select({"select ${columns} FROM ${tableName} where ID = #{id}"})
+    JSONObject getColumnsById(@Param("tableName") String var1, @Param("columns") String var2, @Param("id") long var3);
+
+    @InsertProvider(
+            type = SqlProvider.class,
+            method = "insert"
+    )
+    int insert(@Param("tableName") String var1, @Param("model") JSONObject var2);
+
+    @InsertProvider(
+            type = SqlProvider.class,
+            method = "inserts"
+    )
+    int inserts(@Param("tableName") String var1, @Param("models") JSONObject[] var2, @Param("processor") Consumer<JSONObject> var3);
+
+    @Select({"select count(1) FROM ${tableName} where ${column} = #{value} limit 1"})
+    boolean exists(@Param("tableName") String var1, @Param("column") String var2, @Param("value") Object var3);
+
+    @Select({"select count(1) FROM ${tableName} where ID = #{id} limit 1"})
+    boolean existsById(@Param("tableName") String var1, @Param("id") long var2);
+
+    @Select({"select count(1) FROM ${tableName} where id <> #{id} and ${column} = #{value} limit 1"})
+    boolean existsWithoutId(@Param("tableName") String var1, @Param("id") long var2, @Param("column") String var4, @Param("value") Object var5);
+
+    @UpdateProvider(
+            type = SqlProvider.class,
+            method = "updates"
+    )
+    int updates(@Param("tableName") String var1, @Param("models") Collection<Object> var2, @Param("processor") Consumer<JSONObject> var3);
+
+    /** {@link SqlProvider#updateByIdList(Map)} */
+    @UpdateProvider(
+            type = SqlProvider.class,
+            method = "updateByIdList"
+    )
+    int updateByIdList(@Param("tableName") String var1, @Param("pkName") String pkName
+            , @Param("idList") List<Long> var2, @Param("models") JSONObject models);
+
+    @Select("select id from ${tableName} where ${akColumnName} = #{akColumnValue}")
+    Long selectIdByAkColumn(@Param("tableName") String tableName, @Param("akColumnName") String akColumnName, @Param("akColumnValue") String akColumnValue);
+
+    @Select("select max(${pkName}) from ${tableName}")
+    Long selectMaxId(@Param("tableName") String tableName, @Param("pkName") String pkName);
+
+    /**
+     * 功能描述: 根据id查所有
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param id        主键值
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    @Select("select * from ${tableName} where ${pkName} = #{id}")
+    JSONObject selectById(@Param("tableName") String tableName
+            , @Param("pkName") String pkName, @Param("id") Long id);
+
+    /**
+     * 功能描述: 根据id查所有
+     * {@link SqlProvider#selectByIdList(Map)}
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param idList    主键值
+     * @param showData  需要展示的列
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    @SelectProvider(type = SqlProvider.class, method = "selectByIdList")
+    List<JSONObject> selectByIdList(@Param("tableName") String tableName
+            , @Param("pkName") String pkName, @Param("idList") List<Long> idList
+            , @Param("showData") JSONArray showData);
+
+    /**
+     * 功能描述: 自定义查询,需要查询的字段和value都在condition中
+     * {@link SqlProvider#selectByCondition(Map)}
+     *
+     * @param tableName     tableName
+     * @param condition     condition
+     * @param packCondition 封装好的查询条件
+     * @param showData      需要查询的列
+     * @param orderBy       orderBy
+     * @param limit         分页
+     * @param offset        分页, 可以为null
+     * @return java.util.List<com.alibaba.fastjson.JSONObject>
+     */
+    @SelectProvider(type = SqlProvider.class, method = "selectByCondition")
+    List<JSONObject> selectByCondition(@Param("tableName") String tableName
+            , @Param("condition") JSONObject condition
+            , @Param("packCondition") JSONObject packCondition
+            , @Param("showData") JSONArray showData
+            , @Param("orderBy") String orderBy
+            , @Param("limit") int limit
+            , @Param("offset") int offset);
+
+
+    /**
+     * 功能描述: 自定义查询,需要查询的字段和value都在condition中
+     * {@link SqlProvider#countByCondition(Map)}
+     *
+     * @param tableName     tableName
+     * @param condition     condition
+     * @param packCondition 封装好的查询条件
+     * @return int
+     */
+    @SelectProvider(type = SqlProvider.class, method = "countByCondition")
+    int countByCondition(@Param("tableName") String tableName
+            , @Param("condition") JSONObject condition
+            , @Param("packCondition") JSONObject packCondition);
+
+
+
+
+    public static class SqlProvider {
+        static final String[] READONLY_COLUMNS = new String[]{"OWNERID", "OWNERNAME", "OWNERENAME", "CREATIONDATE", "ID"};
+
+        public SqlProvider() {
+        }
+
+        private static boolean isReadOnly(String column) {
+            String[] var1 = READONLY_COLUMNS;
+            int var2 = var1.length;
+
+            for (int var3 = 0; var3 < var2; ++var3) {
+                String readonlyColumn = var1[var3];
+                if (readonlyColumn.equals(column)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private static boolean isNullOrEmpty(String str) {
+            return str == null || str.length() == 0 || str.trim().length() == 0;
+        }
+
+        private static boolean isNullOrEmpty(JSONObject json) {
+            return json == null || json.isEmpty();
+        }
+
+        private static void keyToUpper(JSONObject json) {
+            String[] keys = new String[json.size()];
+            json.keySet().toArray(keys);
+            String[] var2 = keys;
+            int var3 = keys.length;
+
+            for (int var4 = 0; var4 < var3; ++var4) {
+                String key = var2[var4];
+                if (!key.equals(key.toUpperCase())) {
+                    json.put(key.toUpperCase(), json.get(key));
+                    json.remove(key);
+                }
+            }
+
+        }
+
+        public String update(Map<String, Object> para) {
+            String tableName = (String) para.get("tableName");
+            JSONObject model = (JSONObject) para.get("model");
+            String pkName = (String) para.get("pkName");
+            Long[] ids = (Long[]) para.get("ids");
+            if (StringUtils.isBlank(tableName)) {
+                throw new IllegalArgumentException("tableName 无效");
+            } else if (!model.isEmpty()) {
+                keyToUpper(model);
+                SQL sql = new SQL();
+                sql.UPDATE(tableName);
+
+                // 拼装set
+                model.forEach((key, value)->{
+                    if (!isReadOnly(key)) {
+                        // 此处需要对value加一个""
+                        sql.SET(key + " = \"" + value + "\"");
+                    }
+                });
+
+                // 拼装in
+                StringBuilder inSql = new StringBuilder();
+                for (int i = 0; i < ids.length; ++i) {
+                    inSql.append(String.format("#{ids[%d]}", i));
+                    inSql.append(",");
+                }
+
+                sql.WHERE(pkName + " in (" + inSql.toString());
+                String wholeSql = StringUtils.substringBeforeLast(sql.toString(), ",") + "))";
+                LOGGER.info("更改的sql语句为: {}", wholeSql);
+                return wholeSql;
+            } else {
+                throw new IllegalArgumentException("model 无效");
+            }
+        }
+
+        public String inserts(Map<String, Object> para) {
+            String tableName = (String) para.get("tableName");
+            JSONObject[] models = (JSONObject[]) ((JSONObject[]) para.get("models"));
+            Consumer<JSONObject> processor = (Consumer) para.get("processor");
+            if (isNullOrEmpty(tableName)) {
+                throw new IllegalArgumentException("tableName 无效");
+            } else if (models != null && models.length != 0) {
+                Set<String> columns = new HashSet();
+
+                for (int i = 0; i < models.length; ++i) {
+                    JSONObject model = models[i];
+                    if (model == null) {
+                        models[i] = model = new JSONObject();
+                    }
+
+                    if (processor != null) {
+                        processor.accept(model);
+                    }
+
+                    keyToUpper(model);
+                    columns.addAll(model.keySet());
+                }
+
+                StringBuffer sql = new StringBuffer();
+                sql.append("INSERT INTO ");
+                sql.append(tableName);
+                sql.append("(");
+                sql.append(String.join(",", columns));
+                sql.append(") VALUES");
+
+                for (int i = 0; i < models.length; ++i) {
+                    sql.append("(");
+
+                    for (Iterator var8 = columns.iterator(); var8.hasNext(); sql.append(",")) {
+                        String column = (String) var8.next();
+                        if (models[i].containsKey(column)) {
+                            sql.append(String.format("#{models[%d].%s}", i, column));
+                        } else {
+                            sql.append("default");
+                        }
+                    }
+
+                    sql.setCharAt(sql.length() - 1, ')');
+                    sql.append(",");
+                }
+
+                sql.deleteCharAt(sql.length() - 1);
+                return sql.toString();
+            } else {
+                throw new IllegalArgumentException("model 无效");
+            }
+        }
+
+        public String insert(Map<String, Object> para) {
+            JSONObject model = (JSONObject) para.get("model");
+            String tableName = (String) para.get("tableName");
+            if (isNullOrEmpty(tableName)) {
+                throw new IllegalArgumentException("tableName 无效");
+            } else if (isNullOrEmpty(model)) {
+                throw new IllegalArgumentException("model 无效");
+            } else {
+                SQL sql = new SQL();
+                Set<String> keySet = model.keySet();
+                sql.INSERT_INTO(tableName);
+
+                for (int i = 0; i < model.size(); ++i) {
+                    String key = (String) keySet.toArray()[i];
+                    sql.VALUES(key, "#{model." + key + "}");
+                }
+
+                String sqlStr = sql.toString();
+                LOGGER.info("新增的sql语句为: {}", sqlStr);
+                return sqlStr;
+            }
+        }
+
+
+        public String updateByIdList(Map<String, Object> para) {
+            String tableName = (String) para.get("tableName");
+            String pkName = (String) para.get("pkName");
+            List<Long> idList = (List<Long>) para.get("idList");
+            JSONObject models = (JSONObject) para.get("models");
+
+            StringBuilder wholeSql = new StringBuilder();
+            wholeSql.append("update ").append(tableName).append(" set ");
+            for (Map.Entry<String, Object> entry : models.entrySet()) {
+                String key = entry.getKey();
+                Object value = entry.getValue();
+                wholeSql.append(key).append(" = ").append(value).append(" , ");
+            }
+
+            wholeSql = new StringBuilder(StringUtils.substringBeforeLast(wholeSql.toString(), ","));
+            wholeSql.append(" where ").append(pkName).append(" in ( ");
+
+            for (int i = 0; i < idList.size(); ++i) {
+                wholeSql.append(String.format("#{idList[%d]}", i));
+                wholeSql.append(",");
+            }
+
+            wholeSql.setCharAt(wholeSql.length() - 1, ')');
+            String sqlStr = wholeSql.toString();
+            LOGGER.info("批量更新的sql语句为: {}", sqlStr);
+            return sqlStr;
+
+        }
+
+        public String delete(Map<String, Object> para) {
+            Long[] ids = (Long[]) para.get("ids");
+            String tableName = (String) para.get("tableName");
+            String pkName = (String) para.get("pkName");
+            if (isNullOrEmpty(tableName)) {
+                throw new IllegalArgumentException("tableName 无效");
+            } else if (ids == null) {
+                throw new IllegalArgumentException("ids 无效");
+            } else if (ids.length == 0) {
+                return "";
+            } else if (ids.length == 1) {
+                return "DELETE FROM " + tableName + " where " + pkName + " = #{ids[0]}";
+            } else {
+                StringBuffer sql = new StringBuffer();
+                sql.append("DELETE FROM ");
+                sql.append(tableName);
+                sql.append(" WHERE ");
+                sql.append(pkName + " in (");
+
+                for (int i = 0; i < ids.length; ++i) {
+                    sql.append(String.format("#{ids[%d]}", i));
+                    sql.append(",");
+                }
+
+                sql.setCharAt(sql.length() - 1, ')');
+                String sqlStr = sql.toString();
+                LOGGER.info("删除的sql语句为: {}", sqlStr);
+                return sqlStr;
+            }
+        }
+
+        public String updates(Map<String, Object> para) {
+            String tableName = (String) para.get("tableName");
+            Collection<Object> models = (Collection) para.get("models");
+            Consumer<JSONObject> processor = (Consumer) para.get("processor");
+            Boolean first = true;
+            if (isNullOrEmpty(tableName)) {
+                throw new IllegalArgumentException("tableName 无效");
+            } else if (models != null && models.size() != 0) {
+                JSONObject columnall = new JSONObject(true);
+                Iterator var7 = models.iterator();
+
+                while (var7.hasNext()) {
+                    Object obj = var7.next();
+                    JSONObject columnpart = (JSONObject) obj;
+                    if (columnpart == null) {
+                        columnpart = new JSONObject(true);
+                    }
+
+                    if (processor != null) {
+                        processor.accept(columnpart);
+                    }
+
+                    keyToUpper(columnpart);
+                    columnall.putAll(columnpart);
+                }
+
+                JSONObject clonekeyobj = (JSONObject) columnall.clone();
+                Set<String> keys = columnall.keySet();
+                Iterator var19 = keys.iterator();
+
+                while (var19.hasNext()) {
+                    String column = (String) var19.next();
+                    if (isReadOnly(column)) {
+                        clonekeyobj.remove(column);
+                    }
+                }
+
+                Set<String> firstkeys = clonekeyobj.keySet();
+                StringBuffer sql = new StringBuffer("");
+                sql.append("UPDATE ").append(tableName).append(" a");
+                sql.append(" right join (");
+                int i = -1;
+                Iterator var12 = models.iterator();
+
+                while (true) {
+                    while (var12.hasNext()) {
+                        Object obj = var12.next();
+                        ++i;
+                        JSONObject model = (JSONObject) obj;
+                        Iterator var15;
+                        String key;
+                        if (first.booleanValue()) {
+                            sql.append(" SELECT #{models[0].ID} `ID`,");
+                            var15 = firstkeys.iterator();
+
+                            while (var15.hasNext()) {
+                                key = (String) var15.next();
+                                if (model.get(key) == null) {
+                                    model.put(key, (Object) null);
+                                }
+
+                                sql.append(String.format("#{models[%d].%s} ", i, key));
+                                sql.append("`").append(key).append("`").append(",");
+                            }
+
+                            sql.deleteCharAt(sql.length() - 1);
+                            if (models.size() > 0) {
+                                sql.append(" union all");
+                            }
+
+                            first = false;
+                        } else {
+                            sql.append(" SELECT ");
+                            sql.append(String.format("#{models[%d].%s} ", i, "ID")).append(",");
+                            var15 = firstkeys.iterator();
+
+                            while (var15.hasNext()) {
+                                key = (String) var15.next();
+                                if (model.get(key) == null) {
+                                    model.put(key, (Object) null);
+                                }
+
+                                sql.append(String.format("#{models[%d].%s} ", i, key));
+                                sql.append(",");
+                            }
+
+                            sql.deleteCharAt(sql.length() - 1);
+                            if (i < models.size() - 1) {
+                                sql.append(" union all");
+                            }
+                        }
+                    }
+
+                    sql.append(") b on a.ID=b.ID ");
+                    sql.append(" SET ");
+                    var12 = firstkeys.iterator();
+
+                    while (var12.hasNext()) {
+                        String value = (String) var12.next();
+                        sql.append(" a.").append(value).append("=").append("IFNULL(b.").append(value).append(",").append("a.").append(value).append(")").append(",");
+                    }
+
+                    sql.deleteCharAt(sql.length() - 1);
+                    String sqlStr = sql.toString();
+                    LOGGER.info("更新的sql语句为: {}", sqlStr);
+                    return sqlStr;
+                }
+            } else {
+                throw new IllegalArgumentException("model 无效");
+            }
+        }
+
+        public String selectByCondition(Map<String, Object> para) {
+            JSONObject condition = (JSONObject) para.get("condition");
+            LOGGER.info("前台传过来的查询条件: {}", condition.toJSONString());
+            JSONObject packCondition = (JSONObject) para.get("packCondition");
+            String tableName = (String) para.get("tableName");
+            String orderBy = (String) para.get("orderBy");
+            int limit = (int) para.get("limit");
+            int offset = (int) para.get("offset");
+            JSONArray showData = (JSONArray) para.get("showData");
+
+            StringBuilder wholeSql = new StringBuilder();
+            wholeSql.append("select ");
+            // showData
+            StringBuilder showDataSql = new StringBuilder();
+            if (ObjectUtils.isNotEmpty(showData)) {
+                for (Object columnObj : showData) {
+                    String columnName = (String) columnObj;
+                    showDataSql.append(columnName).append(", ");
+                }
+                wholeSql.append(StringUtils.substringBeforeLast(showDataSql.toString(), ","));
+            } else {
+                showDataSql.append(" * ");
+            }
+
+            wholeSql.append(showDataSql).append(" from ").append(tableName);
+            // 条件
+            packCondition(packCondition, wholeSql);
+
+            wholeSql.append(" order by ").append(orderBy).append(" limit ").append(limit);
+            if (ObjectUtils.isNotEmpty(offset)) {
+                wholeSql.append(", ").append(offset);
+            }
+
+            String result = wholeSql.toString();
+            LOGGER.info("查询拼出的sql语句为:{}", result);
+            return result;
+        }
+
+        public String selectByIdList(Map<String, Object> para) {
+            String tableName = (String) para.get("tableName");
+            String pkName = (String) para.get("pkName");
+            List<Long> idList = (List<Long>) para.get(ID_LIST);
+            JSONArray showData = (JSONArray) para.get("showData");
+
+            StringBuilder wholeSql = new StringBuilder();
+            wholeSql.append("select ");
+            // showData
+            StringBuilder showDataSql = new StringBuilder();
+            if (ObjectUtils.isNotEmpty(showData)) {
+                for (Object columnObj : showData) {
+                    String columnName = (String) columnObj;
+                    showDataSql.append(columnName).append(", ");
+                }
+                wholeSql.append(StringUtils.substringBeforeLast(showDataSql.toString(), ","));
+            } else {
+                showDataSql.append(" * ");
+            }
+
+            wholeSql.append(" from ").append(tableName).append(" where ").append(pkName).append(" in ( ");
+
+            for (int i = 0; i < idList.size(); ++i) {
+                wholeSql.append(String.format("#{idList[%d]}", i));
+                wholeSql.append(",");
+            }
+
+            wholeSql.setCharAt(wholeSql.length() - 1, ')');
+            String sqlStr = wholeSql.toString();
+            LOGGER.info("批量查找的sql语句为: {}", sqlStr);
+            return sqlStr;
+        }
+
+        public String countByCondition(Map<String, Object> para) {
+            JSONObject condition = (JSONObject) para.get("condition");
+            LOGGER.info("前台传过来的查询条件: {}", condition.toJSONString());
+            JSONObject packCondition = (JSONObject) para.get("packCondition");
+            String tableName = (String) para.get("tableName");
+
+            StringBuilder wholeSql = new StringBuilder();
+            wholeSql.append("select count(1)");
+            wholeSql.append(" from ").append(tableName);
+            // 条件
+            packCondition(packCondition, wholeSql);
+
+            String result = wholeSql.toString();
+            LOGGER.info("查询count拼出的sql语句为:{}", result);
+            return result;
+        }
+
+        /**
+         * 功能描述: 判断传过来的值是否需要转义
+         *
+         * @param packCondition 封装的条件
+         * @param wholeSql      sql
+         */
+        private void packCondition(JSONObject packCondition, StringBuilder wholeSql) {
+            if (ObjectUtils.isNotEmpty(packCondition)) {
+                wholeSql.append(" where ");
+                StringBuilder conditionSql = new StringBuilder();
+                for (Map.Entry<String, Object> entry : packCondition.entrySet()) {
+                    String key = entry.getKey();
+                    Object valueObj = entry.getValue();
+                    List<String> types = ((List<String>) valueObj);
+                    // {@link com.boman.system.common.TableServiceCmdService.packColCondition} 这里是拼参数的地方
+                    String value = types.get(0);
+                    String queryType = types.get(1);
+                    String columnType = types.get(2);
+                    conditionSql.append(key).append(covert(queryType, columnType, key, value)).append(" and ");
+                }
+                wholeSql.append(StringUtils.substringBeforeLast(conditionSql.toString(), " and"));
+            }
+        }
+
+        /**
+         * 功能描述: 仅此用来拼装查询条件,不做他用
+         *
+         * @param queryType  like > < =
+         * @param columnType varchar char textarea timestamp
+         * @param key        key
+         * @param value      value
+         * @return java.lang.String
+         */
+        private String covert(String queryType, String columnType, String key, String value) {
+            // false 不需要转义
+            boolean needEscape = columnType.contains(VARCHAR) || columnType.contains(CHAR)
+                    || columnType.contains(DATETIME) || columnType.contains(TIMESTAMP);
+            switch (queryType) {
+                case FormDataConstant.EQ:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " = " + value;
+                case FormDataConstant.LIKE:
+                    return " like " + "concat('%', #{condition." + key + "}, '%')";
+                case FormDataConstant.NE:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " != " + value;
+                case FormDataConstant.GT:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " &gt; " + value;
+                case FormDataConstant.GTE:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " &gt;= " + value;
+                case FormDataConstant.LT:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " &lt; " + value;
+                case FormDataConstant.LTE:
+                    value = needEscape ? escapeStr(value) : value;
+                    return " &lt;= " + value;
+                default:
+                    String[] split = value.split(",");
+                    String front = split[0].replace("[", "");
+                    String back =  split[1].replace("]", "");
+                    String max, min;
+                    if (front.compareTo(back) > 0) {
+                        max = back;
+                        min = front;
+                    } else {
+                        max = front;
+                        min = back;
+                    }
+
+                    max = needEscape ? escapeStr(max) : max;
+                    min = needEscape ? escapeStr(min) : min;
+                    return " between " + min + " and " + max;
+            }
+        }
+    }
+}

+ 569 - 0
boman-web-core/src/main/java/com/boman/web/core/service/TableServiceCmdService.java

@@ -0,0 +1,569 @@
+package com.boman.web.core.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.boman.common.core.utils.DateUtils;
+import com.boman.common.core.utils.SecurityUtils;
+import com.boman.common.core.utils.collection.CollectionUtils;
+import com.boman.common.core.utils.obj.ObjectUtils;
+import com.boman.common.core.web.domain.AjaxResult;
+import com.boman.common.redis.RedisKey;
+import com.boman.common.redis.service.RedisService;
+import com.boman.gen.api.RemoteGenTableService;
+import com.boman.gen.controller.MyController;
+import com.boman.gen.domain.GenTable;
+import com.boman.gen.domain.GenTableColumn;
+import com.boman.gen.domain.GenTableRelation;
+//import com.boman.system.api.RemoteDictDataService;
+//import com.boman.system.domain.SysDictData;
+import com.boman.web.core.utils.IdUtils;
+import com.boman.web.core.constant.DictConstant;
+import com.boman.web.core.constant.FormDataConstant;
+import com.boman.web.core.constant.SubmitConstant;
+import com.boman.web.core.domain.*;
+import com.boman.web.core.service.delete.IBaseDeleteService;
+import com.boman.web.core.service.save.IBaseSaveService;
+import com.boman.web.core.service.select.IBaseSelectService;
+import com.boman.web.core.service.submit.IBaseSubmitService;
+import com.boman.web.core.service.update.IBaseUpdateService;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.Resource;
+import java.sql.Timestamp;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.ifNullSetEmpty;
+import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
+import static com.boman.web.core.constant.FormDataConstant.CONDITION;
+import static com.boman.web.core.constant.FormDataConstant.SHOW_DATA;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 09:51
+ **/
+@Component
+public class TableServiceCmdService {
+
+    @Resource
+    private IBaseDeleteService deleteService;
+    @Resource
+    private IBaseSaveService saveService;
+    @Resource
+    private RedisService redisService;
+    @Resource
+    private IBaseSelectService selectService;
+    @Resource
+    private IBaseSubmitService submitService;
+    @Resource
+    private IBaseUpdateService updateService;
+    @Resource
+    private  RestTemplate restTemplate;
+//    @Resource
+//    private RemoteDictDataService dictTypeService;
+    @Resource
+    private RemoteGenTableService remoteGenTableService;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(TableServiceCmdService.class);
+
+    private BaseTableDTO packTableDTO(BaseTableSaveDTO baseTableSaveDTO) {
+        BaseTableDTO baseTableDTO = new BaseTableDTO();
+        baseTableDTO.setFixedData(baseTableSaveDTO.getFixedData());
+        baseTableDTO.setObjId(baseTableSaveDTO.getObjId());
+        baseTableDTO.setTable(baseTableSaveDTO.getTable());
+        return baseTableDTO;
+    }
+
+    public final AjaxResult objectSave(BaseTableSaveDTO baseTableSaveDTO) {
+        AjaxResult result = AjaxResult.success();
+        BaseTableDTO baseTableDTO = packTableDTO(baseTableSaveDTO);
+        TableServiceContext context = TableServiceContext.createFrom(baseTableDTO);
+        // 拿到pkName和maxId
+        List<GenTableColumn> columns = context.getTable().getColumns();
+        String pkName = IdUtils.getPkName(columns);
+        requireNonNull(pkName, "主键名称为空");
+
+        //
+        List<String> allColumnNameList = columns.stream()
+                .map(GenTableColumn::getColumnName)
+                .collect(Collectors.toList());
+
+        // 新增
+        if (ObjectUtils.ltZero(baseTableDTO.getObjId())) {
+            Long maxId = IdUtils.getMaxId(baseTableDTO.getTable(), pkName);
+            RowResult rowResult = saveService.insertRow(context.getRealTableName(), pkName, maxId, context.getRows().get(0), allColumnNameList);
+            if (RowResult.checkSuccess(rowResult)) {
+                LOGGER.info("保存成功,封装到数据库的数据为: {}", JSON.toJSONString(rowResult.getData()));
+            } else {
+                LOGGER.error("保存失败,保持的原始数据为: {}", JSON.toJSONString(baseTableSaveDTO));
+                result = AjaxResult.error();
+            }
+        }else {
+            JSONObject commitData = context.getRows().get(0).getCommitData();
+
+            // 编辑
+            int effective = updateService.updateByIdList(context, pkName
+                    , Collections.singletonList(baseTableDTO.getObjId()), commitData);
+            if (effective > 0) {
+                LOGGER.info("修改成功,封装到数据库的数据为: {}", JSON.toJSONString(context.getRows().get(0).getCommitData()));
+            } else {
+                LOGGER.error("修改失败,前台传来的原始数据为: {}", JSON.toJSONString(context.getRows().get(0).getCommitData()));
+                result = AjaxResult.error();
+            }
+        }
+
+        return result;
+
+    }
+
+    /**
+     * 功能描述: 通用删除接口 (真的删除)
+     *
+     * @param dto 前台传过来的dto
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult objectDelete(BaseTableSaveDTO dto) {
+        requireNonNull(dto.getTable());
+        Long[] idArr = CollectionUtils.listToArray(dto.getIdList());
+        requireNonNull(idArr);
+        // 拿到pkName
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
+        String pkName = IdUtils.getPkName(genTable.getColumns());
+
+        List<RowResult> result = Lists.newArrayListWithCapacity(idArr.length);
+        for (Long id : idArr) {
+            RowResult rowResult = deleteService.deleteById(dto.getTable(), pkName, id);
+            result.add(rowResult);
+            LOGGER.info(rowResult.getMessage() + ", id: {}", id);
+        }
+
+        // RowResult rowResult = deleteService.objectDelete(idArr, dto.getTable(), requireNonNull(pkName, "主键名称为空"));
+
+        return AjaxResult.success(result);
+    }
+
+
+    /**
+     * 功能描述: 通用删除接口 (真的删除)
+     *
+     * @param dto 前台传过来的dto
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult objectLogicDelete(BaseTableSaveDTO dto) {
+        requireNonNull(dto.getTable());
+        Long[] idArr = CollectionUtils.listToArray(dto.getIdList());
+        requireNonNull(idArr);
+
+        // 拿到pkName
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
+        String pkName = IdUtils.getPkName(genTable.getColumns());
+
+        List<RowResult> result = Lists.newArrayListWithCapacity(idArr.length);
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put(dto.getLogicDelName(), dto.getLogicDelValue());
+        for (Long id : idArr) {
+            RowResult rowResult = deleteService.objectLogicDelete(new Long[]{id}, dto.getTable(), pkName, jsonObject);
+            result.add(rowResult);
+            LOGGER.info(rowResult.getMessage() + ", id: {}", id);
+        }
+
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 功能描述: 获取单表单数据
+     *
+     * @param dto condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult queryList(BaseTableSaveDTO dto) {
+        requireNonNull(dto.getTable());
+
+        // 拿到每个字段对应的查询类型,=、 like、 >、 <
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
+        JSONObject fixedData = dto.getFixedData();
+        fixedData = ifNullSetEmpty(fixedData);
+
+        // 查询条件
+        JSONObject condition = ifNullSetEmpty(fixedData.getJSONObject(CONDITION));
+        List<GenTableColumn> columns = genTable.getColumns();
+        // 封装好以后的查询条件
+        JSONObject packCondition = ifNullSetEmpty(packColCondition(columns, condition));
+        // 需要返回到前台的列
+        JSONArray showData = ifNullSetEmpty(fixedData.getJSONArray(SHOW_DATA));
+        JSONObject rows = new JSONObject();
+        int total = selectService.countByCondition(genTable.getTableName(), condition, packCondition);
+        rows.put(FormDataConstant.PAGE_TOTAL, total);
+        if (total <= 0) {
+            rows.put(FormDataConstant.PAGE_ROWS, null);
+            return AjaxResult.success(rows);
+        }
+
+        List<JSONObject> result = selectService.selectByCondition(genTable.getTableName(), condition, packCondition
+                , showData, dto.getOrderBy(), dto.getLimit(), dto.getOffset());
+        handlerDate(result);
+        result = isCustomized(dto.getTable(),result,"trigger_retrieve");
+        rows.put(FormDataConstant.PAGE_ROWS, result);
+        return AjaxResult.success(rows);
+    }
+
+    /**
+     * 功能描述: 把timeStamp转为string
+     *
+     * @param result 被转的数据
+     */
+    private void handlerDate(List<JSONObject> result) {
+        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
+            return;
+        }
+        for (JSONObject jsonObject : result) {
+            getStrByTimeStamp(jsonObject, FormDataConstant.CREATE_TIME);
+            getStrByTimeStamp(jsonObject, FormDataConstant.UPDATE_TIME.toLowerCase());
+        }
+    }
+
+    /**
+     * 功能描述: 把jsonObject中时间类型转为string,再放到jsonObject中,类型为: yyyy-mm-dd
+     *
+     * @param jsonObject jsonObject
+     * @param columnType create_time update_time...
+     */
+    private void getStrByTimeStamp(JSONObject jsonObject, String columnType) {
+        Date date = jsonObject.getTimestamp(columnType);
+        if (null != date) {
+
+            jsonObject.put(columnType, DateUtils.dateTime(date));
+        }
+    }
+
+
+    /**
+     * 功能描述: 获取单表单数据
+     *
+     * @param dto condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult getObject(BaseTableSaveDTO dto) {
+        requireNonNull(dto.getTable());
+
+        // 拿到每个字段对应的查询类型,=、 like、 >、 <
+        // 拿到pkName
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
+        String pkName = IdUtils.getPkName(genTable.getColumns());
+
+        JSONObject fixedData = dto.getFixedData();
+        fixedData = ifNullSetEmpty(fixedData);
+        Long id = fixedData.getLong(FormDataConstant.ID);
+        requireNonNull(id);
+
+        // 默认查所有字段,不支持自定义
+        JSONObject jsonObject = selectService.selectById(genTable.getTableName(), pkName, id);
+        return AjaxResult.success(jsonObject);
+    }
+
+    /**
+     * 功能描述: 封装成查询条件 key: 列名,  value:查询条件_查询类别
+     * eg: [{"config_name":"系统配置_like"}, {"config_name":"_like"}]
+     *
+     * @param columns columns
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    private JSONObject packColCondition(List<GenTableColumn> columns, JSONObject condition) {
+        requireNonNull(columns);
+
+        JSONObject result = new JSONObject(columns.size());
+        for (Map.Entry<String, Object> entry : condition.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            for (GenTableColumn column : columns) {
+                // long string collection 暂时只作此三种类型判断
+                if (column.getColumnName().equalsIgnoreCase(key) && ObjectUtils.isNotEmpty(value)) {
+                    // columnType 作为判断需不需要转义的一个标准,防止索引失效
+                    result.put(key, Lists.newArrayList(String.valueOf(value), column.getQueryType(), column.getColumnType()));
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 功能描述: 获取表单查询字段、按钮、表头
+     * 注意: 都是从redis中拿的,如果数据库和redis不一致,则需刷新一下redis
+     * 刷新的入口为 {@link MyController#loadTable(GenTable)}
+     * <p>
+     * eg:{
+     * "table": "sys_config",
+     * }
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult getTableQuery(BaseTableSaveDTO condition) {
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
+        List<GenTableColumn> columns = genTable.getColumns();
+        JSONObject jsonObject = new JSONObject();
+        // 查询字段
+        ArrayList<GenTableColumn> queryList = Lists.newArrayListWithCapacity(16);
+        for (GenTableColumn column : columns) {
+            if (GenTableColumn.IS_QUERY.equalsIgnoreCase(column.getIsQuery())) {
+                String dictType = column.getDictType();
+                if (ObjectUtils.isNotEmpty(dictType)) {
+//                    List<SysDictData> sysDictData1 = dictTypeService.listByType(dictType);
+//                    column.setSysDictData(coverSysDictDataToJSONObject(sysDictData1));
+                }
+
+                queryList.add(column);
+            }
+        }
+
+        jsonObject.put(FormDataConstant.QUERY_LIST, queryList);
+        // genTable.getMenuRole() 暂时数据库没有数据,
+        jsonObject.put(FormDataConstant.BUTTON_LIST, Strings.nullToEmpty(genTable.getMenuRole()));
+
+        // 表头
+        List<GenTableColumn> tableHeadList = columns.stream()
+                .filter(genTableColumn -> GenTableColumn.IS_LIST.equals(genTableColumn.getIsList()))
+                .collect(Collectors.toList());
+        jsonObject.put(FormDataConstant.TABLE_HEAD_LIST, tableHeadList);
+        return AjaxResult.success(jsonObject);
+    }
+
+    /**
+     * 功能描述: 获取表单子表
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult objectTab(BaseTableSaveDTO condition) {
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.RELATION, condition.getTable());
+
+        List<GenTable> childTableList = genTable.getRelationList();
+        // 此表没有关联子表,查啥查
+        requireNonNull(childTableList);
+        // todo
+        for (GenTable childTable : childTableList) {
+            String childTableName = childTable.getTableName();
+            Long childTableTableId = childTable.getTableId();
+            List<GenTableColumn> childColumns = childTable.getColumns();
+            //  column_name = 先根据tableName查到id,再用id到relation中查到relation_child_id, 在用这个值去到tableColumn中查到column_name
+            // select * from childTableName where column_name = objId
+
+
+        }
+
+
+        return AjaxResult.success();
+    }
+
+    public String getChildColumnNameByParentTableName(GenTable parentGenTable, Long childTableTableId){
+        requireNonNull(parentGenTable.getTableName(), "主表名称为空");
+//        GenTable primaryTable = redisService.getCacheObject(RedisKey.TABLE_INFO + genTable.getTableName());
+        Long parentTableId = parentGenTable.getTableId();
+        List<GenTableRelation> relations = redisService.getCacheObject(RedisKey.RELATION_INFO);
+        relations = relations.stream()
+                .filter(relation -> relation.getRelationParentId().equals(parentTableId))
+                .collect(Collectors.toList());
+
+        for (GenTableRelation relation : relations) {
+            if (relation.getRelationChildId().equals(6L)) {
+               // tableColumnService.selectGenTableColumnListByTableId(childTableTableId);
+//                return
+            }
+        }
+
+
+        return "";
+
+    }
+
+    /**
+     * 功能描述: 表单提交接口
+     *
+     * @param condition condition
+     * @param isSubmit  提交true, 反提交false
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult objectSubmit(BaseTableSaveDTO condition, boolean isSubmit) {
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
+        List<JSONObject> commitData = condition.getCommitData();
+        requireNonNull(commitData, "啥都不提交, 调什么接口??");
+
+        String tableName = requireNonNull(genTable.getTableName());
+        String pkName = IdUtils.getPkName(genTable.getColumns());
+
+        // 先去查出之前的状态
+        List<Long> idList = commitData.stream().map(jsonObject -> jsonObject.getLong(FormDataConstant.ID))
+                .collect(Collectors.toList());
+        JSONArray showData = new JSONArray();
+        showData.add(FormDataConstant.STATUS);
+        showData.add(pkName);
+        List<JSONObject> beforeList = selectService.selectByIdList(tableName, pkName, idList, showData);
+        requireNonNull(beforeList);
+
+        for (JSONObject commitDatum : commitData) {
+            String dbStatus = getStatusFromFormData(commitDatum, beforeList);
+            // 只能是未提交的状态下,才能调用提交
+            if (isSubmit) {
+                // 只能是未提交的状态下,才能调用提交, 下面是不允许
+                if (!SubmitConstant.NOT_SUBMIT.equals(dbStatus)) {
+                    commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.NOT_ALLOWED);
+                } else {
+                    handlerSubmit(tableName, pkName, commitDatum);
+                }
+            } else {
+                // 只有在已提交的情况下才能反提交, 下面是不允许
+                if (!SubmitConstant.SUBMITTED.equals(dbStatus)) {
+                    commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.NOT_ALLOWED);
+                } else {
+                    handlerSubmit(tableName, pkName, commitDatum);
+                }
+            }
+        }
+        return AjaxResult.success(commitData);
+    }
+
+    /**
+     * 功能描述: 处理提交和反提交
+     *
+     * @param tableName   tableName
+     * @param pkName      pkName
+     * @param commitDatum 返回给前台的数据
+     */
+    private void handlerSubmit(String tableName, String pkName, JSONObject commitDatum) {
+        commitDatum.put(FormDataConstant.CREATE_BY, SecurityUtils.getUserId());
+        commitDatum.put(FormDataConstant.CREATE_TIME, new Timestamp(System.currentTimeMillis()));
+        int effective = submitService.handlerSubmit(tableName, pkName, commitDatum, commitDatum.getLong(FormDataConstant.ID));
+        if (effective > 0) {
+            commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.SUCCESS);
+        } else {
+            commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.FAIL);
+        }
+    }
+
+    private String getStatusFromFormData(JSONObject next, List<JSONObject> commitData) {
+        for (JSONObject jsonObject : commitData) {
+            if (jsonObject.getLong(FormDataConstant.ID).equals(next.getLong(FormDataConstant.ID))) {
+                return jsonObject.getString(FormDataConstant.STATUS);
+            }
+        }
+        throw new IllegalArgumentException("不可能没有一个合适的");
+    }
+
+
+    /**
+     * 是否定制
+     * 判断是否需要转发到定制接口
+     * @param tableName 表明
+     * @param result 结果
+     * @param action 动作
+     * @return 结果
+     */
+    public List<JSONObject> isCustomized(String tableName, List<JSONObject> result, String action) {
+        requireNonNull(tableName);
+        requireNonNull(action);
+        if (result != null && result.size() > 0){
+            //获取到服务名称
+            String triggerName = getTriggerName(tableName, action);
+            if(triggerName != null){
+                //组织请求 acos + RestTemplate
+                return restTemplate.postForObject("http://" + triggerName, result, List.class);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 判断是什么action
+     * @param tableName 表明
+     * @param action 动作
+     * @return
+     */
+    private String getTriggerName(String tableName, String action){
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
+        requireNonNull(genTable);
+        if (action.equals(TriggerActionConstant.ACTION_CREATE)){
+            return genTable.getTriggerCreate();
+        }else if (action.equals(TriggerActionConstant.ACTION_RETRIEVE)){
+            return genTable.getTriggerRetrieve();
+        }else if (action.equals(TriggerActionConstant.ACTION_UPDATE)){
+            return genTable.getTriggerUpdate();
+        }else if (action.equals(TriggerActionConstant.ACTION_DELETE)){
+            return genTable.getTriggerDelete();
+        }else if (action.equals(TriggerActionConstant.ACTION_SUBMIT)){
+            return genTable.getTriggerSubmit();
+        }
+        return null;
+    }
+
+    /**
+     * 功能描述: 查询表从redis中
+     *
+     * @param redisKeyPrefix 前缀
+     * @param tableName      表名
+     * @return com.boman.gen.domain.GenTable
+     */
+    private GenTable getTableFromRedisByTableName(String redisKeyPrefix, String tableName) {
+        String key = requireNonNull(redisKeyPrefix) + requireNonNull(tableName);
+        GenTable genTable = redisService.getCacheObject(key);
+        if (ObjectUtils.isEmpty(genTable)) {
+            genTable = remoteGenTableService.getByTableName(tableName);
+            requireNonNull(genTable, "未找到表对应的信息");
+            // {@link com.boman.gen.controller.MyController.packTableAndInsertToRedis} 失效时间
+            redisService.setCacheObject(key, genTable, 12L, TimeUnit.DAYS);
+        }
+
+        return genTable;
+    }
+
+    /**
+     * 功能描述: 反提交接口, 更改的字段类型和字段值都是一致的
+     *                {
+     *                    "table": "sys_config",
+     *                }
+     *
+     *
+     * @param condition condition
+     * @return com.boman.common.core.web.domain.AjaxResult
+     */
+    public AjaxResult getByTableName(BaseTableSaveDTO condition) {
+        requireNonNull(condition.getTable(), "表名为空");
+        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
+        List<GenTableColumn> columns = genTable.getColumns();
+        for (GenTableColumn column : columns) {
+            String dictType = column.getDictType();
+            if (ObjectUtils.isNotEmpty(dictType)) {
+//                List<SysDictData> sysDictData1 = dictTypeService.listByType(dictType);
+//                column.setSysDictData(coverSysDictDataToJSONObject(sysDictData1));
+            }
+        }
+
+        return AjaxResult.success(genTable);
+    }
+
+//    public List<JSONObject> coverSysDictDataToJSONObject(List<SysDictData> sysDictData) {
+//        List<JSONObject> result = Lists.newArrayListWithCapacity(sysDictData.size());
+//        for (SysDictData data : sysDictData) {
+//            JSONObject jsonObject = new JSONObject();
+//            String dictLabel = data.getDictLabel();
+//            String dictValue = data.getDictValue();
+//            jsonObject.put(DictConstant.DICT_LABEL, dictLabel);
+//            jsonObject.put(DictConstant.DICT_VALUE, dictValue);
+//            result.add(jsonObject);
+//        }
+//
+//        return result;
+//
+//    }
+}
+

+ 67 - 0
boman-web-core/src/main/java/com/boman/web/core/service/delete/BaseDeleteServiceImpl.java

@@ -0,0 +1,67 @@
+package com.boman.web.core.service.delete;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.web.core.domain.RowResult;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author shiqian
+ * @date 2021年03月26日 11:16
+ **/
+@Service
+public class BaseDeleteServiceImpl implements IBaseDeleteService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDeleteServiceImpl.class);
+
+    @Autowired
+    private StandardlyMapper1 mapper;
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param idArr     需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @return com.boman.system.common.RowResult
+     */
+    @Override
+    public RowResult objectDelete(Long[] idArr, String tableName, String pkName) {
+        int delete = mapper.deleteByIds(tableName, idArr, pkName);
+        return RowResult.ok("共删除了 " + delete + " 条记录");
+    }
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param id        需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @return com.boman.system.common.RowResult
+     */
+    @Override
+    public RowResult deleteById(String tableName, String pkName, Long id) {
+        int delete = mapper.deleteById(tableName, pkName, id);
+        return RowResult.ok("共删除了 " + delete + " 条记录");
+    }
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param idArr     需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @param model     逻辑删除的字段和值
+     * @return com.boman.system.common.RowResult
+     */
+    @Override
+    public RowResult objectLogicDelete(Long[] idArr, String tableName, String pkName, JSONObject model) {
+        int delete = mapper.updateById(tableName, model, pkName, idArr);
+        return RowResult.ok("共删除了 " + delete + " 条记录");
+    }
+
+
+}

+ 46 - 0
boman-web-core/src/main/java/com/boman/web/core/service/delete/IBaseDeleteService.java

@@ -0,0 +1,46 @@
+package com.boman.web.core.service.delete;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.web.core.domain.RowResult;
+
+/**
+ * @author shiqian
+ * @date 2021年03月26日 11:16
+ **/
+public interface IBaseDeleteService {
+
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param idArr     需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @return com.boman.system.common.RowResult
+     */
+    RowResult objectDelete(Long[] idArr, String tableName, String pkName);
+
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param id        需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @return com.boman.system.common.RowResult
+     */
+    RowResult deleteById(String tableName, String pkName, Long id);
+
+    /**
+     * 功能描述: 在此不对入参进行校验,所以在调用此方法之前一定要对参数进行校验,以免报错
+     *
+     * @param idArr     需要删除的iD
+     * @param tableName 业务主表
+     * @param pkName    业务表的主键名
+     * @param model     逻辑删除的字段和值
+     * @return com.boman.system.common.RowResult
+     */
+    RowResult objectLogicDelete(Long[] idArr, String tableName, String pkName, JSONObject model);
+
+
+}

+ 69 - 0
boman-web-core/src/main/java/com/boman/web/core/service/save/BaseSaveServiceImpl.java

@@ -0,0 +1,69 @@
+package com.boman.web.core.service.save;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.common.core.utils.SecurityUtils;
+import com.boman.web.core.constant.FormDataConstant;
+import com.boman.web.core.domain.MainTableRecord;
+import com.boman.web.core.domain.RowResult;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 11:25
+ **/
+@Component
+public class BaseSaveServiceImpl implements IBaseSaveService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseSaveServiceImpl.class);
+
+    @Autowired
+    private StandardlyMapper1 mapper;
+
+    /**
+     * 功能描述: 保存一行
+     *
+     * @param tableName         tableName
+     * @param pkName            主键名称
+     * @param maxId             最大的SEQ
+     * @param row               要保存的数据
+     * @param allColumnNameList 这是此表的所有字段属性名称,用来判断是否所有UPDATE_BY和UPDATE_TIME
+     * @return com.boman.system.common.RowResult
+     */
+    @Override
+    public RowResult insertRow(String tableName, String pkName, Long maxId, MainTableRecord row, List<String> allColumnNameList) {
+        JSONObject commitData = row.getMainData().getCommitData();
+        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
+        if (allColumnNameList.contains(FormDataConstant.UPDATE_BY)
+                || allColumnNameList.contains(FormDataConstant.UPDATE_BY.toLowerCase())) {
+            commitData.put(FormDataConstant.UPDATE_BY, SecurityUtils.getUserId());
+        }
+        if (allColumnNameList.contains(FormDataConstant.UPDATE_TIME)
+                || allColumnNameList.contains(FormDataConstant.UPDATE_TIME.toLowerCase())) {
+            commitData.put(FormDataConstant.UPDATE_TIME, SecurityUtils.getUserId());
+        }
+
+        // 新增
+        if (row.getId() > 0) {
+            commitData.put("CREATE_TIME", currentTime);
+            commitData.put("CREATE_BY", SecurityUtils.getUserId());
+        }
+
+        commitData.put(pkName.toUpperCase(), maxId);
+        int ret = mapper.insert(tableName, commitData);
+        if (ret > 0) {
+            commitData.put("successCnt", ret);
+            return RowResult.ok("保存成功", commitData);
+        }
+
+        return RowResult.error("失败");
+    }
+
+}

+ 29 - 0
boman-web-core/src/main/java/com/boman/web/core/service/save/IBaseSaveService.java

@@ -0,0 +1,29 @@
+package com.boman.web.core.service.save;
+
+
+import com.boman.web.core.domain.MainTableRecord;
+import com.boman.web.core.domain.RowResult;
+
+import java.util.List;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月22日 11:25
+ **/
+public interface IBaseSaveService {
+
+
+    /**
+     * 功能描述: 保存一行
+     *
+     * @param tableName         tableName
+     * @param pkName            主键名称
+     * @param maxId             最大的SEQ
+     * @param row               要保存的数据
+     * @param allColumnNameList 这是此表的所有字段属性名称,用来判断是否所有UPDATE_BY和UPDATE_TIME
+     * @return com.boman.system.common.RowResult
+     */
+    RowResult insertRow(String tableName, String pkName, Long maxId, MainTableRecord row, List<String> allColumnNameList);
+
+}

+ 97 - 0
boman-web-core/src/main/java/com/boman/web/core/service/select/BaseSelectServiceImpl.java

@@ -0,0 +1,97 @@
+package com.boman.web.core.service.select;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
+
+/**
+ * @author shiqian
+ * @date 2021年03月29日 10:22
+ **/
+@Service
+public class BaseSelectServiceImpl implements IBaseSelectService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseSelectServiceImpl.class);
+
+    @Autowired
+    private StandardlyMapper1 mapper;
+
+
+    /**
+     * 功能描述: 根据条件查询
+     *
+     * @param tableName     tableName
+     * @param condition     原始查询条件
+     * @param packCondition 封装的查询条件
+     * @param showData      前台需要查询的列
+     * @param orderBy       orderBy
+     * @param limit         分页
+     * @param offset        分页
+     * @return java.util.List<com.alibaba.fastjson.JSONObject>
+     */
+    @Override
+    public List<JSONObject> selectByCondition(String tableName, JSONObject condition
+            , JSONObject packCondition, JSONArray showData, String orderBy, Integer limit, Integer offset) {
+        requireNonNull(tableName, "表名为空");
+//        requireNonNull(showData);
+        requireNonNull(orderBy);
+        return mapper.selectByCondition(tableName, condition, packCondition, showData, orderBy, limit, offset);
+    }
+
+    /**
+     * 功能描述: 根据条件查询
+     *
+     * @param tableName     tableName
+     * @param condition     原始查询条件
+     * @param packCondition 封装的查询条件
+     * @return int
+     */
+    @Override
+    public int countByCondition(String tableName, JSONObject condition, JSONObject packCondition) {
+        requireNonNull(tableName, "表名为空");
+        return mapper.countByCondition(tableName, condition, packCondition);
+    }
+
+    /**
+     * 功能描述: 根据id查所有,不支持自定义查询列
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param id        主键值
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    @Override
+    public JSONObject selectById(String tableName, String pkName, Long id) {
+        requireNonNull(tableName, "表名为空");
+        requireNonNull(pkName, "主键名称为空");;
+        requireNonNull(id);
+        return mapper.selectById(tableName, pkName, id);
+    }
+
+    /**
+     * 功能描述: 根据id查所有,不支持自定义查询列
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param idList    主键值
+     * @param showData  需要展示的列
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    @Override
+    public List<JSONObject> selectByIdList(String tableName, String pkName
+            , List<Long> idList, JSONArray showData) {
+        requireNonNull(tableName, "表名为空");
+        requireNonNull(pkName, "主键名称为空");;
+        requireNonNull(idList);
+
+        return mapper.selectByIdList(tableName, pkName, idList, showData);
+    }
+}

+ 59 - 0
boman-web-core/src/main/java/com/boman/web/core/service/select/IBaseSelectService.java

@@ -0,0 +1,59 @@
+package com.boman.web.core.service.select;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.List;
+
+/**
+ * @author shiqian
+ * @date 2021年03月29日 10:22
+ **/
+public interface IBaseSelectService {
+
+    /**
+     * 功能描述: 根据条件查询
+     *
+     * @param tableName     tableName
+     * @param condition     原始查询条件
+     * @param packCondition 封装的查询条件
+     * @param showData      前台需要查询的列
+     * @param orderBy       orderBy
+     * @param limit         分页
+     * @param offset        分页
+     * @return java.util.List<com.alibaba.fastjson.JSONObject>
+     */
+    List<JSONObject> selectByCondition(String tableName, JSONObject condition, JSONObject packCondition
+            , JSONArray showData, String orderBy, Integer limit, Integer offset);
+
+    /**
+     * 功能描述: 根据条件查询
+     *
+     * @param tableName     tableName
+     * @param condition     原始查询条件
+     * @param packCondition 封装的查询条件
+     * @return int
+     */
+    int countByCondition(String tableName, JSONObject condition, JSONObject packCondition);
+
+    /**
+     * 功能描述: 根据id查所有,不支持自定义查询列
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param id        主键值
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    JSONObject selectById(String tableName, String pkName, Long id);
+
+    /**
+     * 功能描述: 根据id查所有,不支持自定义查询列
+     *
+     * @param tableName 表名
+     * @param pkName    主键名称
+     * @param idList    主键值
+     * @param showData  需要展示的列
+     * @return com.alibaba.fastjson.JSONObject
+     */
+    List<JSONObject> selectByIdList(String tableName, String pkName, List<Long> idList, JSONArray showData);
+}

+ 38 - 0
boman-web-core/src/main/java/com/boman/web/core/service/submit/BaseSubmitServiceImpl.java

@@ -0,0 +1,38 @@
+package com.boman.web.core.service.submit;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
+
+
+/**
+ * @author shiqian
+ * @date 2021年04月01日 14:56
+ **/
+@Service
+public class BaseSubmitServiceImpl implements IBaseSubmitService {
+
+
+    @Autowired
+    private StandardlyMapper1 mapper;
+
+    /**
+     * 功能描述: 处理提交流程
+     *
+     * @param tableName tableName
+     * @param pkName    pkName
+     * @param model     model
+     * @param id        主键
+     * @return int
+     */
+    @Override
+    public int handlerSubmit(String tableName, String pkName, JSONObject model, Long id) {
+        requireNonNull(model, "提交的数据为空");
+        Long[] longs = new Long[1];
+        longs[0] = id;
+        return mapper.updateById(tableName, model, pkName, longs);
+    }
+}

+ 21 - 0
boman-web-core/src/main/java/com/boman/web/core/service/submit/IBaseSubmitService.java

@@ -0,0 +1,21 @@
+package com.boman.web.core.service.submit;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * @author shiqian
+ * @date 2021年03月29日 10:22
+ **/
+public interface IBaseSubmitService {
+
+    /**
+     * 功能描述: 处理提交流程
+     *
+     * @param tableName tableName
+     * @param pkName    pkName
+     * @param model     model
+     * @param id        主键
+     * @return int
+     */
+    int handlerSubmit(String tableName, String pkName, JSONObject model, Long id);
+}

+ 75 - 0
boman-web-core/src/main/java/com/boman/web/core/service/update/BaseUpdateServiceImpl.java

@@ -0,0 +1,75 @@
+package com.boman.web.core.service.update;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.common.core.utils.obj.ObjectUtils;
+import com.boman.gen.domain.GenTableColumn;
+import com.boman.web.core.domain.TableServiceContext;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.escapeStr;
+import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
+import static com.boman.web.core.constant.FormDataConstant.*;
+
+/**
+ * @author shiqian
+ * @date 2021年04月01日 11:07
+ **/
+@Service
+public class BaseUpdateServiceImpl implements IBaseUpdateService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseUpdateServiceImpl.class);
+
+    @Autowired
+    private StandardlyMapper1 mapper;
+
+    /**
+     * 功能描述: 批量修改, 默认需要更改的model,更改的字段类型和字段值都是一致的
+     *
+     * @param context    用到其中的表名和所有的列(用来判断是否需要转义字符)
+     * @param pkName     主键名
+     * @param idList     idList
+     * @param commitData 需要更改的model, 已经转义好了,不需要到mapper层再去转义
+     * @return int
+     */
+    @Override
+    public int updateByIdList(TableServiceContext context, String pkName, List<Long> idList, JSONObject commitData) {
+        requireNonNull(context.getRealTableName(), "表名为空");
+        requireNonNull(pkName, "主键名称为空");;
+        requireNonNull(idList, "需要修改的idList为空");
+        requireNonNull(commitData, "需要更改的参数为空");
+
+        commitData = ObjectUtils.ifNullSetEmpty(escapeByQueryType(context.getTable().getColumns(), commitData));
+        return mapper.updateByIdList(context.getRealTableName(), pkName, idList, commitData);
+    }
+
+    private JSONObject escapeByQueryType(List<GenTableColumn> columns, JSONObject commitData) {
+        requireNonNull(columns);
+        JSONObject result = new JSONObject(columns.size());
+        for (Map.Entry<String, Object> entry : commitData.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            for (GenTableColumn column : columns) {
+                if (column.getColumnName().equalsIgnoreCase(key) && ObjectUtils.isNotEmpty(value)) {
+                    value = covert(column.getColumnType(), String.valueOf(value));
+                    result.put(key, value);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private String covert(String columnType, String value) {
+        // false 不需要转义
+        boolean needEscape = columnType.contains(VARCHAR) || columnType.contains(CHAR)
+                || columnType.contains(DATETIME) || columnType.contains(TIMESTAMP);
+        return needEscape ? escapeStr(value) : value;
+    }
+}

+ 24 - 0
boman-web-core/src/main/java/com/boman/web/core/service/update/IBaseUpdateService.java

@@ -0,0 +1,24 @@
+package com.boman.web.core.service.update;
+
+import com.alibaba.fastjson.JSONObject;
+import com.boman.web.core.domain.TableServiceContext;
+
+import java.util.List;
+
+/**
+ * @author shiqian
+ * @date 2021年03月29日 10:22
+ **/
+public interface IBaseUpdateService {
+
+    /**
+     * 功能描述: 批量修改, 默认需要更改的model,更改的字段类型和字段值都是一致的
+     *
+     * @param context    用到其中的表名和所有的列(用来判断是否需要转义字符)
+     * @param pkName     主键名
+     * @param idList     idList
+     * @param commitData 需要更改的model, 已经转义好了,不需要到mapper层再去转义
+     * @return int
+     */
+    int updateByIdList(TableServiceContext context, String pkName, List<Long> idList, JSONObject commitData);
+}

+ 57 - 0
boman-web-core/src/main/java/com/boman/web/core/utils/IdUtils.java

@@ -0,0 +1,57 @@
+package com.boman.web.core.utils;
+
+import com.boman.common.core.utils.SpringUtils;
+import com.boman.common.redis.RedisKey;
+import com.boman.common.redis.service.RedisService;
+import com.boman.gen.domain.GenTableColumn;
+import com.boman.web.core.mapper.StandardlyMapper1;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.List;
+
+import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;
+
+/**
+ * @author shiqian
+ * @description
+ * @date 2021年03月23日 16:04
+ **/
+public class IdUtils {
+
+
+    public static Long getMaxId(String tableName, String pkName) {
+        RedisService redisService = SpringUtils.getBean(RedisService.class);
+        String sequencesKey = RedisKey.SEQ + tableName.toUpperCase();
+        boolean isExist = redisService.exists(sequencesKey);
+        if (isExist) {
+            return redisService.increment(sequencesKey);
+        }
+
+        // 查数据库
+        StandardlyMapper1 mapper = SpringUtils.getBean(StandardlyMapper1.class);
+        Long maxId = mapper.selectMaxId(tableName, pkName);
+        if (null == maxId || maxId <= 0) {
+            maxId = 1L;
+            redisService.setCacheObject(sequencesKey, maxId);
+        } else {
+            redisService.increment(sequencesKey, ++maxId);
+        }
+
+        return maxId;
+    }
+
+    public static String getPkName(List<GenTableColumn> columnList) {
+        if (CollectionUtils.isEmpty(columnList)) {
+            throw new IllegalArgumentException("获取主键失败");
+        }
+
+        for (GenTableColumn tableColumn : columnList) {
+            if ("1".equalsIgnoreCase(tableColumn.getIsPk())) {
+                return requireNonNull(tableColumn.getColumnName(), "主键名称为空");
+            }
+        }
+
+        throw new IllegalArgumentException("获取主键失败");
+    }
+
+}

+ 17 - 0
boman-web-core/src/main/resources/bootstrap.yml

@@ -0,0 +1,17 @@
+server:
+  port: 9000
+
+spring: 
+  application:
+    name: boman-web-core
+  profiles:
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        server-addr: 192.168.101.10:8848
+      config:
+        server-addr: 192.168.101.10:8848
+        file-extension: yml
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

+ 74 - 0
boman-web-core/src/main/resources/logback.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="logs/boman-web-core" />
+   <!-- 日志输出格式 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+    <!-- 控制台输出 -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+
+    <!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+			<!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+	<logger name="com.boman" level="debug" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="debug">
+		<appender-ref ref="console" />
+	</root>
+	
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+</configuration>

+ 16 - 0
boman-web-core/src/main/resources/rebel.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
+  Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
+-->
+<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
+
+	<id>boman-modules-system</id>
+
+	<classpath>
+		<dir name="E:/boman-framwork/boman-web-core/target/classes">
+		</dir>
+	</classpath>
+
+</application>

+ 0 - 201
ruoyi-ui/src/views/system/table/index.vue

@@ -1,201 +0,0 @@
-<template>
-  <div class="table_total">
-    <div class="table_header">
-      <!-- <p>单表</p>
-      <el-divider></el-divider> -->
-      <div class="table_headerBtun" v-if="queryData.buttonList">
-        <el-button type="primary" plain v-for="(item,index) in queryData.buttonList.split('')" :key="index">{{item | btnConversion}}</el-button>
-      </div>
-      <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" >
-        <dynamic-form :config="queryParams" @inputs = "changeFn" :formConfig="item" v-for="(item,index) in queryData.queryList" :key='index' />
-        <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-        </el-form-item>
-      </el-form>
-    </div>
-    <!-- 内容 -->
-    <div class="table_nav">
-      <!-- <el-collapse v-model="activeNames" @change="handleChange">
-        <el-collapse-item :title="title" :name="index" v-for="(item,index) in 4" :key="index">
-          <el-form :model="queryParams" ref="queryForm" :inline="true">
-            <el-row :gutter="0">
-              <el-col :span="6" v-for="(item,index) in 12" :key="index">
-                <el-form-item :label="labletit" prop="dictName">
-                  <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable size="small"
-                    @keyup.enter.native="handleQuery" />
-                </el-form-item>
-              </el-col>
-            </el-row>
-          </el-form>
-        </el-collapse-item>
-
-      </el-collapse> -->
-    </div>
-
-  </div>
-
-</template>
-
-<script>
-  import {
-    getTableQuery
-  } from '@/api/system/table.js'
-  export default {
-    name: "index",
-    data() {
-      return {
-        // 显示搜索条件
-        showSearch: true,
-        activeNames: ['1'],
-        title: '单表1',
-        queryData: {},
-        // 查询参数
-        queryParams: {
-          pageNum: 1,
-          pageSize: 10,
-        },
-        labletit: '查询参数1233'
-      };
-    },
-    filters:{
-      btnConversion(val) {
-        switch(val){
-          case 'A':
-          return '新增';
-          case 'M':
-          return '修改';
-          case 'D':
-          return '删除';
-          case 'Q':
-          return '查询';
-          case 'S':
-          return '提交';
-          case 'U':
-          return '反提交';
-          case 'I':
-          return '导入';
-          case 'E':
-          return '导出';
-        }
-      }
-    },
-    mounted() {
-      this.init()
-    },
-    methods: {
-      changeFn(obj) {
-        for(let key in obj){
-          this.queryParams[key] = obj[key]
-        }
-      },
-      resetQuery() {
-
-      },
-      /** 搜索按钮操作 */
-      handleQuery() {
-        this.getList();
-      },
-      getList() {
-
-      },
-      init() {
-        getTableQuery({
-          table: 'obj_test'
-        }).then(res => {
-          let data = res.data
-          this.queryData = data
-        })
-      },
-      handleChange(val) {
-        console.log(val);
-      }
-    },
-  };
-</script>
-
-
-<style lang="scss">
-  .table_header {
-    .el-divider--horizontal {
-      margin-top: 16px;
-    }
-    .table_headerBtun{
-      margin-bottom: 20px;
-    }
-  }
-
-  .table_nav {
-    .el-collapse-item__wrap {
-      border-bottom: 0;
-    }
-
-    .el-collapse-item__header {
-      border-bottom: 0;
-      font-size: 15px;
-      font-family: PingFang SC;
-      font-weight: bold;
-      color: #3C8DBC;
-      line-height: 36px;
-    }
-
-    .el-form-item__content {
-      width: 55%;
-    }
-
-    .el-collapse {
-      border-top: 0;
-    }
-  }
-</style>
-
-
-
-<style scoped lang="scss">
-  .app-main {
-    // background-color: #eef0ff !important;
-  }
-
-  .table_total {
-    background-color: #eef0ff;
-    min-height: calc(100vh - 94px);
-    padding: 20px;
-
-    // 头部
-    .table_header {
-      background-color: #fff;
-      border-radius: 6px;
-      padding: 23px 23px 0px;
-      margin-bottom: 20px;
-
-      p {
-        font-size: 15px;
-        font-weight: bold;
-        color: #3C8DBC;
-        line-height: 36px;
-      }
-
-      p::before {
-        content: "";
-        display: block;
-        width: 18px;
-        height: 8px;
-        background: #3C8DBC;
-        border-radius: 3px;
-
-      }
-    }
-
-    // 内容
-    .table_nav {
-      background-color: #fff;
-      border-radius: 6px;
-      padding: 23px;
-    }
-  }
-
-  p {
-    margin: 0;
-
-  }
-</style>