一种基于Service自动生成Controller的实现
目录
- 一、发明名称
- 二、背景技术与背景技术的课题
- 三、本发明的内容(构成、动作、附图等)
- 3.1 概述
- 3.2 自动生成controller模块
- 3.3 自动生成Service模块
- 四、本发明的效果
- 五、希望取得权利的技术要点
注: 被公司毙掉的专利思路,但是觉得其中的观点还是有借鉴意义的,分享给大家。
一、发明名称
一种基于Service自动生成Controller的实现
二、背景技术与背景技术的课题
传统基于Java、SpringMVC进行HTTP RESTFul应用开发时,通常会将程序分为controller层、service层、dao层等,servcie层作为最核心的业务实现必不可少,controller层负责HTTP RESTFul接口的定义,即开发者不得不在实现了service、dao后,需要额外再实现controller来负责Http接口的暴露,并在具体的controller实现方法中将Http请求委托给service层进行处理。实现controller时除了方法的定义,同时还需配合使用大量SpringMVC注解(如@RequestMapping、@RequestParam等)、service委托调用等,增加了开发者的工作量和上手难度。
为了避免传统开发模式下Http RESTFul应用中实现controller所带来的工作量,本发明提出一种基于Service自动生成Controller实现,开发人员仅需编写最核心的service实现,针对编码先行模式下本发明通过Java APT机制自动生成service对应的controller实现,同时针对接口设计先行模式下本发明同样支持根据通用的OpenAPI协议生成对应的service定义,大大提升了开发人员的工作效率,避免了手动实现controller的复杂度。
三、本发明的内容(构成、动作、附图等)
3.1 概述
传统基于Java、SpringMVC进行HTTP RESTFul应用开发时,针对某一业务单元如用户管理,开发者通常会编写用户controller实现、用户service实现等:
本发明提出一种基于Service自动生成Controller实现,开发人员仅需编写最核心的service实现,通过本发明的自动生成controller模块自动生成service对应的controller实现,使得开发人员无需再编写、维护相应的controller实现。目前市面上已存在的自动生成代码实现,都是生成可以编辑的代码文件,还是需要开发者将生成后的代码文件拷贝到开发工具(如Jetbrains IDE、Eclipse)中进行编辑和维护,后续还需将生成的代码上传到Git仓库中,如此开发者还是需要关注代码库中相关生成代码的维护,增加了开发者的维护负担。而本发明通过service自动生成的controller实现是没有实际需要维护的controller代码的,是在编译期自动生成,生成的代码对开发者不可见也无需维护,生成的代码会自动打包到可运行程序文件中,对开发者来说没有任何编辑、维护的负担。
针对编码先行模式下,传统开发过程需要3步,而使用本发明的自动生成controller模块仅需2步,大大提升了开发人员的工作效率,避免了手动实现及维护controller的复杂度:
针对接口设计先行模式下,传统开发过程需要4步,而使用本发明的自动生成service模块仅需3步。自动生成service模块支持根据接口文档(如兼容Swagger、OpenAPI等协议的接口文档)生成对应的service定义,然后再使用本发明中的自动生成controller模块进一步根据service自动生成对应的controller实现,满足了接口设计先行模式下整个开发流程的闭环。
综上,本发明主要分为2大模块:自动生成controller模块、自动生成service模块。
自动生成controller模块: 即根据service自动生成controller实现。针对编码先行模式(即先编写代码,然后通过代码生成接口文档),本模块可将按照指定规则编写的service通过APT生成器自动生成对应的controller实现,在保证了程序执行效率的前提下兼容了市面上主流的在线文档生成插件(SpringDoc、SpringFox、SmartDoc等)。
自动生成service模块: 即根据接口文档自动生成Service定义。针对接口设计先行模式(即先编写接口文档,然后根据接口文档生成代码),本模块支持根据通用的OpenAPI接口文档生成对应的service定义(具体的业务逻辑实现由开发者自行完成)。再结合之前的自动生成controller模块,即可达到接口设计、Service、Controller开发流程的闭环,保证了不同开发模式下(编码先行、接口设计先行)整个开发流程的无缝衔接与任意切换,拓宽了本发明的适用范围。
3.2 自动生成controller模块
自动生成controller模块(根据service自动生成controller实现)可将按照指定规则编写的service通过APT生成器自动生成对应的controller实现。
核心的service编写规则主要如下:
- 给service标注声明注解
- 使用指定的方法名前缀
- 使用指定的参数定义规则
- 使用指定的返回结果定义规则
如上规则支持可配置,即可根据需要自行通过配置进行调整。
注: APT(Annotation Processing Tool)是Java中的一种技术,用于在编译时处理注解。APT允许开发者创建自定义的注解处理器,这些处理器可以在编译期间扫描和处理源代码中的注解,并生成新的源代码或其他文件。
在开发者遵循了之前提到的service编写规则进行service实现后,本模块提供的APT生成器即可自动根据service生成controller实现,APT生成器主要基于Java中的APT(Annotation Processing Tool)技术,APT生成器具体执行过程如下:
1)根据service声明注解获取到所有的service实现类定义;
2)依次遍历service实现类,每个service实现类生成一个controller类(同时标注@RestContoller注解);
3)遍历单个service实现类中的所有方法,每个service方法转换为controller类中的一个方法(若某个service方法不需要转换为controller方法,支持通过注解或其他形式进行排除);
4)保存生成的controller类文件到指定包下。
APT生成器的具体执行过程可以概括为下图:
如上第2步中,service类名即对应controller类名或拼接特定前后缀等,如UserRoleServcie即对应UserRoleController,servcie类名即对应RESTFul基础path,如UserRoleService的基础path即为/user/role或/user_role等,如上转换皆可根据配置进行适当调整。
最核心的就是第3步,针对不同的service操作方法,主要的controller方法转换规则如下:
- controller方法复用service方法签名(方法名、参数列表、返回类型)、注释
- RESTFul接口的请求路径path根据移除方法前缀的方法名进行转换(如addUserRole的即为转换为/user/role或/user_role等,如上转换皆可根据配置进行适当调整)
- controller方法体内直接调用相应的service方法,亦可根据需要将service方法返回结果进行统一封装(如Controller层统一使用SystemResponse对象进行返回结果的封装)
- 根据service方法名前缀区分Http Method类型(如查询类方法使用@GetMapping,新增类使用@PostMapping等)
- 特殊处理上传文件、下载文件相关方法的转换(如设置文件流相关请求头、封装文件下载结果等)
- 自动根据参数类型适配Http请求参数类型(如简单参数使用Path参数格式,复杂参数使用body格式)
通过集成本发明提供的APT生成器,即可在Java程序编译期间自动生成Controller实现到指定包下,之后在程序启动时即可通过Controller实现类支持RESTFul接口调用。由于采用了Java APT机制,在程序编译期就已完成controller的生成(而不是在运行期通过过滤器、代理等进行解析),保证了程序的运行效率,兼容通过SpringDoc、SpringFox等插件动态生成在线接口文档。同时由于在转换期间保留了原service实现的注释说明到controller方法上,兼容SmartDoc等插件根据Java注释动态生成接口文档,大大提升了自动生成接口文档的便利性。
示例
下述为servcie转换成controller的具体示例,以便于更好地理解整个转换规则。
serivce代码:
/*** 业务服务* * @author luohq* @date 2025-03-07*/
interface BizService {/*** 查询单个实体** @param id ID* @return 单个实体*/E find(ID id);/*** 查询多个实体* * @param baseQuery 查询参数* @return 实体列表*/List<E> findList(BaseQuery baseQuery);/*** 查询分页列表* * @param baseQueryDto 分页查询参数* @return 分页查询结果*/IPage<E> findPage(BaseQueryDto baseQueryDto);/*** 新增角色** @param role 角色* @return 新增结果*/UserDetail addRole(Role role);/*** 修改角色** @param role 角色* @return 修改结果*/Boolean updateRole(Role role);/*** 批量删除角色** @param ids ID集合* @return 删除结果*/Boolean removeRole(Collection<ID> ids);/*** 上传文件** @param fileUploadDto 上传参数* @return 文件信息*/public FileInfo uploadFile(FileUploadDto fileUploadDto);/*** 下载用户列表导入模版* * @return 用户列表导入模版*/File downloadUsersTemplate();
}
根据上述servcie自动生成的controller代码:
/*** 业务服务* * @author luohq* @date 2025-03-07*/
@RestController
class BizController {@Autowiredprivate BizService service;/*** 查询单个实体** @param id ID* @return 单个实体*/@GetMapping("/{id}")E findOne(@PathVariable ID id) {return service.one(id);}/*** 查询多个实体* * @param baseQuery 查询参数* @return 实体列表*/@GetMapping("/list")List<E> findList(BaseQuery baseQuery) {return service.findList(baseQuery);}/*** 查询分页列表* * @param baseQueryDto 分页查询参数* @return 分页查询结果*/@GetMapping("/page")IPage<E> findPage(BaseQueryDto baseQueryDto) {return service.fingPage(baseQueryDto);}/*** 新增角色** @param role 角色* @return 新增结果*/@PostMapping("/role")Boolean addRole(@RequestBody Role role) {return service.addRole(role);}/*** 修改角色** @param role 角色* @return 修改结果*/@PutMapping("/role")Boolean updateRole(@RequestBody Role role) {return service.updateRole(role);}/*** 批量删除角色** @param ids ID集合* @return 删除结果*/@DeleteMapping("/role/{ids}")Boolean removeRole(Collection<ID> ids) {return service.removeRole(ids);}/*** 上传文件** @param fileUploadDto 上传参数* @return 文件信息*/@PostMapping(value = {"/file"}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public FileInfo uploadFile(FileUploadDto fileUploadDto) {return service.uploadFile(fileUploadDto);}/*** 下载用户列表导入模板* * @param response 响应对象* @return 用户列表导入模版* @throws IOException*/@GetMapping(value = {"/users_template"})public Resource downloadUsersTemplate(HttpServletResponse response) throws IOException {File file = service.downloadUsersTemplate();response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);response.setContentLength((int) file.length());response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName());return new FileSystemResource(file);}
}
3.3 自动生成Service模块
OpenAPI规范(简称OAS)
RESTful API的接口定义规范,目前支持OAS 2.0和OAS 3.0(前身也叫Swagger规范,在2015后捐赠给Linux Foundation后更名为OpenAPI)。
自动生成service模块(即根据OpenAPI接口文档自动生成Service定义)支持根据OpenAPI接口文档生成对应的service定义(包括service接口、参数类、结果类),具体的业务逻辑实现由开发者自行完成。如此针对接口设计先行模式下,开发者只要使用兼容OpenAPI的在线文档编辑工具(如Yapi、Torna等),并将其导出为标准的OpenAPI接口文档,即可通过本发明根据OpenAPI接口文档快速的生成service代码,大大地提升了开发速度。再结合自动生成controller模块,即可再根据service自动生成controller实现,快速实现RESTFul接口的集成。
本模块的主要生成过程如下:
1)通过OpenAPIV3Parser(由开源软件swagger-parser-v3提供)解析OpenAPI文档内容,生成OpenAPI模型;
2)解析OpenAPI模型生成中间模型;
3)使用中间模型结合自定义service生成模版(支持mustache、freemarker等模版引擎)生成service接口、参数类、结果类文件。
开发者将自动生成的service定义添加到项目中,之后即可在自动生成的service定义上快速地开始业务逻辑的开发,再结合自动生成controller模块,开发者无需再手动实现controller即可自动支持OpenAPI接口文档描述的RESTFul接口,大大地提升了开发速度和接口实现的匹配度。
本模块的主要生成过程可以概括为下图:
OpenAPI模型、中间模型、Service定义间的转换关系(从左至右)见下表:
OpenAPI模型 到 Service定义间的关键转换规则如下:
- 接口请求method对应service方法名前缀,请求路径对应service方法名后缀,如接口POST /user/role则对应addUserRole方法名,请求method的转换即对应自动生成servcie模块的操作类型方法前缀和RESTFul接口method的转换规则,RESTFul接口的请求路径转换为驼峰风格表示方法名后缀(如/user/role即为转换为UserRole,此转换可根据配置进行适当调整);
- 若存在多个参数则统一封装成参数类;
- 响应结果封装成结果类;
- 若多个参数类或结果类的属性相同,则仅保留唯一的参数类或结果类(避免生成多个同样的类);
- service定义(方法、参数、返回结果)、参数类、结果类的注释采用OpenAPI相应的接口、操作、属性等描述信息;
四、本发明的效果
1. 根据service自动生成controller实现,避免了手动实现controller的工作量和复杂度。
针对编码先行模式(即先编写代码,然后通过代码生成接口文档),本发明提出一种基于Service自动生成Controller的实现,开发人员仅需编写最核心的service实现,自动生成controller模块即可将按照指定规则编写的service通过APT生成器自动生成对应的controller实现,区别于其他自动生成实现生成需要开发者进行维护的代码文件,本发明生成的controller对开发者不可见也无需维护,大大提升了开发人员的工作效率,避免了手动实现controller的复杂度。
2. 自动生成的controller兼容主流的接口文档动态生成插件。
由于采用了Java APT机制,在程序编译期就已完成controller的生成(而不是在运行期通过过滤器、代理等进行解析),保证了程序的运行效率,兼容通过SpringDoc、SpringFox等插件动态生成在线接口文档。同时由于在转换期间保留了原service实现的注释说明到controller方法上,兼容SmartDoc等插件根据Java注释动态生成接口文档,大大提升了自动生成接口文档的便利性。
3. 根据接口文档自动生成servcie定义,保证了不同开发模式下(编码先行、接口设计先行)整个开发流程的无缝衔接与任意切换。
针对接口设计先行模式(即先编写接口文档,然后根据接口文档生成代码),自动生成service模块支持根据通用的OpenAPI接口文档生成对应的service定义。如此开发者只要使用兼容OpenAPI的在线文档编辑工具(如Yapi、Torna等),并将其导出为标准的OpenAPI接口文档,即可通过本发明根据OpenAPI接口文档快速的生成service代码,大大地提升了开发速度。再结合自动生成controller模块,即可再根据service自动生成controller实现,快速实现RESTFul接口的集成,达到接口设计、Service、Controller开发流程的闭环,保证了不同开发模式下(编码先行、接口设计先行)整个开发流程的无缝衔接与任意切换,拓宽了本发明的适用范围。
五、希望取得权利的技术要点
- 自动生成controller模块可将按照指定规则编写的service通过APT生成器自动生成对应的controller实现,生成代码对开发者不可见也无需维护,即保证了程序执行效率,又兼容了市面上主流的在线文档生成插件(SpringDoc、SpringFox、SmartDoc等)。
- 自动生成service模块支持根据通用的OpenAPI接口文档生成对应的service定义,再结合之前的自动生成controller模块,即可满足不同开发模式下(编码先行、接口设计先行)整个开发流程的无缝衔接与任意切换。