diff --git a/Dockerfile b/Dockerfile index 89e5bee82a129abc99f63ad18c8a682bc3135606..dc93d603ca5e8d2481fd45eab7623b05d7b6f89c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,4 +11,8 @@ ADD dist/gen /gen/ # set jvm ENV JAVA_OPTS="-server -Xmx64m -Xms64m" -ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Dsolon.config.add=/gen/conf/app.yml -Duser.timezone=Asia/Shanghai -Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -jar /gen/gen.jar" ] +ENV LOCAL_DB_PATH="/opt/gen/gen.db" +ENV CONFIG_FILE="/gen/conf/app.yml" +ENV GEN_EXT_PATH="/gen/ext" + +ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -DLOCAL_DB=$LOCAL_DB_PATH -Djava.ext.dirs=$JAVA_HOME/lib/ext:$GEN_EXT_PATH -Dsolon.config.add=$CONFIG_FILE -Duser.timezone=Asia/Shanghai -Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -jar /gen/gen.jar" ] diff --git a/changelog.md b/changelog.md index dc4e39356f608ed55809206444f3b48fff101a05..45d4b2703788b71aed263fa788068b80f2875e9c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,58 @@ # changelog +## 2.0.5 + +- 新增`${table.columnCount}`变量,返回表字段数量 + +## 2.0.4 + +- 使用jdkhttp + +## 2.0.3 + +- 连接方式管理放在配置文件中 +- solon更新到2.8.5 + + +```yaml +# 连接方式管理, {HOST},{PORT},{DB_NAME} 表示占位符 +connect: + "1": + name: MySQL + driver: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://{HOST}:{PORT}/{DB_NAME}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai + serviceName: com.gitee.gen.gen.mysql.MySqlService + "2": + name: Oracle + driver: oracle.jdbc.driver.OracleDriver + url: jdbc:oracle:thin:@{HOST}:{PORT}{DB_NAME} + serviceName: com.gitee.gen.gen.oracle.OracleService + "3": + name: "SQL Server" + driver: com.microsoft.sqlserver.jdbc.SQLServerDriver + url: jdbc:sqlserver://{HOST}:{PORT};DatabaseName={DB_NAME};trustServerCertificate=true + serviceName: com.gitee.gen.gen.sqlserver.SqlServerService + "4": + name: PostgreSQL + driver: org.postgresql.Driver + url: jdbc:postgresql://{HOST}:{PORT}/{DB_NAME} + serviceName: com.gitee.gen.gen.postgresql.PostgreSqlService + "5": + name: "达梦" + driver: dm.jdbc.driver.DmDriver + url: jdbc:dm://{HOST}:{PORT}/{DB_NAME} + serviceName: com.gitee.gen.gen.dm.DmService +``` + +## 2.0.2 + +- 支持其它数据库代码生成,具体参考项目首页说明 + +## 2.0.1 + +- 新增`${context.dbNameCamel}` 数据库名驼峰,如:shopOrder +- 新增`${context.dbNameClean}` 数据库名驼峰,如:shoporder + ## 2.0.0 - 【新增】底层框架改为solon,启动更快,内存更小(64M) diff --git a/front/public/help/velocity.md b/front/public/help/velocity.md index a6c0b9f82740cc0b74d700366af20659e4767712..e7ecfb424c35d0c400531bad7cb1e3b82d723f55 100644 --- a/front/public/help/velocity.md +++ b/front/public/help/velocity.md @@ -38,11 +38,12 @@ My name is ${name} ```html #foreach($item in $list) $item - $velocityCount + ${foreach.index} #end ``` -其中,`$item`代表遍历的每一项,`$velocityCount`表示当前循环次数的计数器,从1开始 +其中,`$item`代表遍历的每一项,`${foreach.index}`表示当前循环次数的计数器,从0开始 + for循环跳出`#break` diff --git a/front/public/velocity/java.json b/front/public/velocity/java.json index f04a82eab2e1cc7ab30224897ff4800dca2cdc63..5e60bdfba74a86d7bc436deebcb231b6ef20c14b 100644 --- a/front/public/velocity/java.json +++ b/front/public/velocity/java.json @@ -80,7 +80,15 @@ }, { "expression": "${context.dbName}", - "text": "数据库名" + "text": "数据库名,如:shop_order" + }, + { + "expression": "${context.dbNameCamel}", + "text": "数据库名驼峰,如:shopOrder" + }, + { + "expression": "${context.dbNameClean}", + "text": "数据库名,无符号并小写,如:shoporder" }, { "expression": "${context.packageName}", @@ -159,6 +167,10 @@ { "expression": "${table.schema}", "text": "PostgreSQL中的Schema" + }, + { + "expression": "${table.columnCount}", + "text": "字段数量" } ] }, diff --git a/gen/pom.xml b/gen/pom.xml index 0bd3cb408f680c5d9d9be9b207dd62be44ed4a2e..5f411bef770c9d61e43f951df8ce9816289465ca 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -7,13 +7,13 @@ org.noear solon-parent - 2.6.5 + 2.8.6 com.gitee.codegen gen - 2.0 + 2.0.4 一款代码生成器 https://gitee.com/durcframework/code-gen @@ -27,6 +27,17 @@ org.noear solon-api + + + org.noear + solon.boot.smarthttp + + + + + + org.noear + solon.boot.jdkhttp diff --git a/gen/src/main/assembly/assembly-zip.xml b/gen/src/main/assembly/assembly-zip.xml index 062fb350ecef304c6ca8142f88f99fb818e49889..b9b3471cb2405696b5cce1b8e14cff92ef9f5db5 100644 --- a/gen/src/main/assembly/assembly-zip.xml +++ b/gen/src/main/assembly/assembly-zip.xml @@ -31,6 +31,18 @@ 0644 + + + src/main/assembly + + ext.md + + ext + 0644 + + + + src/main/resources diff --git a/gen/src/main/assembly/ext.md b/gen/src/main/assembly/ext.md new file mode 100644 index 0000000000000000000000000000000000000000..8c5fa27f5b320728f8eac7e29d8738130dca5064 --- /dev/null +++ b/gen/src/main/assembly/ext.md @@ -0,0 +1 @@ +将数据库驱动放入该文件夹下 diff --git a/gen/src/main/java/com/gitee/gen/config/Config.java b/gen/src/main/java/com/gitee/gen/config/Config.java index 4a63a42615301065541ff51a3e4d595e7f0ead60..ff8595e1fc25afd3cb1abeba406f033a7aad4d29 100644 --- a/gen/src/main/java/com/gitee/gen/config/Config.java +++ b/gen/src/main/java/com/gitee/gen/config/Config.java @@ -7,6 +7,7 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.lang.StringUtils; import org.noear.solon.Solon; import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Condition; import org.noear.solon.annotation.Configuration; import org.noear.solon.annotation.Init; import org.noear.solon.annotation.Inject; @@ -28,11 +29,20 @@ public class Config { //此下的 db1 与 mybatis.db1 将对应在起来 //可以用 @Db("db1") 注入mapper //typed=true,表示默认数据源。@Db 可不带名字注入 @Bean(name = "db1", typed = true) + @Condition(onProperty="${dbms.enable} = false") public DataSource db1(@Inject("${gen.db1}") BasicDataSource ds) { if (ds.getDriverClassName().contains("sqlite")) { String url = ds.getUrl(); ds.setUrl(url + UpgradeService.getLocalDbPath()); } + log.info("使用本地数据库,url:{}", ds.getUrl()); + return ds; + } + + @Bean(name = "db1", typed = true) + @Condition(onProperty="${dbms.enable} = true") + public DataSource db2(@Inject("${gen.db2}") BasicDataSource ds) { + log.info("使用DBMS存储数据,url={}", ds.getUrl()); return ds; } @@ -49,6 +59,9 @@ public class Config { initStaticFile(); } + /** + * 初始化静态资源文件 + */ private static void initStaticFile() { String frontLocation = Solon.context().cfg().get("gen.front-location", ""); String frontRoot; diff --git a/gen/src/main/java/com/gitee/gen/config/ConnectConfig.java b/gen/src/main/java/com/gitee/gen/config/ConnectConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..69a817e926b495f07d9f921ea0aec4aa3bc847f7 --- /dev/null +++ b/gen/src/main/java/com/gitee/gen/config/ConnectConfig.java @@ -0,0 +1,53 @@ +package com.gitee.gen.config; + +/** + * @author 六如 + */ +public class ConnectConfig { + + private String name; + private String driver; + private String url; + private String serviceName; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDriver() { + return driver; + } + + public void setDriver(String driver) { + this.driver = driver; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public String toString() { + return "ConnectConfig{" + + "name='" + name + '\'' + + ", driver='" + driver + '\'' + + ", url='" + url + '\'' + + '}'; + } +} diff --git a/gen/src/main/java/com/gitee/gen/config/DbTypeConfig.java b/gen/src/main/java/com/gitee/gen/config/DbTypeConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..6fa0ceb5cc21b35c436154ae329c11a35247b2ae --- /dev/null +++ b/gen/src/main/java/com/gitee/gen/config/DbTypeConfig.java @@ -0,0 +1,33 @@ +package com.gitee.gen.config; + +import org.noear.solon.Solon; +import org.noear.solon.annotation.Configuration; +import org.noear.solon.annotation.Inject; + +import java.util.Map; + +/** + * @author 六如 + */ +@Configuration +public class DbTypeConfig { + + @Inject("${connect}") + private Map connectConfigMap; + + public static DbTypeConfig getInstance() { + return Solon.context().getBean(DbTypeConfig.class); + } + + public ConnectConfig getConnectConfig(Integer type) { + return connectConfigMap.get(type); + } + + public Map getConnectConfigMap() { + return connectConfigMap; + } + + public void setConnectConfigMap(Map connectConfigMap) { + this.connectConfigMap = connectConfigMap; + } +} diff --git a/gen/src/main/java/com/gitee/gen/controller/DatasourceConfigController.java b/gen/src/main/java/com/gitee/gen/controller/DatasourceConfigController.java index ef24f8408cedb7ee50f0404bae4d3f92fb778ace..0dbf03b38b69a4cdf968bc7b2e1a1d53d554970f 100644 --- a/gen/src/main/java/com/gitee/gen/controller/DatasourceConfigController.java +++ b/gen/src/main/java/com/gitee/gen/controller/DatasourceConfigController.java @@ -2,9 +2,9 @@ package com.gitee.gen.controller; import com.gitee.gen.common.Action; import com.gitee.gen.common.Result; +import com.gitee.gen.config.DbTypeConfig; import com.gitee.gen.entity.DatasourceConfig; import com.gitee.gen.gen.DBConnect; -import com.gitee.gen.gen.DbType; import com.gitee.gen.gen.GeneratorConfig; import com.gitee.gen.gen.SQLService; import com.gitee.gen.gen.SQLServiceFactory; @@ -17,7 +17,6 @@ import org.noear.solon.annotation.Path; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * @author tanghc @@ -74,8 +73,11 @@ public class DatasourceConfigController { @Mapping("/dbtype") public Result dbType(DatasourceConfig datasourceConfig) { - List dbTypeShowList = Stream.of(DbType.values()) - .map(dbType -> new DbTypeShow(dbType.getDisplayName(), dbType.getType())) + List dbTypeShowList = DbTypeConfig.getInstance() + .getConnectConfigMap() + .entrySet() + .stream() + .map(entry -> new DbTypeShow(entry.getValue().getName(), entry.getKey())) .collect(Collectors.toList()); return Action.ok(dbTypeShowList); } diff --git a/gen/src/main/java/com/gitee/gen/entity/DatasourceConfig.java b/gen/src/main/java/com/gitee/gen/entity/DatasourceConfig.java index ae381da4e5b29b136bdd74b4eedd1bffda88fe5d..42e87c58c5e715c690f2daf741e3fe4dae1ffd6f 100644 --- a/gen/src/main/java/com/gitee/gen/entity/DatasourceConfig.java +++ b/gen/src/main/java/com/gitee/gen/entity/DatasourceConfig.java @@ -10,7 +10,6 @@ public class DatasourceConfig { private Integer id; /** * 数据库类型 - * @see com.gitee.gen.gen.DbType */ private Integer dbType; /** 数据库驱动 */ @@ -217,4 +216,4 @@ public class DatasourceConfig { ", dbGroupName='" + dbGroupName + '\'' + '}'; } -} \ No newline at end of file +} diff --git a/gen/src/main/java/com/gitee/gen/gen/DBConnect.java b/gen/src/main/java/com/gitee/gen/gen/DBConnect.java index 0db7b3318c893976818f198f1a289f2d3524ca4a..01bd169e24a8793560295437257b892111424470 100644 --- a/gen/src/main/java/com/gitee/gen/gen/DBConnect.java +++ b/gen/src/main/java/com/gitee/gen/gen/DBConnect.java @@ -40,6 +40,7 @@ public class DBConnect { con.close(); // 关闭连接,该连接无实际用处 } catch (SQLException e) { e.printStackTrace(); + ret = e.getMessage(); } } } diff --git a/gen/src/main/java/com/gitee/gen/gen/DbType.java b/gen/src/main/java/com/gitee/gen/gen/DbType.java index 2310a699e79f69768c14d410fea01cf84d3276ff..4cf118b8d110d5ed11a3518b8ecf29f267547ea8 100644 --- a/gen/src/main/java/com/gitee/gen/gen/DbType.java +++ b/gen/src/main/java/com/gitee/gen/gen/DbType.java @@ -1,8 +1,11 @@ package com.gitee.gen.gen; /** + * 改成配在app.yml中 + * * @author tanghc */ +@Deprecated public enum DbType { MYSQL(1, @@ -18,7 +21,7 @@ public enum DbType { SQL_SERVER(3, "SQL Server", "com.microsoft.sqlserver.jdbc.SQLServerDriver", - "jdbc:sqlserver://%s:%s;DatabaseName=%s"), + "jdbc:sqlserver://%s:%s;DatabaseName=%s;trustServerCertificate=true"), POSTGRE_SQL(4, "PostgreSQL", diff --git a/gen/src/main/java/com/gitee/gen/gen/GeneratorConfig.java b/gen/src/main/java/com/gitee/gen/gen/GeneratorConfig.java index fcea397f7b3d0b5d2a24e76971ddd569d109a79f..0b1c103733b5676b1b00cef334d1e76d79920e94 100644 --- a/gen/src/main/java/com/gitee/gen/gen/GeneratorConfig.java +++ b/gen/src/main/java/com/gitee/gen/gen/GeneratorConfig.java @@ -1,6 +1,9 @@ package com.gitee.gen.gen; +import com.gitee.gen.config.ConnectConfig; +import com.gitee.gen.config.DbTypeConfig; import com.gitee.gen.entity.DatasourceConfig; +import org.noear.snack.core.utils.StringUtil; public class GeneratorConfig { @@ -10,6 +13,10 @@ public class GeneratorConfig { private String dbName; /** schema(PGSQL专用) */ private String schemaName; + /** + * 驱动class + */ + private String driverClass; /** 数据库host */ private String host; /** 数据库端口 */ @@ -19,6 +26,7 @@ public class GeneratorConfig { /** 数据库密码 */ private String password; + public static GeneratorConfig build(DatasourceConfig datasourceConfig) { GeneratorConfig generatorConfig = new GeneratorConfig(); generatorConfig.setDbName(datasourceConfig.getDbName()); @@ -28,24 +36,26 @@ public class GeneratorConfig { generatorConfig.setUsername(datasourceConfig.getUsername()); generatorConfig.setPassword(datasourceConfig.getPassword()); generatorConfig.setSchemaName(datasourceConfig.getSchemaName()); - return generatorConfig; - } - - public String getDriverClass() { - DbType dbType = DbType.of(this.dbType); - if (dbType == null) { - throw new RuntimeException("不支持数据库类型" + this.dbType + ",请在DbType.java中配置"); + String driver = datasourceConfig.getDriverClass(); + if (StringUtil.isEmpty(driver)) { + ConnectConfig connectConfig = DbTypeConfig.getInstance().getConnectConfig(datasourceConfig.getDbType()); + driver = connectConfig.getDriver(); } - return dbType.getDriverClass(); + generatorConfig.setDriverClass(driver); + return generatorConfig; } public String getJdbcUrl() { - DbType dbType = DbType.of(this.dbType); + ConnectConfig connectConfig = DbTypeConfig.getInstance().getConnectConfig(dbType); if (dbType == null) { - throw new RuntimeException("不支持数据库类型" + this.dbType + ",请在DbType.java中配置"); + throw new RuntimeException("不支持数据库类型" + this.dbType + ",请在 app.yml 中配置"); } - String jdbcUrl = dbType.getJdbcUrl(); - return String.format(jdbcUrl, host, port, dbName); + String jdbcUrl = connectConfig.getUrl(); + // jdbc:mysql://{HOST}:{PORT}/{DB_NAME}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai + jdbcUrl = jdbcUrl.replace("{HOST}", host); + jdbcUrl = jdbcUrl.replace("{PORT}", String.valueOf(port)); + jdbcUrl = jdbcUrl.replace("{DB_NAME}", dbName); + return jdbcUrl; } public String getDbName() { @@ -64,6 +74,10 @@ public class GeneratorConfig { this.dbType = dbType; } + public void setPort(Integer port) { + this.port = port; + } + public String getHost() { return host; } @@ -103,4 +117,12 @@ public class GeneratorConfig { public void setSchemaName(String schemaName) { this.schemaName = schemaName; } + + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + public String getDriverClass() { + return driverClass; + } } diff --git a/gen/src/main/java/com/gitee/gen/gen/SQLContext.java b/gen/src/main/java/com/gitee/gen/gen/SQLContext.java index d1f1dbc05c3ebeeaa55e073e83b35badebcdcd39..6aa03f7e42ae36f34093efcdd8ff841d7f911bfd 100644 --- a/gen/src/main/java/com/gitee/gen/gen/SQLContext.java +++ b/gen/src/main/java/com/gitee/gen/gen/SQLContext.java @@ -58,6 +58,20 @@ public class SQLContext { this.javaPkColumn = this.tableDefinition.getPkColumn(); } + public String getDbNameCamel() { + return FieldUtil.underlineFilter(getDbName()); + } + + /** + * 干净的库名(移除下划线,横杠,点)并小写 + * @return + */ + public String getDbNameClean() { + return getDbName().replace("_", "") + .replace("-", "") + .replace(".", "").toLowerCase(); + } + public String getDatetime() { return localDateTime.format(DATE_TIME_FORMATTER); } diff --git a/gen/src/main/java/com/gitee/gen/gen/SQLServiceFactory.java b/gen/src/main/java/com/gitee/gen/gen/SQLServiceFactory.java index dfb22d8dd63bef2b9bacc0a3eb67fae2f06c3aad..95fe2f3fdd321602caf7e82442c5cc81ea7eae47 100644 --- a/gen/src/main/java/com/gitee/gen/gen/SQLServiceFactory.java +++ b/gen/src/main/java/com/gitee/gen/gen/SQLServiceFactory.java @@ -1,34 +1,28 @@ package com.gitee.gen.gen; -import com.gitee.gen.gen.dm.DmService; -import com.gitee.gen.gen.mysql.MySqlService; -import com.gitee.gen.gen.oracle.OracleService; -import com.gitee.gen.gen.postgresql.PostgreSqlService; -import com.gitee.gen.gen.sqlserver.SqlServerService; +import com.gitee.gen.config.ConnectConfig; +import com.gitee.gen.config.DbTypeConfig; +import org.noear.solon.core.util.ClassUtil; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class SQLServiceFactory { - private static final Map SERVICE_CONFIG = new HashMap<>(16); - - static { - SERVICE_CONFIG.put(DbType.MYSQL.getType(), new MySqlService()); - SERVICE_CONFIG.put(DbType.ORACLE.getType(), new OracleService()); - SERVICE_CONFIG.put(DbType.SQL_SERVER.getType(), new SqlServerService()); - SERVICE_CONFIG.put(DbType.POSTGRE_SQL.getType(), new PostgreSqlService()); - SERVICE_CONFIG.put(DbType.DM.getType(), new DmService()); - - } + private static final Map SERVICE_CONFIG = new ConcurrentHashMap<>(16); public static SQLService build(GeneratorConfig generatorConfig) { - SQLService service = SERVICE_CONFIG.get(generatorConfig.getDbType()); - if (service == null) { - throw new RuntimeException("本系统暂不支持该数据源(" + generatorConfig.getDriverClass() + ")"); - } - return service; + Integer dbType = generatorConfig.getDbType(); + return SERVICE_CONFIG.computeIfAbsent(dbType, k -> { + ConnectConfig connectConfig = DbTypeConfig.getInstance().getConnectConfig(dbType); + String className = connectConfig.getServiceName(); + Class aClass = ClassUtil.loadClass(className); + if (aClass == null) { + throw new RuntimeException("找不到数据库服务类:" + className); + } + return ClassUtil.newInstance(aClass); + }); } } diff --git a/gen/src/main/java/com/gitee/gen/gen/SqlHelper.java b/gen/src/main/java/com/gitee/gen/gen/SqlHelper.java index 8b6618068e6dc574c1c9345a79e265cdc7223839..1e4163b4e0ec3b32464a8726cc011295a7d3b52d 100644 --- a/gen/src/main/java/com/gitee/gen/gen/SqlHelper.java +++ b/gen/src/main/java/com/gitee/gen/gen/SqlHelper.java @@ -1,6 +1,10 @@ package com.gitee.gen.gen; -import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import javax.sql.DataSource; import org.apache.ibatis.jdbc.SqlRunner; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.Environment; @@ -12,14 +16,6 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; - /** * 执行SQL语句的帮助类 * @@ -28,14 +24,6 @@ import java.util.concurrent.ConcurrentHashMap; public class SqlHelper { private static final Logger logger = LoggerFactory.getLogger(SqlHelper.class); - private static final String DRIVER = "driver"; - private static final String URL = "url"; - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - - private static final Map dataSourceMap = new ConcurrentHashMap<>(16); - private static final ThreadLocal connectionLocal = new ThreadLocal<>(); - /** *
      * String sql = "SELECT * FROM datasource_config WHERE dc_id=${id}";
@@ -63,7 +51,7 @@ public class SqlHelper {
         DataSource dataSource = DataSourceManager.getDataSource(generatorConfig);
         String runSql = buildSqlWithParams(dataSource, sql, params);
         String[] sqls = runSql.split(";");
-        Connection conn = null;
+        Connection conn;
         try {
             conn = DataSourceManager.getConnection(generatorConfig);
             SqlRunner runner = buildSqlRunner(conn);
@@ -82,34 +70,14 @@ public class SqlHelper {
         }
     }
 
-
-    public static Connection getConnection(GeneratorConfig generatorConfig) {
-        Connection connection = connectionLocal.get();
-        if (connection == null) {
-            try {
-                connection = getDataSource(generatorConfig).getConnection();
-                connectionLocal.set(connection);
-            } catch (SQLException e) {
-                logger.error("获取Connection失败, jdbcUrl:{}", generatorConfig.getJdbcUrl(), e);
-                throw new RuntimeException("获取Connection失败", e);
-            }
-        }
-        return connection;
-    }
-
-    public static void closeConnection() {
-        Connection connection = connectionLocal.get();
-        if (connection != null) {
-            try {
-                connection.close();
-            } catch (SQLException e) {
-                e.printStackTrace();
-            }
-        }
-        connectionLocal.remove();
-    }
-
-    // 参数绑定
+    /**
+     * 参数绑定
+     *
+     * @param dataSource 数据源
+     * @param sql        sql模板
+     * @param params     参数
+     * @return 构建好的耍起莱
+     */
     private static String buildSqlWithParams(DataSource dataSource, String sql, Map params) {
         Configuration configuration = buildConfiguration(dataSource);
         TextSqlNode node = new TextSqlNode(sql);
@@ -126,21 +94,6 @@ public class SqlHelper {
         return new SqlRunner(connection);
     }
 
-
-    private static DataSource getDataSource(GeneratorConfig generatorConfig) {
-        String jdbcUrl = generatorConfig.getJdbcUrl();
-        return dataSourceMap.computeIfAbsent(jdbcUrl, key -> {
-            Properties properties = new Properties();
-            properties.setProperty(DRIVER, generatorConfig.getDriverClass());
-            properties.setProperty(URL, jdbcUrl);
-            properties.setProperty(USERNAME, generatorConfig.getUsername());
-            properties.setProperty(PASSWORD, generatorConfig.getPassword());
-            PooledDataSourceFactory pooledDataSourceFactory = new PooledDataSourceFactory();
-            pooledDataSourceFactory.setProperties(properties);
-            return pooledDataSourceFactory.getDataSource();
-        });
-    }
-
     private static Configuration buildConfiguration(DataSource dataSource) {
         TransactionFactory transactionFactory = new JdbcTransactionFactory();
         Environment environment = new Environment("development",
diff --git a/gen/src/main/java/com/gitee/gen/gen/TableDefinition.java b/gen/src/main/java/com/gitee/gen/gen/TableDefinition.java
index e8bac0537268e6fdb0ee95e9da7f5e40f0276285..6cf9c61e34c9f8129a989fe36bd79fd6f686c0be 100644
--- a/gen/src/main/java/com/gitee/gen/gen/TableDefinition.java
+++ b/gen/src/main/java/com/gitee/gen/gen/TableDefinition.java
@@ -39,6 +39,15 @@ public class TableDefinition {
         this.tableName = tableName;
     }
 
+    /**
+     * 返回字段数量
+     *
+     * @return 字段数量,>=0
+     */
+    public int getColumnCount() {
+        return columnDefinitions.size();
+    }
+
     /**
      * 是否有时间字段
      * @return true:有
diff --git a/gen/src/main/java/com/gitee/gen/service/DatasourceConfigService.java b/gen/src/main/java/com/gitee/gen/service/DatasourceConfigService.java
index e2d30af6f259b2ae5c16b8be36fd6e45c0fa260d..f11a00a9a91973a6865066627d4215bf0a2a1d38 100644
--- a/gen/src/main/java/com/gitee/gen/service/DatasourceConfigService.java
+++ b/gen/src/main/java/com/gitee/gen/service/DatasourceConfigService.java
@@ -1,7 +1,8 @@
 package com.gitee.gen.service;
 
+import com.gitee.gen.config.ConnectConfig;
+import com.gitee.gen.config.DbTypeConfig;
 import com.gitee.gen.entity.DatasourceConfig;
-import com.gitee.gen.gen.DbType;
 import com.gitee.gen.mapper.DatasourceConfigMapper;
 import org.apache.ibatis.solon.annotation.Db;
 import org.noear.solon.annotation.Component;
@@ -27,9 +28,9 @@ public class DatasourceConfigService {
 
     public void insert(DatasourceConfig templateConfig) {
         templateConfig.setIsDeleted(0);
-        DbType dbType = DbType.of(templateConfig.getDbType());
-        if (dbType != null) {
-            templateConfig.setDriverClass(dbType.getDriverClass());
+        ConnectConfig connectConfig = DbTypeConfig.getInstance().getConnectConfig(templateConfig.getDbType());
+        if (connectConfig != null) {
+            templateConfig.setDriverClass(connectConfig.getDriver());
         }
         datasourceConfigMapper.insert(templateConfig);
     }
diff --git a/gen/src/main/java/com/gitee/gen/service/TemplateConfigService.java b/gen/src/main/java/com/gitee/gen/service/TemplateConfigService.java
index 591244ce6c11933df2bff07fa628ea59323345bf..e4b73b8e7580a2bdba52cffca9f40e0e84b1bee3 100644
--- a/gen/src/main/java/com/gitee/gen/service/TemplateConfigService.java
+++ b/gen/src/main/java/com/gitee/gen/service/TemplateConfigService.java
@@ -4,10 +4,10 @@ import com.gitee.gen.entity.TemplateConfig;
 import com.gitee.gen.mapper.TemplateConfigMapper;
 import com.gitee.gen.util.StringUtil;
 import com.gitee.gen.util.TemplateMetaUtils;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ibatis.solon.annotation.Db;
 import org.noear.solon.annotation.Component;
-import org.smartboot.http.common.utils.CollectionUtils;
 
 import java.util.Collections;
 import java.util.List;
diff --git a/gen/src/main/java/com/gitee/gen/service/UpgradeService.java b/gen/src/main/java/com/gitee/gen/service/UpgradeService.java
index 65f6aa10fa837ae2afae0b17be3b9b005471d6a6..79f8a79eb33694cd6b688ee61ccd94db6e8da2d4 100644
--- a/gen/src/main/java/com/gitee/gen/service/UpgradeService.java
+++ b/gen/src/main/java/com/gitee/gen/service/UpgradeService.java
@@ -50,10 +50,13 @@ public class UpgradeService {
     @Inject
     private SystemConfigService systemConfigService;
 
-    @Inject("${gen.db1.driverClassName}")
+    @Inject("${dbms.enable:false}")
+    private boolean useDbms;
+
+    @Inject("${gen.db2.driverClassName}")
     private String driverClassName;
 
-    @Inject("${gen.db-name:gen}")
+    @Inject("${dbms.database:gen}")
     private String dbName;
 
     public void init() {
@@ -63,6 +66,10 @@ public class UpgradeService {
     }
 
     public void initDatabase() {
+        if (useDbms) {
+            log.info("使用DBMS,跳过sqlit3文件初始化");
+            return;
+        }
         File dbFile = getDbFile();
         if (!dbFile.exists()) {
             try {
@@ -212,12 +219,17 @@ public class UpgradeService {
      */
     public boolean addColumn(String tableName, String columnName, String type) {
         if (!isColumnExist(tableName, columnName)) {
-            if (isMysql()) {
-                upgradeMapper.addColumnMysql(tableName, columnName, type);
-            } else if (isDm()) {
-                upgradeMapper.addColumnDm(tableName, columnName, type);
-            } else {
-                upgradeMapper.addColumn(tableName, columnName, type);
+            try {
+                if (isMysql()) {
+                    upgradeMapper.addColumnMysql(tableName, columnName, type);
+                } else if (isDm()) {
+                    upgradeMapper.addColumnDm(tableName, columnName, type);
+                } else {
+                    upgradeMapper.addColumn(tableName, columnName, type);
+                }
+            } catch (Exception e) {
+                log.error("add column error, tableName={}, columnName={}, type={}",
+                        tableName, columnName, type, e);
             }
             return true;
         }
@@ -298,11 +310,11 @@ public class UpgradeService {
     }
 
     private boolean isMysql() {
-        return this.driverClassName.contains("mysql");
+        return useDbms && this.driverClassName.contains("mysql");
     }
 
     private boolean isDm() {
-        return this.driverClassName.contains("dm");
+        return useDbms && this.driverClassName.contains("dm");
     }
 
 }
diff --git a/gen/src/main/java/com/gitee/gen/util/TemplateMetaUtils.java b/gen/src/main/java/com/gitee/gen/util/TemplateMetaUtils.java
index 7dc53848417a3e20223b14c4b74445da717ea9fb..feba0d4f7ba8089f16802c93f7a63b57a3c9fcf1 100644
--- a/gen/src/main/java/com/gitee/gen/util/TemplateMetaUtils.java
+++ b/gen/src/main/java/com/gitee/gen/util/TemplateMetaUtils.java
@@ -31,11 +31,46 @@ public final class TemplateMetaUtils {
      * 解析元数据信息
      */
     public static Map parseMetaRow(String row) {
+        char[] charArray = row.toCharArray();
+
         Map data = new HashMap<>();
-        String[] paris = row.split("\\s*,\\s*");
-        for (String item : paris) {
-            String[] kv = item.split("=");
-            data.put(kv[0].trim(), kv.length == 1 ? null : kv[1].trim());
+
+        StringBuilder kvBuilder = new StringBuilder();
+        // 剩余未闭合表达式数量
+        int leftExpr = 0;
+        for (int i = 0, len = charArray.length, end = len - 1; i < len; i++) {
+            char c = charArray[i];
+            boolean kvEnd = false;
+            if (i == end) {
+                kvBuilder.append(c);
+                kvEnd = true;
+            } else if (',' == c && leftExpr == 0) {
+                kvEnd = true;
+            }
+
+            if (kvEnd) {
+                String[] kv = kvBuilder.toString().trim().split("=");
+                data.put(kv[0].trim(), kv.length == 1 ? null : kv[1].trim());
+                kvBuilder = new StringBuilder();
+                continue;
+            }
+
+            kvBuilder.append(c);
+            switch (c) {
+                case '{':
+                case '(':
+                    leftExpr++;
+                    break;
+                case '}':
+                case ')':
+                    leftExpr--;
+                    break;
+                default:
+                    break;
+            }
+        }
+        if (leftExpr > 0) {
+            throw new RuntimeException("读取元数据失败,有" + leftExpr + "个表达式未闭合");
         }
         return data;
     }
diff --git a/gen/src/main/resources/app.yml b/gen/src/main/resources/app.yml
index 1909894913bebcb179e864719a5876c040475161..ac3e261d5c2083497ecf82385e2ce4ebb61b08b4 100644
--- a/gen/src/main/resources/app.yml
+++ b/gen/src/main/resources/app.yml
@@ -4,26 +4,27 @@ server:
   port: 6969
 
 
-
 # sqlite3
 #LOCAL_DB: ${user.home}/gen.db
-DATASOURCE_URL: "jdbc:sqlite:"
-DATASOURCE_DRIVE: org.sqlite.JDBC
-DATASOURCE_USERNAME:
-DATASOURCE_PASSWORD:
+gen.db1:
+  url: "jdbc:sqlite:"
+  driverClassName: org.sqlite.JDBC
+  userName:
+  password:
 
 # mysql
-#DATASOURCE_URL: jdbc:mysql://localhost:3306/gen?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
-#DATASOURCE_DRIVE: com.mysql.cj.jdbc.Driver
-#DATASOURCE_USERNAME: root
-#DATASOURCE_PASSWORD: root
+dbms:
+  enable: false
+#  host: localhost:3306
+#  database: gen
+#  username: root
+#  password: root
 
-# 配置数据源
-gen.db1:
-  url: ${DATASOURCE_URL}
-  driverClassName: ${DATASOURCE_DRIVE}
-  userName: ${DATASOURCE_USERNAME}
-  password: ${DATASOURCE_PASSWORD}
+gen.db2:
+  url: jdbc:mysql://${dbms.host:localhost:3306}/${dbms.database:gen}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
+  driverClassName: com.mysql.cj.jdbc.Driver
+  userName: ${dbms.username:gen}
+  password: ${dbms.password:}
 
 # 配置数据源对应的 mybatis 信息(要与 DataSource bean 的名字对上)
 mybatis.db1:
@@ -55,3 +56,33 @@ solon.logging.appender:
     level: INFO
     enable: false #是否启用
 
+
+# 2.0.3新增
+# 连接方式管理, {HOST},{PORT},{DB_NAME} 表示占位符
+connect:
+  1:
+    name: MySQL
+    driver: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://{HOST}:{PORT}/{DB_NAME}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+    serviceName: com.gitee.gen.gen.mysql.MySqlService
+  2:
+    name: Oracle
+    driver: oracle.jdbc.driver.OracleDriver
+    url: jdbc:oracle:thin:@{HOST}:{PORT}{DB_NAME}
+    serviceName: com.gitee.gen.gen.oracle.OracleService
+  3:
+    name: "SQL Server"
+    driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
+    url: jdbc:sqlserver://{HOST}:{PORT};DatabaseName={DB_NAME};trustServerCertificate=true
+    serviceName: com.gitee.gen.gen.sqlserver.SqlServerService
+  4:
+    name: PostgreSQL
+    driver: org.postgresql.Driver
+    url: jdbc:postgresql://{HOST}:{PORT}/{DB_NAME}
+    serviceName: com.gitee.gen.gen.postgresql.PostgreSqlService
+  5:
+    name: "达梦"
+    driver: dm.jdbc.driver.DmDriver
+    url: jdbc:dm://{HOST}:{PORT}/{DB_NAME}
+    serviceName: com.gitee.gen.gen.dm.DmService
+
diff --git a/gen/src/main/resources/gen_init.db b/gen/src/main/resources/gen_init.db
index 2f69f8bd55d0313d70041b6be613986ecfeb7281..795f8f18ac3765db61be902861cd92d74cccccf6 100644
Binary files a/gen/src/main/resources/gen_init.db and b/gen/src/main/resources/gen_init.db differ
diff --git a/gen/src/main/resources/gen_init_v1.db b/gen/src/main/resources/gen_init_v1.db
new file mode 100644
index 0000000000000000000000000000000000000000..2f69f8bd55d0313d70041b6be613986ecfeb7281
Binary files /dev/null and b/gen/src/main/resources/gen_init_v1.db differ
diff --git a/readme.md b/readme.md
index 0933a84ff39c534837e444dfc6e12691f1eb35cf..8d4372386bc8045d274dfa9135c87a77b6db02a4 100644
--- a/readme.md
+++ b/readme.md
@@ -26,10 +26,6 @@
 
 > 升级:后续升级覆盖gen.jar和dist文件夹即可
 
-- 数据库支持
-
-默认支持mysql数据库,如果要支持其他数据库将驱动包放到`gen/lib`下
-
 ### 方式2:docker运行
 
 - 下载公共镜像
@@ -41,15 +37,14 @@
 ```shell
 docker run --name gen --restart=always \
   -p 6969:6969 \
-  -e JAVA_OPTS="-server -Xms64m -Xmx64m -DLOCAL_DB=/opt/gen/gen.db" \
   -v /opt/gen/:/opt/gen/ \
+  -v /opt/gen/conf/:/gen/conf/ \
+  -v /opt/gen/ext:/gen/ext \
   -d registry.cn-hangzhou.aliyuncs.com/tanghc/gen:latest
 ```
 
 浏览器访问`http://ip:6969/`
 
-后续更新替换jar文件和dist文件夹即可。
-
 
 ### 本地构建镜像
 
@@ -61,11 +56,56 @@ clone代码,然后执行`docker-build.sh`脚本
 ```shell
 docker run --name gen --restart=always \
   -p 6969:6969 \
-  -e JAVA_OPTS="-server -Xms64m -Xmx64m -DLOCAL_DB=/opt/gen/gen.db" \
   -v /opt/gen/:/opt/gen/ \
+  -v /opt/gen/conf/:/gen/conf/ \
+  -v /opt/gen/ext:/gen/ext \
   -d <镜像ID>
 ```
 
+## 其它数据库支持
+
+
+默认支持mysql数据库,如果要支持其它数据库,如Oracle,步骤如下:
+
+- docker
+
+1. 将数据库驱动放到`/opt/gen/ext`下
+2. 重启docker
+
+- 本地运行
+
+1. 将数据库驱动放到`gen/ext`下
+2. 设置环境变量JAVA_HOME,指向java安装目录
+3. 编辑`run.sh`文件,添加启动参数:`-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:./ext`
+
+添加后如下:
+
+`java -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:./ext -Dsolon.config.add=./conf/app.yml -Duser.timezone=Asia/Shanghai -jar -Xms64m -Xmx64m gen.jar`
+
+执行`sh run.sh`启动
+
+
+## 使用Mysql存储
+
+默认使用SQLITE3存储,如果要使用mysql存储,需要做如下配置
+
+- 创建数据库, [SQL文件](https://gitee.com/durcframework/code-gen/blob/master/db/mysql.sql)
+- 打开app.yml文件,docker环境下在`/opt/gen/conf`下新建一个`app.yml`文件
+- 添加/修改如下配置
+
+```yaml
+dbms:
+  # 设置为true
+  enable: true
+  # 设置数据库地址,库名,连接账号
+  host: localhost:3306
+  database: gen
+  username: root
+  password: root
+```
+
+重启服务
+
 ## 其它
 
 - [快速搭建SpringBoot+Mybatis应用](https://gitee.com/durcframework/code-gen/wikis/pages?sort_id=2478942&doc_id=27724)
@@ -84,6 +124,7 @@ docker run --name gen --restart=always \
 - 运行`gen`下的`com.gitee.gen.App`(solon-web工程)
 - 运行`front`下的前端项目,详见:[readme](./front/README.md)
 
+
 ## 参与贡献
 
 欢迎贡献代码,完善功能,PR请提交到`pr`分支
diff --git a/templates/fastmybatis-v3.0/controller.vm b/templates/fastmybatis-v3.0/controller.vm
new file mode 100644
index 0000000000000000000000000000000000000000..fdf16790a9874482649a37939f1f67d453298a8c
--- /dev/null
+++ b/templates/fastmybatis-v3.0/controller.vm
@@ -0,0 +1,98 @@
+## filename=${context.javaBeanName}Controller.java, folder=controller
+#set($entityClass="${context.classNamePascal}")
+#set($entityObj="${context.classNameCamel}")
+#set($serviceClass="${context.classNamePascal}Service")
+#set($serviceObj="${context.classNameCamel}Service")
+#set($pkg="${context.packageName}")
+package ${pkg}.web.controller;
+
+import com.gitee.fastmybatis.core.PageInfo;
+import com.gitee.fastmybatis.core.query.Query;
+import com.gitee.fastmybatis.core.query.param.PageParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import ${pkg}.dao.entity.${entityClass};
+import ${pkg}.service.${serviceClass}Service;
+
+import javax.validation.Valid;
+
+/**
+ * @author ${context.author}
+ */
+@RestController
+@RequestMapping("${table.tableName}")
+public class ${entityClass}Controller {
+
+    @Autowired
+    private ${serviceClass} ${serviceObj};
+
+    /**
+     * 分页查询
+     *
+     * @param param 请求参数
+     * @return 返回分页信息
+     */
+    @GetMapping("/page")
+    public Result> page(PageParam param) {
+        Query query = param.toQuery();
+        PageInfo<${entityClass}> pageInfo = ${serviceObj}.page(query);
+        return Result.ok(pageInfo);
+    }
+
+    /**
+     * 新增
+     *
+     * @param $entityObj
+     * @return 返回主键id
+     */
+    @PostMapping("/save")
+    public Result<${pk.javaTypeBox}> save(@Valid @RequestBody ${entityClass} $entityObj) {
+        ${serviceObj}.save($entityObj);
+        // 返回添加后的主键值
+        return Result.ok(${entityObj}.getId());
+    }
+
+    /**
+     * 详情
+     *
+     * @param id
+     * @return 返回详情
+     */
+    @GetMapping("/detail")
+    public Result<${entityClass}> detail(${pk.javaTypeBox} id) {
+    	${entityClass} record = ${serviceObj}.getById(id);
+        return Result.ok(record);
+    }
+
+    /**
+     * 修改
+     *
+     * @param $entityObj 表单数据
+     * @return
+     */
+    @PutMapping("/update")
+    public Result update(@Valid @RequestBody ${entityClass} $entityObj) {
+        ${serviceObj}.update($entityObj);
+        return Result.ok();
+    }
+
+    /**
+     * 删除
+     *
+     * @param id 主键id
+     * @return
+     */
+    @DeleteMapping("/delete")
+    public Result delete(${pk.javaTypeBox} id) {
+        ${serviceObj}.deleteById(id);
+        return Result.ok();
+    }
+
+}
diff --git a/templates/fastmybatis-v3.0/entity.vm b/templates/fastmybatis-v3.0/entity.vm
new file mode 100644
index 0000000000000000000000000000000000000000..ba1b9b7c79d65a38d8f9c614665b295618f2d16b
--- /dev/null
+++ b/templates/fastmybatis-v3.0/entity.vm
@@ -0,0 +1,58 @@
+## filename=${context.javaBeanName}.java, folder=entity
+#set($entityClass="${context.classNamePascal}")
+package ${context.packageName}.dao.entity;
+
+import com.gitee.fastmybatis.annotation.Pk;
+import com.gitee.fastmybatis.annotation.PkStrategy;
+import com.gitee.fastmybatis.annotation.Table;
+import com.gitee.fastmybatis.core.query.LambdaQuery;
+import lombok.Data;
+
+#if(${table.hasDateField})
+import java.util.Date;
+#end
+#if(${table.hasLocalDateField})
+import java.time.LocalDate;
+#end
+#if(${table.hasLocalDateTimeField})
+import java.time.LocalDateTime;
+#end
+#if(${table.hasBigDecimalField})
+import java.math.BigDecimal;
+#end
+
+/**
+ * 表名:${table.tableName}
+#if("$!{table.comment}" != "")
+ * 备注:${table.comment}
+#end
+ *
+ * @author ${context.author}
+ */
+@Table(name = "${table.tableName}", pk = @Pk(name = "${pk.columnName}", strategy = PkStrategy.INCREMENT))
+@Data
+public class ${entityClass} {
+
+#foreach($column in $columns)
+#if("$!{column.comment}" != "")
+    /** 
+     * ${column.comment}
+     */
+#end
+#if(${column.columnName} == "is_deleted")
+    @com.gitee.fastmybatis.annotation.Column(logicDelete = true)
+#end
+    private ${column.javaTypeBox} ${column.javaFieldName};
+
+#end
+    
+    /**
+     * 创建LambdaQuery对象
+     * 
+     * @return 返回LambdaQuery对象
+     */
+    public static LambdaQuery<${entityClass}> query() {
+        return new LambdaQuery<>(${entityClass}.class);
+    }
+
+}
\ No newline at end of file
diff --git a/templates/fastmybatis-v3.0/mapper.vm b/templates/fastmybatis-v3.0/mapper.vm
new file mode 100644
index 0000000000000000000000000000000000000000..25a7fe51d446dd00ee19f095021616b49c8fb0cd
--- /dev/null
+++ b/templates/fastmybatis-v3.0/mapper.vm
@@ -0,0 +1,14 @@
+## filename=${context.javaBeanName}Mapper.java, folder=mapper
+#set($entityClass="${context.classNamePascal}")
+#set($pkg="${context.packageName}")
+package ${pkg}.dao.mapper;
+
+import com.gitee.fastmybatis.core.mapper.BaseMapper;
+import ${pkg}.dao.entity.${entityClass};
+
+/**
+ * @author ${context.author}
+ */
+public interface ${entityClass}Mapper extends BaseMapper<${entityClass}> {
+	
+}
\ No newline at end of file
diff --git a/templates/fastmybatis-v3.0/service.vm b/templates/fastmybatis-v3.0/service.vm
new file mode 100644
index 0000000000000000000000000000000000000000..9c5fe1f0fd4dccb6f7336ded6741329d4fa98d05
--- /dev/null
+++ b/templates/fastmybatis-v3.0/service.vm
@@ -0,0 +1,19 @@
+## filename=${context.javaBeanName}Service.java, folder=service
+#set($entityClass="${context.classNamePascal}")
+#set($mapperClass="${context.classNamePascal}Mapper")
+#set($pkg="${context.packageName}")
+package ${pkg}.mapper;
+
+import com.gitee.fastmybatis.core.support.BaseLambdaService;
+import ${pkg}.dao.entity.${entityClass};
+import ${pkg}.dao.mapper.${mapperClass};
+import org.springframework.stereotype.Service;
+
+
+/**
+ * @author ${context.author}
+ */
+@Service
+public class ${entityClass}Service extends BaseLambdaService<${entityClass}, ${mapperClass}> {
+
+}
\ No newline at end of file