跳到主要内容

后端开发

后端工程规范实践

依赖引入

  • 为确保依赖版本的统一管理和维护,所有依赖包均在根工程 innospots-root 的 POM 文件中进行集中定义。具体而言,依赖包的版本号统一在 properties 变量中声明,其他子模块在引入依赖时不允许直接指定版本号。

  • 项目中所需的所有第三方 jar 包依赖都必须在 dependencyManagement 中进行统一声明和管理。这样可以有效控制依赖版本,避免版本冲突。

  • 对于包含子模块的父模块,其 packaging 类型需设置为 pom。在父模块的 dependencyManagement 中统一定义子模块所需的依赖包。如果某个依赖被所有子模块共用,则可以直接在父模块的 dependencies 中声明,子模块将自动继承。

命名规范

模块命名规范

  • 工程模块全部以innospots-开头
  • 工程模块名称使用kebab-case命名法,单词间以中划线分隔,单词小写
  • 工程模块名称使用2-4个单词命名,最多不超过5个
  • 命名方式上体现模块间的上下级关系,例如:innospots-extension模块下的所有子模块全部以innospots-extension-*开头

包命名规范

  • 包的命名方式采用两种方式: 一种为基于MVC架构的包命名方式,按数据库层,服务层,接口层,模型层,实体层命名,常用于做管理平台类工程或模块使用。一种为基于业务领域,功能模块的命名方式,按包中的业务功能或支撑功能划分包结构。
  • 包名尽量使用完整单词或行业通用缩写词,不建议使用两个单词定义包名
  • 在语义明确的前提下,尽量精简,做到见名知意
  • 包名称命名全部小写

以下为通用功能下的常用包名定义

  • configuration, Spring Configuration,自定义Properties
  • controller, 管理平台端Restful API接口
  • constant, 常量值类
  • entity, 数据库表的实体POJO
  • model, 业务类模型POJO,与实体POJO有对应关系
  • dao, 数据库操作,返回实体类
  • operator, 在管理端对数据库的CURD的操作,对controller层提供实际数据操作实现,包含参数校验,简单的数据层面的逻辑处理
  • mapper, mapstruct的POJO转换Mapper,entity的POJO和业务模型的POJO的转换
  • service, 复杂业务逻辑,多模块的operator的聚合调用
  • enums, 枚举类型定义
  • exception, 业务异常类
  • utils, 工具类定义,日期,字符串转换,国际化,Bean拷贝等
  • endpoint, 服务类API
  • filter, Servlet Filter的自定义实现类
  • starter, Spring Boot 启动后调用的ApplicationRunner实现类
  • server, 应用服务启动主类,或嵌入服务
  • event, 事件定义,基于ApplicationEvent,或自定义Event的实现
  • interceptor, Spring MVC 的interceptor的自定义实现类
  • aspect, 基于Spring AOP的拦截定义
  • listener, event的监听器
  • loader, 资源加载,数据加载

类命名规范

  • 符合Java类基本命名规范
  • 采用驼峰式命名
  • 类名称通常采用主语词+核心功能后缀词的方式定义,采用名词作为后缀词,表明当前类的核心用途,可体现出层级
  • 除了业务POJO外,类名需要使用两个以上单词定义,避免使用单个通用性单词定义类名,例如:Config,Status等,更好方式应该定义为DataConfig,TaskStatus等更加语义明确的名称定义
  • 类注释上必须包含作者,版本号,时间日期,以及类的用途说明

常用类名词参考

  • **Entity, 数据库表实体POJO
  • **Dao, 数据库ORM框架中的实体操作类,集成Mybatis Plus的BaseMapper的数据访问类
  • **Controller, 管理平台Restful API接口
  • **Filter, 管理平台端Servlet javax.servlet.Filter的实现类
  • **Interceptor, 管理平台端 Spring Web中的HandlerInterceptor的实现类
  • **Operator, CURD数据的操作类
  • **Service, 跨模块,多Operator的业务服务实现
  • **Mapper, mapstruct的Mapper,实体POJO与业务模型POJO的转换
  • **Handler, 在业务责任链模式中的输入数据的接收者和业务处理
  • **Encoder, 对数据的编码或加密
  • **Decoder, 对数据的解码或解密
  • **Utils, 工具类,静态类
  • **Loader, 数据加载,资源加载
  • **Operator, 数据的业务模型层的CRUD操作
  • **Endpoint, 服务类型的API接口
  • **Exception, 业务异常,继承RuntimeException
  • **Configuration, Spring Configuration 定义
  • **Properties, Spring Properties的定义
  • **Watcher, 观察者,定时执行,监听执行
  • **Manager, 业务资源管理类,用于资源加载到Manager中,由Manager负责业务资源的处理和缓存
  • **Builder, 构造者模式的构造器,用于创建新的对象和数据
  • **Listener, Spring Application Event事件的监听器
  • **Perparer, 资源预备器,做业务逻辑预先准备使用
  • **Starter, Spring ApplicationRunner接口实现,用于启动加载资源,初始化使用
  • **Matcher, 匹配器,用于执行匹配,例如:UrlPattern的疲累
  • **Generator, 生成器,随机数,主键,字符串等生成
  • **Converter, 数据转换处理
  • **Server, 服务启动主入口
  • **Store, 数据存储
  • **Reader, 数据只读功能
  • **Receiver, 消息队列接收者
  • **Sender, 消息队列发送者
  • **Engine, 执行引擎
  • **Factory, 工厂模式功能类
  • **Facade, 门面模式功能类
  • **Executor, 执行器
  • **Event, Spring ApplicationEvent 自定义事件
  • **Status, 枚举类,业务状态的定义
  • **Type, 枚举类,业务类型定义
  • **Context, 执行上下文,数据上下文
  • **Execution, 执行记录,任务执行,流程执行
  • **Base, 业务模型基础类,用于做扩展集成
  • **Exporter, 数据导出,资源导出
  • **Importer, 基于注解的 Spring Configuration bean的集成导入定义
  • **Container, 业务执行容器
  • **Job, 调度任务定义
  • Base**, 抽象类,基础公共类定义

方法命名规范

  • 方法命名主要采用动词+名词的命名规则,对业务性明确的类中可以直接使用动词做方法名称

以下为常用动词方案

  • fetch,接口获取数据
  • load, 页面加载
  • build,模型构造,对象构建
  • change,状态变更
  • cancel,动作撤销
  • send, 监听模式的发送事件
  • receive,接收事件动作
  • create,新建操作
  • update,modify,更新操作
  • delete,删除操作
  • read,读取数据操作,包含接口获取,read方法主要用于只读功能类中的操作
  • listen,监听事件
  • findqueryselect,查询list或数组中的数据,查询数据库数据,可有多种形式的查询条件,着重不同参数条件的查询
  • filter,对某个数据,按条件过滤
  • extract,抽取操作
  • format,将某对象格式化为固定格式字符串
  • parse,将字符串解析为对象
  • list,返回列表数据,无条件或者条件固定,着重返回的数据,弱化查询条件
  • get,获取模型字段值,获取单一模型数据
  • set,设置模型字段值
  • publish,发布动作
  • save,create或者update
  • record,插入数据,用于日志数据,记录型数据
  • refresh,刷新
  • show,展示显示操作,无翻页
  • clean,清除数据,清除状态
  • remove,移除动作,非物理删除
  • generate,创建生成对象,生成随机数等
  • check,检查值,检查合法性
  • start,开始启动,模块功能启动
  • stop,停止服务,停止线程
  • open,打开配置,打开流,打开资源
  • close,关闭资源
  • prepare,预处理准备
  • compile,编译动作
  • runexecute,执行动作
  • initialize,初始化
  • copy,拷贝对象,拷贝数组
  • fill,填充数据,基于参数数据填充
  • add,添加数据到列表或map
  • contain,是否包含数据
  • match,匹配判断

接口规范

  • 管理平台类Controller接口主要采用Restful风格规范定义
  • 使用Spring MVC的PostMapping,DeleteMapping,PutMapping,GetMapping定义对资源的增删改查
  • Controller使用OpenAPI 3.0定义接口描述和参数信息
  • 对查询条件类字段使用Param类参数
  • 对业务操作类的API需要在URI中增加操作词说明,例如:online,offline,execute等
  • 使用javax.validation来验证输入参数的有效性和合法性,在参数的输入model中包含验证规则注解
  • io.innospots.base.constant.PathConstant定义ROOT_PATH为管理端API的contextPath,所有涉及管理平台端权限管控的API都需要以此常量作为contextPath路径设置
  • API Path路径命名使用kebab-case命名法,单词间以中划线分隔,单词小写
  • 服务类接口定义在endpoint包中,服务类接口只使用POST方法和GET方法定义接口操作

配置规范

  • application.yaml, 服务的基础配置,不跟随环境进行变更
  • application-xxx.yml, 按不同的环境的配置,主要包含数据库的配置,系统变量的配置
  • application-security.yml, 权限拦截,授权key配置

开发实践

管理模块

Innospots提供通用管理平台Libra,包含最小化的管理平台功能支撑包括:工作台,通知消息,权限设置,菜单设置,国际化,系统配置管理以及数据看板

后端模块结构采用MVC结构模式,每个模块都有独立的MVC结构。管理平台的功能扩展通过扩展应用的形式增加平台功能扩展

  • controller, 模块API接口,以资源为粒度定义api接口的controller
  • dao, 物理数据表entity的CRUD功能,对数据表关联较强的场景,可在dao中单独定义连表查询方法,以注释的方式扩展连表查询
  • entity, 数据库实体表,按物理表对应,每个物理表对应一个entity的POJO
  • mapper, 业务模型和实体POJO的转换mapper,这里使用mapstruct做POJO的相互转换
  • model, 业务模型的POJO
  • operator, 数据资源的CRUD功能,对数据字段的有效性进行验证,在无表关联时,通常一个operator引用一个dao,对数据表业务关联关系较强的operator中可引用使用多个dao
  • service, 在包含负责的业务逻辑操作,需要在一个模块中跨多个operator完成时,可单独定义业务类的service,此service将引入多个operator处理复杂的业务逻辑,包含业务逻辑类的数据验证及判断

模块间交互

  • 【service层集成】当有业务场景需要多个模块的功能时可在上层service上引入不同模块的operatorservice实现多模块的功能操作
  • 【数据事件通知】通过Spring Event实现在跨模块间的数据交互,当一个模块中的业务逻辑涉及到跨模块的业务交互时,使用event机制实现数据交互。例如:菜单操作关闭,对应的菜单权限的设置关闭

菜单、权限与操作日志

在管理端的API接口的Controller上定义接口的权限和菜单定义,每一个API接口对应Controller的一个方法,在Controller类和方法上增加注解项,明确定义API接口的菜单项,应页面端的操作以及操作日志

  • 在Controller类上定义菜单项【ModuleMenu】,key值为innospots-application-meta.json中modules的itemKey值,表明当前controller对应的模块操作项
  • 多个Controller对应一个菜单Module时,ModuleMenu设置相同的key值即可
  • 在Controller的方法上添加【ResourceItemOperation】的操作注解,标识菜单的操作接口,用于在菜单权限中设置操作权限配置,操作项不需要设置只读的接口
  • 在Controller的方法上添加【OperationLog】注解用于操作日志的记录,增加OperationLog的注解方法将在操作日志中记录操作日志

POJO

  • 管理平台端定义了两类POJO,一类为Entity,一类为业务Model
  • Entity为数据表结构映射,使用常量TABLE_NAME定义对应的表名称
  • 在Entity的成员中使用了javax.persistence.Column注解标注数据表字段的类型,长度,主键信息,但系统的ORM并不使用Hibernate或JPA做ORM使用
  • 业务POJO用于接口返回数据结构
  • POJO中使用Lombok@Getter@Setter定义属性的操作,POJO中,不使用Lombok的其他注解

异常以及异常码

  • innospots-baseexception中定义系统常用异常类
  • io.innospots.base.exception.BaseException为系统定义的基础异常类,所有其他系统异常继承此异常类
  • 业务自定义异常的方式使用build静态方法创建异常类实例,可参见业务异常类中的build构建实例
  • ErrorResponse作为异常异常的时的数据返回,code,message,detail包含当前的异常信息
  • GlobalExceptionHandler作为全局异常处理类,将拦截所有接口层面抛出的异常
  • io.innospots.base.model.response.ResponseCode中定义了系统状态码code的定义

数据操作

  • 本系统使用Mybatis Plus作为基础dao模块的ORM操作类
  • 业务dao接口继承com.baomidou.mybatisplus.core.mapper.BaseMapper, 将继承对公共资源CRUD以及列表查询操作
  • 业务操作定义在operator中,继承com.baomidou.mybatisplus.extension.service.impl.ServiceImpl,将继承常用业务资源的CRUD功能

模块依赖引入

  • 系统模块采用主动引入的方式将不同模块的'Spring Bean'引入到当前工程模块
  • 在每个模块的基础包定义模块的**Importer注解,此Importer将引入当前模块中所定义配置的'Spring Bean'引入到当前服务中
  • Importer中将明确的定义,Spring ComponentScan的生效的包范围,以及使用的Spring Configuration,在Configuration中明确定义模块中所使用的Spring Bean定义

事件总线

  • 事件总线用于跨模块,跨系统,异步等场景使用,解耦和提升系统处理性能
  • io.innospots.base.events 中为系统自定义使用的事件处理模块
  • 对管理平台中,系统使用自定义的EventBus和对应的EventListener作为事件处理体系

观察者线程

  • innospots-base模块watcher包中定义观察者线程
  • io.innospots.base.watcher.WatcherSupervisor观察者线程池, 系统中定义的观察者线程通过registry方法添加观察者线程的注册,在模块中定义ApplicationRunner中将此模块中的观察者线程添加到
  • 观察者线程由观察者线程池和观察者线程组成,观察者线程将以定时轮询的方式常驻内存执行,用于检查,定时更新等操作
  • 系统中定义了了多种功能的观察者,包括:服务注册观察者,Workflow上线状态观察者,等待定时执行观察者等