SpringBlade bug/优化 代码生成器
一、问题
1、SQL脚本
DROP TABLE IF EXISTS `pms_brand`;
CREATE TABLE pms_brand
(
create_user bigint comment '创建人',
create_time datetime comment '创建时间',
update_user bigint comment '上次修改人',
update_time datetime comment '上次修改时间',
is_deleted int comment '是否已删除',
sort int comment '排序',
tenant_id varchar(12) comment '租户id',
create_dept bigint comment '创建部门',
id bigint not null auto_increment comment '编号',
name varchar(64) comment '名称',
letter varchar(64) comment '每个汉字的首字母',
product_count int comment '关联产品数量',
primary key (id)
);
2、生成后的代码
3、这个我自己用MyBatis-Plus
的代码生成器生成的
4、出错的地方在于数据库问题
原来是数据库备注乱码了,估计是本地以前执行SQL语句的时候忘选择编码了
二、需要注意的地方
1、脚本编码问题
MySQL数据库执行脚本的时候,要注意脚本编码的问题,不然很容易就乱码了
2、数据库版本问题
MySQL数据库版本 5.x和6.x的版本相差比较大,jdbc的配置需要注意,注意就是下面的两个参数
有两个参数需要注意:nullCatalogMeansCurrent
、allowPublicKeyRetrieval
原文:
https://blog.csdn.net/jiaoshaoping/article/details/80748065
https://blog.csdn.net/Yuriey/article/details/80423504
可参考默认数据库链接的配置
#spring.datasource.driver-class-name=com.mysql.cj.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
3、在线代码生成器的问题
在使用前需要配置一下数据源,不然就会使用本地的blade数据库,在数据源管理就可以配置。
4、代码生成器本地调试调试问题
需要特别注意一下数据库链接地址
如是在blade-core-develop
这个项目运行,数据库的配置在这里'resources/templates/code.properties'
如果是在org.springblade
这个项目运行,就需要在线配置一下数据源的地址
这里也有一个数据库配置文件,我把源码改过一下,就没有用到这里的这个文件
三、代码的一些调整
1、修改的类
2、BladeCodeGenerator
/**
* 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.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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.OracleTypeConvert;
import com.baomidou.mybatisplus.generator.config.converts.PostgreSqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
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
*/
@Slf4j
public class BladeCodeGenerator {
// configGlobalConfig 方法使用-----------------------
/**
* 代码所在服务名
*/
private String serviceName = "blade-service";
/**
* 租户字段
*/
private String tenantColumn = "tenant_id";
/**
* 是否包含包装器
*/
private Boolean hasWrapper = Boolean.FALSE;
/**
* 输出路径
*/
private String outputDir;
/**
* 是否启用swagger
*/
private Boolean isSwagger2 = Boolean.TRUE;
/**
* 作者
*/
private String author;
// configDataSource 方法使用-----------------------
/**
* 数据库驱动名
*/
private String driverName;
/**
* 数据库链接地址
*/
private String url;
/**
* 数据库用户名
*/
private String username;
/**
* 数据库密码
*/
private String password;
// configStrategyConfig 方法使用-----------------------
/**
* 需要去掉的表前缀
*/
private String[] tablePrefix = {"blade_"};
/**
* 需要生成的表名(两者只能取其一)
*/
private String[] includeTables = {};
/**
* 需要排除的表名(两者只能取其一)
*/
private String[] excludeTables = {};
/**
* 是否包含基础业务字段
*/
private Boolean hasSuperEntity = Boolean.FALSE;
/**
* 基础业务字段
*/
private String[] superEntityColumns = {"create_time" , "create_user" , "create_dept" , "update_time" , "update_user" , "status" , "is_deleted"};
// configPackageConfig 方法使用-----------------------
/**
* 代码生成的包名
*/
private String packageName = "org.springblade.test";
// configPackageConfig 方法使用-----------------------
/**
* 代码模块名称
*/
private String codeName;
/**
* 代码所在系统
*/
private String systemName = DevelopConstant.SWORD_NAME;
/**
* 前端代码生成的地址
*/
private String packageWebDir;
// getOutputDir 方法使用-----------------------
/**
* 后端代码生成的地址
*/
private String packageDir;
/**
* CodeGenerator这个类使用
* @param codeName 代码模块名称
* @param serviceName 代码所在服务名
* @param systemName 代码所在系统
* @param packageName 代码生成的包名
* @param packageWebDir 前端代码生成的地址
* @param tablePrefix 需要去掉的表前缀
* @param includeTables 需要生成的表名(两者只能取其一)
* @param excludeTables 需要排除的表名(两者只能取其一)
* @param hasSuperEntity 是否包含基础业务字段
* @param superEntityColumns 基础业务字段
*/
public BladeCodeGenerator(String codeName,String serviceName,String systemName,String packageName
,String packageWebDir,String[] tablePrefix,String[] includeTables,String[] excludeTables
,boolean hasSuperEntity,String[] superEntityColumns) {
this.codeName=codeName;
this.serviceName=serviceName;
this.systemName=systemName;
this.packageName=packageName;
this.packageWebDir=packageWebDir;
this.tablePrefix=tablePrefix;
this.includeTables=includeTables;
this.excludeTables=excludeTables;
this.hasSuperEntity=hasSuperEntity;
this.superEntityColumns=superEntityColumns;
// 从配置文件获取数据库链接
Properties props = getProperties();
this.driverName = props.getProperty("spring.datasource.driver-class-name");
this.url = props.getProperty("spring.datasource.url");
this.username = props.getProperty("spring.datasource.username");
this.password = props.getProperty("spring.datasource.password");
this.author = props.getProperty("author");
}
/**
* CodeController类使用
* @param driverName 数据库驱动名
* @param url 数据库链接地址
* @param username 数据库用户名
* @param password 数据库密码
* @param systemName 代码所在系统
* @param serviceName 代码所在服务名
* @param packageName 代码生成的包名
* @param packageDir 后端代码生成的地址
* @param packageWebDir 前端代码生成的地址
* @param tablePrefix 需要去掉的表前缀
* @param includeTables 需要生成的表名(两者只能取其一)
* @param hasSuperEntity 需要排除的表名(两者只能取其一)
* @param hasWrapper 是否包含基础业务字段
*/
public BladeCodeGenerator(String driverName,String url,String username,String password
,String systemName,String serviceName,String packageName,String packageDir,String packageWebDir
,String[] tablePrefix,String[] includeTables,boolean hasSuperEntity,boolean hasWrapper){
this.driverName=driverName;
this.url=url;
this.username=username;
this.password=password;
this.systemName=systemName;
this.serviceName=serviceName;
this.packageName=packageName;
this.packageDir=packageDir;
this.packageWebDir=packageWebDir;
this.tablePrefix=tablePrefix;
this.includeTables=includeTables;
this.hasSuperEntity=hasSuperEntity;
this.hasWrapper=hasWrapper;
//其它值的初始化
this.outputDir = getOutputDir();
}
/**
* 自定义生成文件配置
*
* @return
*/
private InjectionConfig configCustomerConfig() {
String servicePackage = serviceName.split("-").length > 1 ? serviceName.split("-")[1] : serviceName;
// 自定义配置
Map<String, Object> map = new HashMap<>(16);
InjectionConfig config = new InjectionConfig() {
@Override
public void initMap() {
map.put("codeName" , codeName);
map.put("serviceName" , serviceName);
map.put("servicePackage" , servicePackage);
map.put("servicePackageLowerCase" , servicePackage.toLowerCase());
map.put("tenantColumn" , tenantColumn);
map.put("hasWrapper" , hasWrapper);
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()));
map.put("menuId" , IdWorker.getId());
map.put("addMenuId" , IdWorker.getId());
map.put("editMenuId" , IdWorker.getId());
map.put("removeMenuId" , IdWorker.getId());
map.put("viewMenuId" , IdWorker.getId());
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;
}
});
if (hasWrapper) {
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";
}
});
}
}
config.setFileOutConfigList(focList);
return config;
}
/**
* 全局配置
*
* @return
*/
private GlobalConfig configGlobalConfig() {
GlobalConfig config = new GlobalConfig();
config.setOutputDir(this.outputDir);
config.setAuthor(this.author);
config.setFileOverride(true);
config.setOpen(false);
config.setActiveRecord(false);
config.setEnableCache(false);
config.setBaseResultMap(true);
config.setBaseColumnList(true);
config.setMapperName("%sMapper");
config.setXmlName("%sMapper");
config.setServiceName("I%sService");
config.setServiceImplName("%sServiceImpl");
config.setControllerName("%sController");
config.setSwagger2(isSwagger2);
return config;
}
/**
* 数据源配置
*
* @return
*/
private DataSourceConfig configDataSource() {
DataSourceConfig config = new DataSourceConfig();
if (StringUtil.containsAny(this.driverName, DbType.MYSQL.getDb())) {
config.setDbType(DbType.MYSQL);
config.setTypeConvert(new MySqlTypeConvert());
} else if (StringUtil.containsAny(this.driverName, DbType.POSTGRE_SQL.getDb())) {
config.setDbType(DbType.POSTGRE_SQL);
config.setTypeConvert(new PostgreSqlTypeConvert());
} else {
config.setDbType(DbType.ORACLE);
config.setTypeConvert(new OracleTypeConvert());
}
config.setDriverName(this.driverName);
config.setUrl(this.url);
config.setUsername(this.username);
config.setPassword(this.password);
return config;
}
/**
* 策略配置
*
* @return
*/
private StrategyConfig configStrategyConfig() {
// 策略配置
StrategyConfig config = new StrategyConfig();
// config.setCapitalMode(true);// 全局大写命名
// config.setDbColumnUnderline(true);//全局下划线命名
config.setNaming(NamingStrategy.underline_to_camel);
config.setColumnNaming(NamingStrategy.underline_to_camel);
config.setTablePrefix(tablePrefix);
if (includeTables.length > 0) {
config.setInclude(includeTables);
}
if (excludeTables.length > 0) {
config.setExclude(excludeTables);
}
if (hasSuperEntity) {
config.setSuperEntityClass("org.springblade.core.mp.base.BaseEntity");
config.setSuperEntityColumns(superEntityColumns);
config.setSuperServiceClass("org.springblade.core.mp.base.BaseService");
config.setSuperServiceImplClass("org.springblade.core.mp.base.BaseServiceImpl");
} else {
config.setSuperServiceClass("com.baomidou.mybatisplus.extension.service.IService");
config.setSuperServiceImplClass("com.baomidou.mybatisplus.extension.service.impl.ServiceImpl");
}
// 自定义 controller 父类
config.setSuperControllerClass("org.springblade.core.boot.ctrl.BladeController");
config.setEntityBuilderModel(false);
config.setEntityLombokModel(true);
config.setControllerMappingHyphenStyle(true);
return config;
}
/**
* 包名策略配置
*
* @return
*/
private PackageConfig configPackageConfig() {
// 包配置
PackageConfig config = new PackageConfig();
// 控制台扫描
config.setModuleName(null);
config.setParent(packageName);
config.setController("controller");
config.setEntity("entity");
config.setXml("mapper");
return config;
}
/**
* 获取配置文件
*
* @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;
}
public void run() {
AutoGenerator mpg = new AutoGenerator();
mpg.setGlobalConfig(configGlobalConfig());
mpg.setDataSource(configDataSource());
mpg.setStrategy(configStrategyConfig());
mpg.setPackageInfo(configPackageConfig());
mpg.setCfg(configCustomerConfig());
mpg.execute();
}
}
3、CodeGenerator
public static void run() {
BladeCodeGenerator generator = new BladeCodeGenerator(
CODE_NAME,SERVICE_NAME,SYSTEM_NAME,PACKAGE_NAME
,PACKAGE_WEB_DIR,TABLE_PREFIX,INCLUDE_TABLES
,EXCLUDE_TABLES,HAS_SUPER_ENTITY,SUPER_ENTITY_COLUMNS
);
generator.run();
}
4、CodeController
/**
* 代码生成
*/
@PostMapping("/gen-code")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "代码生成" , notes = "传入ids")
public R genCode(@ApiParam(value = "主键集合" , required = true) @RequestParam String ids, @RequestParam(defaultValue = "sword") String system) {
Collection<Code> codes = codeService.listByIds(Func.toLongList(ids));
codes.forEach(code -> {
String driverName = "";
String url = "";
String username = "";
String password = "";
String systemName = "";
String serviceName = "";
String packageName = "";
String packageDir = "";
String packageWebDir = "";
String[] tablePrefix = null;
String[] includeTables = null;
boolean hasSuperEntity = false;
boolean hasWrapper = false;
// 设置数据源
Datasource datasource = datasourceService.getById(code.getDatasourceId());
driverName = datasource.getDriverClass();
url = datasource.getUrl();
username = datasource.getUsername();
password = datasource.getPassword();
// 设置基础配置
systemName = system;
serviceName = code.getServiceName();
packageName = code.getPackageName();
packageDir = code.getApiPath();
packageWebDir = code.getWebPath();
tablePrefix = Func.toStrArray(code.getTablePrefix());
includeTables = Func.toStrArray(code.getTableName());
hasSuperEntity = code.getBaseMode() == 2;
hasWrapper = code.getWrapMode() == 2;
//构造函数初始化
BladeCodeGenerator generator = new BladeCodeGenerator(driverName, url, username, password
, systemName, serviceName, packageName, packageDir, packageWebDir
, tablePrefix, includeTables, hasSuperEntity, hasWrapper
);
generator.run();
});
return R.success("代码生成成功");
}