一键生成代码

天行健,君子以自强不息;地势坤,君子以厚德载物。


每个人都有惰性,但不断学习是好好生活的根本,共勉!


文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。

一键生成代码

  • 功能简介
  • 开发环境:
  • 实现
    • 1. 项目包结构预览
    • 2. 完整依赖
    • 3. 配置文件
    • 4. 项目启动类
    • 5. jdbc参数读取配置文件
    • 6. 代码模板配置文件(文本文件)
    • 7. 代码生成工具类代码
      • 7.1 文件IO工具
      • 7.2 生成代码注释及引入配置
      • 7.3 代码生成工具类
      • 7.4 对象实体类属性校验工具
      • 7.5 结果返回工具
    • 8. 请求控制类
    • 9. 请求调用
      • 9.1 url
      • 9.2 postman截图
      • 9.3 控制台打印
      • 9.4 生成的代码文件截图
  • 拓展:


功能简介

想不想一次性生成增删改查所需的所有代码(包括请求类controller)?我也想啊!
最近在学习研究自动生成代码的一些方法,学到了一些新的东西,好不好用自己试过才知道,但自己用着的确还可以,分享一下。
大家都知道mybatis框架中有一个插件可生成代码,但生成的代码比较局限,很多地方需要修改。接下来的内容就是在其基础上通过配置来更简单的实现生成更完善的代码的功能,也就是最少修改甚至不修改即可用的一键生成代码工具。


开发环境:

JDK版本:1.8
maven版本:3.9.0
开发工具:IDEA社区版ideaIC-2018.3
项目框架:spring boot 版本为 2.7.3 springboot搭建传送门

实现

1. 项目包结构预览

包结构需要创建的就是com.code下的config包、controller包、utils包
code_package包是自动创建的,用来存放生成代码的包,可在代码中定义
这里需要注意的是,utils包最好是按照我这个来,且不管你utils包在哪里,都希望你能把utils包里的这几个文件放在utils包里,当然也可以不,只需根据参数进行修改代码或模板即可,具体看自己了。
在这里插入图片描述

2. 完整依赖

pom.xml

<?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>com.code</groupId>
    <artifactId>code_ge_demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!--spring boot 父依赖 版本管理-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>
    <dependencies>
        <!--spring boot web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring boot test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--mysql 连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc连接 使用jdbc依赖时或者jpa依赖时默认注入事物管理,不需任何配置,可直接使用@Transactional注解进行事物管理-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.13</version>
        </dependency>
        <!--mybatis plugin-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.2</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--不可用-->
<!--        <dependency>-->
<!--            <groupId>com.github.pagehelper</groupId>-->
<!--            <artifactId>pagehelper-spring-boot</artifactId>-->
<!--            <version>1.3.0</version>-->
<!--        </dependency>-->
        <!--分页-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.3.2</version>
        </dependency>
        <!--json工具-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.32</version>
        </dependency>
    </dependencies>

</project>

3. 配置文件

application.yml

spring:
  profiles:
    active: dev
  application:
    name: code_ge

application-dev.yml

server:
  port: 9001

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/database_1?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

4. 项目启动类

CodeGeApplication.java

package com.code;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @ClassDescription: 
 * @Author:李白
 * @Date:2023/6/7 13:31
 */
@SpringBootApplication
public class CodeGeApplication {
    public static void main(String[] args) {
        SpringApplication.run(CodeGeApplication.class, args);
    }
}

5. jdbc参数读取配置文件

通过配置文件读取yml中的jdbc连接参数(@Value注解读取)
注解读取参数方法请见文章末尾拓展
JdbcConfig.java

package com.code.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassDescription: jdbc数据库连接参数读取
 * @Author:李白
 * @Date:2023/6/06 16:54
 */
@Component
public class JdbcConfig {
    @Value("${spring.datasource.url}")
    public String url;
    @Value("${spring.datasource.username}")
    public String username;
    @Value("${spring.datasource.password}")
    public String password;
    @Value("${spring.datasource.driver-class-name}")
    public String driver_class_name;
}

6. 代码模板配置文件(文本文件)

生成代码的mapper模板,会根据此文件生成对象实体、接口实现类、数据操作映射接口、数据操作映射文件,共四个文件。
CodeGeTemMapper.txt

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <plugin type="org.mybatis.generator.plugins.RenameExampleClassPlugin">
            <property name="searchString" value="Example$"/>
            <property name="replaceString" value="Impl"/>
        </plugin>
        <commentGenerator type="@CommentGenerator@"/>
        <jdbcConnection driverClass="@driverClassName@"
                        connectionURL="@url@"
                        userId="@username@"
                        password="@password@">

            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>
        <javaModelGenerator targetPackage="@codePackage@" targetProject="src/main/java"/>
        <sqlMapGenerator targetPackage="@codePackage@" targetProject="src/main/java"/>
        <javaClientGenerator type="XMLMAPPER" targetPackage="@codePackage@" targetProject="src/main/java"/>
        <table tableName="@tableName@">
            <generatedKey column="id" sqlStatement="MySql" identity="true"/>
        </table>
    </context>
</generatorConfiguration>

生成代码的controller模板,会根据此文件生成controller请求类,共一个文件。
CodeGeTemController.txt

package @codePath@;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import @codePath@.TestJwhGenerateCode;
import @codePath@.TestJwhGenerateCodeImpl;
import @codePath@.TestJwhGenerateCodeMapper;
import @utilPath@.*;
import @utilPath@.ResultJsonObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

@RestController
@EnableAutoConfiguration
@RequestMapping("/test-jwh-url")
public class TestJwhGenerateCodeController {

    @Autowired
    TestJwhGenerateCodeMapper testJwhGenerateCodeMapper;

    /**
     * 新增数据
     * @param body 数据json
     * @return
     * @throws Exception
     */
    @CrossOrigin
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping(value = "/insert", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResultJsonObject insert(@RequestBody JSONObject body) throws Exception {

        if (!body.containsKey("records"))
            throw new Exception("请求体中无此key:records");

        JSONArray records = body.getJSONArray("records");

        for (int n = 0; n < records.size(); n++) {
            JSONObject record = records.getJSONObject(n);
            JSONObject validateInfo = ClazzValidateUtil.clazzValidate(record,TestJwhGenerateCode.class);
            Boolean validateResult = (Boolean) validateInfo.get("clazzValidateResult");

            if (!validateResult) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new Exception("数据不符合类的格式,info信息:"+validateInfo.get("info"));
            }

            TestJwhGenerateCode testJwhGenerateCode = JSON.parseObject(JSON.toJSONString(record), TestJwhGenerateCode.class);

            testJwhGenerateCodeMapper.insert(testJwhGenerateCode);
        }
        return new ResultJsonObject("success:数据插入成功",200);
    }

    /**
     * 根据id查询数据
     * @param body 数据json
     * @return
     * @throws Exception
     */
    @CrossOrigin
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping(value = "/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResultJsonObject delete(@RequestBody JSONObject body) throws Exception {

        if (!body.containsKey("records"))
            throw new Exception("请求体中无此key:records");

        JSONArray records = body.getJSONArray("records");

        for (int i = 0; i < records.size(); i++) {
            JSONObject record = records.getJSONObject(i);
            JSONObject validateInfo = ClazzValidateUtil.clazzValidate(record,TestJwhGenerateCode.class);
            Boolean validateResult = (Boolean) validateInfo.get("clazzValidateResult");

            if (!validateResult) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new Exception("数据不符合类的格式,info信息:"+validateInfo.get("info"));
            }

            if (!record.containsKey("id")) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new Exception("数据无此查询条件:id");
            }


            TestJwhGenerateCode testJwhGenerateCode = JSON.parseObject(JSON.toJSONString(record), TestJwhGenerateCode.class);

            testJwhGenerateCodeMapper.deleteByPrimaryKey(testJwhGenerateCode.getId());
        }
        return new ResultJsonObject("success:数据删除成功",200);
    }

    /**
     * 更新数据
     * @param body 数据json
     * @return
     * @throws Exception
     */
    @CrossOrigin
    @RequestMapping(value = "/update", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResultJsonObject update(@RequestBody JSONObject body) throws Exception {

        // update record by primary key id
        if (!body.containsKey("records"))
            throw new Exception("请求体中无此key:records");

        JSONArray records = body.getJSONArray("records");

        for (int n = 0; n < records.size(); n++) {
            JSONObject record = records.getJSONObject(n);
            JSONObject validateInfo = ClazzValidateUtil.clazzValidate(record,TestJwhGenerateCode.class);
            Boolean validateResult = (Boolean) validateInfo.get("clazzValidateResult");

            if (!validateResult) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new Exception("数据不符合类的格式,info信息:"+validateInfo.get("info"));
            }

            if (!record.containsKey("id")) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new Exception("数据无此查询条件:id");
            }

            // 修改的数据
            TestJwhGenerateCode testJwhGenerateCode = record.toJavaObject(TestJwhGenerateCode.class);
            testJwhGenerateCodeMapper.updateByPrimaryKeySelective(testJwhGenerateCode);
        }
        return new ResultJsonObject("success:数据更新成功",200);
    }

    /**
     * 查询数据
     * @param body 数据json
     * @return
     * @throws Exception
     */
    @CrossOrigin
    @RequestMapping(value = "/list", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResultJsonObject list(@RequestBody JSONObject body) throws Exception {

        if (!body.containsKey("criteria"))
            throw new Exception("无查询条件key:criteria");

        if (!body.containsKey("pageNum"))
            throw new Exception("无分页页数key:pageNum");

        if (!body.containsKey("pageSize"))
            throw new Exception("无分页每页数量key:pageSize");

        TestJwhGenerateCodeImpl testJwhGenerateCodeImpl = new TestJwhGenerateCodeImpl();
        TestJwhGenerateCodeImpl.Criteria criteria = testJwhGenerateCodeImpl.createCriteria();
        JSONArray criList = body.getJSONArray("criteria");

        for (int i = 0; i < criList.size(); i++) {
            JSONObject cri = criList.getJSONObject(i);
            Map.Entry<String, String> maps = (Map.Entry<String, String>) cri.entrySet();
            //addCriterion的参数有三种情况
//            criteria.addCriterion("condition");
//            criteria.addCriterion(maps.getKey()+"=");

//            criteria.addCriterion(condition,value,property);
            criteria.addCriterion(maps.getKey()+"=",maps.getValue(),maps.getKey());

//            criteria.addCriterion(condition,value1,value2,property);
//            criteria.addCriterion("id not between","3","5","id");
        }

        PageHelper.startPage(body.getIntValue("pageNum"), body.getIntValue("pageSize"));
        PageInfo<TestJwhGenerateCode> pageInfo = new PageInfo<>(testJwhGenerateCodeMapper.selectByExample(testJwhGenerateCodeImpl));

        JSONObject retObject = new JSONObject();
        retObject.put("pageInfo", pageInfo);
        return new ResultJsonObject("success:数据查询成功",200);

    }

}

7. 代码生成工具类代码

首先看主要的代码生成工具,也就是除去生成controller之外的代码。有三个工具类:文件输入输出流工具FileUtil.java、生成代码注释工具CommentGenerator.java、生成代码工具CodeUtil.java。

7.1 文件IO工具

在生成代码文件时需读取文本文件内容及生成文件需要用到文件读写工具。
FileIoUtil.java

package com.code.utils;

import java.io.*;

/**
 * @ClassDescription: 文件读写流工具 读和写
 * @Author:李白
 * @Date:2023/6/06 18:22
 */

public class FileIoUtil {
    /**
     * 将字符串内容写入指定文件中
     * @param filePath 文件的绝对路径,如 c:/files/student.text
     * @param content
     * @throws IOException
     */
    public static void writeStringToFile(String filePath, String content) throws IOException {
        File file = new File(filePath);
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        Writer out = new FileWriter(file);
        out.write(content);
        out.close();
    }

    /**
     * 将文件中的内容读取成字符串返回
     * @param filePath
     * @return
     * @throws IOException
     */
    public static String readFileAsString(String filePath) throws IOException {
        File file = new File(filePath);
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        StringBuilder stringBuilder = new StringBuilder();
        String s = "";
        while ((s = bufferedReader.readLine()) != null){
            stringBuilder.append(s).append("\n");
        }
        bufferedReader.close();
        return stringBuilder.toString();
    }

}

7.2 生成代码注释及引入配置

对生成的代码文件中的内容新增注释或关闭多余注释,新增引入的类等。
CommentGenerator.java

package com.code.utils;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

/**
 * @ClassDescription: 根据数据库表生成代码(注释部分--增加或者取消注释)
 * @Author:李白
 * @Date:2023/6/06 14:56
 */
public class CommentGenerator extends DefaultCommentGenerator {
    private Properties properties;
    private boolean suppressDate;
    private boolean suppressAllComments;

    public CommentGenerator(){
        this.properties = new Properties();
        this.suppressDate = false;
        this.suppressAllComments = false;
    }

    /**
     * 生成代码文件顶端注释以及接口和类注解引入
     * @param compilationUnit
     */
    public void addJavaFileComment(CompilationUnit compilationUnit){
        compilationUnit.addFileCommentLine("/**\n * copyright (c) 2023 HanShan \n */");
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String geTime = simpleDateFormat.format(date);
        compilationUnit.addFileCommentLine(String.format("/**\n * version: 1.0.0 \n * generate time: %s \n */", geTime));

        if (compilationUnit instanceof Interface){
            Interface interfaces = (Interface) compilationUnit;
            interfaces.addJavaDocLine("import org.apache.ibatis.annotations.Mapper;");
            interfaces.addJavaDocLine("@Mapper");
        }else {
            TopLevelClass topLevelClass = (TopLevelClass) compilationUnit;
            if (topLevelClass.getType().toString().endsWith("Impl")){
                topLevelClass.addJavaDocLine("import org.springframework.stereotype.Service;");
                topLevelClass.addJavaDocLine("@Service");
            }
        }
    }

    /**
     * XML file Comment
     * @param xmlElement
     */
    public void addComment(XmlElement xmlElement){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * 时间注释关闭
     * @param field
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn){
        if (this.suppressAllComments){
            return;
        }
        if (introspectedColumn.getJdbcTypeName().equals("TIMESTAMP")){
            field.addJavaDocLine("@DateTimeFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")");
            field.addJavaDocLine("@JsonFormat(shape=JsonFormat.Shape.STRING, pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")");
        }
    }

    /**
     * 属性注释关闭 Comment of Example field
     * @param field the field
     * @param introspectedTable the introspected table
     */
    public void addFieldComment(Field field, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * java对象注释配置
     * @param topLevelClass the top level class
     * @param introspectedTable the introspected table
     */
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
        topLevelClass.addJavaDocLine("import lombok.Data;");
        topLevelClass.addJavaDocLine("import org.springframework.stereotype.Component;");
        topLevelClass.addJavaDocLine("@Data");
        topLevelClass.addJavaDocLine("@Component");
    }

    public void addClassComment(InnerInterface innerInterface, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * 类注释关闭 Comment of Example inner class(GeneratedCriteria, Criterion)
     * @param innerClass the inner class
     * @param introspectedTable the introspected table
     */
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * enum注释关闭
     * @param innerEnum
     * @param introspectedTable
     */
    public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * 方法注释关闭
     * @param method
     * @param introspectedTable
     */
    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * getter注释关闭
     * @param method
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn){
        if (this.suppressAllComments){
            return;
        }
    }

    /**
     * setter注释关闭
     * @param method
     * @param introspectedTable
     * @param introspectedColumn
     */
    public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn){
        if (this.suppressAllComments){
            return;
        }
    }

}

7.3 代码生成工具类

生成代码需要调用的方法。
CodeUtil.java

package com.code.utils;

import com.code.config.JdbcConfig;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
import java.sql.SQLException;
import java.util.*;

/**
 * @ClassDescription:  代码自动生成工具(entity、mapper.java、impl、mapper.xml)
 * @Author:李白
 * @Date:2023/6/6 12:44
 */
@Component
public class CodeUtil {

    @Autowired
    JdbcConfig jdbcConfig;

    private static JdbcConfig geJdbcCfg;

    @PostConstruct
    public void init(){
        geJdbcCfg = jdbcConfig;
    }

    /**
     * 代码生成总方法
     * @param tablesPackages map形式存放表和包路径(可多个)
     * @param utilPackage 工具类包路径(生成代码中的引入参数等相关)
     * @throws XMLParserException
     * @throws SQLException
     * @throws IOException
     * @throws InterruptedException
     * @throws InvalidConfigurationException
     */
    public static void CodeGe(HashMap<String, String> tablesPackages, String utilPackage) throws XMLParserException, SQLException, IOException, InterruptedException, InvalidConfigurationException {
        //遍历集合,拿到表名和包路径
        for (Map.Entry<String,String> tbPc : tablesPackages.entrySet()){
            //获取表名 如 test_jwh_generate_code
            String tableName = tbPc.getKey();
            //获取代码存放包路径 如 com.code.code_package
            String codePackage = tbPc.getValue();
            //实体类对象名为表名的首字母大写后续每个短杠后的字母大写 如 TestJwhGenerateCode
            String modelName = Arrays.stream(tableName.split("_")).map(el -> {
                String elx = el;
                return elx.substring(0,1).toUpperCase()+elx.substring(1);
            }).reduce((x,y)->x+y).map(Objects::toString).orElse("");

            //对象变量名 如 testJwhGenerateCode
            String objectName = modelName.substring(0,1).toLowerCase()+modelName.substring(1);

            //生成mapper.xml(数据映射文件) mapper.java(映射接口) impl(接口实现类) model(对象实体类)
            createMapper(geJdbcCfg, codePackage,utilPackage, tableName);
            //生成controller
            createController(codePackage, utilPackage, modelName, objectName);
            //修改生成文件 新增truncate (接口文件)
            modifyJavaMapper(codePackage, modelName);
            //修改生成文件 新增truncate (xml mapper)
            modifyXmlMapper(codePackage, modelName, tableName);
        }
    }

    /**
     * model_service_mapper文件的生成(四个:实体类,xml映射文件,映射文件接口,接口实现类)
     * 注意事项:在对应的CodeGenerateConfig_Mapper.txt文件中的jdbcConnection位置,driverClassName和url必须放在前两个为位置,不然会解析报错
     * @param jdbcConfig jdbc配置文件参数类
     * @param codePackage 代码存储位置
     * @param tableName 表名
     * @throws IOException
     * @throws XMLParserException
     * @throws InvalidConfigurationException
     * @throws SQLException
     * @throws InterruptedException
     */
    public static void createMapper(JdbcConfig jdbcConfig, String codePackage, String utilsPackage, String tableName) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        //读取文本文件(mapper.xml的模板)
        String rawConfig = FileIoUtil.readFileAsString("src/main/resources/CodeGeTemMapper.txt");
        //jdbc用户名替换
        rawConfig = rawConfig.replace("@username@", jdbcConfig.username);
        //jdbc密码替换
        rawConfig = rawConfig.replace("@password@", jdbcConfig.password);
        //jdbc url替换
        rawConfig = rawConfig.replace("@url@", jdbcConfig.url.replace("&","&amp;"));
        //jdbc 驱动替换
        rawConfig = rawConfig.replace("@driverClassName@", jdbcConfig.driver_class_name);
        //存放生成代码的包的路径
        rawConfig = rawConfig.replace("@codePackage@", codePackage);
        //所生成代码的表名
        rawConfig = rawConfig.replace("@tableName@", tableName);
        //生成器参数配置文件的位置参数替换,放在工具类里,则和创建controller函数中的参数一致,如果没有放在utils包中,则需要自行修改这个包路径
        rawConfig = rawConfig.replace("@CommentGenerator@", utilsPackage+".CommentGenerator");
        List<String> warnings = new ArrayList<>();
        InputStream inputStream = new ByteArrayInputStream(rawConfig.getBytes());
        ConfigurationParser configurationParser = new ConfigurationParser(warnings);
        Configuration configuration = configurationParser.parseConfiguration(inputStream);
        inputStream.close();
        DefaultShellCallback defaultShellCallback = new DefaultShellCallback(true);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, defaultShellCallback, warnings);
        myBatisGenerator.generate(null);
        for (String warning : warnings){
            System.out.println(warning);
        }
    }

    /**
     * Controller.java 文件创建
     * @param codePackage 代码存储位置
     * @param modelName 对象名
     * @param objectName 对象变量名
     * @throws IOException
     */
    public static void createController(String codePackage, String modelName, String objectName) throws IOException {
        String content = FileIoUtil.readFileAsString("src/main/resources/CodeGeTemController.txt");
        content = content.replace("@codePath@", codePackage);
        content = content.replace("TestJwhGenerateCode", modelName);
        content = content.replace("testJwhGenerateCode",objectName);
//        content = content.replace("test-jwh-url", UUID.randomUUID().toString());

        String controllerPath = String.format("src/main/java/%s/%s", codePackage.replace(".", "/"), modelName+"Controller.java");
        FileIoUtil.writeStringToFile(controllerPath, content);
    }

    /**
     * Controller.java 文件创建
     * @param codePackage 代码存储位置
     * @param utilPackage 工具类所在位置
     * @param modelName 对象名
     * @param objectName 对象变量名
     * @throws IOException
     */
    public static void createController(String codePackage, String utilPackage, String modelName, String objectName) throws IOException {
        String content = FileIoUtil.readFileAsString("src/main/resources/CodeGeTemController.txt");
        content = content.replace("@codePath@", codePackage);
        content = content.replace("@utilPath@", utilPackage);
        content = content.replace("TestJwhGenerateCode", modelName);
        content = content.replace("testJwhGenerateCode",objectName);
//        content = content.replace("test-jwh-url", UUID.randomUUID().toString());

        String controllerPath = String.format("src/main/java/%s/%s", codePackage.replace(".", "/"), modelName+"Controller.java");
        FileIoUtil.writeStringToFile(controllerPath, content);
    }

    /**
     * Mapper.java文件 修改
     * @param codePackage 代码存储位置
     * @param modelName 对象名
     * @throws IOException
     */
    public static void modifyJavaMapper(String codePackage, String modelName) throws IOException {
        String mapperPath = String.format("scr/main/java/%s/%s", codePackage.replace(".", "/"), modelName+"Mapper.java");
        try {
            File file = new File(mapperPath);
            FileReader fileReader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            StringBuilder stringBuilder = new StringBuilder();
            String line = "";
            while((line = bufferedReader.readLine()) != null){
                stringBuilder.append(line).append("\n");
                if (line.indexOf("updateByPrimaryKey(")>0){
                    stringBuilder.append("\n    void truncate();\n\n");
                }
            }
            bufferedReader.close();
            FileIoUtil.writeStringToFile(mapperPath, stringBuilder.toString());
        }catch (FileNotFoundException fileNotFoundException){
//            fileNotFoundException.printStackTrace();
            System.out.println("这里会出现Mapper.java文件的“系统找不到指定的路径“错误,但不影响代码生成的位置,所以抓取错误不打印----->");
        }
    }

    /**
     * Mapper.xml文件 修改
     * @param codePackage 代码存储位置
     * @param modelName 对象名
     * @param tableName 表名
     * @throws IOException
     */
    public static void modifyXmlMapper(String codePackage, String modelName, String tableName) throws IOException {
        String mapperPath = String.format("scr/main/java/%s/%s", codePackage.replace(".", "/"), modelName+"Mapper.xml");
        try {
            File file = new File(mapperPath);
            FileReader fileReader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            StringBuilder stringBuilder = new StringBuilder();
            String line = "";
            while ((line = bufferedReader.readLine()) != null){
                if (line.indexOf("/mapper")>0){
                    stringBuilder.append("  <update id=\"truncateTable\">TRUNCATE TABLE " + tableName + "</update>\n");
                }
                stringBuilder.append(line).append("\n");
            }
            bufferedReader.close();
            FileIoUtil.writeStringToFile(mapperPath, stringBuilder.toString());
        }catch (FileNotFoundException fileNotFoundException){
            System.out.println("这里会出现Mapper.xml文件的“系统找不到指定的路径“错误,但不影响代码生成的位置,所以抓取错误不打印----->");
        }
    }

}

然后是两个关于controller文件内容引入的工具类,类校验工具ClazzValidateUtil.java,结果返回工具ResultJsonObject.java,当然了,这两个东西也可以不用,特别是结果返回这个,如果觉得没必要,可以自己写,或者干脆不写也可。如果不要这个记得去模板里把controller的模板文件中的对应的内容剔除或修改。

7.4 对象实体类属性校验工具

主要对传入的对象参数进行校验,如果不满足条件则返回对应的提示结果。
ClazzValidateUtil.java

package com.code.utils;

import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassDescription: 对象校验工具
 * @Author:李白
 * @Date:2023/6/8 10:34
 */
public class ClazzValidateUtil {
    /**
     * 检验json对象(可包含多个内容)内容是否符合class对象内容
     * @param jsonObject 需要校验的json对象
     * @param clazz 需要匹配的参照对象
     * @return
     */
    public static JSONObject clazzValidate(JSONObject jsonObject, Class<?> clazz){
        JSONObject result = new JSONObject();
        Boolean clazzValidateResult = true;
        result.put("clazzValidateResult",clazzValidateResult);
        Field[] fields = clazz.getDeclaredFields();
        List<String> segments = Arrays.stream(fields).map(s->s.getName()).collect(Collectors.toList());
                List<String> errorKeys = new ArrayList<>();
        for (Object key : jsonObject.keySet()) {
            if (!segments.contains(key)){
                result.put("clazzValidateResult",false);
                result.put("errorKeys",errorKeys.add((String) key));
            }
        }
        result.put("info",errorKeys.stream().distinct().reduce((x,y)->x+", "+y).map(Object::toString).orElse(""));
        return result;

    }
}

7.5 结果返回工具

主要是方便返回固定格式的json结果
ResultJsonObject.java

package com.code.utils;

import org.springframework.stereotype.Component;

/**
 * @ClassDescription: 结果返回工具类
 * @Author:李白
 * @Date:2023/6/8 9:58
 */
@Component
public class ResultJsonObject {
    private String msg;
    private Integer code;

    public ResultJsonObject() {
    }

    public ResultJsonObject(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

8. 请求控制类

将表名和代码存放的包路径以键值形式存入map中作为参数,再将工具类的包路径作为参数参数传入
通过此请求调用函数进行代码生成。
CodeGeTestController.java

package com.code.controller;

import com.code.utils.CodeUtil;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;

/**
 * @ClassDescription: 生成代码 请求
 * @Author:李白
 * @Date:2023/6/6 12:42
 */
@RestController
//@EnableAutoConfiguration
@RequestMapping("/code")
public class CodeGeTestController {

    @RequestMapping(value = "/url", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String code() throws XMLParserException, SQLException, IOException, InterruptedException, InvalidConfigurationException {
        //创建集合存储数据
        HashMap<String, String> tablePackage = new HashMap<>();
        //将表名与代码存储位置路径以键值对形式存入(可多个)
//        tablePackage.put("test_jwh_generate_code1","com.code.code_package1");
        tablePackage.put("test_jwh_generate_code","com.code.code_package");
        //调用函数传入参数,集合与工具类包路径(包路径中的utils里有生成的controller中需要用到的代码)
        CodeUtil.CodeGe(tablePackage,"com.code.utils");
        //成功则返回
        return "code ge!";

    }
}

需要注意的是,utils包路径这个参数不仅对controller的生成和文件内容有影响,还对放在utils包中的CommentGeneratejava文件在mapper.txt模板中的位置有影响。具体请看具体文件中对应的参数。

9. 请求调用

启动项目,使用postman调用接口

9.1 url

127.0.0.1:9001/code/url

9.2 postman截图

在这里插入图片描述

9.3 控制台打印

在这里插入图片描述

9.4 生成的代码文件截图

在这里插入图片描述
当然了,如果觉得每次生成都要启动项目然后再调用请求执行方法比较麻烦,可以考虑将方法的调用通过main方法执行或者直接尝试在test中做一个单元测试来直接执行。

以上就是意见生成代码的所有内容。


拓展:

  • 参数读取相关文章:
    @Value注解读取配置文件中的参数
    @ConfigurationProperties注解读取配置文件中的参数
  • xml配置自动生成代码相关文章:
    springboot集成mybatis【使用generatorConfig.xml配置自动生成代码】
    Springboot集成mysql、mybatis、增删改查

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/27208.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++/C按照时间命名保存bin文件

背景 在Linux应用编程过程中&#xff0c;使用C或者C语言保存、读取bin文件是比较常见的需求。这里详细记录一下使用C保存bin文件&#xff0c;也可以使用C语言实现。 代码 C/C语言保存bin文件函数&#xff0c;C中也能使用 正确写入返回0&#xff0c;错误返回-1 // C 保存bi…

ASP.NET Core Web API入门:创建新项目

ASP.NET Core Web API入门&#xff1a;创建新项目 一、引言二、创建新项目三、加入Startup类&#xff0c;并替换Program.cs内容四、编辑Program.cs代码五、修改控制器的路由六、运行项目 一、引言 最近闲着&#xff0c;想着没真正从0-1开发过ASP.NET Core Web API的项目&#…

找不到xinput1_3.dll怎么办?xinput1_3.dll丢失的四个修复方法

在我们打开游戏的或者软件的时候&#xff0c;电脑提示“找不到xinput1_3.dll&#xff0c;无法继续执行此代码”怎么办&#xff1f;相信困扰着不少小伙伴&#xff0c;我再在打开吃鸡的时候&#xff0c;然后花了一上午的时候时间研究&#xff0c;现在终于知道xinput1_3.dll文件是…

中国电子学会2023年05月份青少年软件编程Scratch图形化等级考试试卷三级真题(含答案)

2023-05 Scratch三级真题 分数&#xff1a;100 题数&#xff1a;38 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 关于变量&#xff0c;下列描述错误的是&#xff1f;&#xff08;A &#xff09;&#xff08;2分&#xff09; A.只能建一个变量 …

Visual Studio 2022 v17.6 正式发布

Visual Studio 17.6 正式发布&#xff0c;这个最新版本提供了一系列强大的工具和功能&#xff0c;旨在使你能够制作出最先进的应用程序。 提高生产力 通过 Visual Studio 2022&#xff0c;目标是帮助你在更短的时间内完成 IDE 内的所有开发任务&#xff0c;在这个版本中&…

OpenPCDet安装、使用方式及自定义数据集训练

OpenPCDet安装、使用方式及自定义数据集训练 个人博客 OpenPCDet安装 # 先根据自己的cuda版本&#xff0c;安装对应的spconv pip install spconv-cu113# 下载OpenPCDet并安装 git clone https://github.com/open-mmlab/OpenPCDet.git cd OpenPCDet pip install -r requireme…

Linux 负载均衡集群 LVS_NAT模式 LVS_DR模式

集群 由多台主机组成&#xff0c;只做一件事&#xff0c;对外表现为一个整体。 只干一件事 &#xff1a;集群 干不同的事&#xff1a;分布式 企业集群分类 负载均衡群集&#xff08;load balance cluster&#xff09; 提高系统响应效率&#xff0c;处理更多的访问请…

深度学习的低秩优化:在紧凑架构和快速训练之间取得平衡(上)

论文出处&#xff1a;[2303.13635] Low Rank Optimization for Efficient Deep Learning: Making A Balance between Compact Architecture and Fast Training (arxiv.org) 由于篇幅有限&#xff0c;本篇博客仅引出问题的背景、各种张量分解方法及其分解FC/Conv层的方法&#x…

车牌识别之UI(Tkinter + OpenCV显示Picture和Video)

画一张总图&#xff1a; 图形界面开发 本篇只介绍图形界面开发。 遇到的第一个问题就是选择什么开发语言和技术。因为我之前用Python做过Tkinter的小东西&#xff0c;所以这次还是用Python Tkinter OpenCV来搞吧。 这里面需要注意几个地方&#xff1a; 1. Tkinter 的布局 …

冒泡排序、插入排序、希尔排序、选择排序

一、排序协议的定义 在博客的开头的&#xff0c;我们先给出排序协议的定义。因为我们本篇博客含有多种排序方式&#xff0c;为了使每种排序方法对外调用方式一致&#xff0c;我们需要定义一个排序的相关协议。所有排序的相关类都必须遵循该协议&#xff0c;让此协议来定义具体…

快速实现一个分布式定时器

定时器&#xff08;Timer&#xff09;是一种在业务开发中常用的组件&#xff0c;主要用在执行延时通知任务上。本文以笔者在工作中的实践作为基础&#xff0c;介绍如何使用平时部门最常用的组件快速实现一个业务常用的分布式定时器服务。同时介绍了过程中遇到问题的一些解决方案…

Android AIDL的使用(配源码)

零、完整源代码 链接: https://github.com/jx0260/TestGradle 一、创建AIDL文件 // IShopAidlInterface.aidl package com.example.testgradle;// Declare any non-default types here with import statementsinterface IShopAidlInterface {String getProductInfo(int prod…

【2023最新教程】一文3000字从0到1教你做app自动化测试(保姆级教程)

一、什么是App自动化&#xff1f;为什么要做App自动化&#xff1f; App自动化是指给 Android或iOS上的软件应用程序做的自动化测试。手工测试和自动化测试的对比如下&#xff1a; 手工测试优势&#xff1a;不可替代、发现更多bug、包含了人的想象力与理解力。 注意&#xff0c…

迅为iTOP-RK3588开发板Android12源码定制开发kernel开发

内核版本是 5.10.66 版本&#xff0c;内核默认的配置文件是 3588-android12/kernel-5.10/arch/arm64/configs/rockchip_defconfig 如果我们要使用图形化界面配置内核&#xff0c;操作方法如下所示&#xff1a; 方法一&#xff1a; 1 首先将默认的配置文件 rockchip_defconf…

博客系统测试用例设计之自动化测试

测试用例设计之自动化测试 &#x1f337; 一 测试用例设计&#x1f33a; 1 功能测试&#x1f338; &#xff08;1&#xff09;登录功能&#x1f338; &#xff08;2&#xff09;列表页功能&#x1f338; &#xff08;3&#xff09;编辑博客功能&#x1f338; &#xff08;4&…

DC LAB8SDC约束四种时序路径分析

DC LAB 1.启动DC2.读入设计3. 查看所有违例的约束报告3.1 report_constraint -all_violators (alias rc)3.2 view report_constraint -all_violators -verbose -significant_digits 4 (打印详细报告) 4.查看时序报告 report_timing -significant_digits 45. 约束组合逻辑(adr_i…

17 条件随机场

文章目录 17 条件随机场——CRF&#xff08;Condition Random Field&#xff09;17.1 背景介绍17.2 HMM与MEMM的区别17.3 MEMM与CRF的区别17.4 CRF模型17.4.1 CRF的概率密度函数17.4.2 CRF概率密度函数简化&#xff08;向量形式&#xff09; 17.5 CRF需要解决的问题17.6 边缘概…

测试者必知—如何做Web测试?常见测试点总结

目录 前言&#xff1a; 一、Web应用程序 二、功能测试 三、易用性测试&#xff08;界面测试&#xff09; 四、兼容性测试 五、安全性测试 六、性能测试 前言&#xff1a; Web测试是指对基于Web技术的应用程序进行测试&#xff0c;以测试其功能、性能、安全和稳定性等方面的表…

【图书推荐 | 12】前端系列

【赠书活动第十二期 】 图书推荐 本期书籍&#xff1a;前端系列 图书列表&#xff1a; Vue.js核心技术解析Nuxt.js实战Nuxt.js Web开发实战HTML5CSS 从入门到精通Flutter2 开发实例精解Electron项目开发实战 Vue.js核心技术解析 Nuxt.js实战 Nuxt.js Web开发实战 HTML5CSS 从入…

【业务功能篇20】Springboot java逻辑实现动态行转列需求

在此前&#xff0c;我也写过一个行转列的文章&#xff0c;是用存储过程sql处理的一个动态的逻辑 Mysql 存储过程\Mybatis框架call调用 实现动态行转列 那么后面我们同样又接收了业务的一个新需求&#xff0c;针对的是不同的业务数据&#xff0c;做的同样的一个展示数据报表&…