Implementierung des Java-Code-Generators


Vorwort

Ich habe kürzlich ein Open-Source-Projekt gesehen, jfinal-layui, und in diesem Projekt gibt es 代码生成器eine

Bildbeschreibung hier einfügen

Obwohl ich vorher einen Codegenerator benutzt habe, habe ich den entsprechenden Quellcode nie gesehen, also habe ich ihn studiert.Ich persönlich finde den Codegenerator für dieses Projekt ziemlich gut. Er kann Frontend- und Backend-Codes entsprechend generieren zu den angegebenen Datenbanken und Tabellen, aber dies Der Rahmen des Projekts ist, jfinaldass das direkte Kopieren des Codes, der sich auf diesen Codegenerator bezieht, in Ihr eigenes Projekt nicht funktioniert, und die Struktur jedes Projekts einige einzigartige Eigenschaften hat, es ist schwierig, einen zu finden Code-Generator, der verwendet werden kann Aus diesem Grund habe ich einen relativ einfachen Code-Generator basierend auf der Struktur meines Projekts geschrieben, indem ich die vom jfinalFramework und teilte mit, wie ich ihn implementiert habe.

Wenn Sie jfinal-layuidieses , können Sie auf den Link https://gitee.com/QinHaiSenLin/Jfinal-layui klicken , um den Quellcode dieses Projekts abzurufen.


I. Übersicht

Wie der Name schon sagt, ist der Codegenerator eine Software, die Code generiert. In der täglichen Entwicklung können wir den Codegenerator verwenden, um einige sich wiederholende Entwicklungsarbeiten zu reduzieren und die Effizienz des Öffnens zu verbessern. Beispielsweise mybatisgibt es Die Entitätsklassen, die der Datenbank, den Mapper- und XML-Dateien usw. entsprechen, sind eigentlich ein Codegenerator.

Was ist das Prinzip des Codegenerators?

Eigentlich ist es ganz einfach: Die Dateien, die wir erzeugen wollen, müssen bestimmte Regeln haben, und dann schreiben wir eine einheitliche Datei nach dieser Regel 模板und generieren den entsprechenden Code nach dieser Vorlage.


2. Handgeschriebener Code


1. Kurze Beschreibung

Der folgende Inhalt dient nur als Referenz. Was ich zur Verfügung stelle, ist nur eine Implementierungslösung, die möglicherweise nicht für Ihr Projekt geeignet ist, aber solange Sie verstehen, wie ich sie implementiert habe, können Sie auch einen für Ihr eigenes Projekt geeigneten Codegenerator schreiben.

Geschäft außerhalb der eigentlichen Szene ist sinnlos. Wie ich bereits sagte, jedes Projekt hat seine Einzigartigkeit. Ich schreibe einen Codegenerator, der meine Anforderungen erfüllt, basierend auf meinem eigenen Projekt, also lassen Sie mich zuerst über mein eigenes Projekt sprechen. Eine einfache Struktur.

Um beispielsweise in meinem Projekt einen vollständigen Satz von Schnittstellen zum Hinzufügen, Löschen, Ändern und Überprüfen zu implementieren, müssen die folgenden Klassen vorhanden sein, und die ausgewählten Teile (User.java, UserMapper.java und 红色框UserMapper.xml 实体类) mapper 文件sind xml 文件vorhanden alles verfügbar. Es wird durch das Reverse Engineering von mybatis generiert, und 绿色框der ausgewählte Teil muss von mir manuell geschrieben werden, also ist der Codegenerator, den ich schreiben muss, eine Datei, die mir helfen kann, den ausgewählten Teil des grünen Rahmens zu generieren, z wie: Controller , Service, ServiceImp, 请求体 dto, 相应体 dtound subclass 包下的转换器.

Bildbeschreibung hier einfügen

Für die spezifische Konstruktion meines Projekts lesen Sie bitte diesen Blog: SpringBoot - Quick Construction

Wie soll ich das dann umsetzen?Zunächst einmal schlage ich vor, dass Sie selbst eine Standard-Ergänzung, -Löschung, -Änderung und -Abfrage schreiben und dann eine Vorlage gemäß dem schreiben, was Sie geschrieben haben. Zum Beispiel habe ich einen Controller für eine Position geschrieben Code ist wie folgt:

package com.duojiala.mikeboot.controller;

import com.duojiala.mikeboot.domain.req.QueryPostListReq;
import com.duojiala.mikeboot.domain.req.SavePostReq;
import com.duojiala.mikeboot.domain.dto.ResponseBean;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import com.duojiala.mikeboot.service.PostService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
 * 顶部导航 Controller
 * @author: mike
 * @date: 2023-04-26 17:03
 */
@Slf4j
@RestController
@RequestMapping(value = "/post")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@CrossOrigin(origins = "*", methods = {
    
    RequestMethod.POST, RequestMethod.GET})
public class PostController {
    
    

    private final PostService postService;

    @PostMapping(value = "/save")
    @ApiOperation(value = "保存")
    public ResponseBean save(@RequestBody @Validated SavePostReq req) {
    
    
        postService.save(req);
        return ResponseBean.success();
    }

    @PostMapping(value = "/update")
    @ApiOperation(value = "修改")
    public ResponseBean update(@RequestBody @Validated SavePostReq req) {
    
    
        postService.update(req);
        return ResponseBean.success();
    }

    @PostMapping(value = "/detail")
    @ApiOperation(value = "查询详情")
    public ResponseBean detail(@RequestParam(required = false) String id) {
    
    
        return ResponseBean.success(postService.detail(id));
    }

    @PostMapping(value = "/delete")
    @ApiOperation(value = "删除")
    public ResponseBean delete(@RequestParam(required = false) String id) {
    
    
        postService.delete(id);
        return ResponseBean.success();
    }

    @PostMapping(value = "/batch-delete")
    @ApiOperation(value = "批量删除")
    public ResponseBean batchDelete(@RequestParam(required = false) List<String> ids) {
    
    
        postService.batchDelete(ids);
        return ResponseBean.success();
    }

    @PostMapping(value = "/paginate-list")
    @ApiOperation(value = "分页查询列表")
    public ResponseBean paginateList(@RequestBody @Validated QueryPostListReq req) {
    
    
        return ResponseBean.success(postService.paginateList(req));
    }


}

Also habe ich die controller_template.jfVorlagendatei

package #(controllerPackagePath);

#if(isCRUD)
import com.duojiala.mikeboot.domain.req.#(QueryTargetListReq??);
import com.duojiala.mikeboot.domain.req.#(SaveTargetReq??);
import com.duojiala.mikeboot.domain.dto.ResponseBean;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import java.util.List;
#end
import com.duojiala.mikeboot.service.#(ServiceName??);
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
 * #(controllerRemark??) Controller
 * @author: #(author?? 'JBolt-Generator')
 * @date: #date()
 */
@Slf4j
@RestController
@RequestMapping(value = "/#(pathValue??)")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.GET})
public class #(ControllerName??) {

    private final #(ServiceName??) #(serviceName??);

#if(isCRUD)
    @PostMapping(value = "/save")
    @ApiOperation(value = "保存")
    public ResponseBean save(@RequestBody @Validated #(SaveTargetReq??) req) {
        #(serviceName??).save(req);
        return ResponseBean.success();
    }

    @PostMapping(value = "/update")
    @ApiOperation(value = "修改")
    public ResponseBean update(@RequestBody @Validated #(SaveTargetReq??) req) {
        #(serviceName??).update(req);
        return ResponseBean.success();
    }

    @PostMapping(value = "/detail")
    @ApiOperation(value = "查询详情")
    public ResponseBean detail(@RequestParam(required = false) String id) {
        return ResponseBean.success(#(serviceName??).detail(id));
    }

    @PostMapping(value = "/delete")
    @ApiOperation(value = "删除")
    public ResponseBean delete(@RequestParam(required = false) String id) {
        #(serviceName??).delete(id);
        return ResponseBean.success();
    }

    @PostMapping(value = "/batch-delete")
    @ApiOperation(value = "批量删除")
    public ResponseBean batchDelete(@RequestParam(required = false) List<String> ids) {
        #(serviceName??).batchDelete(ids);
        return ResponseBean.success();
    }

#if(needPaginate)
    @PostMapping(value = "/paginate-list")
    @ApiOperation(value = "分页查询列表")
    public ResponseBean paginateList(@RequestBody @Validated #(QueryTargetListReq??) req) {
        return ResponseBean.success(#(serviceName??).paginateList(req));
    }
#else
    @PostMapping(value = "/list")
    @ApiOperation(value = "查询列表")
    public ResponseBean list(@RequestBody @Validated #(QueryTargetListReq??) req) {
        return ResponseBean.success(#(serviceName??).list(req));
    }
#end
#end


}

Dies geschieht durch den Code, der oft in Ihrem eigenen Projekt geschrieben wird, und behalten Sie dann den gemeinsamen Ort bei und ersetzen Sie den Unterschied durch die Syntax einiger Template-Engines. Es spielt keine Rolle, ob Sie ihn vorübergehend nicht verstehen (die Syntax von Die Template-Engine schreibt diesen Code. Ich verstehe den Generator nicht, aber ich kann ihn trotzdem schreiben, indem ich vergleiche, was andere geschrieben haben.)

endgültige Wirkung


2. Codeschreiben

Da ich mir das Rad jfinalvon , habe ich hier auf jfinaleine Abhängigkeit verwiesen

        <!--JFianl-->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>5.0.4</version>
        </dependency>

Es gibt auch einige Tools (diese werden nach Ihrem eigenen Projekt ausgewählt)

        <!-- 转化器自动转换 -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.4.2.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.4.2.Final</version>
        </dependency>

        <!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>

        <!--工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>

Dann habe ich auch eine Aufzählungsklasse geschrieben, in der Hoffnung, dass jedes Mal, wenn eine Tabelle eingefügt wird, eine Aufzählung der Tabelle zu dieser Aufzählungsklasse hinzugefügt werden kann

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 表名枚举
 */
@Getter
@AllArgsConstructor
public enum TableEnum {
    
    
    USER("用户表"),
    ;

    private final String desc;
}

Erstellen Sie ein Paket zum Speichern des Codegenerators LogicGenerator.java. Lassen Sie mich Ihnen zunächst zeigen, wie die Methode zum Generieren Controllerder Ebene implementiert wird

    /**
     * 生成 Controller 层的代码
     */
    public void genController(LogicBean logicBean) {
    
    
        // 获取实体类名称
        String entityName = logicBean.getEntityClass().getSimpleName();
        // 生成 Controller 类的名称
        String controllerName = entityName + "Controller";
        // 生成 Controller 类的完整名称
        String controllerFullName = controllerName + ".java";
        // 获取 Controller 类的路径
        String controllerPackagePath = logicBean.getControllerPackagePath();
        this.printMessageWithDate(String.format("正在生成 Controller:%s...", controllerFullName));
        // 获取 Controller 生成路径
        String targetOutputDir = this.getDirFromPackage(controllerPackagePath);
        this.printMessageWithDate(String.format("Controller 生成路径:%s...", targetOutputDir));
        // 判断将要生成的 Controller.java 是否存在
        if (FileUtil.exist(targetOutputDir + File.separator + controllerFullName)) {
    
    
            this.printMessageWithDate(String.format("Controller 文件[%s]已存在,忽略生成 ~~ ", controllerFullName));
        } else {
    
    
            String serviceName = entityName + "Service";
            // 替换 .jf 文件中的内容,比如在 #(author??) 会替换成 logicBean.getAuthor() 这个值
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("controllerPackagePath", controllerPackagePath)
                    .set("QueryTargetListReq", "Query"+entityName+"ListReq")
                    .set("SaveTargetReq", "Save"+entityName+"Req")
                    .set("ServiceName", serviceName)
                    .set("controllerRemark", logicBean.getTableEnumDes())
                    .set("pathValue", StringUtils.isBlank(logicBean.getPathValue())?toFirstLower(entityName):logicBean.getPathValue())
                    .set("ControllerName", controllerName)
                    .set("serviceName", toFirstLower(serviceName))
                    .set("needPaginate", logicBean.isNeedPaginate())
                    .set("isCRUD",logicBean.isCrudType());
            // 配置好模板路径,通过 engine 去生成相应的内容
            String content = this.engine.getTemplate(controllerTemplate).renderToString(data);
            // IO 写文件
            this.writeToFile(targetOutputDir, controllerFullName, content);
        }
    }

Schreiben Sie dann eine Klasse mit maineiner Methode als Eintrag zum Starten des Generators

public class MainLogicGenerator extends LogicGenerator {
    
    
    public static void main(String[] args) {
    
    
        // 启动代码生成器
    }
}    

3. Vollständiger Code

LogicGenerator.javaCode zeigen wie folgt:

package com.duojiala.mikeboot.extend.gen;

import cn.hutool.core.io.FileUtil;
import com.duojiala.mikeboot.utils.DateUtil;
import com.jfinal.kit.StrKit;
import com.jfinal.template.Engine;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.Table;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 代码生成器主类
 */
public class LogicGenerator {
    
    

    // 分隔符
    public final String SEPARATOR;
    // 项目路径
    private final String PROJECT_PATH;
    // 枚举类路径
    private final String PROJECT_TABLE_ENUM_PATH;
    // Controller 层模板
    private static final String controllerTemplate = "/genera/controller_template.jf";
    // Service 模板
    private static final String serviceTemplate = "/genera/service_template.jf";
    // ServiceImpl 模板
    private static final String serviceImplTemplate = "/genera/service_impl_template.jf";
    // 转换器模板
    private static final String converterTemplate = "/genera/converter_template.jf";
    // 通用 dto 模板
    private static final String commonDtoTemplate = "/genera/common_dto_template.jf";
    // 查询 dto 模板
    private static final String queryDtoTemplate = "/genera/query_dto_template.jf";
    // 生成类队列
    private final List<LogicBean> logicBeans;
    // jfinal 处理 jf 文件的引擎
    private Engine engine;

    /**
     * 初始化
     */
    public LogicGenerator() {
    
    
        this.SEPARATOR = File.separator;
        this.PROJECT_PATH = System.getProperty("user.dir");
        this.PROJECT_TABLE_ENUM_PATH = this.PROJECT_PATH + this.SEPARATOR + "src" + this.SEPARATOR + "main" + this.SEPARATOR + "java" + this.SEPARATOR + "com" + this.SEPARATOR + "duojiala" + this.SEPARATOR + "mikeboot" + this.SEPARATOR + "extend" + this.SEPARATOR + "system" + this.SEPARATOR + "TableEnum.java";

        logicBeans = new ArrayList<>();
        this.initGenConfig();
        this.initEngine();
    }

    /**
     * 初始化模板引擎
     */
    private void initEngine() {
    
    
        this.printMessageWithDate("初始化模板引擎 ...");
        this.engine = new Engine();
        this.engine.setToClassPathSourceFactory();
        this.engine.addSharedMethod(new StringKit());
    }

    /**
     * 根据生成类队列里面的信息生成代码
     */
    public void generate() {
    
    
        this.printMessageWithDate("开始执行生成......");
        this.logicBeans.forEach(this::generateOne);
        this.printMessageWithDate("全部生成 结束 ...");
        this.printMessageWithDate("==请刷新项目目录,检查生成结果==");
    }

    public void generateOne(LogicBean logicBean) {
    
    
        this.printMessageWithDate("正在生成 ===> ["+logicBean.getEntityClass().getName()+"]");
        // 生成枚举
        this.genTableEnum(logicBean);
        // 生成 Controller 类
        this.genController(logicBean);
        // 生成 Service 类
        this.genService(logicBean);
        // 生成 ServiceImpl 类
        this.genServiceImpl(logicBean);
        // 生成 相应的 DTO 类
        this.genReqRespConverter(logicBean);
    }

    public void genTableEnum(LogicBean logicBean) {
    
    
        Class<?> entityClass = logicBean.getEntityClass();
        String simpleName = entityClass.getSimpleName();
        this.printMessageWithDate("正在生成 "+simpleName+" 表枚举类型");
        boolean exist = FileUtil.exist(this.PROJECT_TABLE_ENUM_PATH);
        if (!exist) {
    
    
            throw new RuntimeException(this.PROJECT_TABLE_ENUM_PATH + "文件不存在");
        } else {
    
    
            List<String> codeLines = FileUtil.readLines(this.PROJECT_TABLE_ENUM_PATH, "UTF-8");
            if (codeLines != null && codeLines.size() != 0) {
    
    
                Table annotation = entityClass.getAnnotation(Table.class);
                String reallyName = annotation.name();
                String tableEnumName = StringUtils.upperCase(reallyName);
                String tableEnumDes = logicBean.getTableEnumDes()==null?tableEnumName:logicBean.getTableEnumDes();
                String code = tableEnumName + "(\"" + tableEnumDes + "\"),";
                if (this.checkFileContainCode(codeLines, code)) {
    
    
                    this.printMessageWithDate(String.format("TableEnum 文件中已存在 [%s][%s] 的定义,略过",tableEnumName,tableEnumDes));
                } else {
    
    
                    int size = codeLines.size();
                    int insertIndex = 0;
                    int startIndex = -1;

                    for(int i = 1; i < size; ++i) {
    
    
                        String tmpCode = (String)codeLines.get(i);
                        if (!StringUtils.isBlank(tmpCode)) {
    
    
                            if (startIndex == -1 && tmpCode.trim().startsWith("public enum TableEnum")) {
    
    
                                startIndex = i + 1;
                            }

                            if (tmpCode.trim().equals(";")) {
    
    
                                insertIndex = i;
                            }
                        }
                    }

                    boolean needProcessUpComma = true;
                    if (insertIndex == 0) {
    
    
                        insertIndex = startIndex;
                        code = code + ",";
                        needProcessUpComma = false;
                    }

                    if (startIndex > 0) {
    
    
                        codeLines.add(insertIndex, "\t" + code);
                        if (needProcessUpComma) {
    
    
                            for(int i = insertIndex - 1; i > startIndex; --i) {
    
    
                                String tmp = (String)codeLines.get(i);
                                if (!StringUtils.isBlank(tmp)) {
    
    
                                    String tmpTrim = tmp.trim();
                                    if (tmpTrim.endsWith(",") || tmpTrim.endsWith(";") || tmpTrim.endsWith("{") || tmpTrim.endsWith("}")) {
    
    
                                        break;
                                    }

                                    if (tmpTrim.charAt(tmpTrim.length() - 1) != ',') {
    
    
                                        codeLines.set(i, "\t" + tmpTrim + ",");
                                        break;
                                    }
                                }
                            }
                        }

                        this.printMessageWithDate("正在重新生成新的 TableEnum...");
                        FileUtil.writeLines(codeLines, this.PROJECT_TABLE_ENUM_PATH, "UTF-8");
                    }
                }
            } else {
    
    
                throw new RuntimeException(this.PROJECT_TABLE_ENUM_PATH + "文件内容异常");
            }
        }
    }

    private boolean checkFileContainCode(List<String> codeLines, String code) {
    
    
        Iterator<String> var4 = codeLines.iterator();

        String tmpCode;
        String codeLine;
        do {
    
    
            if (!var4.hasNext()) {
    
    
                return false;
            }

            codeLine = (String)var4.next();
            tmpCode = codeLine.trim();
        } while(StringUtils.isBlank(tmpCode) || tmpCode.startsWith("package ") || tmpCode.startsWith("public class ") || tmpCode.startsWith("return ") || tmpCode.equals("}") || !codeLine.contains(code));

        return true;
    }

    public void genController(LogicBean logicBean) {
    
    
        String entityName = logicBean.getEntityClass().getSimpleName();
        String controllerName = entityName + "Controller";
        String controllerFullName = controllerName + ".java";
        String controllerPackagePath = logicBean.getControllerPackagePath();
        this.printMessageWithDate(String.format("正在生成 Controller:%s...", controllerFullName));
        String targetOutputDir = this.getDirFromPackage(controllerPackagePath);
        this.printMessageWithDate(String.format("Controller 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + controllerFullName)) {
    
    
            this.printMessageWithDate(String.format("Controller 文件[%s]已存在,忽略生成 ~~ ", controllerFullName));
        } else {
    
    
            String serviceName = entityName + "Service";
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("controllerPackagePath", controllerPackagePath)
                    .set("QueryTargetListReq", "Query"+entityName+"ListReq")
                    .set("SaveTargetReq", "Save"+entityName+"Req")
                    .set("ServiceName", serviceName)
                    .set("controllerRemark", logicBean.getTableEnumDes())
                    .set("pathValue", StringUtils.isBlank(logicBean.getPathValue())?toFirstLower(entityName):logicBean.getPathValue())
                    .set("ControllerName", controllerName)
                    .set("serviceName", toFirstLower(serviceName))
                    .set("needPaginate", logicBean.isNeedPaginate())
                    .set("isCRUD",logicBean.isCrudType());
            String content = this.engine.getTemplate(controllerTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, controllerFullName, content);
        }
    }

    private void genService(LogicBean logicBean) {
    
    
        Class<?> entityClass = logicBean.getEntityClass();
        String entityName = entityClass.getSimpleName();
        String serviceName = entityName + "Service";
        String serviceFullName = serviceName + ".java";
        String servicePackagePath = logicBean.getServicePackagePath();
        this.printMessageWithDate(String.format("正在生成 Service:%s...", serviceFullName));
        String targetOutputDir = this.getDirFromPackage(servicePackagePath);
        this.printMessageWithDate(String.format("Service 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + serviceFullName)) {
    
    
            this.printMessageWithDate(String.format("Service 文件[%s]已存在,忽略生成 ~~ ", serviceFullName));
        } else {
    
    
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("servicePackagePath", servicePackagePath)
                    .set("QueryTargetListReq", "Query"+entityName+"ListReq")
                    .set("SaveTargetReq", "Save"+entityName+"Req")
                    .set("EntityName", entityName)
                    .set("QueryTargetListResp", "Query"+entityName+"ListResp")
                    .set("ServiceName", serviceName)
                    .set("needPaginate", logicBean.isNeedPaginate())
                    .set("isCRUD",logicBean.isCrudType());
            String content = this.engine.getTemplate(serviceTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, serviceFullName, content);
        }
    }

    private void genServiceImpl(LogicBean logicBean) {
    
    
        Class<?> entityClass = logicBean.getEntityClass();
        String entityName = entityClass.getSimpleName();
        String serviceImplName = entityName + "ServiceImpl";
        String serviceImplFullName = serviceImplName + ".java";
        String serviceImplPackagePath = logicBean.getServiceImplPackagePath();
        this.printMessageWithDate(String.format("正在生成 ServiceImpl:%s...", serviceImplFullName));
        String targetOutputDir = this.getDirFromPackage(serviceImplPackagePath);
        this.printMessageWithDate(String.format("ServiceImpl 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + serviceImplFullName)) {
    
    
            this.printMessageWithDate(String.format("ServiceImpl 文件[%s]已存在,忽略生成 ~~ ", serviceImplFullName));
        } else {
    
    
            List<Toggle> toggleList = new ArrayList<>();
            Field[] declaredFields = entityClass.getDeclaredFields();
            boolean isSoftDel = false;
            for (Field declaredField : declaredFields) {
    
    
                String fieldName = declaredField.getName();
                if ("delFlag".equals(fieldName)) {
    
    
                    isSoftDel = true;
                    continue;
                }
                Type genericType = declaredField.getGenericType();
                String[] genericArr = genericType.toString().split("\\.");
                String type = genericArr[genericArr.length - 1];
                if ("Boolean".equals(type)) {
    
    
                    toggleList.add(new Toggle(fieldName,"req.get" + toFirstUpper(fieldName) + "()"));
                }
            }

            String keywordSelect = logicBean.getKeywordSelect();
            boolean hasKeyword = false;
            if (StringUtils.isNotBlank(keywordSelect)) {
    
    
                // 有关键字,则拼装查询条件
                hasKeyword = true;
                String[] keywordArr = keywordSelect.split(",");
                StringBuilder builder = new StringBuilder();
                int i = 0;
                builder.append("criteria.andCondition(\"");
                do {
    
    
                    if (i != 0) {
    
    
                        builder.append("+ \" or \" + \"");
                    }
                    builder.append(keywordArr[i]).append(" like \" + ").append("\"%\"+").append("req.getKeyword()").append("+\"%\"");
                } while (i++<keywordArr.length-1);
                builder.append(");");
                keywordSelect = builder.toString();
            }

            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("serviceImplPackagePath", serviceImplPackagePath)
                    .set("QueryTargetListRespConverter", "Query"+entityName+"ListRespConverter")
                    .set("queryTargetListRespConverter", "query"+entityName+"ListRespConverter")
                    .set("SaveTargetReqConverter", "Save"+entityName+"ReqConverter")
                    .set("saveTargetReqConverter", "save"+entityName+"ReqConverter")
                    .set("QueryTargetListReq", "Query"+entityName+"ListReq")
                    .set("SaveTargetReq", "Save"+entityName+"Req")
                    .set("EntityName", entityName)
                    .set("entityName", toFirstLower(entityName))
                    .set("QueryTargetListResp", "Query"+entityName+"ListResp")
                    .set("ServiceName", entityName + "Service")
                    .set("ServiceImplName", serviceImplName)
                    .set("toggleList", toggleList)
                    .set("hasKeyword", hasKeyword)
                    .set("keywordSelect", keywordSelect)
                    .set("isSoftDel", isSoftDel)
                    .set("needPaginate", logicBean.isNeedPaginate())
                    .set("isCRUD",logicBean.isCrudType());
            String content = this.engine.getTemplate(serviceImplTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, serviceImplFullName, content);
        }
    }

    private void genReqRespConverter(LogicBean logicBean) {
    
    
        boolean isCRUD = logicBean.isCrudType();
        if (isCRUD) {
    
    
            genRequestBody(logicBean,OptionEnum.SAVE);
            genRequestBody(logicBean,OptionEnum.PAGINATE);
            genResponseBody(logicBean);
        }
    }

    private void genRequestBody(LogicBean logicBean, OptionEnum optionEnum) {
    
    
        // 生成请求体
        Class<?> entityClass = logicBean.getEntityClass();
        String entityName = entityClass.getSimpleName();
        String targetReq = null;
        boolean havePageInfo = false;
        switch (optionEnum) {
    
    
            case SAVE:
                targetReq = "Save" + entityName + "Req";
                break;
            case PAGINATE:
                targetReq = "Query" + entityName + "ListReq";
                havePageInfo = true;
                break;
            default:
                return;
        }

        String targetReqFullName = targetReq + ".java";
        String requestPackagePath = logicBean.getRequestPackagePath();
        this.printMessageWithDate(String.format("正在生成 RequestBoy:%s...", requestPackagePath));
        String targetOutputDir = this.getDirFromPackage(requestPackagePath);
        this.printMessageWithDate(String.format("RequestBoy 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + targetReqFullName)) {
    
    
            this.printMessageWithDate(String.format("RequestBoy 文件[%s]已存在,忽略生成 ~~ ", targetReqFullName));
        } else {
    
    
            List<String> inserts = new ArrayList<>();
            // 通过反射获取目标对象的属性
            Field[] declaredFields = entityClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
    
    
                String fieldName = declaredField.getName();
                switch (optionEnum) {
    
    
                    case SAVE:
                        if ("createTime".equals(fieldName)) continue;
                        if ("updateTime".equals(fieldName)) continue;
                        if ("delFlag".equals(fieldName)) continue;
                        inserts.add("private String " + fieldName + ";");
                        break;
                    case PAGINATE:
                        if ("delFlag".equals(fieldName)) continue;
                        Type genericType = declaredField.getGenericType();
                        String[] genericArr = genericType.toString().split("\\.");
                        String type = genericArr[genericArr.length - 1];
                        if ("Boolean".equals(type)) {
    
    
                            inserts.add("private " + type + " " + fieldName + ";");
                        }
                        break;
                }
            }
            if (OptionEnum.PAGINATE == optionEnum) {
    
    
                inserts.add("private String keyword;");
            }
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("dtoPackagePath",requestPackagePath)
                    .set("DtoName", targetReq)
                    .set("havePageInfo", havePageInfo)
                    .set("inserts",inserts);
            String content = this.engine.getTemplate(commonDtoTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, targetReqFullName, content);
        }
        if (OptionEnum.SAVE == optionEnum) {
    
    
            genConverter(logicBean,targetReq,entityName,requestPackagePath+"."+targetReq);
        }
    }

    private void genResponseBody(LogicBean logicBean) {
    
    
        Class<?> entityClass = logicBean.getEntityClass();
        String entityName = entityClass.getSimpleName();
        String targetReq = "Query" + entityName + "ListResp";
        String targetReqFullName = targetReq + ".java";
        String responsePackagePath = logicBean.getResponsePackagePath();
        this.printMessageWithDate(String.format("正在生成 ResponseBoy:%s...", responsePackagePath));
        String targetOutputDir = this.getDirFromPackage(responsePackagePath);
        this.printMessageWithDate(String.format("ResponseBoy 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + targetReqFullName)) {
    
    
            this.printMessageWithDate(String.format("ResponseBoy 文件[%s]已存在,忽略生成 ~~ ", targetReqFullName));
        } else {
    
    
            List<String> inserts = new ArrayList<>();
            Field[] declaredFields = entityClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
    
    
                String fieldName = declaredField.getName();
                if ("createTime".equals(fieldName)) continue;
                if ("updateTime".equals(fieldName)) continue;
                if ("delFlag".equals(fieldName)) continue;
                Type genericType = declaredField.getGenericType();
                String[] genericArr = genericType.toString().split("\\.");
                String type = genericArr[genericArr.length - 1];
                inserts.add("private " + type + " " + fieldName + ";");
            }
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("dtoPackagePath",responsePackagePath)
                    .set("DtoName", targetReq)
                    .set("inserts",inserts);
            String content = this.engine.getTemplate(queryDtoTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, targetReqFullName, content);
        }
        genConverter(logicBean,targetReq,entityName,responsePackagePath+"."+targetReq);
    }

    private void genConverter(LogicBean logicBean,String A,String B,String AAllPath) {
    
    
        String converterName = A + "Converter";
        String converterFullName = converterName + ".java";
        String converterPackagePath = logicBean.getConverterPackagePath();
        this.printMessageWithDate(String.format("正在生成 Converter:%s...", converterPackagePath));
        String targetOutputDir = this.getDirFromPackage(converterPackagePath);
        this.printMessageWithDate(String.format("Converter 生成路径:%s...", targetOutputDir));
        if (FileUtil.exist(targetOutputDir + File.separator + converterFullName)) {
    
    
            this.printMessageWithDate(String.format("Converter 文件[%s]已存在,忽略生成 ~~ ", converterFullName));
        } else {
    
    
            Kv<String,Object> data = Kv.by("author", (Object)logicBean.getAuthor())
                    .set("converterPackagePath", converterPackagePath)
                    .set("Target", A)
                    .set("EntityName", B)
                    .set("TargetAllPath",AAllPath);
            String content = this.engine.getTemplate(converterTemplate).renderToString(data);
            this.writeToFile(targetOutputDir, converterFullName, content);
        }
    }

    private void writeToFile(String targetOutputDir, String fileName, String content) {
    
    
        if (!FileUtil.exist(targetOutputDir)) {
    
    
            FileUtil.mkdir(targetOutputDir);
        }

        String target = targetOutputDir + File.separator + fileName;
        if (!FileUtil.exist(target)) {
    
    
            FileUtil.writeUtf8String(content, target);
        }
    }

    /**
     * 初始化配置,供子类实现
     */
    public void initGenConfig() {
    
    
    }

    private String getDirFromPackage(String targetPackageName) {
    
    
        return PROJECT_PATH + "/src/main/java/" + targetPackageName.replace(".", "/");
    }

    public void printMessageWithDate(String message) {
    
    
        System.out.println("[Generate Log]:[" + DateUtil.format(new Date(), DateUtil.YMDHMS) + "]" + message);
    }

    public String toFirstLower(String var) {
    
    
        return var.substring(0, 1).toLowerCase() + var.substring(1);
    }

    public String toFirstUpper(String var) {
    
    
        return var.substring(0, 1).toUpperCase() + var.substring(1);
    }

    public void addGenBean(LogicBean logicBean) {
    
    
        this.logicBeans.add(logicBean);
    }

    private enum OptionEnum {
    
    
        SAVE,
        PAGINATE;
    }

    public static class Toggle {
    
    
        private String key;
        private String value;

        public Toggle() {
    
    
        }

        public Toggle(String key, String value) {
    
    
            this.key = key;
            this.value = value;
        }

        public String getKey() {
    
    
            return key;
        }

        public void setKey(String key) {
    
    
            this.key = key;
        }

        public String getValue() {
    
    
            return value;
        }

        public void setValue(String value) {
    
    
            this.value = value;
        }
    }

    public static class StringKit extends StrKit {
    
    
        private static final long serialVersionUID = -808251639784763326L;
    }

    /**
     * 生成对象类
     */
    public static class LogicBean {
    
    
        private Class<?> entityClass;
        private String author;
        private String projectPath;
        private String controllerPackagePath;
        private String servicePackagePath;
        private String serviceImplPackagePath;
        private String converterPackagePath;
        private String requestPackagePath;
        private String responsePackagePath;
        private String pathValue;
        private String keywordSelect;
        private boolean isCrudType;
        private boolean needPaginate;
        private boolean needSort;
        private String tableEnumDes;

        public LogicBean() {
    
    
        }

        public LogicBean(Class<?> entityClass,
                         String tableDes,
                         String author,
                         String pathValue,
                         String controllerPackagePath,
                         String servicePackagePath,
                         String serviceImplPackagePath,
                         String converterPackagePath,
                         String requestPackagePath,
                         String responsePackagePath,
                         String keywordSelect,
                         boolean needPaginate,
                         boolean isCrudType) {
    
    
            if (!entityClass.isAnnotationPresent(Table.class)) {
    
    
                throw new RuntimeException("Entity:" + entityClass.getName() + "必须有 @Table 注解");
            }
            this.entityClass = entityClass;
            this.tableEnumDes = tableDes;
            this.author = author;
            this.pathValue = pathValue;
            this.controllerPackagePath = controllerPackagePath;
            this.servicePackagePath = servicePackagePath;
            this.serviceImplPackagePath = serviceImplPackagePath;
            this.converterPackagePath = converterPackagePath;
            this.requestPackagePath = requestPackagePath;
            this.responsePackagePath = responsePackagePath;
            this.keywordSelect = keywordSelect;
            this.needPaginate = needPaginate;
            this.isCrudType = isCrudType;

        }

        public Class<?> getEntityClass() {
    
    
            return entityClass;
        }

        public void setEntityClass(Class<?> entityClass) {
    
    
            if (!entityClass.isAnnotationPresent(Table.class)) {
    
    
                throw new RuntimeException("Entity:" + entityClass.getName() + "必须有 @Table 注解");
            }
            this.entityClass = entityClass;
        }

        public String getAuthor() {
    
    
            return author;
        }

        public void setAuthor(String author) {
    
    
            this.author = author;
        }

        public String getProjectPath() {
    
    
            return projectPath;
        }

        public void setProjectPath(String projectPath) {
    
    
            this.projectPath = projectPath;
        }

        public String getControllerPackagePath() {
    
    
            return controllerPackagePath;
        }

        public void setControllerPackagePath(String controllerPackagePath) {
    
    
            this.controllerPackagePath = controllerPackagePath;
        }

        public String getServicePackagePath() {
    
    
            return servicePackagePath;
        }

        public void setServicePackagePath(String servicePackagePath) {
    
    
            this.servicePackagePath = servicePackagePath;
        }

        public String getServiceImplPackagePath() {
    
    
            return serviceImplPackagePath;
        }

        public void setServiceImplPackagePath(String serviceImplPackagePath) {
    
    
            this.serviceImplPackagePath = serviceImplPackagePath;
        }

        public String getTableEnumDes() {
    
    
            return tableEnumDes;
        }

        public void setTableEnumDes(String tableEnumDes) {
    
    
            this.tableEnumDes = tableEnumDes;
        }

        public boolean isCrudType() {
    
    
            return isCrudType;
        }

        public void setCrudType(boolean crudType) {
    
    
            isCrudType = crudType;
        }

        public boolean isNeedPaginate() {
    
    
            return needPaginate;
        }

        public void setNeedPaginate(boolean needPaginate) {
    
    
            this.needPaginate = needPaginate;
        }

        public String getPathValue() {
    
    
            return pathValue;
        }

        public void setPathValue(String pathValue) {
    
    
            this.pathValue = pathValue;
        }

        public boolean isNeedSort() {
    
    
            return needSort;
        }

        public void setNeedSort(boolean needSort) {
    
    
            this.needSort = needSort;
        }

        public String getConverterPackagePath() {
    
    
            return converterPackagePath;
        }

        public void setConverterPackagePath(String converterPackagePath) {
    
    
            this.converterPackagePath = converterPackagePath;
        }

        public String getRequestPackagePath() {
    
    
            return requestPackagePath;
        }

        public void setRequestPackagePath(String requestPackagePath) {
    
    
            this.requestPackagePath = requestPackagePath;
        }

        public String getResponsePackagePath() {
    
    
            return responsePackagePath;
        }

        public void setResponsePackagePath(String responsePackagePath) {
    
    
            this.responsePackagePath = responsePackagePath;
        }

        public String getKeywordSelect() {
    
    
            return keywordSelect;
        }

        public void setKeywordSelect(String keywordSelect) {
    
    
            this.keywordSelect = keywordSelect;
        }
    }

    public static class Kv<K,V> extends HashMap<K,V> {
    
    

        private static final long serialVersionUID = -808251639784763326L;

        public Kv() {
    
    
        }

        public Kv<K,V> set(K key, V value) {
    
    
            super.put(key, value);
            return this;
        }

        public Kv<K,V> set(Map<K,V> map) {
    
    
            super.putAll(map);
            return this;
        }

        public Kv<K,V> delete(K key) {
    
    
            super.remove(key);
            return this;
        }

        public static <K,V> Kv<K,V> by(K key, V value) {
    
    
            return (new Kv<K,V>()).set(key, value);
        }

        public static <K,V> Kv<K,V> create() {
    
    
            return new Kv<K,V>();
        }

        public Kv<K,V> setIfNotNull(K key, V value) {
    
    
            if (value != null) {
    
    
                this.set(key, value);
            }
            return this;
        }

    }
}

MainLogicGenerator.javaCode zeigen wie folgt:

package com.duojiala.mikeboot.extend.gen;

import com.duojiala.mikeboot.domain.entity.Post;

/**
 * Controller Service 代码生成器
 */
public class MainLogicGenerator extends LogicGenerator {
    
    
    public static void main(String[] args) {
    
    
        new MainLogicGenerator().generate();
    }

    @Override
    public void initGenConfig() {
    
    
        // 以哪个实体类生成代码
        Class<?> clazz = Post.class;
        // 表描述
        String tableDes = "职位";  // TableEnum.java 类中的枚举,tableDes 为表的描述信息,如果不填默认为类名的全大写
        // 生成 java 代码的默认作者
        String author = "mike";
        // 映射路径
        String pathValue = ""; // 如果不填默认为类的全小写
        // Controller 类生成路径
        String controllerPackagePath = "com.duojiala.mikeboot.controller";
        // Service 类生成路径
        String servicePackagePath = "com.duojiala.mikeboot.service";
        // ServiceImpl 类生成路径
        String serviceImplPackagePath = "com.duojiala.mikeboot.service.imp";
        // Converter 转换器类生成路径
        String converterPackagePath = "com.duojiala.mikeboot.domain.converter.subclass";
        // Request 请求体类生成路径
        String requestPackagePath = "com.duojiala.mikeboot.domain.req";
        // Response 响应体类生成路径
        String responsePackagePath = "com.duojiala.mikeboot.domain.resp";
        // 是否需要分页查询
        boolean needPaginate = true;
        // 是否为普通增删操作
        boolean isCrudType = true;
        // 以那些字段进行模糊查询,多个用 "," 拼接,不设置默认为 name
        String keywordSelect = "";

        //创建主逻辑生成配置Bean
        LogicBean logicBean = new LogicBean(clazz, tableDes, author, pathValue,
                controllerPackagePath, servicePackagePath, serviceImplPackagePath,converterPackagePath,requestPackagePath,responsePackagePath,keywordSelect, needPaginate, isCrudType);

        //加入到生成队列中
        addGenBean(logicBean);
    }
}


4. Testeffekt

Ich muss nur die entsprechenden Informationen in MainLogicGeneratorder Startup- , z. B. hinzufügen, löschen, ändern und abfragen, welche Tabelle generiert werden soll, die entsprechende konfigurieren .class, einige Bedingungen wie Autor, Pfad festlegen, ob Paging-Methoden generiert werden sollen usw. und Führen Sie miandie Methode .

Bildbeschreibung hier einfügen
Zum Beispiel möchte ich, wie oben gezeigt, einige grundlegende Operationen im Zusammenhang mit postder Tabelle , und Sie können sehen, dass ich Controller、Service、ServiceImplhier keine solchen Dateien habe.

Bildbeschreibung hier einfügen

Sie können sehen, dass diese Dateien auch nach dem Ausführen generiert werden.


3. Quellcode des Projekts

Dies ist der Code-Generator, den ich geschrieben habe, und ich stelle auch den Download-Link des Projekts unten bereit, damit jeder spielen kann:

Link: Baidu Netdisk
Extraktionscode: xb1k

Zweitens möchte ich erklären, dass Sie, wenn Sie alle Dateien und Frontends dieser Entitätsklassen generieren möchten, vorschlagen, dass Sie sich ansehen, wie jfinales implementiert ist .

Supongo que te gusta

Origin blog.csdn.net/xhmico/article/details/130390843
Recomendado
Clasificación