AutoGenerator.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /**
  2. * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.baomidou.mybatisplus.generator;
  17. import java.io.BufferedWriter;
  18. import java.io.File;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.OutputStreamWriter;
  22. import java.text.SimpleDateFormat;
  23. import java.util.Date;
  24. import java.util.HashMap;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Properties;
  28. import org.apache.ibatis.logging.Log;
  29. import org.apache.ibatis.logging.LogFactory;
  30. import org.apache.velocity.Template;
  31. import org.apache.velocity.VelocityContext;
  32. import org.apache.velocity.app.Velocity;
  33. import org.apache.velocity.app.VelocityEngine;
  34. import com.baomidou.mybatisplus.generator.config.ConstVal;
  35. import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
  36. import com.baomidou.mybatisplus.generator.config.FileOutConfig;
  37. import com.baomidou.mybatisplus.generator.config.GlobalConfig;
  38. import com.baomidou.mybatisplus.generator.config.PackageConfig;
  39. import com.baomidou.mybatisplus.generator.config.StrategyConfig;
  40. import com.baomidou.mybatisplus.generator.config.TemplateConfig;
  41. import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
  42. import com.baomidou.mybatisplus.generator.config.po.TableField;
  43. import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  44. import com.baomidou.mybatisplus.toolkit.CollectionUtils;
  45. import com.baomidou.mybatisplus.toolkit.StringUtils;
  46. /**
  47. * 生成文件
  48. *
  49. * @author YangHu, tangguo
  50. * @since 2016-08-30
  51. */
  52. public class AutoGenerator {
  53. private static final Log logger = LogFactory.getLog(AutoGenerator.class);
  54. protected ConfigBuilder config;
  55. protected InjectionConfig injectionConfig;
  56. /**
  57. * 数据源配置
  58. */
  59. private DataSourceConfig dataSource;
  60. /**
  61. * 数据库表配置
  62. */
  63. private StrategyConfig strategy;
  64. /**
  65. * 包 相关配置
  66. */
  67. private PackageConfig packageInfo;
  68. /**
  69. * 模板 相关配置
  70. */
  71. private TemplateConfig template;
  72. /**
  73. * 全局 相关配置
  74. */
  75. private GlobalConfig globalConfig;
  76. /**
  77. * velocity引擎
  78. */
  79. private VelocityEngine engine;
  80. /**
  81. * 生成代码
  82. */
  83. public void execute() {
  84. logger.debug("==========================准备生成文件...==========================");
  85. // 初始化配置
  86. initConfig();
  87. // 创建输出文件路径
  88. mkdirs(config.getPathInfo());
  89. // 获取上下文
  90. Map<String, VelocityContext> ctxData = analyzeData(config);
  91. // 循环生成文件
  92. for (Map.Entry<String, VelocityContext> ctx : ctxData.entrySet()) {
  93. batchOutput(ctx.getKey(), ctx.getValue());
  94. }
  95. // 打开输出目录
  96. if (config.getGlobalConfig().isOpen()) {
  97. try {
  98. String osName = System.getProperty("os.name");
  99. if (osName != null) {
  100. if (osName.contains("Mac")) {
  101. Runtime.getRuntime().exec("open " + config.getGlobalConfig().getOutputDir());
  102. } else if (osName.contains("Windows")) {
  103. Runtime.getRuntime().exec("cmd /c start " + config.getGlobalConfig().getOutputDir());
  104. } else {
  105. logger.debug("文件输出目录:" + config.getGlobalConfig().getOutputDir());
  106. }
  107. }
  108. } catch (IOException e) {
  109. e.printStackTrace();
  110. }
  111. }
  112. logger.debug("==========================文件生成完成!!!==========================");
  113. }
  114. /**
  115. * <p>
  116. * 开放表信息、预留子类重写
  117. * </p>
  118. *
  119. * @param config 配置信息
  120. * @return
  121. */
  122. protected List<TableInfo> getAllTableInfoList(ConfigBuilder config) {
  123. return config.getTableInfoList();
  124. }
  125. /**
  126. * <p>
  127. * 分析数据
  128. * </p>
  129. *
  130. * @param config 总配置信息
  131. * @return 解析数据结果集
  132. */
  133. private Map<String, VelocityContext> analyzeData(ConfigBuilder config) {
  134. List<TableInfo> tableList = this.getAllTableInfoList(config);
  135. Map<String, String> packageInfo = config.getPackageInfo();
  136. Map<String, VelocityContext> ctxData = new HashMap<>();
  137. String superEntityClass = getSuperClassName(config.getSuperEntityClass());
  138. String superMapperClass = getSuperClassName(config.getSuperMapperClass());
  139. String superServiceClass = getSuperClassName(config.getSuperServiceClass());
  140. String superServiceImplClass = getSuperClassName(config.getSuperServiceImplClass());
  141. String superControllerClass = getSuperClassName(config.getSuperControllerClass());
  142. String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
  143. VelocityContext ctx;
  144. for (TableInfo tableInfo : tableList) {
  145. ctx = new VelocityContext();
  146. if (null != injectionConfig) {
  147. /**
  148. * 注入自定义配置
  149. */
  150. injectionConfig.initMap();
  151. ctx.put("cfg", injectionConfig.getMap());
  152. }
  153. /* ---------- 添加导入包 ---------- */
  154. if (config.getGlobalConfig().isActiveRecord()) {
  155. // 开启 ActiveRecord 模式
  156. tableInfo.setImportPackages("com.baomidou.mybatisplus.activerecord.Model");
  157. }
  158. if (tableInfo.isConvert()) {
  159. // 表注解
  160. tableInfo.setImportPackages("com.baomidou.mybatisplus.annotations.TableName");
  161. }
  162. if (tableInfo.isLogicDelete(config.getStrategyConfig().getLogicDeleteFieldName())) {
  163. // 逻辑删除注解
  164. tableInfo.setImportPackages("com.baomidou.mybatisplus.annotations.TableLogic");
  165. }
  166. if (StringUtils.isNotEmpty(config.getSuperEntityClass())) {
  167. // 父实体
  168. tableInfo.setImportPackages(config.getSuperEntityClass());
  169. } else {
  170. tableInfo.setImportPackages("java.io.Serializable");
  171. }
  172. // Boolean类型is前缀处理
  173. if (config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix()) {
  174. for (TableField field : tableInfo.getFields()) {
  175. if (field.getPropertyType().equalsIgnoreCase("boolean")) {
  176. if (field.getPropertyName().contains("is")) {
  177. field.setPropertyName(config.getStrategyConfig(),
  178. StringUtils.removePrefixAfterPrefixToLower(field.getPropertyName(), 2));
  179. }
  180. }
  181. }
  182. }
  183. // RequestMapping 连字符风格 user-info
  184. if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
  185. ctx.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
  186. ctx.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
  187. }
  188. ctx.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
  189. ctx.put("package", packageInfo);
  190. ctx.put("author", config.getGlobalConfig().getAuthor());
  191. ctx.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
  192. ctx.put("activeRecord", config.getGlobalConfig().isActiveRecord());
  193. ctx.put("date", date);
  194. ctx.put("table", tableInfo);
  195. ctx.put("enableCache", config.getGlobalConfig().isEnableCache());
  196. ctx.put("baseResultMap", config.getGlobalConfig().isBaseResultMap());
  197. ctx.put("baseColumnList", config.getGlobalConfig().isBaseColumnList());
  198. ctx.put("entity", tableInfo.getEntityName());
  199. ctx.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
  200. ctx.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
  201. ctx.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
  202. ctx.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
  203. ctx.put("superEntityClass", superEntityClass);
  204. ctx.put("superMapperClassPackage", config.getSuperMapperClass());
  205. ctx.put("superMapperClass", superMapperClass);
  206. ctx.put("superServiceClassPackage", config.getSuperServiceClass());
  207. ctx.put("superServiceClass", superServiceClass);
  208. ctx.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
  209. ctx.put("superServiceImplClass", superServiceImplClass);
  210. ctx.put("superControllerClassPackage", config.getSuperControllerClass());
  211. ctx.put("superControllerClass", superControllerClass);
  212. ctxData.put(tableInfo.getEntityName(), ctx);
  213. }
  214. return ctxData;
  215. }
  216. /**
  217. * <p>
  218. * 获取类名
  219. * </p>
  220. *
  221. * @param classPath
  222. * @return
  223. */
  224. private String getSuperClassName(String classPath) {
  225. if (StringUtils.isEmpty(classPath))
  226. return null;
  227. return classPath.substring(classPath.lastIndexOf(".") + 1);
  228. }
  229. /**
  230. * <p>
  231. * 处理输出目录
  232. * </p>
  233. *
  234. * @param pathInfo 路径信息
  235. */
  236. private void mkdirs(Map<String, String> pathInfo) {
  237. for (Map.Entry<String, String> entry : pathInfo.entrySet()) {
  238. File dir = new File(entry.getValue());
  239. if (!dir.exists()) {
  240. boolean result = dir.mkdirs();
  241. if (result) {
  242. logger.debug("创建目录: [" + entry.getValue() + "]");
  243. }
  244. }
  245. }
  246. }
  247. /**
  248. * <p>
  249. * 合成上下文与模板
  250. * </p>
  251. *
  252. * @param context vm上下文
  253. */
  254. private void batchOutput(String entityName, VelocityContext context) {
  255. try {
  256. TableInfo tableInfo = (TableInfo) context.get("table");
  257. Map<String, String> pathInfo = config.getPathInfo();
  258. String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + ConstVal.ENTITY_NAME), entityName);
  259. String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + ConstVal.JAVA_SUFFIX), entityName);
  260. String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
  261. String serviceFile = String.format((pathInfo.get(ConstVal.SERIVCE_PATH) + File.separator + tableInfo.getServiceName() + ConstVal.JAVA_SUFFIX), entityName);
  262. String implFile = String.format((pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + ConstVal.JAVA_SUFFIX), entityName);
  263. String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + ConstVal.JAVA_SUFFIX), entityName);
  264. TemplateConfig template = config.getTemplate();
  265. // 根据override标识来判断是否需要创建文件
  266. if (isCreate(entityFile)) {
  267. vmToFile(context, template.getEntity(), entityFile);
  268. }
  269. if (isCreate(mapperFile)) {
  270. vmToFile(context, template.getMapper(), mapperFile);
  271. }
  272. if (isCreate(xmlFile)) {
  273. vmToFile(context, template.getXml(), xmlFile);
  274. }
  275. if (isCreate(serviceFile)) {
  276. vmToFile(context, template.getService(), serviceFile);
  277. }
  278. if (isCreate(implFile)) {
  279. vmToFile(context, template.getServiceImpl(), implFile);
  280. }
  281. if (isCreate(controllerFile)) {
  282. vmToFile(context, template.getController(), controllerFile);
  283. }
  284. if (injectionConfig != null) {
  285. /**
  286. * 输出自定义文件内容
  287. */
  288. List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
  289. if (CollectionUtils.isNotEmpty(focList)) {
  290. for (FileOutConfig foc : focList) {
  291. vmToFile(context, foc.getTemplatePath(), foc.outputFile(tableInfo));
  292. }
  293. }
  294. }
  295. } catch (IOException e) {
  296. logger.error("无法创建文件,请检查配置信息!", e);
  297. }
  298. }
  299. /**
  300. * <p>
  301. * 将模板转化成为文件
  302. * </p>
  303. *
  304. * @param context 内容对象
  305. * @param templatePath 模板文件
  306. * @param outputFile 文件生成的目录
  307. */
  308. private void vmToFile(VelocityContext context, String templatePath, String outputFile) throws IOException {
  309. if (StringUtils.isEmpty(templatePath)) {
  310. return;
  311. }
  312. VelocityEngine velocity = getVelocityEngine();
  313. Template template = velocity.getTemplate(templatePath, ConstVal.UTF8);
  314. File file = new File(outputFile);
  315. if (!file.getParentFile().exists()) {
  316. // 如果文件所在的目录不存在,则创建目录
  317. if (!file.getParentFile().mkdirs()) {
  318. logger.debug("创建文件所在的目录失败!");
  319. return;
  320. }
  321. }
  322. FileOutputStream fos = new FileOutputStream(outputFile);
  323. BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, ConstVal.UTF8));
  324. template.merge(context, writer);
  325. writer.close();
  326. logger.debug("模板:" + templatePath + "; 文件:" + outputFile);
  327. }
  328. /**
  329. * 设置模版引擎,主要指向获取模版路径
  330. */
  331. private VelocityEngine getVelocityEngine() {
  332. if (engine == null) {
  333. Properties p = new Properties();
  334. p.setProperty(ConstVal.VM_LOADPATH_KEY, ConstVal.VM_LOADPATH_VALUE);
  335. p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
  336. p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
  337. p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
  338. p.setProperty(Velocity.OUTPUT_ENCODING, ConstVal.UTF8);
  339. p.setProperty("file.resource.loader.unicode", "true");
  340. engine = new VelocityEngine(p);
  341. }
  342. return engine;
  343. }
  344. /**
  345. * 检测文件是否存在
  346. *
  347. * @return 是否
  348. */
  349. private boolean isCreate(String filePath) {
  350. File file = new File(filePath);
  351. return !file.exists() || config.getGlobalConfig().isFileOverride();
  352. }
  353. // ================================== 相关配置 ==================================
  354. /**
  355. * 初始化配置
  356. */
  357. protected void initConfig() {
  358. if (null == config) {
  359. config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
  360. if (null != injectionConfig) {
  361. injectionConfig.setConfig(config);
  362. }
  363. }
  364. }
  365. public DataSourceConfig getDataSource() {
  366. return dataSource;
  367. }
  368. public AutoGenerator setDataSource(DataSourceConfig dataSource) {
  369. this.dataSource = dataSource;
  370. return this;
  371. }
  372. public StrategyConfig getStrategy() {
  373. return strategy;
  374. }
  375. public AutoGenerator setStrategy(StrategyConfig strategy) {
  376. this.strategy = strategy;
  377. return this;
  378. }
  379. public PackageConfig getPackageInfo() {
  380. return packageInfo;
  381. }
  382. public AutoGenerator setPackageInfo(PackageConfig packageInfo) {
  383. this.packageInfo = packageInfo;
  384. return this;
  385. }
  386. public TemplateConfig getTemplate() {
  387. return template;
  388. }
  389. public AutoGenerator setTemplate(TemplateConfig template) {
  390. this.template = template;
  391. return this;
  392. }
  393. public ConfigBuilder getConfig() {
  394. return config;
  395. }
  396. public AutoGenerator setConfig(ConfigBuilder config) {
  397. this.config = config;
  398. return this;
  399. }
  400. public GlobalConfig getGlobalConfig() {
  401. return globalConfig;
  402. }
  403. public AutoGenerator setGlobalConfig(GlobalConfig globalConfig) {
  404. this.globalConfig = globalConfig;
  405. return this;
  406. }
  407. public InjectionConfig getCfg() {
  408. return injectionConfig;
  409. }
  410. public AutoGenerator setCfg(InjectionConfig injectionConfig) {
  411. this.injectionConfig = injectionConfig;
  412. return this;
  413. }
  414. }