# legendshop代码生成器 **Repository Path**: yonglehou/legendshop-code-generator ## Basic Information - **Project Name**: legendshop代码生成器 - **Description**: 基于数据库用于专门生成LegendShop的后台代码,生成之后可以手动拷贝到idea或者eclipse中,也可以用easycode来生成代码。 - **Primary Language**: Java - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2025-04-22 - **Last Updated**: 2025-04-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 一、使用帮助 ### 1. 编辑 db-config.properties ```bash author=Legendshop version=4.2.0 #0:oracle,1:mysql 暂时只支持这2种数据库 dataBaseType=1 #是否输出到文件 logLevel=0 sequence=1 #是否重写原有文件 overWrite=true #####################################以下配置要根据实际情况修改 #mysql配置 dbType=mysql dbDriver=com.mysql.jdbc.Driver #2. DEV开发环境 dbSchema=admin dbUsername=legendshop dbPasswd=123456 dbConnectString=jdbc:mysql://192.168.0.11:3306 #文件将要写到的系统路径 #path=C:/Legendshop_CodeGen/ path=/output #基本的包路径 packagePath=com.legendshop.business #Model参数 modelPackagePath=com.legendshop.model.entity #Dao参数 daoPackagePath=com.legendshop.business.dao #Service参数 servicePackagePath=com.legendshop.business.service #Controller参数 controllerPackagePath=com.legendshop.business.controller #xml配置文件 xmlConfigPath=spring jspPath=pages ####################################将要生成的表名和实体类的名字,要一一对应,之间用逗号相隔 actionPrex=/admin TableName=ls_prod Entityname=Product ``` ## 二、执行脚本 ```bash SourceGen.bat ``` ## 三、应用分层规范 ### 1.概述 LegendShop电商平台采用三层架构的分层软件架构设计、MVC设计模式、移动端采用MVVM设计模式。后端工程采用Spring Boot + Dubbo 的方式,提供前端接口或jsp模板;前端请求后端接口,后端采用自上而下,从Controller层传递到Service层最后传递到Dao层,最后每层处理完后把结果逐级往上返回。 故此,我们需要通过制定规范,明确各层的职责规范,上层与下层之间的依赖关系、输入与输出、信息传递以及一些代码命名规范。 ### 2.应用分层架构规范 如下内容,部分引用自 《阿里巴巴Java开发手册(详尽版)》 。 分层架构图 批注:上图默认上层依赖下层(没有箭头的那种),箭头关系表示的是直接依赖。如:开放接口层可以依赖于Web层,也可以直接依赖于Service层,依此类推。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2d907d70793b4248acb6a91da71377e4.png#pic_center) - 开放接口层: 可直接封装Service方法暴露成RPC接口;通过Web封装成http接口;供外部系统调用;进行网关安全控制、流量控制等。 - 终端显示层: 各个端的模板渲染并执行显示的层。当前主要是JSP渲染,JS渲染,移动端Vue渲染等。 - Web层: 主要是接收Http请求,各类基本参数校验,对进行转发或重定向,响应客户端,或者对不复用的业务简单处理等(记住是不复用的业务才处理)。 - Service层: 相对具体的业务逻辑服务层,具体的业务逻辑都应该在Service层处理。 - Manager层: 通用业务处理层,它有如下特征: 1) 对第三方平台封装的层,预处理返回结果及转化异常信息; 2) 对Service层通用能力的下沉,如缓存方案、中间件通用处理; 3) 与DAO层交互,对多个DAO的组合复用。 - DAO层: 数据访问层,与底层MySQL、Oracle、Hbase等进行数据交互。 外部接口或第三方平台: 包括其它部门RPC开放接口,基础平台,其它公司的HTTP接口, 比如微信开放平台。 - 开放接口层, - 终端展示层, 根据前后端是否分离,还分jsp渲染和vue渲染、小程序,PC端还未前后端分离,用的是JSP,移动端已经是采用vue和小程序实现了完全的前后端分离。 Manager层, 目前还未有用起来,但其实SAAS日后会有很多第三方对接的业务,所以Manager层需要用起来。 ### 3.领域模型规范 下面引用阿里巴巴的领域模型规范 + DO(Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。 + DTO(Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。 + BO(Business Object):业务对象。由Service层输出的封装业务逻辑的对象。 + AO(Application Object):应用对象。在Web层与Service层之间抽象的复用对象模型,极为贴近展示层,复用度不高。 + VO(View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。 + Query:数据查询对象,各层接收上层的查询请求。注意超过2个参数的查询封装,禁止使用Map类来传输。 阿里巴巴的领域模型规范是分的很细的,但每个公司的业务复杂度和架构的不同,选择也会不同,照搬阿里的规范可能是杀鸡用牛刀了,不单没带来理想的效果,反而会给开发造成负担,影响效率。 但是有些最基本的原则是要遵守的: + 尽量降低各层之间的耦合 + DO只能在Dao层和Service层用,不能由Service层暴露到Controller层。 + 禁止使用Map,JSONObject这种可读性、维护性差的数据类型在各层之间传输。 + 入参不超过3个的,不建议封装领域模型。 + 我们在满足上述原则的基础上可以适当的灵活变通,有些复杂的业务如果需要向阿里巴巴分的这么细的可以按照阿里的规范。大部分没有必要分细的,就可以让一些领域模型在各层之间复用: + DTO、BO允许在Service层和Controller层复用。 + 新定义一个领域模型CO,用于Controller层接收http请求参数,当Controller入参不想和Service入参复用时可以用。 不需要应用AO、Query这两种。 所以,我们根据自身项目情况,按照自下而上进行各层的选择 #### Dao层 入参,使用DO 出参,使用DO Service层/Manager层 入参,使用DTO 如果使用DTO是能和Controller复用的,可能会加上Bean Validation 和 Swagger注解。 出参,使用BO本来想着用DTO就算了,因为考虑到Service的出参应该是不会复用入参DTO的,入参的DTO可能会有Bean Validation 和 Swagger注解,也用作出参的话会很别扭。所以用DTO也是要写入参DTO和出参DTO, 这样还不如用BO来区分开。 #### Controller层 入参,使用DTO或CO 通常Controller入参可以直接传入到Service层做业务处理,所以Controller可以让其复用ServiceDTO。如果ServiceDTO不够用的情况下,可以定义CO。 出参, 使用BO或VO,通常Service的出参可以直接用做Controller出参,所以Controller的出参可以复用BO。如果ServiceBO不够用的情况下或不想复用可以使用VO。 上面提到了Controller会复用Service的DTO,这样的话Service的DTO就难免需要写Bean Validation,Swagger注解,笔者我是觉得有点别扭的。但是如果不这样的话,我们要多些一个CO,并且要写CO到DTO的转换代码,代价也挺高的,所以还是让其可以复用;BO在Controller层复用也是一样的道理。 #### 领域模型转换关系 * CO 转 DTO * BO 转 VO * DTO 转 DO * DO 转 BO * 注:只能按照上述转换关系转换, 也不能逆向转换。 #### 领域模型命名规范 * DO: 数据库表名 + DO后缀,例如ls_user表对应的领域模型,UserDO;但现在我们很多是写为“User”的,没有“DO”后缀,所以直接等于表名即可,不需要加后缀DO。 * DTO:业务模型名 + DTO后缀,例如:UserDTO,xxxDTO。 * BO:业务模型名 + BO后缀,例如:UserBO,xxxBO。 * VO:页面渲染模型名 + VO后缀,例如:xxxVO、UserVO。 领域模型存放位置 * DO: DO不应该暴露到Web工程依赖,所以要放到services工程下。因为SAAS分库了,并且分库的逻辑是和数据库对应的。所以应该放到对应的service实现工程下。比如商品的DO,应该要放到legendshop-shop-service下。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f50f9d72c4674f1c9f7837084665155f.png#pic_center) * DTO、BO:因为DTO和BO是service层下的,但又需要暴露给web层依赖,所以要放到legendshop-xxx-api下。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/36d61f626296489398441b5a8d84cff2.png#pic_center) * VO、CO: VO和CO只在web层依赖,如果需要在所有web层共享的,则放在web-common下,如果只在某个web工程下使用,则放到这个web工程下。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/60ee5f41817c495387aefb31a2fd2155.png#pic_center) 下层向上层返回结果规范 * Dao层 update、delete 返回int类型, 小于1则等于失败。 save 返回记录主键或DO,为null代表失败。 抛出DaoException代表失败,我们在Dao层不需要写代码处理,由LegendDao来负责往上抛出,Service/Manger层进行try Catch。 没有出现上述失败,则代表成功。 * Service/Manager层 Spring声明式事务一般应用在Service/Manager层,并且是基于异常进行事务回滚的,所以会有以下两种向上层返回结果的方式。 当不需要回滚事务时,封装通用的CommonResult来记录 状态码、消息提示、以及对应数据。通过状态码来区分成功和各种逻辑及异常,具体请看CommonResult的定义。 当需要回滚事务时,封装通用的BusinessException,里面会有错误码和错误提示,然后throw抛出。 * Controller层 service层没有发生异常时,直接返回service层返回的CommonResult或者返回jsp视图 service发生异常后,在GlobalExceptionHandler全局异常处理器拦截异常并进行处理,处理的方式最终也是转换为CommonResult或jsp视图。 这里有个疑惑的地方,由于我们PC端还未做前后端分离,有些是异步的请求接收json格式响应,有些是同步请求接收的是页面,全局异常该如何区分处理? #### 入参数据校验规范 入参校验我认为分两种即可 HTTP请求参数的基本校验, 比如非空校验、长度校验、手机号码格式等不需要调用RPC服务查询数据库就能完成的校验。 业务数据校验,结合业务逻辑,查询数据库才能完成的校验。比如查询店铺名是否已存在、是否超过限制创建的店铺数等。 对于第一种,指的是在Controller层完成的校验,对Controller的入参,也就是对CO、DTO进行数据校验,使用Bean Validation规范、Hibernate Validate实现,在DTO上加上相应的验证注解定义校验规则,在GlobalExceptionHandler进行统一拦截处理校验结果。 例如: ![在这里插入图片描述](https://img-blog.csdnimg.cn/1949168f21de46e59cc690ae7d564bae.png#pic_center) 对于第二种,指的是在Service层完成的校验,对Service的入参进行校验,也就是对DTO进行校验。因为在Controller层已经做过一轮基本校验了,在service层就只做业务逻辑层面的校验,这时候通过手写代码进行校验, 将校验结果写到CommonResult里面的状态码,消息提示里面即可。 例如: ![在这里插入图片描述](https://img-blog.csdnimg.cn/b07d2aec86604a82bef2b45eb33fcdca.png#pic_center) #### 领域模型相互转换/复制规范 上面提到了各层会有各层的领域模型,领域模型在层之间传递的时候需要一层转换,这时候可以采用Mapstruct实现。 参见 https://blog.csdn.net/u013679515/article/details/128492584?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128492584%22%2C%22source%22%3A%22u013679515%22%7D