diff --git a/blade-core-boot/pom.xml b/blade-core-boot/pom.xml
index b05be16..7dcec94 100644
--- a/blade-core-boot/pom.xml
+++ b/blade-core-boot/pom.xml
@@ -5,7 +5,7 @@
+ * 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 + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * 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(); + } + +} diff --git a/blade-core-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java b/blade-core-develop/src/main/java/org/springblade/develop/constant/DevelopConstant.java new file mode 100644 index 0000000..53be4ac --- /dev/null +++ b/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). + *
+ * 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 + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * 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"; +} diff --git a/blade-core-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java b/blade-core-develop/src/main/java/org/springblade/develop/support/BladeCodeGenerator.java new file mode 100644 index 0000000..e24298e --- /dev/null +++ b/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). + *
+ * 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 + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * 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
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+}
diff --git a/blade-core-develop/src/main/resources/entityDTO.java.vm b/blade-core-develop/src/main/resources/entityDTO.java.vm
new file mode 100644
index 0000000..a7f0512
--- /dev/null
+++ b/blade-core-develop/src/main/resources/entityDTO.java.vm
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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;
+
+}
diff --git a/blade-core-develop/src/main/resources/entityVO.java.vm b/blade-core-develop/src/main/resources/entityVO.java.vm
new file mode 100644
index 0000000..cc88136
--- /dev/null
+++ b/blade-core-develop/src/main/resources/entityVO.java.vm
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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;
+
+}
diff --git a/blade-core-develop/src/main/resources/mapper.java.vm b/blade-core-develop/src/main/resources/mapper.java.vm
new file mode 100644
index 0000000..81f3422
--- /dev/null
+++ b/blade-core-develop/src/main/resources/mapper.java.vm
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
diff --git a/blade-core-develop/src/main/resources/mapper.xml.vm b/blade-core-develop/src/main/resources/mapper.xml.vm
new file mode 100644
index 0000000..9384ff7
--- /dev/null
+++ b/blade-core-develop/src/main/resources/mapper.xml.vm
@@ -0,0 +1,34 @@
+
+
+
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
diff --git a/blade-core-develop/src/main/resources/serviceImpl.java.vm b/blade-core-develop/src/main/resources/serviceImpl.java.vm
new file mode 100644
index 0000000..d025d13
--- /dev/null
+++ b/blade-core-develop/src/main/resources/serviceImpl.java.vm
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
diff --git a/blade-core-develop/src/main/resources/sql/menu.sql.vm b/blade-core-develop/src/main/resources/sql/menu.sql.vm
new file mode 100644
index 0000000..01866c8
--- /dev/null
+++ b/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);
diff --git a/blade-core-develop/src/main/resources/sword/action.js.vm b/blade-core-develop/src/main/resources/sword/action.js.vm
new file mode 100644
index 0000000..e0eb476
--- /dev/null
+++ b/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,
+ };
+}
diff --git a/blade-core-develop/src/main/resources/sword/add.js.vm b/blade-core-develop/src/main/resources/sword/add.js.vm
new file mode 100644
index 0000000..459b1bb
--- /dev/null
+++ b/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 = (
+
+ );
+
+ return (
+
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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