Java开发规范

本文总结了阿里巴巴的Java开发手册规范和SpringBoot应用的编码规则,强调了安全、数据库设计和RESTful接口实践等方面,包括用户权限控制、SQL注入防护、CSRF过滤、MySQL建表规范、异常处理和HTTP状态码的使用。此外,还讨论了业务代码的组织结构和异常统一处理策略。
摘要由CSDN通过智能技术生成

阿里巴巴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 安全过滤。

 解释:这个CSRF安全过滤是跨站点请求伪造,也就是比如攻击者会伪造我们浏览器发送请求到指定站点,修改我们的参数,就可能到指定网站访问成功获取我们信息等。
比如我刚访问了一个银行取钱,取钱之后没多久,我访问了一个恶意站点,它获取到我们的访问银行的url信息,修改参数,继续访问银行从而窃取金钱。
 
解决方案:
 
         1.第一种方式是检查Referer字段,我们发送请求到银行站点,这个请求头header里面会有referer字段,这个字段就表示来源站点地址,也就是我们浏览器地址,银行那边就会判断地址是否可信和安全,
 
而如果攻击者指挥获取我们的请求url发送,所以银行站点就可以将其拦截下来。
 
         2.使用添加token字段。
 
           当用户第一次访问关键信息时,比如取钱等操作,我们就会生成一个随机token字段给用户,存储到用户浏览器端,而如果是用户再次访问就会带着token来,而攻击者是无法获取token信息,因为这个存储到用户浏览器端,他只会获取用户的请求url
 
 

        2.常见Mysql数据库建表规范       

                       (1).【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint ( 1 表示是,0 表示否

解释:我们在设计表时,如果是boolean类型,都会将其设置为is_xxx命名,如果我们java代码实体类是POJO,POJO就是指没有实现或者继承任何类的类,只是一个简单实体类,如果POJO类中有boolean

属性,这个属性命名前缀不需要加is,对应的数据库表字段是需要加is_作为前缀

                       (2).【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。

解释:一般我们建表名或者字段名统一使用小写,多个单词使用_隔开,而且表名使用复数形式,他只是表示实体,跟我们RestFul风格有点不一样

                       (3).【强制】禁用保留字,如 descrangematchdelayed 等,请参考 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,独立出来一张表,用主键来对应,避免影响其它字段索

引效率。
 
解释:比如我们在存储日志内容时,我们都会将日志表拆分为两个表,一个日志基本信息表包括发表时间,发表人,主题,标题等,但是日志内容我们都会抽取出来,见一个日志内容表,用主键对应,所以在查询时,text字段
 
会影响其他字段的效率,所以将其抽取成一个表。
 
                      (8).【强制】表必备三字段:id, gmt_create, gmt_modified
 
解释:设计表时,加入这两个字段是为了代表这条记录创建时间和修改时间。
 
                       (9).【推荐】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
 
解释:建议强制,比如我们建表时都要给这个字段添加含义,修改字段含义都要及时更新字段注释,不然有个人用到你的实体类,但是实体类字段含义它不知道,所以它就要去查看表的注释,所以建议每个字段添加注释
 
并及时更新,方便其他人和自己阅读。
 
                        (10).【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
                                          1不是频繁修改的字段。
                                          2不是 varchar 超长字段,更不能是 text 字段。
 
解释:比如用户查看订单,需要显示出订单的用户真实姓名,如果我们要显示出来,就需要先去订单表查询订单信息,再去用户表查询用户姓名,订单表只有user_id但是user_name字段,所以就要查询两次表,对于这种
 
查询频率较高但是不是频繁修改的字段,我们就可以使用冗余字段,打破第三范式,这样就只需要查询一张表,避免了关联查询。
 
 
 
 
 

三.SpringBoot编码规范

           1.基于RestFul风格开发

                 一般Springboot项目都是前后端分离项目,前后端分离就需要使用restful风格开发,以前前后端未分离,都是前端写好静态页面交给后端开发,后端填充数据,后端如果在开发中发现问题就叫前端去
 
处理,处理好之后再返回给后端继续开发。
 
               而接口开发,就是前端写好页面,控制跳转方向,之前前后端未分离都是后端控制跳转方向,返回一个视图,现在只需要后端只需要定义好请求路径和返回数据就可以,以及前后端开发需要对应好参
 
数,相比于以前耦合度降低了。
 
               restful风格使用统一的接口,通过使用相同的接口进行资源的访问,接口应该使用标准的HTTP方法如GET,PUT, POST,DELETE等 , 并遵循这些方法的语义。
 
                    1>GET(SELECT):从服务器取出资源(一项或多项)。
                    2>POST(CREATE):在服务器新建一个资源。
                    3>PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
                    4>PUT更新整个对象 PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性【补丁】)。
                    5>PATCH更新个别属性 DELETE(DELETE):从服务器删除资源。
 

              2.常见Http响应状态码

                      200:服务器正常响应,表示请求成功。
 
                      302:浏览器端进行页面跳转。
 
                      304:服务器告诉浏览器使用本地缓存
 
                      400:请求无法被服务器理解,一般都是参数问题
 
                      401:请求没有权限访问
 
                      404:请求找不到资源,一般都是url路径错误
 
                      500:服务器内部错误,一般是后端java代码有问题,可以在控制台看到错误信息
 

              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层,统一写在业务层,除非特殊情况。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值