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的物理地址, 然后点击载入


等上一秒钟,然后就可以看到效果了


再看看 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进行合并管理,方便大家导入使用

看下生成后的效果


至此一个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);

}

以上俩个类就是本工具的核心了,所有功能都是基于以上俩个类做的扩展,大家也可以根据需要做一些定制化的功能

因为是试用版本,肯定有很多不足之处,也欢迎大家留下宝贵的意见, 后续我会持续改进

posted @ 2020-08-05 09:24  荭丶尘  阅读(227)  评论(0编辑  收藏  举报