阿里巴巴java开发手册规范和SpringBoot规范总结
一.前言
为什么我们要学习阿里巴巴规范?
答:因为阿里巴巴作为互联网行业巨头,再加上阿里巴巴也是网站也是使用java编写,对于我们这些java后端开发程序员有着指导意义。阿里巴巴的开发规范是经过阿里的大规模实战总结出来,最后反馈给我们。
现在软件行业对于编码规范要求越来越高,没有规范的代码可读性比较,你写好的代码别人都看不懂,而且对于我们维护而言,不规范的代码维护成本太大,所以遵循一个规范,可以提高我们开发效率,能码出高质量的代码。
二.阿里巴巴java开发手册规范总结
1.常见的安全规范
(1). 【强制】隶属于用户个人的页面或者功能必须进行权限控制校验。
解释:也就是说,比如我们在做后台项目或者其他项目,肯定需要使用权限控制进行检验,利用RBAC原理,每个人分配不同角色,不同角色对应不同权限,个人与角色是多对多关系,角色与权限是多对多关系,
设计思路:员工表-角色表-权限表-员工与角色中间表(uid-rid)--角色与权限表(rid-qid),这样将其关联起来,至于权限怎么设计,一般都是自定义注解,注解里包含权限名和权限表达式,在用户访问此接口方法时会进行拦截,查询出当前用户的所有权限,接着进行判断。
考虑到后续如果用户量增加可以结合redis使用,将用户权限放到redis中作为缓存。
(2). 【强制】用户敏感数据禁止直接展示,必须对展示数据进行脱敏。
解释:比如登录用户账号后,查看个人信息时,如果关系的手机号、身份证号等都会将关键信息隐藏起来,比如手机号中间四位隐藏起来,这个主要是前端做的。像我们点外面,生成的外面单上都只会显示用户手机号最后四位,外卖小哥也只知道用户手机号最后四位。
(3).【强制】用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入, 禁止字符串拼接 SQL 访问数据库。
解释:之前我们在学Mybatis时,有#{}和${},#{}是预编译处理,就是为了防止sql注入的,如果是那种${}直接就是字符串替换,到时候恶意访问就可以输入一些非法字符,一样能成功请求成功,所以就会导致信息泄露。
比如select * from users where username='' or 1=1#' and password=md5(''),这条语句,就是一个非法输入参数,'' or 1=1#'属于非法输入参数,在mysql中#后面是注释掉,所以当恶意访问时输入这样的参数,sql语句就变成了select * from users where username='' or 1=1,这样明显该sql成立。
(4).【强制】表单、AJAX 提交必须执行 CSRF 安全过滤。
2.常见Mysql数据库建表规范
(1).【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint ( 1 表示是,0 表示否)。
解释:我们在设计表时,如果是boolean类型,都会将其设置为is_xxx命名,如果我们java代码实体类是POJO,POJO就是指没有实现或者继承任何类的类,只是一个简单实体类,如果POJO类中有boolean
属性,这个属性命名前缀不需要加is,对应的数据库表字段是需要加is_作为前缀
(2).【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
解释:一般我们建表名或者字段名统一使用小写,多个单词使用_隔开,而且表名使用复数形式,他只是表示实体,跟我们RestFul风格有点不一样
(3).【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。
解释:跟我们java代码一样也是起参数名禁止使用关键字和保留字,而且数据库命名、表名、字段名、索引名都不允许使用保留字,数据库命名不允许使用关键字;
如果需要区分,我们写sql时,都会加单引号去区分他们与关键字以及保留字的不同
(4).【强制】主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
解释: pk表示primary key,uk表示unique key,idx表示index key
(5).【强制】小数类型为 decimal,禁止使用 float 和 double。
解释:float和double都存在精度丢失问题,这个跟我们java代码一致,我们java代码使用BigDecimal来表示精度准确,它就对应着我们数据库中的decimal。这个decimal拆分存储,它是这样做,因为在计算机语言
里面整数加减乘除效率高,没有精度丢失,如果存储的数据超过decimal范围,我们会将这个小数拆分,整数存储到一个表字段中,小数将其转换为整数后存储到另一个表字段,当需要使用的时候取出这两个表的字段拼
接一起就可以。
(6).【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
解释:因为char定长字符串类型长度在磁盘上是固定的,而varchar变长字符串类型长度在磁盘上是根据存储的字段的长度决定的,长度是可变的,所以他的存储效率相对于char定长字符串类型效率会慢一点.
比如我们存储手机号,一般都是固定长度11位,如果还要加些什么+0086等前缀,手机号也是固定,所以我们存储手机号字段就可以使用char定长字符串类型,而不是使用变长字符串。
(7).【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索
三.SpringBoot编码规范
1.基于RestFul风格开发
2.常见Http响应状态码
3.异常统一处理
用户在输入一些信息,会出现一些逻辑错误,比如账号密码不正确等,或者你没有权限,这些定义的异常信息都是我们自定义的,我们都是通过自定义一个异常,来返回给用户我们想要给用户看
的异常信息,throw new 自定义异常(“异常信息”),像这样返回给用户看。
这时就会出现一个问题,比如很多业务逻辑都有这些异常信息,都手动抛一次,那样就会出现重复代码,所以定义一个全局异常处理类,统一处理异常类,springboot提供@ControllerAdvice注
解,我们使用它定义一个统一异常处理类,它里面有个@ExceptionHandler,定义拦截的异常,这个类就相当于在我们控制器上加了一层保护膜,当从控制器抛出异常都会被它检测到并进行拦截,我们再使用定
义一个错误消息实体类,里面有code,msg,data字段,如果是自定义异常统一返回501,如果是系统异常统一返回400,这样前端就可以根据code来进行判断,做一些处理
/**
* 统一异常处理类
* 动态处理方式增加一些额外功能
*/
@ControllerAdvice
public class uniformExceptionHandler {
@ExceptionHandler(LogicException.class)
@ResponseBody
public Object logicException(Exception e, HttpServletResponse resp){
e.printStackTrace();
resp.setContentType("application/json;charset=utf-8");
return JsonResult.error(JsonResult.CODE_ERROR_PARAM,e.getMessage(),null);
}
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Object runtimeException(Exception e, HttpServletResponse resp){
e.printStackTrace();
resp.setContentType("application/json;charset=utf-8");
return JsonResult.defaultError();
}
}
public class LogicException extends RuntimeException{
public LogicException(String msg){
super(msg);
}
}
@Setter
@Getter
@NoArgsConstructor
public class JsonResult<T> {
public static final int CODE_SUCCESS = 200;
public static final String MSG_SUCCESS = "操作成功";
public static final int CODE_NOLOGIN = 401;
public static final String MSG_NOLOGIN = "请先登录";
public static final int CODE_ERROR = 500;
public static final String MSG_ERROR = "系统异常,请联系管理员";
public static final int CODE_ERROR_PARAM = 501; //参数异常
private int code; //区分不同结果, 而不再是true或者false
private String msg;
private T data; //除了操作结果之后, 还行携带数据返回
public JsonResult(int code, String msg, T data){
this.code = code;
this.msg = msg;
this.data = data;
}
public static <T> JsonResult success(T data){
return new JsonResult(CODE_SUCCESS, MSG_SUCCESS, data);
}
public static JsonResult success(){
return new JsonResult(CODE_SUCCESS, MSG_SUCCESS, null);
}
public static <T> JsonResult error(int code, String msg, T data){
return new JsonResult(code, msg, data);
}
public static JsonResult defaultError(){
return new JsonResult(CODE_ERROR, MSG_ERROR, null);
}
public static JsonResult noLogin() {
return new JsonResult(CODE_NOLOGIN, MSG_NOLOGIN, null);
}
}
4.业务代码存放位置
这里我们业务代码不能写在controller层,统一写在业务层,除非特殊情况。