domain代碼生成修改工具,批量生成swagger、javax.validation註解,減少重複工作

在這個微服務化爲主流的階段,domain的重要性不言而喻,他即體現了一個服務的業務能力,又是服務間通信的契約,
市面上已經有一些很成熟的domain代碼生成工具,比如Mybatis-Generator, 但是基本沒看到可以支撐domain進行二次代碼修改的自動化工具.

這在很多場景下增加了額外的開發工作量

例如前後端分離,很多小夥伴會選擇swagger作爲api文檔生成工具,但這也意味着我們需要對原有的domain進行較大的修改,添加swagger註解.

例如在業務不清晰多變的場景,尤其是前端業務多變,增/減字段,後端小夥伴也要批量去修改相應的Rquest、VO

針對以上等現象,我開發了一個小工具https://github.com/zhaojun123/domainmanage.git

爲了方便演示效果,這裏創建一個測試項目(domain_test) 模擬前後端分離
在這裏插入圖片描述
創建目錄結構 controller, request(入參),vo(出參)

pom.xml 添加swagger支持

		<dependency>
			<groupId>com.spring4all</groupId>
			<artifactId>swagger-spring-boot-starter</artifactId>
			<version>1.9.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>swagger-bootstrap-ui</artifactId>
			<version>1.9.3</version>
		</dependency>

DomainTestApplication.java 啓用swagger

@EnableSwagger2Doc
@SpringBootApplication
@EnableSwaggerBootstrapUI
public class DomainTestApplication {

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

}

UserController.java 添加@Api、@ApiOperation註解

@Api(tags = "用戶模塊")
@RestController
public class UserController {


    @ApiOperation("添加用戶")
    @PostMapping("/addUser")
    public String addUser(@RequestBody AddUserForm addUserForm){
        return null;
    }


    @ApiOperation("用戶查詢")
    @GetMapping("/detail")
    public UserDetailVO detail(String userId){
        return null;
    }

}

啓動項目 訪問http://localhost:9999/doc.html在這裏插入圖片描述
在這裏插入圖片描述
點擊添加用戶菜單,可以看到swagger已經幫我們寫好了請求示例的json結構
但是並沒有相應的參數說明和示例數據, 所以這隻能算半成品,交出去會被前端小夥伴揍的

針對於這個例子,我們還需要完善AddUserForm 在每個field上添加@ApiModelProperty註解

AddUserForm

/**
 * 添加用戶模型
 */
public class AddUserForm {

    /**
     * 賬號
     */
    private String account;

    /**
     * 密碼
     */
    private String password;

    /**
     * 年齡
     */
    private Integer age;

    /**
     * 性別 男、女
     */
    private String sex;

    /**
     * 姓名
     */
    private String userName;

    /**
     * 添加所屬單位
     */
    private OrganForAdd organ;

	//省略get set
}

/**
 * 添加單位模型
 */
public class OrganForAdd {

    /**
     * 單位名稱
     */
    private String organName;

    /**
     * 單位地址
     */
    private String organAddress;

    /**
     * 單位地區
     */
    private String area;
	
	//省略get set
}

這工作量就多了不少,如果這樣的domain有十個 百個,那一天寶貴的時間就全部去寫swagger註解了

接下來我們看下自動化工具是如何解決這個問題的,啓動domainmanage項目,訪問地址
http://localhost:8888/domainManage/domain
在這裏插入圖片描述
複製我們需要改造的doamin的物理地址, 然後點擊載入
在這裏插入圖片描述

在這裏插入圖片描述
勾選AddUserForm、OrganForAdd, 然後點擊批量生成Swagger註解
在這裏插入圖片描述
等上一秒鐘,然後就可以看到效果了
在這裏插入圖片描述
在這裏插入圖片描述
再看看 http://localhost:9999/doc.html
在這裏插入圖片描述
發現field相對應的參數說明已經有了,但是@ApiModelProperty註解裏面的example依然爲空,這要一個個寫的話依然很麻煩, 而且其中還包含了大量重複的field, 例如常用的userId、organId、userName等

我們還是需要用工具解決這個問題, 點擊設置example選項卡
在這裏插入圖片描述
因爲我們是第一次使用這個功能,所以顯示的是空的列表, 點擊快速生成example
在這裏插入圖片描述
這個功能會分析你載入的domain,提取所有的field,並且根據fieldType類型以及是否重複做過濾,最終會生成一個列表, 可以在這裏快速的填寫example
在這裏插入圖片描述
在這裏插入圖片描述
填寫的數據會保存在你當前的工作目錄下${user.dir}/example.properties
在這裏插入圖片描述
也可以通過導入功能,導入別人寫好的example.properties,該操作是增量操作,不會覆蓋你本地已寫好的example,所以任何情況都可以大膽的導入
可以通過git 、svn等將example.properties進行合併管理,方便大家導入使用
在這裏插入圖片描述
填寫好了example 我們需要先點擊清除swagger註解,再重新生成swagger註解, 這是爲了防止將你手動修改過的代碼覆蓋了
在這裏插入圖片描述
看下生成後的效果
在這裏插入圖片描述
在這裏插入圖片描述
至此一個api文檔就完成了

自動生成javax.validation註解

在這裏插入圖片描述
點擊相應的類可以進入修改頁面
在這裏插入圖片描述
在這裏可以對field字段添加validation註解,目前只做了@NotNull 、@NotEmpty、NotBlank,大家也可以根據需要自己做擴展,
已經生成好相應的錯誤提示,只需要勾選相應的註解, 點擊修改即可
在這裏插入圖片描述

其它功能

該工具還包括
批量添加/刪除 field、 查詢 、排序 、field字典 、代碼查看等小功能, 主要作用還是方便使用, 也可以根據自身需要在這個基礎上做擴展

部分代碼解析

該工具的原理是讀取java文件, 根據正則表達式解析相應的 package、import、class、field、method、annotation、註釋 , 然後根據需要對其進行相應的增刪改,再重新寫回java文件

Java代碼解析類com.zkml.domainmanage.support.metadata.DomainDelegate

/**
     * 逐行讀取內容,進行正則匹配處理
     */
    public DomainMetadata init(){
        String content = domainMetadata.getContent();
        if(!StringUtils.isBlank(content)){
            contentList = Collections.unmodifiableList(Arrays.asList(content.split("\n")));
            domainMetadata.setContentList(contentList);
        }
        for(lineIndex=0;lineIndex<contentList.size();lineIndex++){
            String contentLine = contentList.get(lineIndex).trim();
            if(analysisPackage(contentLine))
                continue;
            if(analysisImport(contentLine))
                continue;
            if(analysisNote(contentLine))
                continue;
            if(analysisAnnotation(contentLine))
                continue;
            if(analysisClass(contentLine))
                continue;
            if(analysisField(contentLine))
                continue;
            if(analysisMethod(contentLine))
                continue;
        }
        domainMetadata.setImportList(Collections.unmodifiableList(importList));
        domainMetadata.setFieldMetadataList(Collections.unmodifiableList(fieldList));
        domainMetadata.setMethodMetadataList(Collections.unmodifiableList(gsMethodList));
        return domainMetadata;
    }

解析後會生成相應的屬性模型
在這裏插入圖片描述

其中 swaggerMetadata、validationMetadata是根據業務需要做的擴展

com.zkml.domainmanage.support.metadata.DomainMetadataHandle
對field、method、class等屬性進行增刪減操作的接口,所有業務邏輯只要涉及到修改java代碼都會調用這個接口
默認實現類是
com.zkml.domainmanage.support.metadata.DefaultDomainMetadataHandle

public interface DomainMetadataHandle {

    /**
     * 初始化DomainMetadata,這裏傳入的DomainMetadata包含localPath、fileName,content、className
     * 需要解析fieldMetadataList、methodMetadataList、importList、classNote、fullClassName
     * @param domainMetadata
     */
    DomainMetadata init(DomainMetadata domainMetadata);

    /**
     * 刪除field
     * @param fieldMetadata 需要刪除的fieldMetadata
     * @param domainMetadata field所屬的domainMetadata
     * @param status ALL,GET,SET,NONE 是否對get/set方法進行操作
     */
    void delete(FieldMetadata fieldMetadata, DomainMetadata domainMetadata,FieldMetadata.Status status);

    /**
     * 批量刪除field
     * @param fieldMetadataList
     * @param domainMetadata
     * @param status
     */
    void delete(List <FieldMetadata> fieldMetadataList, DomainMetadata domainMetadata,FieldMetadata.Status status);

    /**
     * 添加field
     * @param fieldMetadata 包含fieldContent getMethodContent,setMethodContent,sortNo,status
     * @param domainMetadata field所屬的domainMetadata
     * @param status ALL,GET,SET,NONE 是否對get/set方法進行操作
     */
    void add(FieldMetadata fieldMetadata,DomainMetadata domainMetadata,FieldMetadata.Status status);

    /**
     * 批量添加field
     * @param fieldMetadataList
     * @param domainMetadata
     * @param status
     */
    void add(List<FieldMetadata> fieldMetadataList,DomainMetadata domainMetadata,FieldMetadata.Status status);

    /**
     * 對class的 annotation note進行修改
     * @param classMetadata
     * @param domainMetadata
     */
    void update(ClassMetadata classMetadata,DomainMetadata domainMetadata);
    /**
     * 修改field
     * @param fieldMetadata
     * @param domainMetadata field所屬的domainMetadata
     * @param status ALL,GET,SET,NONE 是否對get/set方法進行操作
     */
    void update(FieldMetadata fieldMetadata,DomainMetadata domainMetadata,FieldMetadata.Status status);

    /**
     * 批量修改field
     * @param fieldMetadataList
     * @param domainMetadata
     * @param status
     */
    void update(List<FieldMetadata> fieldMetadataList,DomainMetadata domainMetadata,FieldMetadata.Status status);
    /**
     * 批量添加import
     * @param importList
     * @param domainMetadata
     */
    void add(List<OtherMetadata> importList,DomainMetadata domainMetadata);

    /**
     * 批量刪除import
     * @param importList
     * @param domainMetadata
     */
    void delete(List<OtherMetadata> importList,DomainMetadata domainMetadata);

}

以上倆個類就是本工具的核心了,所有功能都是基於以上倆個類做的擴展,大家也可以根據需要做一些定製化的功能

因爲是試用版本,肯定有很多不足之處,也歡迎大家留下寶貴的意見, 後續我會持續改進

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章