项目代码的结构仁者见仁智者见智,没有特定的规范,更加没有银弹,只有合适不合适! 首先module的组成: ``` fw-sample-admin fw-sample-api fw-sample-job fw-sample-mqc fw-sample-portal fw-sample-rpc fw-sample-service ``` 所有业务都集中在了service module中;通过包名区分功能边界; admin/portal组成后台管理系统; api作为客户端服务接口提供方和rpc的服务提供方; rpc作为服务提供方的对外共享包; mqc作为消息队列的消费方启动(可放在api中); job作为独立的任务服务; portal方案是参考的免费小说项目作为基础结构; 下面是包的具体说明: # fw-sample-admin 包结构描述 com.mokasz.fw.admin controller //Api controller AdminApplication //Api启动类 resources //资源文件 # fw-sample-api 包结构描述 com.mokasz.fw.api //针对小程序端,和RPC服务端 controller //Api controller ApiApplication //Api启动类 resources //资源文件 # fw-sample-job 包结构描述 com.mokasz.fw.job controller //Job controller JobApplication //Job启动类 resources //资源文件 # fw-sample-mqc 包结构描述 com.mokasz.fw.job MqcApplication //Mqc启动类 resources //资源文件 # fw-sample-rpc 包结构描述 com.mokasz.fw.rpc query //rpc 请求对象 vo //rpc返回对象 # service包结构描述 com.mokasz.fw api //接口api query //请求视图对象 vo //返回视图对象 admin //后台api & vue query //请求视图对象 vo //返回视图对象 common //通用层 bean //spring bean config //configruation aspect //切面逻辑 context //上下文 enums //枚举 constant //常量 util //工具类 ds //数据源 convert //map struct event //spring application event exception //自定义异常 interceptor //拦截器 properties //配置项对象 model //通用模型 filter //过滤器 vm //velocity模板文件 lib //(复杂业务、领域业务处理) model //领域层对象 manager //(二方、三方包封装) mq //(消息消费、发送) listener //消息监听 producer //消息生产 job //(任务调度相关) rpc.impl //dubbo rpc 实现 service //业务层 dto //业务层对象 impl //业务层实现 mapper //持久层 xml //mybatis xml entity //持久层对象 ## 说明 ### dynamic-datasource-spring-boot-starter https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter ### com.mokasz.sample.common.annotation.GlobalApiResponse Controller上加上该注解由框架封装ApiResponse ### ApiContext 该上下文提供了xxl sso的用户信息 ### AvoidDuplicateSubmitInterceptor 防重复提交 使用注解 @AvoidDuplicateSubmit ### 统一线程池 ThreadPoolTaskExecutor;ttlExecutor增强版 ## 一些边界说明 - controller可以直接使用service, mapper(针对简单的功能) - POST requestBody 必须是Query,ENT - POST responseBody 必须是ENT, DTO,VO - 针对复杂的,业务弱关独立的功能,代码放在lib包下,通过报名区分功能; - 一个接口只做一件事情(单一职责) - 前期开发还没那么多业务特性的时候,别整一些有的没得设计模式进行套用。当业务清晰的时候,有时间进行重构。 - 为什么必须: 明确数据来源,当你看到Query的时候,就可以很明确的知道它是来自接口入参,其他同理; 为什么不接口复用:通过字段区分不同功能,然后if else 它看起来就复用了吗? 职责单一才能复用。