從零搭建SpringBoot3一,手動編寫一套屬于自己風(fēng)格的代碼生成器一鍵生成系統(tǒng)

簡介

雖然 java 的代碼生成工具有很多,可是很多時候不是自己喜歡的風(fēng)格,改起來比較困難,所以我準(zhǔn)備從零和大家一起搭建一套基于 springboot3.0 的框架,
這次就先搞定一套代碼生成功能,后續(xù)再不斷的完善其它

我們使用到的三方庫:

  1. beelt 模版引擎,用于生成代碼。官網(wǎng):http://ibeetl.com
  2. mybatis-plug 官網(wǎng):https://www.baomidou.com/

開始

第一步,創(chuàng)建一個 maven 項(xiàng)目,然后在 pom.xml 中引入相關(guān)依賴,用到數(shù)據(jù)庫驅(qū)動,阿里的數(shù)據(jù)庫連接池等

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springboot-generate</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>20</maven.compiler.source>
        <maven.compiler.target>20</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
    </parent>

    <!-- Add typical dependencies for a web application -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.ibeetl/beetl -->
        <dependency>
            <groupId>com.ibeetl</groupId>
            <artifactId>beetl-springboot-starter-jdk17</artifactId>
            <version>3.15.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <!-- Package as an executable jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

第二步,在 java 文件夾下創(chuàng)建個包 com.light,并在下創(chuàng)建啟動入口 Application.java,注意不要直接在 java 下創(chuàng)建,代碼

@MapperScan("com.light.business.*.mapper") 
@EnableBeetl //會攔截.btl文件使用Beetl語法解析
@RestController
@SpringBootApplication
public class Application {
    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

第三步,去實(shí)現(xiàn)代碼生成,思路是通過一個頁面(這樣可視化,看起來更直觀)來展示可以生成的表,選擇后調(diào)用一個接口生成到項(xiàng)目中所以,我們先來個html用于展示表名以及操作
我們在 resouces 下創(chuàng)建 templates/generate/index.btl 文件,templates是缺省目錄,我們就直接用,而index.btl不用.html因?yàn)槲覀冇媚0逡妗?br> 可以看到,很簡單展示一下表名稱,然后可以選擇提交

<head>
    <meta charset="UTF-8">
    <title>代碼自動生成器</title>
</head>
<style>
    body {
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 25px;
    }
</style>
<body>
    <h1> 歡迎使用 Light 代碼一鍵生成器 </h1>
    <div style="min-width: 450px">
        <div>
            <input type="button" style="margin-right:45px" onclick="selectReverse()" value="反選">
            <input type="button" value="提交并生成代碼" onclick="document.tableForm.submit()">
        </div>
        <div style="margin-top: 12px;margin-bottom: 2px">
            <b>請選擇要生成的數(shù)據(jù)表:</b>
        </div>
        <form name="tableForm" method="post" action="index">
            <% 
                for(tableName in tableNames) { 
                    println("<input type='checkbox' name='table' value='" + tableName + "'>" + tableName + "<br>");
                }
            %>
        </form>
    </div>
    <script>
        function selectReverse() {
            let tables = document.getElementsByName("table");
            for (let table of tables) {
                table.checked = !table.checked;
            }
        }
    </script>
</body>

第四步,因?yàn)樯弦徊街行枰故颈砻詰?yīng)該要一個查詢表名稱的方法,我們在 com.light 下創(chuàng)建 common.generate.service.GenerateService.java,然后添加查詢表名的方法

@Autowired
private JdbcTemplate jdbcTemplate;

public List<String> getTableNames(String tableSchema) {
    String sql = "SELECT table_name as tableName FROM INFORMATION_SCHEMA.TABLES\n" +
            "WHERE table_schema = '" + tableSchema + "'";
    return jdbcTemplate.query(sql, new RowMapper<String>() {
        @Override
        public String mapRow(ResultSet resultSet, int i) throws SQLException {
            return resultSet.getString(1);
        }
    });
}

第五步,我們在 com.light 下創(chuàng)建common.generate.controller.GenerateController,來用于訪問,如果有選擇了表,就會調(diào)用生成功能

@Value("${spring.datasource.url}")
private String databaseUrl;
@Autowired
private GenerateService generateService;
//引入包的前綴
private static String comPath = "com.light.business";
//文件生成的路徑
private static String[] filePath = new String[]{ System.getProperty("user.dir"), "src", "main", "java", "com", "light", "business" };

@RequestMapping(value = "/index")
public ModelAndView index(String[] table) throws IOException {
    String schema = databaseUrl.substring(databaseUrl.lastIndexOf("/") + 1, databaseUrl.indexOf("?"));

    if (table != null) {
        generateService.generation(Util.addFileSeparator(filePath), comPath, schema, Arrays.asList(table));
    }

    ModelAndView view = new ModelAndView();
    view.setViewName("/generate/index.btl");
    view.addObject("tableNames", generateService.getTableNames(schema));
    return view;
}

第六步,可以看到核心就是 servicegeneration 方法,所以在 GenerateService.java 中添加方法

public void generation(String filePath, String comPath, String schema, List<String> tableNames) throws IOException {
    //我們在 resouces下創(chuàng)建個 beetl-back-end 用于放模板
    ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("beetl-back-end");
    Configuration cfg = Configuration.defaultConfiguration();
    //加載模板組
    GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
    //獲取表以及其字段等信息
    List<TableInfo> tableInfoList = getTableInfoList(schema, tableNames);

    System.out.println("generate start");
    for (TableInfo tableInfo: tableInfoList) {
        //生成PO...
        doPo(gt, tableInfo, comPath, filePath);
        doVo(gt, tableInfo, comPath, filePath);

        doMapperJava(gt, tableInfo, comPath, filePath);
        doMapperXml(gt, tableInfo, comPath, filePath);

        doService(gt, tableInfo, comPath, filePath);
        doController(gt, tableInfo, comPath, filePath);
    }
    System.out.println("generate over");
}

其它代碼就不貼出來了,開源的,可以自己到 github 上。

當(dāng)前可以生成 controller, service, mapjava, mapxml, PO, VO

思考

預(yù)留了根據(jù)注釋生成對應(yīng)字段的枚舉功能,因?yàn)檫€在思考如何才合理。那么是否還可以根據(jù)數(shù)據(jù)字段信息來生成校驗(yàn)功能呢?或者你認(rèn)為還有什么是需要生成的呢?然后我們再來繼續(xù)擴(kuò)展

使用

下載項(xiàng)目后,配置 application.yml 中的數(shù)據(jù)庫連接

1.png

啟動項(xiàng)目后在瀏覽器中輸入 http://localhost:8888/generate/index 即可訪問代碼生成入口,我們?nèi)x后點(diǎn)擊提交

2.png

然后就完成了,可以看到項(xiàng)目的 com.light 下創(chuàng)建了個 business 目錄,里面就是生成的代碼了,所有的功能就已經(jīng)完成了

3.png

如果添加表或修改了表,點(diǎn)擊需要的表重新生成即可,PO、VO等會覆蓋生成,具體在 com.light.common.generate.Config.java 中配置了

測試

由于我們從零開始創(chuàng)建的,所以還沒有 swagger 等等,postman 一個一個測試太慢了,所以我們這里借助前端自動生成功能來測試

由于前端是在線生成,所以訪問本地存在跨域問題,那們在本地我們先允許任何域訪問,在com.light.common下創(chuàng)建 config.CustomCorsConfiguration.java,簡單配置:

@Configuration
public class CustomCorsConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 放行哪些原始域
                .allowedOrigins("*")
                // 放行哪些請求方式
                .allowedMethods("*")
                // 放行哪些原始請求頭部信息
                .allowedHeaders("*");
    }
}

重啟項(xiàng)目

打開前端代碼生成器網(wǎng)站:https://light2f.com 到我的項(xiàng)目下,點(diǎn)擊 AI創(chuàng)建項(xiàng)目,輸入數(shù)據(jù)庫信息或者導(dǎo)入數(shù)據(jù)庫結(jié)構(gòu)

4.png

如果沒有配置過端口與path應(yīng)該輸入如下基本路徑信息。
后選擇或自動生成一套母版使用

5.png

由于我們springboot框架是從零搭建的,所以還沒有封裝 response,所以將模版修改紅框中數(shù)據(jù)為下面

6.png

直接確定生成

7.png

點(diǎn)擊剛剛生成的項(xiàng)目點(diǎn)擊眼睛進(jìn)入預(yù)覽

8.png

我們還沒有token與登錄,所以直接點(diǎn)擊右邊跳過

9.png

ok, 接口字段等已經(jīng)接入,可以測試了。

1.gif

總結(jié)

一個完成的從前到后功能已經(jīng)完成了,但是實(shí)際使用中會有安全問題、權(quán)限問題等等,那么我們那一期再完善一下 token 等,或者等小伙伴提需求
一起一步一步完善后繼搭建

地址

springboot-generate 開源地址:https://github.com/yangaijun/springboot-generate
前端在線生成網(wǎng)站:https://light2f.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容