SpringBoot+MyBatis-Plus+Velocity實現(xiàn)代碼自動生成
1. 前提條件
開發(fā)環(huán)境:
- Spring Boot 2.x
- MyBatis-Plus
- Lombok
- Swagger & Knife4j
- Velocity 模板引擎
- 數(shù)據(jù)庫(MySQL)
所需依賴:
在 pom.xml
中加入以下依賴:
<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis-Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> <!-- Swagger --> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> <version>1.6.0</version> </dependency> <!-- Knife4j --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-springdoc-ui</artifactId> <version>2.0.6</version> </dependency> <!-- Velocity --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.3</version> </dependency> </dependencies>
2. 代碼生成器設計
接下來我們創(chuàng)建一個 代碼生成器,該生成器能夠通過查詢數(shù)據(jù)庫的表信息并生成相應的代碼。
2.1 配置代碼生成器
在 CodeGenerator.java
中,編寫生成代碼的邏輯。主要是從數(shù)據(jù)庫讀取表結(jié)構(gòu)信息,并通過 Velocity 模板生成對應的實體類、Mapper、Service、Controller 等代碼。
package com.example.demo.generator; import java.sql.*; import java.util.*; public class CodeGenerator { public static void main(String[] args) { // 配置數(shù)據(jù)庫連接 String url = "jdbc:mysql://localhost:3306/your_database"; String username = "root"; String password = "password"; String database = "your_database"; String tableName = "your_table"; // 獲取表信息并生成代碼 Map<String, Object> tableInfo = getTableInfo(url, username, password, database, tableName); generateCode(tableInfo); } public static Map<String, Object> getTableInfo(String url, String username, String password, String database, String tableName) { Map<String, Object> map = new HashMap<>(); try (Connection conn = DriverManager.getConnection(url, username, password)) { // 查詢表注釋 String tableQuery = "SELECT table_comment FROM information_schema.tables WHERE table_schema = ? AND table_name = ?"; try (PreparedStatement ps = conn.prepareStatement(tableQuery)) { ps.setString(1, database); ps.setString(2, tableName); ResultSet rs = ps.executeQuery(); if (rs.next()) { map.put("tableComment", rs.getString("table_comment")); } } // 查詢字段信息 String columnQuery = "SELECT column_name, column_type, column_comment FROM information_schema.columns WHERE table_schema = ? AND table_name = ?"; List<Map<String, String>> columns = new ArrayList<>(); try (PreparedStatement ps = conn.prepareStatement(columnQuery)) { ps.setString(1, database); ps.setString(2, tableName); ResultSet rs = ps.executeQuery(); while (rs.next()) { Map<String, String> columnInfo = new HashMap<>(); columnInfo.put("columnName", rs.getString("column_name")); columnInfo.put("javaName", toCamelCase(rs.getString("column_name"))); // 轉(zhuǎn)換為 Java 變量名 columnInfo.put("javaType", sqlTypeToJavaType(rs.getString("column_type"))); // 轉(zhuǎn)換為 Java 類型 columnInfo.put("comment", rs.getString("column_comment")); columns.add(columnInfo); } } map.put("columns", columns); map.put("tableName", tableName); map.put("entityName", toCamelCase(tableName)); } catch (SQLException e) { e.printStackTrace(); } return map; } private static String sqlTypeToJavaType(String sqlType) { sqlType = sqlType.toLowerCase(); if (sqlType.contains("int")) { return "Integer"; } else if (sqlType.contains("bigint")) { return "Long"; } else if (sqlType.contains("char") || sqlType.contains("text") || sqlType.contains("varchar")) { return "String"; } else if (sqlType.contains("datetime") || sqlType.contains("timestamp")) { return "LocalDateTime"; } else if (sqlType.contains("date")) { return "LocalDate"; } else if (sqlType.contains("decimal") || sqlType.contains("double")) { return "BigDecimal"; } else { return "String"; } } private static String toCamelCase(String name) { StringBuilder result = new StringBuilder(); String[] parts = name.split("_"); for (int i = 0; i < parts.length; i++) { if (i == 0) { result.append(parts[i].toLowerCase()); } else { result.append(Character.toUpperCase(parts[i].charAt(0))).append(parts[i].substring(1).toLowerCase()); } } return result.toString(); } private static void generateCode(Map<String, Object> tableInfo) { // 讀取表信息 String entityName = (String) tableInfo.get("entityName"); String tableName = (String) tableInfo.get("tableName"); String tableComment = (String) tableInfo.get("tableComment"); List<Map<String, String>> columns = (List<Map<String, String>>) tableInfo.get("columns"); // 設置 Velocity 配置 VelocityEngine velocityEngine = new VelocityEngine(); velocityEngine.init(); // 配置模板目錄 String templateDir = "path/to/your/templates"; // 模板文件的路徑 // 設置輸出目錄 String outputDir = "path/to/output"; // 輸出的代碼文件夾路徑 // 創(chuàng)建 Velocity 上下文 VelocityContext context = new VelocityContext(); context.put("package", "com.example"); // 設置包路徑 context.put("entityName", entityName); context.put("tableName", tableName); context.put("tableComment", tableComment); context.put("columns", columns); // 生成 Entity 文件 generateFile(velocityEngine, context, templateDir, "entity.vm", outputDir + "/entity/" + entityName + ".java"); // 生成 Mapper 文件 generateFile(velocityEngine, context, templateDir, "mapper.vm", outputDir + "/mapper/" + entityName + "Mapper.java"); // 生成 Service 接口文件 generateFile(velocityEngine, context, templateDir, "service.vm", outputDir + "/service/" + entityName + "Service.java"); // 生成 ServiceImpl 文件 generateFile(velocityEngine, context, templateDir, "serviceImpl.vm", outputDir + "/service/impl/" + entityName + "ServiceImpl.java"); // 生成 Controller 文件 generateFile(velocityEngine, context, templateDir, "controller.vm", outputDir + "/controller/" + entityName + "Controller.java"); } private static void generateFile(VelocityEngine velocityEngine, VelocityContext context, String templateDir, String templateName, String outputFilePath) { // 獲取模板 Template template = velocityEngine.getTemplate(templateDir + "/" + templateName); // 創(chuàng)建文件輸出流 try (FileWriter writer = new FileWriter(outputFilePath)) { // 將上下文數(shù)據(jù)渲染到模板中 template.merge(context, writer); } catch (IOException e) { e.printStackTrace(); } } }
2.2 Velocity 模板
Entity 模板(entity.vm)
package ${package.Entity}; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; import java.math.BigDecimal; @Data @TableName("${tableName}") @ApiModel(value = "${entityName} 實體") public class ${entityName} implements Serializable { private static final long serialVersionUID = 1L; @TableId @ApiModelProperty("主鍵ID") private Long id; #foreach ($column in $columns) @ApiModelProperty("${column.comment}") private ${column.javaType} ${column.javaName}; #end }
Mapper 模板(mapper.vm)
package ${package.Mapper}; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import ${package.Entity}.${entityName}; import org.apache.ibatis.annotations.Mapper; @Mapper public interface ${entityName}Mapper extends BaseMapper<${entityName}> { }
Service 模板(service.vm)
package ${package.Service}; import ${package.Entity}.${entityName}; import com.baomidou.mybatisplus.extension.service.IService; public interface ${entityName}Service extends IService<${entityName}> { }
ServiceImpl 模板(serviceImpl.vm)
package ${package.ServiceImpl}; import ${package.Entity}.${entityName}; import ${package.Mapper}.${entityName}Mapper; import ${package.Service}.${entityName}Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; @Service public class ${entityName}ServiceImpl extends ServiceImpl<${entityName}Mapper, ${entityName}> implements ${entityName}Service { }
Controller 模板(controller.vm)
package ${package.Controller}; import ${package.Entity}.${entityName}; import ${package.Service}.${entityName}Service; import org.springframework.web.bind.annotation.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import javax.annotation.Resource; import java.util.List; @RestController @RequestMapping("/${tableName}") @Api(tags = "${tableComment}") public class ${entityName}Controller { @Resource private ${entityName}Service service; @GetMapping("/list") @ApiOperation("獲取所有 ${tableComment}") public List<${entityName}> list() { return service.list(); } @PostMapping("/add") @ApiOperation("新增 ${tableComment}") public boolean add(@RequestBody ${entityName} entity) { return service.save(entity); } @PutMapping("/update") @ApiOperation("更新 ${tableComment}") public boolean update(@RequestBody ${entityName} entity) { return service.updateById(entity); } @DeleteMapping("/delete/{id}") @ApiOperation("刪除 ${tableComment}") public boolean delete(@PathVariable Long id) { return service.removeById(id); } }
3. 運行生成代碼
- 啟動 Spring Boot 項目,配置好數(shù)據(jù)庫連接。
- 運行
CodeGenerator.java
,自動從數(shù)據(jù)庫中讀取表信息,并生成相應的代碼。 - 查看生成的代碼:
- 實體類:包含數(shù)據(jù)庫表字段的實體類代碼。
- Mapper、Service、ServiceImpl、Controller:自動生成增刪改查接口和實現(xiàn)。
4. 測試接口
啟動項目后,使用 Swagger UI 進行接口測試。訪問 http://localhost:8080/doc.html
可以看到自動生成的接口文檔,通過 Swagger 的 UI 直接進行增刪改查操作。
5. 總結(jié)
通過本教程,我們利用 Spring Boot、MyBatis-Plus 和 Velocity 模板引擎 實現(xiàn)了一個自動化的代碼生成器,能夠根據(jù)數(shù)據(jù)庫表結(jié)構(gòu)自動生成增刪改查操作的代碼,并且集成了 Lombok、Swagger 和 Knife4j,極大地提高了開發(fā)效率。
到此這篇關(guān)于SpringBoot+MyBatis-Plus+Velocity實現(xiàn)代碼自動生成的文章就介紹到這了,更多相關(guān)SpringBoot MyBatisPlus 代碼自動生成內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot如何使用MyBatisPlus逆向工程自動生成代碼
- SpringBoot集成Mybatis-plus并實現(xiàn)自動生成相關(guān)文件的示例代碼
- Springboot Mybatis Plus自動生成工具類詳解代碼
- SpringBoot項目使用mybatis-plus逆向自動生成全套代碼
- SpringBoot整合Mybatis Generator自動生成代碼
- SpringBoot根據(jù)目錄結(jié)構(gòu)自動生成路由前綴的實現(xiàn)代碼
- springboot整合freemarker代碼自動生成器
- SpringBoot整合screw實現(xiàn)數(shù)據(jù)庫文檔自動生成的示例代碼
- springboot 通過代碼自動生成pid的方法
相關(guān)文章
elasticsearch的靈魂唯一master選舉機制原理分析
這篇文章主要為大家介紹了elasticsearch的靈魂唯一master選舉機制原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04java線程中synchronized和Lock區(qū)別及介紹
這篇文章主要為大家介紹了java線程中synchronized和Lock區(qū)別及介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06Spring?Boot整合Kafka+SSE實現(xiàn)實時數(shù)據(jù)展示
本文主要介紹了Spring?Boot整合Kafka+SSE實現(xiàn)實時數(shù)據(jù)展示2024-06-06Java高并發(fā)編程之CAS實現(xiàn)無鎖隊列代碼實例
這篇文章主要介紹了Java高并發(fā)編程之CAS實現(xiàn)無鎖隊列代碼實例,在多線程操作中,我們通常會添加鎖來保證線程的安全,那么這樣勢必會影響程序的性能,那么為了解決這一問題,于是就有了在無鎖操作的情況下依然能夠保證線程的安全,需要的朋友可以參考下2023-12-12java實現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法
這篇文章主要介紹了java實現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法,涉及java調(diào)用新浪微博Oauth接口的使用技巧,具有一定參考接借鑒價值,需要的朋友可以參考下2015-07-07Java調(diào)用Python腳本傳遞數(shù)據(jù)并返回計算結(jié)果
實際工程項目中可能會用到Java和python兩種語言結(jié)合進行,這樣就會涉及到一個問題,Java如何調(diào)用Python腳本,感興趣的可以了解一下2021-05-05scala 隱式轉(zhuǎn)換與隱式參數(shù)的使用方法
這篇文章主要介紹了scala 隱式轉(zhuǎn)換與隱式參數(shù)的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11