项目总结项目开发规范
Posted 胡毛毛_三月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目总结项目开发规范相关的知识,希望对你有一定的参考价值。
目录
背景
后端规范像Java一般就可以参考阿里巴巴Java开发手册,前端也有其自己的规范,详细的可以参考他们。这篇文章主要定义在开发中的一些业务相关的规范,提高团队开发效率,提升代码的可读性和可维护性。
后端规范
一、接口api规范
1.接口风格接口风格统一采用restful规范
- GET请求用于查询
- POST请求用于新增
- PUT请求用于修改
- DELETE请求用于删除
ps:特殊查询/删除资源请求GET/DELETE不能使用,可使用POST请求
restful风格规范可参考阮一峰的网络日志:
2.接口api命名规范
- 接口统一命名格式=="/api/数据库表名/业务名"==
- 表名和业务名统一采用“-”符号连接(多单词),例如:GET、"/api/user/user-job-role"——查询用户及岗位和角色信息
- 如果是对单表进行增删改查操作,可省略业务名,例如:POST、"/api/user"——代表新增一条用户数据
3.接口参数规范
-
GET/DELETE请求参数规范(参数在请求头携带)
-
一般按照主键id查询或者删除,或者查询、删除条件少,选择一个参数遵循如下规范:
-
api路径:"/api/数据库表名/业务名/参数名",例如"/api/user/id"。前端请求为“/api/user/1”
-
在路径上加的参数,添加注解
@PathVariable
,在swagger参数后设置paramType = "path"
,说明参数是在路径上拼接的,而不是写在params
中。@GetMapping("/id") @ApiOperation(value = "查询一条用户表信息", notes = "根据主键id查询 \\n author:RenShiWei") @ApiImplicitParam(name = "id", value = "用户表id", paramType = "path") public ResponseResult<User> userFindById ( @PathVariable Long id ) User user = userService.getById(id); if (ObjectUtil.isNull(user)) log.error("【查看用户表失败"); return ResponseResult.ok(ResponseEnum.DATA_NOT_FOUND); return ResponseResult.ok(user);
-
-
-
POST/PUT请求参数规范(参数在请求体携带)
- 对于参数是表的实体类,强烈建议封装DTO,选择需要的参数。而不是使用实体类(会显示大量不必要的参数)
-
参数需要进行校验
- 实体类/DTO中使用SpringMVC的参数校验规则(如:@NotBlank、@NotNull等),接口参数前添加
@Validated
注解 - 基本数据类型,如有需要在业务中进行参数校验
- 实体类/DTO中使用SpringMVC的参数校验规则(如:@NotBlank、@NotNull等),接口参数前添加
-
参数类型统一使用application/json,前端使用qs进行全局统一拦截解析。不强制使用
@RequestParam
,如果qs解析没有问题,不强制使用@RequestBody
4.接口响应数据/状态码规范
4.1响应数据结构
[
"code":"",
"message":"",
"data":""
]
相应数据说明:
-
code 为自定义业务状态码
-
message 为详细响应信息
-
data 为响应数据
4.2Http状态码使用
状态码(status) | 说明 | 备注 |
---|---|---|
200 | 正常 | |
401 | 未登录 | |
403 | 权限不足 | |
404 | 访问资源不存在 | |
500 | 不可控的服务器异常 | 可控制的业务逻辑异常使用code代表 |
4.3自定义code的使用(自定义状态码暂定,需完善和确定)
自定义code | 说明 | 备注 |
---|---|---|
0 | 正常 | 无特殊含义 |
401 | 未登录 | 通用遵从http |
403 | 权限不足,认证失败 | 通用遵从http |
404 | 访问资源不存在 | 通用遵从http |
500 | 不可控的服务器异常 | 通用遵从http |
1xxx | 通用业务状态 | 以1开头代表通用业务状态 |
2xxx | 具体项目中的业务定义状态 | 以2开头代表具体项目中的业务定义状态 |
3xxx | 第三方依赖状态,如微信等 | 以3开头代表第三方依赖状态 |
例如:
/**
* 成功(默认返回状态码)
*/
SUCCESS(0, "SUCCESS"),
/**
* 全局未知异常
*/
SEVER_ERROR(500, "服务器异常,请重试"),
/**
* 请求失败(一般前端处理,不常用)
*/
BAD_REQUEST(400, "请求失败"),
/**
* 请求资源不存在(静态资源不存在,不常用)
*/
DATA_NOT_FOUND(404, "没有数据了"),
/*
* 登录、权限认证异常
*/
LOGIN_EXPIRE(401, "未登录"),
IDENTITY_NOT_POW(403, "您的用户权限不足"),
/*
====通用异常====
*/
/*
1001-1010 通用操作相关
*/
OPERATION_FAIL(1001, "操作失败!"),
SELECT_OPERATION_FAIL(1002, "查询操作失败!"),
UPDATE_OPERATION_FAIL(1003, "更新操作失败!"),
DELETE_OPERATION_FAIL(1004, "删除操作失败!"),
INSERT_OPERATION_FAIL(1005, "新增操作失败!"),
/*
1011-1050 登录注册相关
*/
LOGIN_FAIL(1011, "登录失败,账号或者密码错误"),
LOGIN_FAIL_RELOGIN(1012, "登录失败,请重试"),
LOGIN_FAIL_CODE(1013, "验证码错误"),
NO_USER(1014, "用户不存在"),
REGISTER_FAIL(1015, "注册失败,手机号已经存在"),
NO_USER_PHONE(1016, "认证失败,手机号不存在"),
PARAMS_NOT_NULL(1017, "请求参数不能为空"),
/*
1051-1070 短信业务相关
*/
SMS_NOT_SEND(1051, "短信发送失败"),
SMS_CODE_EXPIRE(1052, "短信验证码失效"),
SMS_CODE_VERITY_FAIL(1053, "短信验证码验证失败"),
/*
1071-1100 文件、资源相关
*/
FILE_OVERSTEP_SIZE(1071, "文件超出规定大小"),
FILE_UPLOAD_FAIL(1072, "文件上传失败"),
FILE_LOADING_FAIL(1073, "文件不存在,加载失败"),
FILE_REQUEST_FAIL(1074, "文件类型不支持查看"),
FILE_TYPE_IMAGE_FAIL(1075, "请上传图片类型的文件"),
/*
1101-1199 请求参数相关
*/
PARAM_IS_INVALID(1101, "参数无效"),
PARAM_IS_BLANK(1102, "参数为空"),
PARAM_TYPE_BIND_ERROR(1003, "参数类型错误"),
PARAM_NOT_COMPLETE(1004, "参数缺失"),
/*
-----------平安科院 业务相关(2xxx)------------
*/
PAKY_VISITED_NOT_EXIT(2024, "被访人不存在"),
APPOINTMENT_NOT_FIND(2100, "预约id不存在"),
VISITOR_VALUE_FORMAT(2101, "访客链接value格式不对"),
APPOINTMENT_QUERY_TIME_ERROR(2102, "查询时间有误"),
APPOINTMENT_TIME_OUT(2103, "预约时间过期,自动签为过期"),
REIDS_ADD(2200, "redis 服务添加异常"),
REIDS_GET(2201, "redis 服务无此信息"),
USER_ROLE_ERROR(2204, "用户角色异常"),
NO_ROLE(2203, "无此角色id"),
HIK_ADD_ORDER(2202, "海康 添加失败"),
/*
第三方相关(3xxx)
*/
/*
3001-3020 微信公众号
*/
WX_GZH_ACCESS_TOKEN_FAIL(3001, "微信公众号JSSDK获取access_token失败"),
WX_GZH_JS_API_TICKET_FAIL(3002, "微信公众号JSSDK获取jsapi_ticket失败"),
WX_GZH_SIGN_FAIL(3003, "微信公众号JSSDK获取SIGN失败"),
WX_CODE_EMPTY(3004, "微信wxCode为空"),
WX_CODE_OUTTIME(3005, "微信wxCode失效或不正确请重新获取"),
4.4如何使用Http状态码和自定义code
- 在出现Http状态码使用的情况时,推荐使用Http状态码,表述业务状态。自定义code如果没有特殊含义,同时遵循http状态(200除外)。
- 业务状态码统一使用自定义code表述,http状态码使用200
5.接口访问权限
- 开发阶段接口不明确其访问权限,将接口设置为匿名接口。即接口添加注解
@AnonymousAccess
- 在得知接口的访问权限时,添加权限注解——
@PreAuthorize("@permissions.check('admin')")
- 项目测试/上线前,审查所有接口的访问权限是否对应。尤其是去掉不必要的匿名接口标识
@AnonymousAccess
二、异常处理规范
1.使用异常处理的方式(暂定)
throw new BadRequestException(String msg);
throw new BadRequestException(HttpStatus status,String msg);
2.什么是使用异常处理?
接口业务逻辑,有出错的风险的都建议进行异常处理。比如查询返回集合数据为空,异常的入参方式…
总的来说,只要有出错风险或者是不符合要求的情况下,提前做好业务的异常处理
三、事务规范
1.什么时候使用事务?
- 只要有多条(大于等于2条)对数据库增删改操作的接口强制添加数据库事务处理
- 事务控制在Service层的方法添加
@Transactional(rollbackFor = Exception.class)
- MybatisPlus如果直接使用service的数据库操作方法,在controller也需要添加
@Transactional(rollbackFor = Exception.class)
- MybatisPlus如果直接使用service的数据库操作方法,在controller也需要添加
四、日志规范
1.什么时候使用日志?
- 一般在使用异常处理的使用,同时记录日志
- 日志级别warn/error
- 在进行接口操作(业务处理)时使用日志记录
- info/warn
2.如何使用日志记录?
-
使用lombok提供的快速日志操作。在类上添加
@Slfj
注解,在业务中直接使用log.info/warn/error(“记录日志”)。 -
日志记录格式:log.日志级别("【业务名】详细业务操作信息"),例如:
log.info("【修改用户】userId:" + userId); log.error("【修改用户失败】userId:" + userId);
3.日志文件生成
- 日志文件在项目根目录下生成,跟项目走,以logs命名
- 以每天每小时生成一个日志文件命名为——server.log.%dyyyy-MM-dd-HH
五、文件夹结构规范
1.在指定的package下开发,业务逻辑代码一般放在system模块的modules下
2.common模块尽量封装在任何项目,任何模块都有可能使用的通用方法和工具类。
- 如果代码在不同的项目/模块可能不一样,尽量不要封装在common模块中
3.文件夹结构
-common 通用模块
-system 核心业务模块
-tool 第三方工具模块
4.通用文件夹结构
-modules
--业务模块名
---api
----controller
----service
-----impl(service实现类的包)
----mapper(mybatis统一使用)/dao
----entity(统一使用)/domain
----bo
----vo
----dto
-config
-utils
六、Mybatis/MybatisPlus规范
1.联表查询使用注解
- 写联表查询(及非单表操作时),推荐在mapper层使用注解写sql,而不是使用xml来写(会产生大量的xml文件)。
2.条件构造器的使用
- 在使用条件构造器Wrapper时,强烈推荐使用其Lambda语法(这样使用的好处是,不用以数据库字段为条件,而是以JavaBean的getter、setter方法为条件,与数据库解耦,增强其可读性和可维护性)
- Lambda语法使用方式一:使用LambdaQueryWrapper、LambdaUpdateWrapper,直接使用Lambda语法
- Lambda语法使用方式二:使用QueryWrapper、UpdateWrapper的lambda()方法,使用其Lambda语法
3.自定义属性注入
- 使用自定义属性注入维护createTime、updateTime、createBy、updateBy等,需要注意在使用MybatisPlus提供的方法会维护,但是使用注解手撸sql时并不能维护。所以在使用注解手写sql时,不要忘记了维护createTime、updateTime、createBy、updateBy等数据。
4.逻辑删除
- 逻辑删除字段在yml文件中配置,数据库统一好逻辑删除字段,推荐使用
is_deleted
(不能使用is_delete,转Javabean去掉is,delete为mysql关键字) - 逻辑删除推荐使用0为未删除,1为逻辑删除,并且数据库设置默认值为0
- 手写sql,即在mapper类中写的sql语句,在做
SELECT
、UPDATE
操作时需要维护is_deleted
- 统一使用逻辑删除(暂定包括中间表),所有删除操作,手写sql全部使用
UPDATE
,将is_deleted
改为1.
5.MybatisPlus代码生成
- 代码生成时间类型默认为Java8数据格式LocalDateTime
- 代码生成推荐开放ActiveRecord模式(setActiveRecord(true)),实体类会继承Model接口
- 推荐JavaBean支持链式操作(setChainModel(true)),并且移除is前缀(setEntityBooleanColumnRemoveIsPrefix(true))
6.业务逻辑写在service层,还是写在controller层
因为MybatisPlus支持service直接操作数据库,而且比mapper层提供的方法更加丰富,所以业务逻辑写在service层,还是写在controller层,是个值得考虑的问题。推荐根据以下情况决定,业务逻辑写在哪里:
- 如果业务逻辑比较简单,只有很少的代码量,推荐业务逻辑写在controller层
- 如果业务逻辑比较复杂,有大量的逻辑判断和代码,推荐将业务逻辑写在service层。并将方法拆分进行封装,暴露给controller的方法声明为public,其余方法声明为private,只提供给本service类使用
- 如果需要在mapper层手写sql,调用其mapper方法,则==强制==使其业务逻辑方法写在service层
七、Java开发业务规范
1.阿里巴巴Java开发手册和IDEA阿里巴巴代码检查插件
推荐开发前看阿里巴巴Java开发手册,并在IDEA中下载阿里巴巴代码检查插件(养成习惯,写出及规范又优美的代码)
2.推荐枚举类enum的使用
- 数据库tinyint类型数据的判断,在Java中推荐封装枚举类进行判断
- 业务逻辑if判断,如果判断条件比较多,推荐使用枚举类判断
3.文件上传/下载规范
- 文件上传位置跟项目走,在项目根目录下建立upload文件夹
- 文件命名推荐添加uuid作为内容之一,防止文件命名重复导致异常
- 文件、上传都要走安全框架,需要做权限控制
- 文件浏览/下载不能直接访问,需要走接口,进行权限控制
4.工具类封装
- 工具类位置,推荐封装在utils下
- 通用工具类封装在common模块下
- 和某个模块相关业务的工具类,封装在相关模块下
- 工具类推荐封装成static静态方法(有的不能不强求,比如需要bean注册)
5.配置类
-
配置类位置,推荐封装在config下
- 通用配置类封装在common模块下
- 和某个模块相关业务的配置类,封装在相关模块下
-
配置类使用配置方式
-
推荐使用Java配置类
-
不推荐使用xml配置(日志配置除外)
-
推荐配置参数写在yml中进行读取
- 大量的配置读取,推荐写Properties类。可以省去大量属性的@Value读取
@Data @Configuration //表示为配置类,注册到spring bean容器中 @ConfigurationProperties(prefix = "jwt") //读取的yml配置的公共前缀 public class SecurityProperties
-
6.SpringBoot
-
SpringBoot推荐使用2.1.0.RELEASE版本,多次使用稳定版本,暂未发现异常
-
AppRun推荐放置在根包下,一般要进行各种扫描,如果不这样防止,可能会出现扫描不到的错误(主要由
@SpringBootApplication
注解引起) -
推荐配置类使用yml文件,更好的层级结构
-
推荐配置开发环境、测试环境、生成环境的配置文件。在不同环境下使用不同的配置文件
7.注释规范
-
所有class、interface、enum等强制在类头部加注释
-
注释方式:javadoc注释
-
注释内容
- 功能描述(description)
- 作者(@author)
- 日期(@Date)
-
注释模板
/** * description:对返回前端数据进行封装 * * @author RenShiWei * Date: 2020/7/9 22:09 **/ @Data public class ResponseResult<T>
-
-
所有成员变量,推荐添加注释
-
注释方式:javadoc注释
-
注释模板
/** * 方式一: * 状态码 */ private Integer code; /** 方式二:状态信息说明 */ private String message;
-
-
所有方法,强制添加注释
-
注释内容:
- 功能描述(description)
- 参数信息(@param)
- 返回值信息(@return)
- 作者(@author)(推荐,可知道方法谁写的,方便维护)
- 日期(@Date)(推荐,可知道方法大致是在什么时候写的)
-
注释模板
/** * description: 接口调用成功,返回枚举中自定义的状态码及数据 * * @param responseEnum 自定义枚举 状态码和信息 * @param data 返回数据 * @return 枚举中自定义的状态码及数据 * @author RenShiWei * Date: 2020/7/10 19:57 */ public static <E> ResponseResult<E> ok ( ResponseEnum responseEnum, E data ) return new ResponseResult<>(responseEnum, data);
-
-
swagger注释(一般在controller),如果有swagger,可不写javadoc注释
-
注释内容
- 参数
-
注释模板
/** * 根据主键id查询一条部门表信息 * * @param id 部门表ID * @return 部门表信息 * @author RenShiWei * @since 2020-08-06 */ @GetMapping("/id") @ApiOperation(value = "查询一条部门表信息", notes = "根据主键id查询 \\n author:RenShiWei") @ApiImplicitParam(name = "id", value = "部门表id", paramType = "path") public ResponseResult<Dept> deptFindById ( @PathVariable Long id ) Dept dept = iDeptService.getById(id); if (ObjectUtil.isNull(dept)) log.error("【查看部门表失败"); return ResponseResult.ok(ResponseEnum.DATA_NOT_FOUND); return ResponseResult.ok(dept);
-
注释规范
- 如果路径中有==“/id”类似这样的参数,并且在参数前使用
@PathVariable
注解,那么在swagger中@ApiImplicitParam
,需要将paramType设置为"path"==。 - 参数都必须加@ApiImplicitParam注解,包含name和value,paramType选填
- 接口方法加@ApiOperation注解,包含value和notes。note写上作者信息,方便在swagger中得知接口是谁写的。
- 如果路径中有==“/id”类似这样的参数,并且在参数前使用
-
-
业务注释
- 业务中多写注释,方便开发和维护,养成良好习惯
- 一块业务使用块级注释
- 一行代码使用行级注释
八、第三方依赖规范
1.第三方依赖的引入规范
- 强制不推荐随意引入第三方依赖。引入依赖前需要经过对比和调研,并且知晓其优缺点
- 同一项技术,强烈建议统一使用同一项技术。保持规范和一致,提高代码的可读性和可维护性;同时减少依赖的引入,降低项目的冗余。
- 引入第三方依赖,推荐引入其稳定版本。防止第三方依赖出现未知异常。大多数时候,最新版本,并不一定是最好的。
2.Java工具包推荐使用依赖
- Java第三方工具包推荐使用——hutool。轻量级,基本涵盖Java开发80%以上的工具类。官方文档https://hutool.cn/docs/#/
- JSON序列化也推荐使用hutool下的json处理
九、Maven规范
1.pom文件规范
-
SpingBoot提前规定好父版本
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> </parent>
-
jar引入规范
- jar包版本统一在下定义,使用时$lombok.version。方便统一管理所有jar包版本
- 下定义<project.build.sourceEncoding>和<project.reporting.outputEncoding>为UTF-8;<java.version>为1.8
- 如果是分模块开发在父工程的pom文件中先使用锁定jar包版本,在需要的时候引入jar包。防止jar包在不需要的模块中引入,造成冗余。
- 如果不想某个引来会发生依赖传递,设置当前依赖true
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <hutool.version>5.2.5</hutool.version> <lombok.version>1.18.8</lombok.version> </properties> <!-- 锁定jar包版本 --> <dependencyManagement> <dependencies> <!-- hutool的java开发工具包 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>$hutool.version</version> </dependency> <!--lombok插件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>$lombok.version</version> <optional>true</optional> </dependency> </dependencies> </dependencyManagement>
-
在要打jar的模块下添加如下插件(最好不要在父工程添加,可能造成打包异常)
<build> <plugins> <!-- spring-boot插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> 以上是关于项目总结项目开发规范的主要内容,如果未能解决你的问题,请参考以下文章