项目规范

一、后端开发规范的意义

  • 提高团队的协作能力

  • 提高代码的复用利用率

  • 写出质量更高,效率更好的代码

  • 为后期维护提供更好的支持

二、项目介绍

  1. 该项目主要负责的是某软件的数据管理

  2. 该项目的开发语言:Java8

  3. 该项目所用到的技术:

    1. 数据库:Mysql

    2. 数据库框架:MyBatis Plus

    3. 应用框架:Spring Boot

    4. 权限框架:Spring Security + JWT

    5. 接口文档 :Swagger2

    6. 项目构建工具:Maven

  4. 该项目所用到的开发工具:

    1. 开发工具:IntelliJ IDEA

    2. 代码同步工具:Git

    3. 接口测试工具:Postman

  5. 该项目的设计原则:SOLID

    1. SRP 单一原则

    2. OCP 开闭原则

    3. LSP 里氏替换原则

    4. ISP 接口隔离原则

    5. DIP 依赖倒置原则

  6. 该项目的接口风格是Resful

  7. 该项目的代码规范遵循阿里巴巴Java开发手册V1.5( 下载点我)

三、项目下载及导入所需要的SDK

1.项目下载

git clone ([email protected]:alanchen/next-web-server.git)(括号里的可以换成git项目地址)

2.导入SDK

打开wz-out-files文件,运行readme.sh脚本即可。

3.运行程序

运行程序,测试依赖是否成功导入

四、开发规范

1.层级结构:entity(实体层)、dao(持久层)、service(业务层)、controller(控制层)

entity

实体层

1) 命名:类名以及属性名使用驼峰式命名首字母大写

2) 统一使用Lombok插件,在开头加上@Data注释,不需要写get、set、toString方法

3) 统一继承BaseEntity类,因此实体类中一般不需要加上id、createTime、updateTime、deleted字段

4)需要备注的字段前面要加上@ApiModelProperty("注释内容")

@Data
public class UserProfession  extends BaseEntity {
​
 @NotNull
 private String userId;
​
 @ApiModelProperty("单位全称")
 private String company;
​
 @ApiModelProperty("部门")
 private String department;
​
 @ApiModelProperty("最高职位")
 private String topProfession;
​
 @ApiModelProperty("入职年份")
 private String year;
​
 @ApiModelProperty("位置序号")
 private Integer position;
​
 private String createUserId;
​
 private String updateUserId;
​
 @ApiModelProperty("授权方id")
 private String sourceId;
​
}

dao

持久层

1)命名:现在基本用到的是mybatisplus框架,现在的接口命名还是与业务逻辑层的接口命名保持一致以‘I’开头以‘Dao’结尾,其中接口继承了BaseMapper

  1. 在开头加上@Mapper@Repository注解

3)dao中的方法都需要加以备注说明此方法的功能

4)为了框架的灵活性,该项目采取写sql语句来实现增删改查的方法,sql写在resources中的mapper包里对应的...Mapper(注意:一般删除用的是update逻辑删除

例子(上面为接口,下面是用sql实现):

@Mapper
@Repository
public interface IRoleDao extends BaseMapper {

 /**
  * 获取角色列表
  * @param sourceId
  * @return
  */
 List getUserRole(@Param("sourceId") String sourceId);

 

5)特别注意的是:插入新数据使用mybatisplus自带的insert方法,插入一个对象,这时,由于我们的实体类是继承了BaseEntity的,所以在用insert插入时,插入的对象不需要设置BaseEntity的字段

UserPayAccount newAccount = new UserPayAccount();
newAccount.setAccountIdentity(wzMobileCodeRequest.getAccountIdentity());
newAccount.setPriority(888);
newAccount.setAccountType("2");
newAccount.setUserId(wzMobileCodeRequest.getId());
newAccount.setSourceId(wzMobileCodeRequest.getSourceId());
userPayAccountDao.insert(newAccount);           

service

业务层包括接口层和实现层 主要负责业务逻辑

接口层

1)命名:驼峰式命名,以‘I’开头以‘Service’结尾,中间放实体类的名字。

2)每个接口都需要加上注释,说明接口的目的

 /**
 * 根据授权方id获取角色列表
 * @param sourceId
 * @param adminId
 * @return
 */
 List getRole(String sourceId,String adminId);
实现层

1)命名:驼峰式命名,开头实体类的名字首字母大写以‘ServiceImpl’结尾。

2)前面加上@Service注解

3)在需要注入的Bean前面加上@Autowired注解

4)实现接口方法前需要加上@Override注解

@Service
public class RoleServiceImpl implements IRoleService {
 @Autowired
 IRoleDao roleDao;
​
 @Autowired
 IRoleMenuRelationDao roleMenuDao;
​
 @Autowired
 IMenuDao menuDao;
​
 @Autowired
 IUserAdminDao userAdminDao;
​
 @Override
 public List getRole(String sourceId,String agentId) {
 List agent = roleMenuDao.getAllAgentRole("代理");
 List allRole = roleDao.getUserRole(sourceId);
 //如果不是代理则不显示有关代理的角色
 if(StringUtils.isBlank(agentId)){
 allRole.removeAll(agent);
 }
 return allRole;
 }
}

controller

控制层

1. 接口风格

遵循Resful风格接口(详情)。

1. 请求方式 : post:新增 、 get 获取 、 put 与 patch是修改 、 delete 删除

2. 拒绝动词 : 在请求路径里面不要存在动词,基本是名词并且一看就能明白你要做什么!!!

2. 统一返回机制

该项目有做统一返回参数的处理,查询的接口需要定义返回类型,增删改统一返回void就行

3. 注解

1)在smm里已经把该用到的注解包装成@TRestController("/自定义url")

2)开头需要加上@Api(tags = "总接口介绍暴露给前端")注解

3)在需要注入的Bean前面加上@Autowired注解

4)每个接口前加上@ApiOperation("接口功能描述")注解

5)根据需求在每个接口前加上**@Post/Get/Put/DeleteMapping(/自定义url)****注解

6)根据传参方式,在传参的地方加上@RequestBody@RequestBody注解,如果是需要进行数据校验则需要加上@Valid

4. 自定义url

定义url需要注意的是全小写,不带任何动词,不可避免时用 '-' 来隔开;

5. 拒绝逻辑

在控制层不需要做任何逻辑判断,只有调用业务逻辑层并返回的数据。所有的业务逻辑必须放到业务逻辑层。

@Api(tags = "角色管理")
@TRestController(value = "/user-roles")
public class RoleContrller {
​
 @Autowired
 IRoleService userRoleService;
​
 @Autowired
 IMenuService menuService;

 @ApiOperation("根据授权方id分页查询角色列表,也可以通过角色名称查询(角色列表用的)")
 @GetMapping("/list")
 public IPage pageUserRole(UserRoleSearch search){
 return userRoleService.pageUserRole(search);
 }

 @ApiOperation("新增角色,角色名字、授权方id、可以查看的菜单名字不能为空")
 @PostMapping
 public void addUserRole (@RequestBody @Valid UserRoleVO userRole){
 userRoleService.addUserRole(userRole);
 }

}

2.VO

该项目对vo的理解:表现层对象(View Object),主要对应展示界面显示的数据对象,用一个VO对象来封装整个界面展示所需要的对象数据。

  1. 运用场景:一般在查询的时候会需要定义一个vo来返回所需要的字段给前端

  2. 注解:和实体类一样,需要用到@Data、@ApiModelProperty("描述")注释,若需要进行数据校验,还需要加上校验的注解,例如:@NotBlank(message = "....")

  3. 特别注意:id也是要传的,id也是要传的,id也是要传的前端操作需要的参数也是要传的,前端操作需要的参数也是要传的,前端操作需要的参数也是要传的

@Data
public class MenuVO {

    @ApiModelProperty("菜单id")
    private String id;

    @ApiModelProperty("菜单名字")
    @NotBlank(message = "菜单名字不能为空")
    private String menuName;

    @ApiModelProperty("上级菜单id")
    private String parentId;

    @ApiModelProperty("菜单url(标识符)")
    @NotBlank(message = "菜单url不能为空")
    private String menuUrl;

    @ApiModelProperty("菜单优先级(排序不用传)")
    private Integer priority;

    @ApiModelProperty("是否独有,0不是1是")
    @NotBlank(message = "标识不能为空")
    private String isJinhui;
}

3.分页查询

该项目所用到的是MyBatis Plus的分页插件

参考文档:https://mp.baomidou.com/guide/page.html

在该项目使用分页查询时需要注意的地方:

  1. 统一写sql来实现分页查询,返回类型为IPage,传参一般为(Page page,@Param("search") ...Search search),到这里你可能会问何为search?

  2. search是继承了page的类放在search包中,在这个类中,你可以放要求筛选的字段,并且在sql中进行筛选,注解和vo、entity的注解类似

 /**
     * 分页查询角色列表
     *
     * @param page
     * @param search
     * @return
     */
    IPage pageUserRole(@Param("page") Page page, @Param("search") UserRoleSearch search);
@Data
public class UserRoleSearch extends Page {

    @ApiModelProperty("授权方id")
    @NotBlank(message = "授权方id不能为空")
    private String sourceId;

    @ApiModelProperty("角色名称")
    private String roleName;
}
    

执行sql后的结果:

image

分页查询测试结果:

{
    "code": 200,
    "data": {
        "current": 1,
        "orders": [],
        "pages": 1,
        "records": [
            {
                "id": "1a8bd785c6b84be3a5da2b670a417c44",
                "roleName": "厂库管理员"
            },
            {
                "id": "599b9f54004f4731a17af279420a1491",
                "roleName": "代理管理员"
            }
        ],
        "searchCount": true,
        "size": 10,
        "sourceId": "a79745b785fc4a928a8fbbb86111e859",
        "total": 2
    },
    "msg": ""
}

4.枚举

  1. 应用场景:当要用到数字甚至字母来表示某一状态的时候

  2. 意义:枚举可以限定参数的个数,对调用者的行为能更加严格地进行控制;它的对象在一个枚举类生成的时候已经确定。

  3. 用法(直接上例子):

public enum UserAdminTypeEnum implements IEnum {

        /**
         * 0:普通用户
         * 1:管理员
         */
        USER(0,"普通用户"),
        ADMIN(1,"管理员"),
        IT_ADMIN(2,"IT管理员");

        private Integer code;
        private String msg;

        UserAdminTypeEnum(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        @Override
        public Serializable getValue() {
            return this.code;
        }

        @JsonValue
        public String getMsg(){
            return this.msg;
        }
    }

//其他类调用时:
Boolean isITAdmin = userAdmin.getAdminType() == UserAdminTypeEnum.IT_ADMIN.getValue();

Boolean isLianzhi = userAdmin.getSourceId().equals(sourceProperty.getLianzhiSourceId());

5.config、authority以及utils

config用于系统全局环境的设置

现用来进行全局异常、全局返回参数、跨域请求、swagger配置、Mybatis Plus配置处理

authority用于权限管理

现用来进行密码加密、登陆后的个人信息返回以及权限的放行

utils用于存放辅助工具

现有的有支付宝提现、图片上传、创建报表、生成随机码、金钱转换、商品落地等等

6.application.yml

用于存放端口号连接数据库的参数以及全局变量

开发时特需注意的是

  1. 冒号后要加空格,冒号后要加空格,冒号后要加空格

  2. 换行要对齐,换行要对齐,换行要对齐

  3. 端口号以及数据库参数不要随意改,端口号以及数据库参数不要随意改,端口号以及数据库参数不要随意改

7.阿里巴巴代码规约扫描

image
image
image

五、接口测试

  1. 测试工具:postman

  2. 测试路径:localhost:端口号(一般是8080)/comtroller开头自定义的路径名/接口自定义的路径名

  3. 请求方式:post、get、put、delete

  4. 测试用例:针对自己的接口想出有针对性的用例,避免重复改bug

六、GIT操作

参考:https://www.jianshu.com/p/1d9067b044ab

七、开发插件推荐

  1. mybatiscodehelperpro

  2. 阿里巴巴代码规约扫描 alibaba

  3. lombok

你可能感兴趣的:(项目规范)