Explorar o código

:tada: 2.2.1.RELEASE

smallchill %!s(int64=6) %!d(string=hai) anos
pai
achega
7a159ae92e
Modificáronse 34 ficheiros con 1850 adicións e 16 borrados
  1. 1 1
      blade-core-boot/pom.xml
  2. 1 1
      blade-core-cloud/pom.xml
  3. 39 0
      blade-core-develop/pom.xml
  4. 88 0
      blade-core-develop/src/main/java/org/springblade/develop/CodeGenerator.java
  5. 33 0
      blade-core-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java
  6. 329 0
      blade-core-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java
  7. 5 0
      blade-core-develop/src/main/resources/code.properties
  8. 150 0
      blade-core-develop/src/main/resources/controller.java.vm
  9. 162 0
      blade-core-develop/src/main/resources/entity.java.vm
  10. 38 0
      blade-core-develop/src/main/resources/entityDTO.java.vm
  11. 44 0
      blade-core-develop/src/main/resources/entityVO.java.vm
  12. 46 0
      blade-core-develop/src/main/resources/mapper.java.vm
  13. 34 0
      blade-core-develop/src/main/resources/mapper.xml.vm
  14. 50 0
      blade-core-develop/src/main/resources/saber/api.js.vm
  15. 176 0
      blade-core-develop/src/main/resources/saber/crud.vue.vm
  16. 45 0
      blade-core-develop/src/main/resources/service.java.vm
  17. 47 0
      blade-core-develop/src/main/resources/serviceImpl.java.vm
  18. 11 0
      blade-core-develop/src/main/resources/sql/menu.sql.vm
  19. 37 0
      blade-core-develop/src/main/resources/sword/action.js.vm
  20. 75 0
      blade-core-develop/src/main/resources/sword/add.js.vm
  21. 99 0
      blade-core-develop/src/main/resources/sword/edit.js.vm
  22. 84 0
      blade-core-develop/src/main/resources/sword/list.js.vm
  23. 88 0
      blade-core-develop/src/main/resources/sword/model.js.vm
  24. 26 0
      blade-core-develop/src/main/resources/sword/service.js.vm
  25. 76 0
      blade-core-develop/src/main/resources/sword/view.js.vm
  26. 51 0
      blade-core-develop/src/main/resources/wrapper.java.vm
  27. 1 1
      blade-core-launch/pom.xml
  28. 2 2
      blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
  29. 1 1
      blade-core-log/pom.xml
  30. 1 1
      blade-core-mybatis/pom.xml
  31. 1 1
      blade-core-secure/pom.xml
  32. 1 1
      blade-core-swagger/pom.xml
  33. 1 1
      blade-core-tool/pom.xml
  34. 7 6
      pom.xml

+ 1 - 1
blade-core-boot/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.springblade</groupId>
         <artifactId>blade-tool</artifactId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-cloud/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 39 - 0
blade-core-develop/pom.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>blade-tool</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>2.2.1</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-core-develop</artifactId>
+    <name>${project.artifactId}</name>
+    <version>${blade.tool.version}</version>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <!--Blade-->
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-tool</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <!--Mybatis-Plus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>${mybatis.plus.version}</version>
+        </dependency>
+        <!--Velocity-->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+            <version>1.7</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 88 - 0
blade-core-develop/src/main/java/org/springblade/develop/CodeGenerator.java

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.develop;
+
+
+import org.springblade.develop.support.BladeCodeGenerator;
+
+/**
+ * 代码生成器
+ *
+ * @author Chill
+ */
+public class CodeGenerator {
+
+	/**
+	 * 代码生成的模块名
+	 */
+	public static String CODE_NAME = "应用管理";
+	/**
+	 * 代码所在服务名
+	 */
+	public static String SERVICE_NAME = "blade-system";
+	/**
+	 * 代码生成的包名
+	 */
+	public static String PACKAGE_NAME = "org.springblade.system";
+	/**
+	 * 前端代码生成所属系统
+	 */
+	public static String SYSTEM_NAME = "saber";
+	/**
+	 * 前端代码生成地址
+	 */
+	public static String PACKAGE_WEB_DIR = "/Users/chill/Workspaces/product/Saber";
+	/**
+	 * 需要去掉的表前缀
+	 */
+	public static String[] TABLE_PREFIX = {"blade_"};
+	/**
+	 * 需要生成的表名(两者只能取其一)
+	 */
+	public static String[] INCLUDE_TABLES = {"blade_client"};
+	/**
+	 * 需要排除的表名(两者只能取其一)
+	 */
+	public static String[] EXCLUDE_TABLES = {};
+	/**
+	 * 是否包含基础业务字段
+	 */
+	public static Boolean HAS_SUPER_ENTITY = Boolean.TRUE;
+	/**
+	 * 基础业务字段
+	 */
+	public static String[] SUPER_ENTITY_COLUMNS = {"id", "create_time", "create_user", "update_time", "update_user", "status", "is_deleted"};
+
+
+	/**
+	 * RUN THIS
+	 */
+	public static void run() {
+		BladeCodeGenerator generator = new BladeCodeGenerator();
+		generator.setCodeName(CODE_NAME);
+		generator.setServiceName(SERVICE_NAME);
+		generator.setSystemName(SYSTEM_NAME);
+		generator.setPackageName(PACKAGE_NAME);
+		generator.setPackageWebDir(PACKAGE_WEB_DIR);
+		generator.setTablePrefix(TABLE_PREFIX);
+		generator.setIncludeTables(INCLUDE_TABLES);
+		generator.setExcludeTables(EXCLUDE_TABLES);
+		generator.setHasSuperEntity(HAS_SUPER_ENTITY);
+		generator.setSuperEntityColumns(SUPER_ENTITY_COLUMNS);
+		generator.run();
+	}
+
+}

+ 33 - 0
blade-core-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java

@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.develop.constant;
+
+/**
+ * 系统常量.
+ *
+ * @author zhuangqian
+ */
+public interface DevelopConstant {
+	/**
+	 * sword 系统名
+	 */
+	String SWORD_NAME = "sword";
+
+	/**
+	 * saber 系统名
+	 */
+	String SABER_NAME = "saber";
+}

+ 329 - 0
blade-core-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java

@@ -0,0 +1,329 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.develop.support;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
+import com.baomidou.mybatisplus.generator.config.converts.PostgreSqlTypeConvert;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.develop.constant.DevelopConstant;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * 代码生成器配置类
+ *
+ * @author Chill
+ */
+@Data
+@Slf4j
+public class BladeCodeGenerator {
+	/**
+	 * 代码所在系统
+	 */
+	private String systemName = DevelopConstant.SWORD_NAME;
+	/**
+	 * 代码模块名称
+	 */
+	private String codeName;
+	/**
+	 * 代码所在服务名
+	 */
+	private String serviceName = "blade-service";
+	/**
+	 * 代码生成的包名
+	 */
+	private String packageName = "org.springblade.test";
+	/**
+	 * 代码后端生成的地址
+	 */
+	private String packageDir;
+	/**
+	 * 代码前端生成的地址
+	 */
+	private String packageWebDir;
+	/**
+	 * 需要去掉的表前缀
+	 */
+	private String[] tablePrefix = {"blade_"};
+	/**
+	 * 需要生成的表名(两者只能取其一)
+	 */
+	private String[] includeTables = {"blade_test"};
+	/**
+	 * 需要排除的表名(两者只能取其一)
+	 */
+	private String[] excludeTables = {};
+	/**
+	 * 是否包含基础业务字段
+	 */
+	private Boolean hasSuperEntity = Boolean.FALSE;
+	/**
+	 * 基础业务字段
+	 */
+	private String[] superEntityColumns = {"id", "create_time", "create_user", "update_time", "update_user", "status", "is_deleted"};
+	/**
+	 * 租户字段
+	 */
+	private String tenantColumn = "tenant_code";
+	/**
+	 * 是否启用swagger
+	 */
+	private Boolean isSwagger2 = Boolean.TRUE;
+
+	public void run() {
+		Properties props = getProperties();
+		AutoGenerator mpg = new AutoGenerator();
+		GlobalConfig gc = new GlobalConfig();
+		String outputDir = getOutputDir();
+		String author = props.getProperty("author");
+		gc.setOutputDir(outputDir);
+		gc.setAuthor(author);
+		gc.setFileOverride(true);
+		gc.setOpen(false);
+		gc.setActiveRecord(false);
+		gc.setEnableCache(false);
+		gc.setBaseResultMap(true);
+		gc.setBaseColumnList(true);
+		gc.setMapperName("%sMapper");
+		gc.setXmlName("%sMapper");
+		gc.setServiceName("I%sService");
+		gc.setServiceImplName("%sServiceImpl");
+		gc.setControllerName("%sController");
+		gc.setSwagger2(isSwagger2);
+		mpg.setGlobalConfig(gc);
+		DataSourceConfig dsc = new DataSourceConfig();
+		String driverName = props.getProperty("spring.datasource.driver-class-name");
+		if (StringUtil.containsAny(driverName, DbType.MYSQL.getDb())) {
+			dsc.setDbType(DbType.MYSQL);
+			dsc.setTypeConvert(new MySqlTypeConvert());
+		} else {
+			dsc.setDbType(DbType.POSTGRE_SQL);
+			dsc.setTypeConvert(new PostgreSqlTypeConvert());
+		}
+		dsc.setUrl(props.getProperty("spring.datasource.url"));
+		dsc.setDriverName(driverName);
+		dsc.setUsername(props.getProperty("spring.datasource.username"));
+		dsc.setPassword(props.getProperty("spring.datasource.password"));
+		mpg.setDataSource(dsc);
+		// 策略配置
+		StrategyConfig strategy = new StrategyConfig();
+		// strategy.setCapitalMode(true);// 全局大写命名
+		// strategy.setDbColumnUnderline(true);//全局下划线命名
+		strategy.setNaming(NamingStrategy.underline_to_camel);
+		strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+		strategy.setTablePrefix(tablePrefix);
+		if (includeTables.length > 0) {
+			strategy.setInclude(includeTables);
+		}
+		if (excludeTables.length > 0) {
+			strategy.setExclude(excludeTables);
+		}
+		if (hasSuperEntity) {
+			strategy.setSuperEntityClass("org.springblade.core.mp.base.BaseEntity");
+			strategy.setSuperEntityColumns(superEntityColumns);
+			strategy.setSuperServiceClass("org.springblade.core.mp.base.BaseService");
+			strategy.setSuperServiceImplClass("org.springblade.core.mp.base.BaseServiceImpl");
+		} else {
+			strategy.setSuperServiceClass("com.baomidou.mybatisplus.extension.service.IService");
+			strategy.setSuperServiceImplClass("com.baomidou.mybatisplus.extension.service.impl.ServiceImpl");
+		}
+		// 自定义 controller 父类
+		strategy.setSuperControllerClass("org.springblade.core.boot.ctrl.BladeController");
+		strategy.setEntityBuilderModel(false);
+		strategy.setEntityLombokModel(true);
+		strategy.setControllerMappingHyphenStyle(true);
+		mpg.setStrategy(strategy);
+		// 包配置
+		PackageConfig pc = new PackageConfig();
+		// 控制台扫描
+		pc.setModuleName(null);
+		pc.setParent(packageName);
+		pc.setController("controller");
+		pc.setEntity("entity");
+		pc.setXml("mapper");
+		mpg.setPackageInfo(pc);
+		mpg.setCfg(getInjectionConfig());
+		mpg.execute();
+	}
+
+	private InjectionConfig getInjectionConfig() {
+		String servicePackage = serviceName.split("-").length > 1 ? serviceName.split("-")[1] : serviceName;
+		// 自定义配置
+		Map<String, Object> map = new HashMap<>(16);
+		InjectionConfig cfg = new InjectionConfig() {
+			@Override
+			public void initMap() {
+				map.put("codeName", codeName);
+				map.put("serviceName", serviceName);
+				map.put("servicePackage", servicePackage);
+				map.put("tenantColumn", tenantColumn);
+				this.setMap(map);
+			}
+		};
+		List<FileOutConfig> focList = new ArrayList<>();
+		focList.add(new FileOutConfig("/templates/sql/menu.sql.vm") {
+			@Override
+			public String outputFile(TableInfo tableInfo) {
+				map.put("entityKey", (tableInfo.getEntityName().toLowerCase()));
+				return getOutputDir() + "/" + "/sql/" + tableInfo.getEntityName().toLowerCase() + ".menu.mysql";
+			}
+		});
+		focList.add(new FileOutConfig("/templates/entityVO.java.vm") {
+			@Override
+			public String outputFile(TableInfo tableInfo) {
+				return getOutputDir() + "/" + packageName.replace(".", "/") + "/" + "vo" + "/" + tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
+			}
+		});
+		focList.add(new FileOutConfig("/templates/entityDTO.java.vm") {
+			@Override
+			public String outputFile(TableInfo tableInfo) {
+				return getOutputDir() + "/" + packageName.replace(".", "/") + "/" + "dto" + "/" + tableInfo.getEntityName() + "DTO" + StringPool.DOT_JAVA;
+			}
+		});
+		focList.add(new FileOutConfig("/templates/wrapper.java.vm") {
+			@Override
+			public String outputFile(TableInfo tableInfo) {
+				return getOutputDir() + "/" + packageName.replace(".", "/") + "/" + "wrapper" + "/" + tableInfo.getEntityName() + "Wrapper" + StringPool.DOT_JAVA;
+			}
+		});
+		if (Func.isNotBlank(packageWebDir)) {
+			if (Func.equals(systemName, DevelopConstant.SWORD_NAME)) {
+				focList.add(new FileOutConfig("/templates/sword/action.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/actions" + "/" + tableInfo.getEntityName().toLowerCase() + ".js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/model.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/models" + "/" + tableInfo.getEntityName().toLowerCase() + ".js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/service.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/services" + "/" + tableInfo.getEntityName().toLowerCase() + ".js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/list.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/pages" + "/" + StringUtil.upperFirst(servicePackage) + "/" + tableInfo.getEntityName() + "/" + tableInfo.getEntityName() + ".js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/add.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/pages" + "/" + StringUtil.upperFirst(servicePackage) + "/" + tableInfo.getEntityName() + "/" + tableInfo.getEntityName() + "Add.js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/edit.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/pages" + "/" + StringUtil.upperFirst(servicePackage) + "/" + tableInfo.getEntityName() + "/" + tableInfo.getEntityName() + "Edit.js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/sword/view.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/pages" + "/" + StringUtil.upperFirst(servicePackage) + "/" + tableInfo.getEntityName() + "/" + tableInfo.getEntityName() + "View.js";
+					}
+				});
+			} else if (Func.equals(systemName, DevelopConstant.SABER_NAME)) {
+				focList.add(new FileOutConfig("/templates/saber/api.js.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/api" + "/" + servicePackage.toLowerCase() + "/" + tableInfo.getEntityName().toLowerCase() + ".js";
+					}
+				});
+				focList.add(new FileOutConfig("/templates/saber/crud.vue.vm") {
+					@Override
+					public String outputFile(TableInfo tableInfo) {
+						return getOutputWebDir() + "/views" + "/" + servicePackage.toLowerCase() + "/" + tableInfo.getEntityName().toLowerCase() + ".vue";
+					}
+				});
+			}
+		}
+		cfg.setFileOutConfigList(focList);
+		return cfg;
+	}
+
+	/**
+	 * 获取配置文件
+	 *
+	 * @return 配置Props
+	 */
+	private Properties getProperties() {
+		// 读取配置文件
+		Resource resource = new ClassPathResource("/templates/code.properties");
+		Properties props = new Properties();
+		try {
+			props = PropertiesLoaderUtils.loadProperties(resource);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return props;
+	}
+
+	/**
+	 * 生成到项目中
+	 *
+	 * @return outputDir
+	 */
+	public String getOutputDir() {
+		return (Func.isBlank(packageDir) ? System.getProperty("user.dir") + "/blade-ops/blade-develop" : packageDir) + "/src/main/java";
+	}
+
+	/**
+	 * 生成到Web项目中
+	 *
+	 * @return outputDir
+	 */
+	public String getOutputWebDir() {
+		return (Func.isBlank(packageWebDir) ? System.getProperty("user.dir") : packageWebDir) + "/src";
+	}
+
+	/**
+	 * 页面生成的文件名
+	 */
+	private String getGeneratorViewPath(String viewOutputDir, TableInfo tableInfo, String suffixPath) {
+		String name = StringUtils.firstToLowerCase(tableInfo.getEntityName());
+		String path = viewOutputDir + "/" + name + "/" + name + suffixPath;
+		File viewDir = new File(path).getParentFile();
+		if (!viewDir.exists()) {
+			viewDir.mkdirs();
+		}
+		return path;
+	}
+
+}

+ 5 - 0
blade-core-develop/src/main/resources/code.properties

@@ -0,0 +1,5 @@
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+spring.datasource.url=jdbc:mysql://localhost:3306/blade?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&serverTimezone=GMT%2B8
+spring.datasource.username=root
+spring.datasource.password=root
+author=Blade

+ 150 - 0
blade-core-develop/src/main/resources/controller.java.vm

@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package $!{package.Controller};
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import javax.validation.Valid;
+
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.system.feign.IDictClient;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springframework.web.bind.annotation.*;
+#if($!{superEntityClass})
+import org.springframework.web.bind.annotation.RequestParam;
+#end
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import $!{package.Entity}.$!{entity};
+#set($voPackage=$package.Entity.replace("entity","vo"))
+import $!{voPackage}.$!{entity}VO;
+#set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
+import $!{wrapperPackage}.$!{entity}Wrapper;
+import $!{package.Service}.$!{table.serviceName};
+#if($!{superControllerClassPackage})
+import $!{superControllerClassPackage};
+#end
+#if(!$!{superEntityClass})
+#end
+import java.util.List;
+
+/**
+ * $!{table.comment} 控制器
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("#if($!{package.ModuleName})/$!{package.ModuleName}#end/$!{cfg.entityKey}")
+@Api(value = "$!{table.comment}", tags = "$!{table.comment}接口")
+#if($!{superControllerClass})
+public class $!{table.controllerName} extends $!{superControllerClass} {
+#else
+public class $!{table.controllerName} {
+#end
+
+	private $!{table.serviceName} $!{table.entityPath}Service;
+
+	private IDictClient dictClient;
+
+	/**
+	* 详情
+	*/
+	@GetMapping("/detail")
+	@ApiOperation(value = "详情", notes = "传入$!{table.entityPath}", position = 1)
+	public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) {
+		$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
+		$!{entity}Wrapper $!{table.entityPath}Wrapper = new $!{entity}Wrapper(dictClient);
+		return R.data($!{table.entityPath}Wrapper.entityVO(detail));
+	}
+
+	/**
+	* 分页 $!{table.comment}
+	*/
+	@GetMapping("/list")
+	@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}", position = 2)
+	public R<IPage<$!{entity}VO>> list($!{entity} $!{table.entityPath}, Query query) {
+		IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
+		$!{entity}Wrapper $!{table.entityPath}Wrapper = new $!{entity}Wrapper(dictClient);
+		return R.data($!{table.entityPath}Wrapper.pageVO(pages));
+	}
+
+	/**
+	* 自定义分页 $!{table.comment}
+	*/
+	@GetMapping("/page")
+	@ApiOperation(value = "分页", notes = "传入$!{table.entityPath}", position = 3)
+	public R<IPage<$!{entity}VO>> page($!{entity}VO $!{table.entityPath}, Query query) {
+		IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath});
+		return R.data(pages);
+	}
+
+	/**
+	* 新增 $!{table.comment}
+	*/
+	@PostMapping("/save")
+	@ApiOperation(value = "新增", notes = "传入$!{table.entityPath}", position = 4)
+	public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
+		return R.status($!{table.entityPath}Service.save($!{table.entityPath}));
+	}
+
+	/**
+	* 修改 $!{table.comment}
+	*/
+	@PostMapping("/update")
+	@ApiOperation(value = "修改", notes = "传入$!{table.entityPath}", position = 5)
+	public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
+		return R.status($!{table.entityPath}Service.updateById($!{table.entityPath}));
+	}
+
+	/**
+	* 新增或修改 $!{table.comment}
+	*/
+	@PostMapping("/submit")
+	@ApiOperation(value = "新增或修改", notes = "传入$!{table.entityPath}", position = 6)
+	public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
+		return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath}));
+	}
+
+	#if($!{superEntityClass})
+
+	/**
+	* 删除 $!{table.comment}
+	*/
+	@PostMapping("/remove")
+	@ApiOperation(value = "逻辑删除", notes = "传入ids", position = 7)
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status($!{table.entityPath}Service.deleteLogic(Func.toIntList(ids)));
+	}
+
+	#else
+
+	/**
+	* 删除 $!{table.comment}
+	*/
+	@PostMapping("/remove")
+	@ApiOperation(value = "删除", notes = "传入ids", position = 7)
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status($!{table.entityPath}Service.removeByIds(Func.toIntList(ids)));
+	}
+
+	#end
+
+}

+ 162 - 0
blade-core-develop/src/main/resources/entity.java.vm

@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package $!{package.Entity};
+
+#foreach($pkg in $!{table.importPackages})
+import $!{pkg};
+#end
+#if($!{entityLombokModel})
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#end
+#if($!{swagger2})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+
+/**
+ * $!{table.comment}实体类
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+#if($!{entityLombokModel})
+@Data
+#end
+#if($!{table.convert})
+@TableName("$!{table.name}")
+#end
+#if($!{superEntityClass})
+@EqualsAndHashCode(callSuper = true)
+#end
+#if($!{swagger2})
+@ApiModel(value = "$!{entity}对象", description = #if ("$!{table.comment}"=="")"$!{entity}对象"#else"$!{table.comment}"#end)
+#end
+#if($!{superEntityClass})
+public class $!{entity} extends $!{superEntityClass}#if($!{activeRecord})<$!{entity}>#end {
+#elseif($!{activeRecord})
+@Accessors(chain = true)
+public class $!{entity} extends Model<$!{entity}> {
+#else
+public class $!{entity} implements Serializable {
+#end
+
+    private static final long serialVersionUID = 1L;
+
+## ----------  BEGIN 字段循环遍历  ----------
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+#if($!{field.keyFlag})
+#set($keyPropertyName=$!{field.propertyName})
+#end
+#if("$!field.comment" != "")
+    /**
+     * $!{field.comment}
+     */
+  #if($!{swagger2})
+  @ApiModelProperty(value = "$!{field.comment}")
+  #end
+#end
+#if($!{field.keyFlag})
+## 主键
+#if($!{field.keyIdentityFlag})
+  @TableId(value = "$!{field.name}", type = IdType.AUTO)
+#elseif(!$null.isNull($!{idType}) && "$!idType" != "")
+  @TableId(value = "$!{field.name}", type = IdType.$!{idType})
+#elseif($!{field.convert})
+  @TableId("$!{field.name}")
+#end
+## 普通字段
+#elseif($!{field.fill})
+## -----   存在字段填充设置   -----
+#if($!{field.convert})
+  @TableField(value = "$!{field.name}", fill = FieldFill.$!{field.fill})
+#else
+  @TableField(fill = FieldFill.$!{field.fill})
+#end
+#elseif($!{field.convert})
+  @TableField("$!{field.name}")
+#end
+## 乐观锁注解
+#if($!{versionFieldName}==$!{field.name})
+  @Version
+#end
+## 逻辑删除注解
+#if($!{logicDeleteFieldName}==$!{field.name})
+  @TableLogic
+#end
+  private $!{field.propertyType} $!{field.propertyName};
+#end
+#end
+## ----------  END 字段循环遍历  ----------
+
+#if(!$!{entityLombokModel})
+#foreach($field in $!{table.fields})
+#if($!{field.propertyType.equals("boolean")})
+#set($getprefix="is")
+#else
+#set($getprefix="get")
+#end
+
+    public $!{field.propertyType} $!{getprefix}$!{field.capitalName}() {
+        return $!{field.propertyName};
+    }
+
+#if($!{entityBuilderModel})
+    public $!{entity} set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
+#else
+    public void set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
+#end
+        this.$!{field.propertyName} = $!{field.propertyName};
+#if($!{entityBuilderModel})
+        return this;
+#end
+    }
+#end
+#end
+
+#if($!{entityColumnConstant})
+#foreach($field in $!{table.fields})
+    public static final String $!{field.name.toUpperCase()} = "$!{field.name}";
+
+#end
+#end
+#if($!{activeRecord})
+    @Override
+    protected Serializable pkVal() {
+#if($!{keyPropertyName})
+        return this.$!{keyPropertyName};
+#else
+        return this.id;
+#end
+    }
+
+#end
+#if(!$!{entityLombokModel})
+    @Override
+    public String toString() {
+        return "$!{entity}{" +
+#foreach($field in $!{table.fields})
+#if($!{velocityCount}==1)
+        "$!{field.propertyName}=" + $!{field.propertyName} +
+#else
+        ", $!{field.propertyName}=" + $!{field.propertyName} +
+#end
+#end
+        "}";
+    }
+#end
+}

+ 38 - 0
blade-core-develop/src/main/resources/entityDTO.java.vm

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#set($dtoPackage=$package.Entity.replace("entity","dto"))
+package $!{dtoPackage};
+
+import $!{package.Entity}.$!{entity};
+#if($!{entityLombokModel})
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#end
+
+/**
+ * $!{table.comment}数据传输对象实体类
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+#if($!{entityLombokModel})
+@Data
+@EqualsAndHashCode(callSuper = true)
+#end
+public class $!{entity}DTO extends $!{entity} {
+	private static final long serialVersionUID = 1L;
+
+}

+ 44 - 0
blade-core-develop/src/main/resources/entityVO.java.vm

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#set($voPackage=$package.Entity.replace("entity","vo"))
+package $!{voPackage};
+
+import $!{package.Entity}.$!{entity};
+#if($!{entityLombokModel})
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#end
+#if($!{swagger2})
+import io.swagger.annotations.ApiModel;
+#end
+
+/**
+ * $!{table.comment}视图实体类
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+#if($!{entityLombokModel})
+@Data
+@EqualsAndHashCode(callSuper = true)
+#end
+#if($!{swagger2})
+@ApiModel(value = "$!{entity}VO对象", description = #if ("$!{table.comment}"=="")"$!{entity}VO对象"#else"$!{table.comment}"#end)
+#end
+public class $!{entity}VO extends $!{entity} {
+	private static final long serialVersionUID = 1L;
+
+}

+ 46 - 0
blade-core-develop/src/main/resources/mapper.java.vm

@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package $!{package.Mapper};
+
+import $!{package.Entity}.$!{entity};
+#set($voPackage=$package.Entity.replace("entity","vo"))
+import $!{voPackage}.$!{entity}VO;
+import $!{superMapperClassPackage};
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import java.util.List;
+
+/**
+ * $!{table.comment} Mapper 接口
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+#if($!{kotlin})
+interface $!{table.mapperName} : $!{superMapperClass}<$!{entity}>
+#else
+public interface $!{table.mapperName} extends $!{superMapperClass}<$!{entity}> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param $!{table.entityPath}
+	 * @return
+	 */
+	List<$!{entity}VO> select$!{entity}Page(IPage page, $!{entity}VO $!{table.entityPath});
+
+}
+#end

+ 34 - 0
blade-core-develop/src/main/resources/mapper.xml.vm

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="$!{package.Mapper}.$!{table.mapperName}">
+
+#if($!{enableCache})
+    <!-- 开启二级缓存 -->
+    <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
+
+#end
+#if($!{baseResultMap})
+    <!-- 通用查询映射结果 -->
+    <resultMap id="$!{table.entityPath}ResultMap" type="$!{package.Entity}.$!{entity}">
+#foreach($field in $!{table.fields})
+#if($!{field.keyFlag})##生成主键排在第一位
+        <id column="$!{field.name}" property="$!{field.propertyName}"/>
+#end
+#end
+#foreach($field in $!{table.commonFields})##生成公共字段
+        <result column="$!{field.name}" property="$!{field.propertyName}"/>
+#end
+#foreach($field in $!{table.fields})
+#if(!$!{field.keyFlag} && $!{field.name} != $!{cfg.tenantColumn})##生成普通字段
+        <result column="$!{field.name}" property="$!{field.propertyName}"/>
+#end
+#end
+    </resultMap>
+
+#end
+
+    <select id="select$!{entity}Page" resultMap="$!{table.entityPath}ResultMap">
+        select * from $!{table.name} where is_deleted = 0
+    </select>
+
+</mapper>

+ 50 - 0
blade-core-develop/src/main/resources/saber/api.js.vm

@@ -0,0 +1,50 @@
+import request from '@/router/axios';
+
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/list',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size,
+    }
+  })
+}
+
+export const getDetail = (id) => {
+  return request({
+    url: '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+export const remove = (ids) => {
+  return request({
+    url: '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/remove',
+    method: 'post',
+    params: {
+      ids,
+    }
+  })
+}
+
+export const add = (row) => {
+  return request({
+    url: '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/submit',
+    method: 'post',
+    data: row
+  })
+}
+
+export const update = (row) => {
+  return request({
+    url: '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/submit',
+    method: 'post',
+    data: row
+  })
+}
+

+ 176 - 0
blade-core-develop/src/main/resources/saber/crud.vue.vm

@@ -0,0 +1,176 @@
+<template>
+  <basic-container>
+    <avue-crud :option="option"
+               :data="data"
+               :page="page"
+               @row-del="rowDel"
+               v-model="form"
+               :permission="permissionList"
+               @row-update="rowUpdate"
+               @row-save="rowSave"
+               :before-open="beforeOpen"
+               @search-change="searchChange"
+               @search-reset="searchReset"
+               @selection-change="selectionChange"
+               @on-load="onLoad">
+      <template slot="menuLeft">
+        <el-button type="danger"
+                   size="small"
+                   icon="el-icon-delete"
+                   plain
+                   v-if="permission.$!{table.entityPath}_delete"
+                   @click="handleDelete">删 除
+        </el-button>
+      </template>
+    </avue-crud>
+  </basic-container>
+</template>
+
+<script>
+  import {getList, getDetail, add, update, remove} from "@/api/$!{cfg.servicePackage}/$!{cfg.entityKey}";
+  import {mapGetters} from "vuex";
+
+  export default {
+    data() {
+      return {
+        form: {},
+        page: {
+          pageSize: 10,
+          currentPage: 1,
+          total: 0
+        },
+        selectionList: [],
+        option: {
+          tip: false,
+          border: true,
+          index: true,
+          viewBtn: true,
+          selection: true,
+          column: [
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+            {
+              label: "$!{field.comment}",
+              prop: "$!{field.propertyName}",
+              rules: [{
+                required: true,
+                message: "请输入$!{field.comment}",
+                trigger: "blur"
+              }]
+            },
+#end
+#end
+          ]
+        },
+        data: []
+      };
+    },
+    computed: {
+      ...mapGetters(["permission"]),
+      permissionList() {
+        return {
+          addBtn: this.permission.$!{table.entityPath}_add,
+          viewBtn: this.permission.$!{table.entityPath}_view,
+          delBtn: this.permission.$!{table.entityPath}_delete,
+          editBtn: this.permission.$!{table.entityPath}_edit
+        };
+      },
+      ids() {
+        let ids = [];
+        this.selectionList.forEach(ele => {
+          ids.push(ele.id);
+        });
+        return ids.join(",");
+      }
+    },
+    methods: {
+      rowSave(row, loading) {
+        add(row).then(() => {
+          loading();
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+        });
+      },
+      rowUpdate(row, index, loading) {
+        update(row).then(() => {
+          loading();
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+        });
+      },
+      rowDel(row) {
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(row.id);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+      },
+      searchReset() {
+        this.onLoad(this.page);
+      },
+      searchChange(params) {
+        this.onLoad(this.page, params);
+      },
+      selectionChange(list) {
+        this.selectionList = list;
+      },
+      handleDelete() {
+        if (this.selectionList.length === 0) {
+          this.$message.warning("请选择至少一条数据");
+          return;
+        }
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(this.ids);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            this.$refs.crud.toggleSelection();
+          });
+      },
+
+      beforeOpen(done, type) {
+        if (["edit", "view"].includes(type)) {
+          getDetail(this.form.id).then(res => {
+            this.form = res.data.data;
+          });
+        }
+        done();
+      },
+      onLoad(page, params = {}) {
+        getList(page.currentPage, page.pageSize, params).then(res => {
+          const data = res.data.data;
+          this.page.total = data.total;
+          this.data = data.records;
+        });
+      }
+    }
+  };
+</script>
+
+<style>
+</style>

+ 45 - 0
blade-core-develop/src/main/resources/service.java.vm

@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package $!{package.Service};
+
+import $!{package.Entity}.$!{entity};
+#set($voPackage=$package.Entity.replace("entity","vo"))
+import $!{voPackage}.$!{entity}VO;
+import $!{superServiceClassPackage};
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/**
+ * $!{table.comment} 服务类
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+#if($!{kotlin})
+interface $!{table.serviceName} : $!{superServiceClass}<$!{entity}>
+#else
+public interface $!{table.serviceName} extends $!{superServiceClass}<$!{entity}> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param $!{table.entityPath}
+	 * @return
+	 */
+	IPage<$!{entity}VO> select$!{entity}Page(IPage<$!{entity}VO> page, $!{entity}VO $!{table.entityPath});
+
+}
+#end

+ 47 - 0
blade-core-develop/src/main/resources/serviceImpl.java.vm

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package $!{package.ServiceImpl};
+
+import $!{package.Entity}.$!{entity};
+#set($voPackage=$package.Entity.replace("entity","vo"))
+import $!{voPackage}.$!{entity}VO;
+import $!{package.Mapper}.$!{table.mapperName};
+import $!{package.Service}.$!{table.serviceName};
+import $!{superServiceImplClassPackage};
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+/**
+ * $!{table.comment} 服务实现类
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+@Service
+#if($!{kotlin})
+open class $!{table.serviceImplName} : $!{superServiceImplClass}<$!{table.mapperName}, $!{entity}>(), $!{table.serviceName} {
+
+}
+#else
+public class $!{table.serviceImplName} extends $!{superServiceImplClass}<$!{table.mapperName}, $!{entity}> implements $!{table.serviceName} {
+
+	@Override
+	public IPage<$!{entity}VO> select$!{entity}Page(IPage<$!{entity}VO> page, $!{entity}VO $!{table.entityPath}) {
+		return page.setRecords(baseMapper.select$!{entity}Page(page, $!{table.entityPath}));
+	}
+
+}
+#end

+ 11 - 0
blade-core-develop/src/main/resources/sql/menu.sql.vm

@@ -0,0 +1,11 @@
+INSERT INTO `blade_menu`(`parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `remark`, `is_deleted`)
+VALUES (0, '$!{cfg.entityKey}', '$!{cfg.codeName}', 'menu', '/$!{cfg.servicePackage}/$!{cfg.entityKey}', NULL, 1, 1, 0, 1, NULL, 0);
+set @parentid = (SELECT LAST_INSERT_ID());
+INSERT INTO `blade_menu`(`parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `remark`, `is_deleted`)
+VALUES (@parentid, '$!{cfg.entityKey}_add', '新增', 'add', '/$!{cfg.servicePackage}/$!{cfg.entityKey}/add', 'plus', 1, 2, 1, 1, NULL, 0);
+INSERT INTO `blade_menu`(`parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `remark`, `is_deleted`)
+VALUES (@parentid, '$!{cfg.entityKey}_edit', '修改', 'edit', '/$!{cfg.servicePackage}/$!{cfg.entityKey}/edit', 'form', 2, 2, 1, 2, NULL, 0);
+INSERT INTO `blade_menu`(`parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `remark`, `is_deleted`)
+VALUES (@parentid, '$!{cfg.entityKey}_delete', '删除', 'delete', '/api/$!{cfg.serviceName}/$!{cfg.entityKey}/remove', 'delete', 3, 2, 1, 3, NULL, 0);
+INSERT INTO `blade_menu`(`parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `remark`, `is_deleted`)
+VALUES (@parentid, '$!{cfg.entityKey}_view', '查看', 'view', '/$!{cfg.servicePackage}/$!{cfg.entityKey}/view', 'file-text', 4, 2, 1, 2, NULL, 0);

+ 37 - 0
blade-core-develop/src/main/resources/sword/action.js.vm

@@ -0,0 +1,37 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+export const $!{upperEntityPath}_NAMESPACE = '$!{table.entityPath}';
+
+export function $!{upperEntityPath}_LIST(payload) {
+  return {
+    type: `${$!{upperEntityPath}_NAMESPACE}/fetchList`,
+    payload,
+  };
+}
+
+export function $!{upperEntityPath}_DETAIL(id) {
+  return {
+    type: `${$!{upperEntityPath}_NAMESPACE}/fetchDetail`,
+    payload: { id },
+  };
+}
+
+export function $!{upperEntityPath}_CLEAR_DETAIL() {
+  return {
+    type: `${$!{upperEntityPath}_NAMESPACE}/clearDetail`,
+    payload: {},
+  };
+}
+
+export function $!{upperEntityPath}_SUBMIT(payload) {
+  return {
+    type: `${$!{upperEntityPath}_NAMESPACE}/submit`,
+    payload,
+  };
+}
+
+export function $!{upperEntityPath}_REMOVE(payload) {
+  return {
+    type: `${$!{upperEntityPath}_NAMESPACE}/remove`,
+    payload,
+  };
+}

+ 75 - 0
blade-core-develop/src/main/resources/sword/add.js.vm

@@ -0,0 +1,75 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+import React, { PureComponent } from 'react';
+import { Form, Input, Card, Button } from 'antd';
+import { connect } from 'dva';
+import Panel from '../../../components/Panel';
+import styles from '../../../layouts/Sword.less';
+import { $!{upperEntityPath}_SUBMIT } from '../../../actions/$!{table.entityPath}';
+
+const FormItem = Form.Item;
+
+@connect(({ loading }) => ({
+  submitting: loading.effects['$!{table.entityPath}/submit'],
+}))
+@Form.create()
+class $!{entity}Add extends PureComponent {
+  handleSubmit = e => {
+    e.preventDefault();
+    const { dispatch, form } = this.props;
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        dispatch($!{upperEntityPath}_SUBMIT(values));
+      }
+    });
+  };
+
+  render() {
+    const {
+      form: { getFieldDecorator },
+      submitting,
+    } = this.props;
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 12 },
+        md: { span: 10 },
+      },
+    };
+
+    const action = (
+      <Button type="primary" onClick={this.handleSubmit} loading={submitting}>
+        提交
+      </Button>
+    );
+
+    return (
+      <Panel title="新增" back="/$!{cfg.servicePackage}/$!{table.entityPath}" action={action}>
+        <Form hideRequiredMark style={{ marginTop: 8 }}>
+          <Card className={styles.card} bordered={false}>
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+            <FormItem {...formItemLayout} label="$!{field.comment}">
+              {getFieldDecorator('$!{field.propertyName}', {
+                rules: [
+                  {
+                    required: true,
+                    message: '请输入$!{field.comment}',
+                  },
+                ],
+              })(<Input placeholder="请输入$!{field.comment}" />)}
+            </FormItem>
+#end
+#end
+          </Card>
+        </Form>
+      </Panel>
+    );
+  }
+}
+
+export default $!{entity}Add;

+ 99 - 0
blade-core-develop/src/main/resources/sword/edit.js.vm

@@ -0,0 +1,99 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+import React, { PureComponent } from 'react';
+import { Form, Input, Card, Button } from 'antd';
+import { connect } from 'dva';
+import Panel from '../../../components/Panel';
+import styles from '../../../layouts/Sword.less';
+import { $!{upperEntityPath}_DETAIL, $!{upperEntityPath}_SUBMIT } from '../../../actions/$!{table.entityPath}';
+
+const FormItem = Form.Item;
+
+@connect(({ $!{table.entityPath}, loading }) => ({
+  $!{table.entityPath},
+  submitting: loading.effects['$!{table.entityPath}/submit'],
+}))
+@Form.create()
+class $!{entity}Edit extends PureComponent {
+  componentWillMount() {
+    const {
+      dispatch,
+      match: {
+        params: { id },
+      },
+    } = this.props;
+    dispatch($!{upperEntityPath}_DETAIL(id));
+  }
+
+  handleSubmit = e => {
+    e.preventDefault();
+    const {
+      dispatch,
+      match: {
+        params: { id },
+      },
+      form,
+    } = this.props;
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        const params = {
+          id,
+          ...values,
+        };
+        console.log(params);
+        dispatch($!{upperEntityPath}_SUBMIT(params));
+      }
+    });
+  };
+
+  render() {
+    const {
+      form: { getFieldDecorator },
+      $!{table.entityPath}: { detail },
+      submitting,
+    } = this.props;
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 12 },
+        md: { span: 10 },
+      },
+    };
+
+    const action = (
+      <Button type="primary" onClick={this.handleSubmit} loading={submitting}>
+        提交
+      </Button>
+    );
+
+    return (
+      <Panel title="修改" back="/$!{cfg.servicePackage}/$!{table.entityPath}" action={action}>
+        <Form hideRequiredMark style={{ marginTop: 8 }}>
+          <Card className={styles.card} bordered={false}>
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+            <FormItem {...formItemLayout} label="$!{field.comment}">
+              {getFieldDecorator('$!{field.propertyName}', {
+                rules: [
+                  {
+                    required: true,
+                    message: '请输入$!{field.comment}',
+                  },
+                ],
+                initialValue: detail.$!{field.propertyName},
+              })(<Input placeholder="请输入$!{field.comment}" />)}
+            </FormItem>
+#end
+#end
+          </Card>
+        </Form>
+      </Panel>
+    );
+  }
+}
+
+export default $!{entity}Edit;

+ 84 - 0
blade-core-develop/src/main/resources/sword/list.js.vm

@@ -0,0 +1,84 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+import React, { PureComponent } from 'react';
+import { connect } from 'dva';
+import { Button, Col, Form, Input, Row } from 'antd';
+import Panel from '../../../components/Panel';
+import { $!{upperEntityPath}_LIST } from '../../../actions/$!{table.entityPath}';
+import Grid from '../../../components/Sword/Grid';
+
+const FormItem = Form.Item;
+
+@connect(({ $!{table.entityPath}, loading }) => ({
+  $!{table.entityPath},
+  loading: loading.models.$!{table.entityPath},
+}))
+@Form.create()
+class $!{entity} extends PureComponent {
+  // ============ 查询 ===============
+  handleSearch = params => {
+    const { dispatch } = this.props;
+    dispatch($!{upperEntityPath}_LIST(params));
+  };
+
+  // ============ 查询表单 ===============
+  renderSearchForm = onReset => {
+    const { form } = this.props;
+    const { getFieldDecorator } = form;
+
+    return (
+      <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
+        <Col md={6} sm={24}>
+          <FormItem label="查询名称">
+            {getFieldDecorator('name')(<Input placeholder="查询名称" />)}
+          </FormItem>
+        </Col>
+        <Col>
+          <div style={{ float: 'right' }}>
+            <Button type="primary" htmlType="submit">
+              查询
+            </Button>
+            <Button style={{ marginLeft: 8 }} onClick={onReset}>
+              重置
+            </Button>
+          </div>
+        </Col>
+      </Row>
+    );
+  };
+
+  render() {
+    const code = '$!{table.entityPath}';
+
+    const {
+      form,
+      loading,
+      $!{table.entityPath}: { data },
+    } = this.props;
+
+    const columns = [
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+      {
+        title: '$!{field.comment}',
+        dataIndex: '$!{field.propertyName}',
+      },
+#end
+#end
+    ];
+
+    return (
+      <Panel>
+        <Grid
+          code={code}
+          form={form}
+          onSearch={this.handleSearch}
+          renderSearchForm={this.renderSearchForm}
+          loading={loading}
+          data={data}
+          columns={columns}
+        />
+      </Panel>
+    );
+  }
+}
+export default $!{entity};

+ 88 - 0
blade-core-develop/src/main/resources/sword/model.js.vm

@@ -0,0 +1,88 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+import { message } from 'antd';
+import router from 'umi/router';
+import { $!{upperEntityPath}_NAMESPACE } from '../actions/$!{table.entityPath}';
+import { list, submit, detail, remove } from '../services/$!{table.entityPath}';
+
+export default {
+  namespace: $!{upperEntityPath}_NAMESPACE,
+  state: {
+    data: {
+      list: [],
+      pagination: false,
+    },
+    detail: {},
+  },
+  effects: {
+    *fetchList({ payload }, { call, put }) {
+      const response = yield call(list, payload);
+      if (response.success) {
+        yield put({
+          type: 'saveList',
+          payload: {
+            list: response.data.records,
+            pagination: {
+              total: response.data.total,
+              current: response.data.current,
+              pageSize: response.data.size,
+            },
+          },
+        });
+      }
+    },
+    *fetchDetail({ payload }, { call, put }) {
+      const response = yield call(detail, payload);
+      if (response.success) {
+        yield put({
+          type: 'saveDetail',
+          payload: {
+            detail: response.data,
+          },
+        });
+      }
+    },
+    *clearDetail({ payload }, { put }) {
+      yield put({
+        type: 'removeDetail',
+        payload: { payload },
+      });
+    },
+    *submit({ payload }, { call }) {
+      const response = yield call(submit, payload);
+      if (response.success) {
+        message.success('提交成功');
+        router.push('/$!{cfg.servicePackage}/$!{table.entityPath}');
+      }
+    },
+    *remove({ payload }, { call }) {
+      const {
+        data: { keys },
+        success,
+      } = payload;
+      const response = yield call(remove, { ids: keys });
+      if (response.success) {
+        success();
+      }
+    },
+  },
+  reducers: {
+    saveList(state, action) {
+      return {
+        ...state,
+        data: action.payload,
+      };
+    },
+    saveDetail(state, action) {
+      return {
+        ...state,
+        detail: action.payload.detail,
+      };
+    },
+    removeDetail(state) {
+      return {
+        ...state,
+        detail: {},
+      };
+    },
+  },
+};

+ 26 - 0
blade-core-develop/src/main/resources/sword/service.js.vm

@@ -0,0 +1,26 @@
+#set($params="$" + "{stringify" + "(params)" + "}")
+import { stringify } from 'qs';
+import func from '../utils/Func';
+import request from '../utils/request';
+
+export async function list(params) {
+  return request(`/api/$!{cfg.serviceName}/$!{cfg.entityKey}/list?$!{params}`);
+}
+
+export async function submit(params) {
+  return request('/api/$!{cfg.serviceName}/$!{cfg.entityKey}/submit', {
+    method: 'POST',
+    body: params,
+  });
+}
+
+export async function detail(params) {
+  return request(`/api/$!{cfg.serviceName}/$!{cfg.entityKey}/detail?$!{params}`);
+}
+
+export async function remove(params) {
+  return request('/api/$!{cfg.serviceName}/$!{cfg.entityKey}/remove', {
+    method: 'POST',
+    body: func.toFormData(params),
+  });
+}

+ 76 - 0
blade-core-develop/src/main/resources/sword/view.js.vm

@@ -0,0 +1,76 @@
+#set($upperEntityPath=$table.entityPath.toUpperCase())
+import React, { PureComponent } from 'react';
+import router from 'umi/router';
+import { Form, Card, Button } from 'antd';
+import { connect } from 'dva';
+import Panel from '../../../components/Panel';
+import styles from '../../../layouts/Sword.less';
+import { $!{upperEntityPath}_DETAIL } from '../../../actions/$!{table.entityPath}';
+
+const FormItem = Form.Item;
+
+@connect(({ $!{table.entityPath} }) => ({
+  $!{table.entityPath},
+}))
+@Form.create()
+class $!{entity}View extends PureComponent {
+  componentWillMount() {
+    const {
+      dispatch,
+      match: {
+        params: { id },
+      },
+    } = this.props;
+    dispatch($!{upperEntityPath}_DETAIL(id));
+  }
+
+  handleEdit = () => {
+    const {
+      match: {
+        params: { id },
+      },
+    } = this.props;
+    router.push(`/$!{cfg.servicePackage}/$!{table.entityPath}/edit/$!{id}`);
+  };
+
+  render() {
+    const {
+      $!{table.entityPath}: { detail },
+    } = this.props;
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 12 },
+        md: { span: 10 },
+      },
+    };
+
+    const action = (
+      <Button type="primary" onClick={this.handleEdit}>
+        修改
+      </Button>
+    );
+
+    return (
+      <Panel title="查看" back="/$!{cfg.servicePackage}/$!{table.entityPath}" action={action}>
+        <Form hideRequiredMark style={{ marginTop: 8 }}>
+          <Card className={styles.card} bordered={false}>
+#foreach($field in $!{table.fields})
+#if($!{field.name}!=$!{cfg.tenantColumn})
+            <FormItem {...formItemLayout} label="$!{field.comment}">
+              <span>{detail.$!{field.propertyName}}</span>
+            </FormItem>
+#end
+#end
+          </Card>
+        </Form>
+      </Panel>
+    );
+  }
+}
+export default $!{entity}View;

+ 51 - 0
blade-core-develop/src/main/resources/wrapper.java.vm

@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
+package $!{wrapperPackage};
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.mp.support.BaseEntityWrapper;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.system.feign.IDictClient;
+import $!{package.Entity}.$!{entity};
+#set($voPackage=$package.Entity.replace("entity","vo"))
+import $!{voPackage}.$!{entity}VO;
+
+/**
+ * $!{table.comment}包装类,返回视图层所需的字段
+ *
+ * @author $!{author}
+ * @since $!{date}
+ */
+@AllArgsConstructor
+public class $!{entity}Wrapper extends BaseEntityWrapper<$!{entity}, $!{entity}VO>  {
+
+	private IDictClient dictClient;
+
+	@Override
+	public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) {
+		$!{entity}VO $!{table.entityPath}VO = BeanUtil.copy($!{table.entityPath}, $!{entity}VO.class);
+
+		/*R<String> dict = dictClient.getValue("$!{table.entityPath}" , $!{table.entityPath}VO.getCategory());
+		if (dict.isSuccess()) {
+			String categoryName = dict.getData();
+			$!{table.entityPath}VO.setCategoryName(categoryName);
+		}*/
+
+		return $!{table.entityPath}VO;
+	}
+
+}

+ 1 - 1
blade-core-launch/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 2 - 2
blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java

@@ -22,7 +22,7 @@ package org.springblade.core.launch.constant;
  */
 public interface TokenConstant {
 
-	String SIGN_KEY = "BladeX";
+	String SIGN_KEY = "Blade";
 	String AVATAR = "avatar";
 	String HEADER = "blade-auth";
 	String BEARER = "bearer";
@@ -38,7 +38,7 @@ public interface TokenConstant {
 	String TENANT_CODE = "tenant_code";
 	String CLIENT_ID = "client_id";
 	String LICENSE = "license";
-	String LICENSE_NAME = "powered by bladex";
+	String LICENSE_NAME = "powered by blade";
 	String DEFAULT_AVATAR = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
 	Integer AUTH_LENGTH = 7;
 

+ 1 - 1
blade-core-log/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-mybatis/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-secure/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-swagger/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>blade-tool</artifactId>
         <groupId>org.springblade</groupId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 1 - 1
blade-core-tool/pom.xml

@@ -6,7 +6,7 @@
     <parent>
         <groupId>org.springblade</groupId>
         <artifactId>blade-tool</artifactId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>

+ 7 - 6
pom.xml

@@ -5,7 +5,7 @@
 
     <groupId>org.springblade</groupId>
     <artifactId>blade-tool</artifactId>
-    <version>2.2.0</version>
+    <version>2.2.1</version>
     <packaging>pom</packaging>
     <name>blade-tool</name>
     <description>
@@ -36,13 +36,13 @@
     </scm>
 
     <properties>
-        <blade.tool.version>2.2.0</blade.tool.version>
+        <blade.tool.version>2.2.1</blade.tool.version>
 
         <java.version>1.8</java.version>
         <maven.plugin.version>3.8.0</maven.plugin.version>
         <swagger.version>2.9.2</swagger.version>
         <swagger.models.version>1.5.21</swagger.models.version>
-        <swagger.bootstrapui.version>1.9.0</swagger.bootstrapui.version>
+        <swagger.bootstrapui.version>1.9.2</swagger.bootstrapui.version>
         <mybatis.plus.version>3.1.0</mybatis.plus.version>
         <curator.framework.version>4.0.1</curator.framework.version>
         <protostuff.version>1.6.0</protostuff.version>
@@ -61,13 +61,14 @@
 
     <modules>
         <module>blade-core-boot</module>
+        <module>blade-core-cloud</module>
+        <module>blade-core-develop</module>
         <module>blade-core-launch</module>
-        <module>blade-core-secure</module>
-        <module>blade-core-tool</module>
         <module>blade-core-log</module>
         <module>blade-core-mybatis</module>
+        <module>blade-core-secure</module>
         <module>blade-core-swagger</module>
-        <module>blade-core-cloud</module>
+        <module>blade-core-tool</module>
     </modules>
 
     <dependencyManagement>