一键生成代码

news2024/12/23 20:53:43

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


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


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

一键生成代码

  • 功能简介
  • 开发环境:
  • 实现
    • 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.coloradmin.cn/o/628442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(五)CSharp-进一步理解接口

一、什么是接口 接口是指定一组函数成员而不实现它们的引用类型。 实现接口&#xff1a; 只能由类和结构来实现接口。 二、声明接口 接口声明不能包含以下成员&#xff1a; 数据成员静态成员 接口声明只能包含如下类型的非静态成员函数的声明&#xff1a; 方法属性事件索…

25张python代码速查表,让你python能力突飞猛进的秘诀!

在学习函数时&#xff0c;总是会有很多东西学得很快&#xff0c;遗忘得也很快。但其实在学习中&#xff0c;只需要知道相关参数&#xff0c;加以调整就够了。所以你可能需要这本秘籍&#xff01; 即整理了Python科学速查表&#xff0c;就可以帮你解决以上的问题。当你在练习的时…

怎样正确做 Web 应用的压力测试?字节8年测试5个步骤给我看师了

Web应用&#xff0c;通俗来讲就是一个网站&#xff0c;主要依托于浏览器来访问其功能。 那怎么正确做网站的压力测试呢&#xff1f; 提到压力测试&#xff0c;我们想到的是服务端压力测试&#xff0c;其实这是片面的&#xff0c;完整的压力测试包含服务端压力测试和前端压力测…

高可用系统架构总结

文章目录 系统设计的一些原则海恩法则墨菲定律 软件架构中的高可用设计什么是高可用故障的度量与考核解决高可用问题具体方案 集群化部署负载均衡负载均衡实现内部服务外部服务数据库 负载均衡算法round-robinip_hashhash key 失败重试健康检查TCPHTTP 隔离线程隔离进程隔离集群…

华秋观察 | 通讯产品 PCB 面临的挑战,一文告诉你

印制电路板是电子产品的关键电子互联件&#xff0c;被誉为“电子产品之母”。随着电子产品相关技术应用更快发展、迭代、融合&#xff0c;PCB作为承载电子元器件并连接电路的桥梁&#xff0c;为满足电子信息领域的新技术、新应用的需求&#xff0c;行业将迎来巨大的挑战和发展机…

rocky9脚本py格式

在linux7上编写/root/CreateFile.py的python3脚本&#xff0c;创建20个文件/root/test/File01至/root/test/File20&#xff0c;如果文件存在&#xff0c;则先删除再创建&#xff1b;每个文件的内容同文件名&#xff0c;如File01文件的内容为”File01” 先在root目录下建立所需…

使用单片机遇到的几个问题及解决方案1

1.为什么我跟着视频学习的过程中&#xff0c;我没有找到“端口"的选项呢&#xff1f;我甚至没有出现“其他插口”。 想要找到设备管理器最快的方法就是&#xff1a; 首先如果把输入法调为大写形式&#xff0c;然后按下“WINX”&#xff0c;再按“M”就会出现一个设备管理…

python制作炸弹人游戏,一起来爆破消灭敌人吧

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 《炸弹人》是HUDSON出品的一款ACT类型游戏&#xff0c;经典的第一作登陆在FC版本&#xff0c;游戏于1983年发行。 游戏具体操作是一个机器人放置炸弹来炸死敌人&#xff0c;但也可以炸死自己&#xff0c;还有些增强威力…

K8S之服务Service(十三)

1、Service概念&#xff1a; Kubernetes中的 Pod是有生命周期的&#xff0c;它们可以被创建&#xff0c;也可以被销毁&#xff0c;然而一旦被销毁pod生命就永远结束&#xff0c;这个pod就不存在了&#xff0c;通过ReplicaSets能够动态地创建和销毁Pod&#xff08;例如&#xff…

【计算思维题】少儿编程 蓝桥杯青少组计算思维 数学逻辑思维真题详细解析第8套

少儿编程 蓝桥杯青少组计算思维题真题及解析第8套 1、下列哪个选项填到填到下图空缺处最合适 A、 B、 C、 D、 答案:D 考点分析:主要考查小朋友们的观察能力,从给定的图中可以看到,图中的线条都是有实现和虚

【C++ 学习 ⑨】- 万字详解 string 类(上)

目录 一、为什么学习 string 类&#xff1f; 二、标准库中的 string 类 三、C STL容器是什么&#xff1f; 四、string 类的成员函数 4.1 - 构造函数 4.2 - 赋值运算符重载 4.3 - 容量操作 4.4 - 遍历及访问操作 4.4.1 - operator[] 和 at 4.4.2 - 迭代器 4.5 - 修改…

Node.js 使用踩坑

重装电脑后&#xff0c;重装node.js 出现一个问题&#xff1a; npm install 会报错 按提示操作后 而npm run serve 会报xlsx和echart的错误&#xff0c;提示引用不对之类的&#xff0c;但是公司项目固定的&#xff0c;不可以随便改&#xff0c;而且之前是没问题的。 此时需要找…

华为OD机试真题B卷 Java 实现【数组拼接】,附详细解题思路

一、题目描述 现在有多组整数数组&#xff0c;需要将它们合并成一个新的数组。 合并规则&#xff0c;从每个数组里按顺序取出固定长度的内容合并到新的数组中&#xff0c;取完的内容会删除掉&#xff0c;如果该行不足固定长度或者已经为空&#xff0c;则直接取出剩余部分的内…

Anaconda教程,Python版本控制

Anaconda教程,Python版本控制 文章目录 Anaconda教程,Python版本控制1&#xff1a;Anaconda安装1.1&#xff1a;Windows1.2&#xff1a;Linux1.3&#xff1a;MacOS 2&#xff1a;Anaconda使用2.1&#xff1a;创建一个新的环境2.2&#xff1a;安装 Python 包2.3&#xff1a;激活…

hash模式下路由跳转页面不刷新

mode为hash时&#xff0c;纯粹页面&#xff0c;路由跳转过之后跳转上一级重复路由页面不会重新渲染 举个例子&#xff1a;当我在注册页面->注册状态页面->注册页面&#xff0c;在这个期间我从注册状态页面进行缓存的数据想要在注册页面使用&#xff0c;然而注册页面不会…

【YOLO系列】YOLO v5(网络结构图+代码)

文章目录 推理转换onnx网络架构SPP VS SPPFAutoAnchorLoss 参考 【YOLO系列】YOLO v3&#xff08;网络结构图代码&#xff09; 【YOLO 系列】YOLO v4-v5先验知识 【YOLO系列】YOLO v4&#xff08;网络结构图代码&#xff09; 我是在自己笔记本上配置的YOLO v5环境。首先&#x…

饼状图使用属性时,使用驼峰命名法

饼状图是使用D3.js等JavaScript库来绘制的&#xff0c;而JavaScript中的属性名通常采用驼峰式命名法&#xff0c;即第一个单词的首字母小写&#xff0c;后面单词的首字母大写&#xff0c;例如fontSize、fontWeight等。而CSS中的属性名采用连字符命名法&#xff0c;即单词之间用…

Top 5 Best Open Source Projects on GitHub 2023

这里介绍Github上 5 个增长最快的开源项目&#xff0c;它们为原有的解决方案提供了更加具有成本效益的替代方案&#xff0c;并为开发者、数据分析师和企业提供了高可用的工具产品。利用开源的优势&#xff0c;这5个项目拓展了强大而有效的解决方案&#xff0c;是值得收藏、分享…

比ureport好用的报表系统-VeryReport报表系统

随着数据时代的到来&#xff0c;数据成为企业管理和决策的重要依据。然而&#xff0c;在处理海量数据的同时&#xff0c;如何快速准确地生成各种形式的报表却成为了一个痛点。手工制作报表费时费力、容易出错&#xff1b;而传统的报表工具又复杂难用&#xff0c;无法满足不同用…

基于jsp+mysql+Spring+mybatis+Springboot的SpringBoot婚纱影楼摄影预约网站

运行环境: 最好是java jdk 1.8&#xff0c;我在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以&#xff0c;如果编译器的版本太低&#xff0c;需要升级下编译器&#xff0c;不要弄太低的版本 tomcat服务器环…