Java后端开发规范

  一、技术栈规约

  二、命名规范

  三、Java代码规范(注释规范、异常与日志、代码逻辑规范)

  四、Mybatis与SQL规范

  五、结果检查(单元测试及代码扫描)

  六、安全规范

一、技术栈规约

二、命名规范

  • 命名使用英文词组合,严禁使用中文拼音或拼音首字母组合命名(专有名词例外) - OrganizationTreeNode, OrganizationVO ; 不推荐使用PSTree , Tlogs
  • groupId,package包名前缀统一为:  com.wiwj
  • 包名第三位为产品分类名,如com.wiwj.cbs
  • 常量命名全大写,单词间下划线分隔。如: DEFAULT_PAGE_SIZE
  • 其他命名遵循驼峰式命名法:
    • 类名:首字母大写的UpperCamelCase,如: Organization
    • 方法名、变量名:首字母小写的lowerCamelCase,如: orgName
  • 特定标识命名:
    • 领域模型增加类型后缀标识,如xxVO, yyDAO
    • 基类/抽象类使用Base/Abstract等前缀标识
    • 设计模式类添加Factory,Builder,Proxy等标识
    • Controller, Service, Mapper统一添加到对应分层目录
    • 接口实现类添加Impl后缀标识
    • 枚举类添加Enum后缀标识
    • CRUD接口采用统一前缀: get, count, create, delete, update, batchCreate …

三、Java代码规范

  注释规范

  • Java文件统一添加固定Header,通过IDE统一配置(code templates) 

      /**

       * <Description> <br>

       * @author mazhicheng@5i5j.com<br>

       * @version 1.0<br>

       * @date ${YEAR}/${MONTH}/${DAY} <br>

       */

  • 接口和方法统一添加Java Doc标准注释

    /**

      *缓存key-value并设定过期时间

      * @param key 缓存对象的key

       * @param valueList 缓存对象

      * @return 缓存是否成功

      */

      <T> boolean addList(String key, List<T> valueList);

  • 需暂留的弃用类/方法添加 @Deprecated 废弃标记 和 @see 链接指向新接口

    * @see com.wiwj.common.cache.redis.JedisSentinelPoolUtil

    */

    @Deprecated

    public class JedisUtils {…}

  异常与日志

  • 调用外部服务等可能异常的代码块,用 try/catch 代码块捕获并在catch中记录异常跟踪日志及业务逻辑处理
  • 禁止吞掉异常信息

    禁止catch里不做任何记录和处理,吞掉异常及其堆栈信息

    禁止: logger.error(“XXX操作异常”) 或 logger.error(“XXX操作异常”+e) 或 e.printStackTrace()

    正确: logger.error("XXX操作异常", e)

  • 对于非预期的条件,尽量增加else记录跟踪日志
  • 禁止通过System.*.out()打印日志(单元测试例外)
  • 日志记录logger需使用Slf4J代理声明,禁止绑死具体日志系统的API,避免后期更换日志组件导致代码的大量改动

    private static final Logger log = LoggerFactory.getLogger(OrganizationServiceImpl.class);

     如采用了lombok,可用 @Slf4j 注解替代以上声明。

  • 对 trace/debug/info 级别的日志输出,必须使用占位符形式,避免直接String拼接异常信息(即使日志级别不匹配也会执行拼接操作空耗资源)。

    正确写法如:

       log.debug("当前用户id: {} ,操作对象: {}=>{} ", userId, objectType, objectId);

      或条件输出形式如:

        if(log.isDebugEnabled()){

           log.debug("当前用户id: “+id+” ,操作对象: “+ objectType +”=> “+ objectId);

         }

  逻辑代码规范

  • 废弃的/无用的代码一律直接删除,禁止以注释等方式保留。如需查看历史代码,通过SVN/Git的history找回

    (无用的代码会干扰团队成员的阅读/或被误调,越积越多会导致代码维护成本增高)

  • 接口类中的方法不需添加 public 修饰符
  • 需要序列化的Bean类统一实现Serializable接口并用IDE生成serialVersionUID

    public class MyEntity implements Serializable {

       private static final long serialVersionUID = 123456L;

       ...

    }

  • 常用字符串统一定义在常量类里,如: “utf-8”, “yyyyMMdd”
  • 避免数字类型比较的坑: 统一采用equals进行比较其值,不用==进行比较,避免踩坑。
  • if/else/for/while语句后必须使用大括号,即使只有一行代码。(需求总是变化的,一行是暂时的)
  • 嵌套层次过多的代码块利用反向思维缩减层次
  • 方法单一职责: 单个方法代码行数控制在100行以内,超长的需要拆分(拆分成多个方法或类)
  • 避免NPE(NullPointException)的一些建议:

    • equals比较将非空对象前置:如 "true".equals(request.getParameter("isXx")),即使后者为空也不会导致NPE。

    • 数据库字段可空的映射属性使用包装类型定义:如基本数据类型的int映射到数据库的null值将产生NPE,而用吧包装类型 Integer 则不会。

    • 可能为空的变量进行必要判空,并在非预期条件下打印必要的跟踪日志,不但避免NPE,还非常便于跟踪调试。如:

    • 级联调用 obj.getA().getB().getC() 易产生 NPE,先进行判空或使用 JDK8 的 Optional 类包装。

    • 调用Dubbo接口拿到返回值时,进行判空。

    • 封装统一的判空类用于常用类型的判空,代码需要判空时统一调用即可。如  XX.isEmpty(), XX.isNotEmpty()

  • 遵循: Don’t Repeat Yourself,即 DRY 原则。避免进行简单的复制粘贴修改,当出现重复代码时思考是否封装

    当代码中存在大量重复代码时,一旦代码逻辑变动将很容易导致顾此失彼,产生bug,非常不利于维护。

  • Bean属性拷贝推荐用Spring BeanCopier或者Mapstruct,避免Apache BeanUtils或调用setter
  • 禁止在循环中执行耗时的操作,如在循环中执行SQL语句/调用外部服务等

    // 错误的示例:

    for(Long id : idList){

      // 循环执行SQL查询或调用外部系统接口,产生性能问题

      Entity entity = xxService.getEntityById(id);

       ...

    }

    // 此案例的更优方案是 通过idList一次性查询获取到Entity集合,然后转换为Map<Id, Entity>供后续获取。

  • 需要多次使用的可复用对象将对象单独定义,禁止多次调用取不同属性。如:

    String name = userService.getUser(id).getName();

    Long deptId = userService.getUser(id).getDepeId();

    替换为:

    User user = userService.getUser(id); String name = user.getName(), ….

  • 可异步执行的耗时操作采用异步处理:使用Spring @Async 或 MQ,或夜间Timer定时
  • 常用数据考虑缓存,存入Redis,设置缓存过期时间
  • 需要保证写一致性的逻辑,在外层方法上添加事务 @Transactional(rollbackFor = Exception.class)

四、Mybatis与SQL规范

  • 表名、字段名、索引等数据结构定义大小写: Oracle大写, MySQL小写。名称使用英文+下划线,并控制总长度,如 user_name。
  • 表名建议采用“模块标识_”前缀,如 bas_user(如果模块库独立可省略模块名标识)
  • 禁止程序中的SQL使用并行计算 /*+parallel(t,n)*/
  • SQL使用标准SQL,避免出现数据库特定的语法
  • 未经评审不可直接使用视图、触发器、存储过程 SQL JOIN表数量不超过3张,超过3张表需要经过评审 (拆分成多次单表查询、主表冗余、程序绑定id-name映射、根据条件动态JOIN等)。
  • 合理创建索引,并尽量避免不走索引的情况: 如
    • LIKE右/任意匹配(‘%xx’, ‘%xx%’)不走索引, 换为“精确匹配=”或固定前缀的左匹配’张%’
    • 不等条件(!=、<>、NOT)不走索引,应尽量避免(转换成IN/BETWEEN等)
    • IS (NOT) NULL 不走索引,应尽量避免(如字段给定默认值,避免NULL)
    • 索引列使用函数或隐式转换都将导致索引失效,如 to_char(create_date,'yyyymmdd') = '20190102'
  • 禁止手动拼接SQL语句,利用Mybatis等ORM框架的动态SQL实现。 参数使用#{} (避免${}产生SQL注入问题)。
  • 禁止使用数据库处理函数 decode(),改为Java枚举或Map定义,通过id进行绑定 decode(client.TYPE, 1, '私客', 2, '店组公客', 3, '组团公客‘)
  • 禁止动态拼接时强加 1=1 之类的写法,如WHERE 1=1。使用Mybatis动态SQL标签实现,如<where>,<set>,<trim>
  • SQL中的参数类型确保与列定义一致,避免数据库隐式转换开销且无法使用索引,如:
    • 列定义为日期类型,参数要转换为Date日期类型进行比较:

      CREATE_TIME <= '2019-04-14 23:59:59’

      CREATE_TIME <= to_date('2019-04-14 00:00:00','yyyy-MM-dd HH24:mi:ss’)

    • 列定义为数字类型,参数不用String DEPT_ID = '123’
  • ID主键自增的情况下,按create_time排序改为按ID排序,效果一样效率更高

五、检查结果

  • 后端服务及其他需要自测的代码,编写对应的单元测试类,统一采用Junit,禁止直接在原Java类中写main()方法自测。

    单元测试会在打包前统一运行,可及时发现受影响的代码问题(比如新代码导致了之前的代码逻辑产生问题,如果有单元测试可在打包时及时发现)

    Junit单元测试类示例:

    public class TestApollo {

      @Test // 标记为单元测试方法

      public void testApolloConfig(){

        String appId = Foundation.app().getAppId();

        // 预期结果断言

        Assert.assertNotNull(appId);

      }

    }

  • IDE中安装代码质量检查插件: FindBugs 及 Alibaba Java Coding Guidelines

  

六、安全规约

  

规范——Java后端开发规范的更多相关文章

  1. Java后端开发规范

    基于阿里巴巴JAVA开发规范整理 一.命名风格 [强制]类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO / DTO / VO / AO 正例:Marco ...

  2. JAVA 代码开发规范

    一.开发工具规范: 1. 开发工具经项目负责人调试后统一确定. 2. 开发工具一经确定不允许集成任何非统一插件,若有需要,经项目负责人同意后统一为 项目组成员添加. 3. 开发工具的编码格式不允许修改 ...

  3. 转:Java项目开发规范参考

    Java项目开发规范参考 - KevinLee的博客 - 博客频道 - CSDN.NEThttp://blog.csdn.net/u011383131/article/details/51227860 ...

  4. 2022美团Java后端开发春招实习面经

    2022美团Java后端开发春招实习面经 一面 1.讲一下计算机网络的五层架构,每层分别有什么协议 ​ 五层架构:应用层.运输层.网络层.数据链路层.物理层 ​ 2.什么是 Http 协议,各种 Ht ...

  5. Java后端开发

    Java后端开发 名称 内容 基本框架 Spring.Mybatis Linux服务器   数据库优化   消息服务 rabbitMQ.activeMq rocketMq 缓存服务 memcached ...

  6. Java后端开发书架

    本人摘录于江南白衣文章,文章地址:http://calvin1978.blogcn.com/articles/javabookshelf.html 书架主要针对Java后端开发. 3.0版把一些后来买 ...

  7. Java后端开发奋斗之路

    本人方向:Java后端开发方向,本文中内容持续更新中 Java技术栈:https://www.cnblogs.com/wyb666/p/10222070.html 推荐书籍:<程序员代码面试指南 ...

  8. Java后端开发常用工具

    Java后端开发常用工具推荐: 俗话说,工欲善其事,必先利其器.不过初学时候不大建议过度依赖IDE等过多工具,这会让自己的编程基础功变得很差,比如各种语法的不熟悉,各种关键字比如synchronize ...

  9. Java后端开发工程师是否该转大数据开发?

    撰写我对java后端开发工程师选择方向的想法,写给在java后端选择转方向的人 背景 看到一些java开发工程师,对java后端薪酬太悲观了.认为换去大数据领域就会高工资.觉得java后端没有前途.我 ...

随机推荐

  1. 中文NER的那些事儿4. 数据增强在NER的尝试

    这一章我们不聊模型来聊聊数据,解决实际问题时90%的时间其实都是在和数据作斗争,于是无标注,弱标注,少标注,半标注对应的各类解决方案可谓是百花齐放.在第二章我们也尝试通过多目标对抗学习的方式引入额外的 ...

  2. DeWeb第1个通用化模块:登录模块,仅需要修改一个配置文件即可实现登录功能

    演示: https://delphibbs.com/login.dw 开发环境和源代码 https://gitee.com/xamh/dewebsdk 效果图: 配置方法: 在Runtime目录中放一 ...

  3. SimpleNVR流媒体服务在多分屏直播实时阅览时所遇到问题的解决

    视频有一个流的概念,称为流媒体.当大量的客户端或WEB访问监控摄像机的时候,大多数的录像机无法承受那么大的网络压力,这时候SimpleNVR流媒体服务器的优势就显示出来了.其能将客户端的访问压力转到服 ...

  4. Qt 信号与槽的自动关联机制

    前言 对于一些简单的事件判别,如点击按钮.无需写代码关联信号和槽函数. connect(ui->Btnshowhello,SIGNAL(clicked(bool)),this,SLOT(Btns ...

  5. FAIL : Keyword 'BuiltIn.Log' expected 1 to 6 arguments, got 12(解决方法)

    RF运行关键字:Run Keyword If ,log输出报错"FAIL : Keyword 'BuiltIn.Log' expected 1 to 6 arguments, got 12. ...

  6. Python Excel工具类封装, 给excel表头搞点颜色

    封装Excel工具类 我们常用的excel工具类,读有xlrd,写有xlwt.有读有写,新一代库有pandas,openpyxl等等. 大家用法都差不多,今天博主就介绍新手最爱,我也爱的xlrd和xl ...

  7. 大一C语言学习笔记(1)---编译顺序问题;不同数据类型赋值,运算问题;算数运算符易错点(以解一元二次方程为例)

    废话少说,上代码: #include<stdio.h> #include<math.h> int main()//解一元二次方程 { int a,b,c; double too ...

  8. 分布式配置系统Apollo如何实时更新配置的?

    引言 记得我们那时候刚开始学习Java的时候都只是一个单体项目,项目里面的配置基本都是写在项目里面的properties文件中,比如数据库配置啥的,各种逻辑开关,一旦这些配置修改了,还需要重启项目这修 ...

  9. WPF仿Tabcontrol加载切换多个不同View

    在同一块区域显示不同的视图内容,直接使用Tabcontrol,可能要重写TabItem的控件模板,最直接的方法通过按钮的切换,控制一个ContentControl的Content值,实现切换不同的视图 ...

  10. [luogu7092]计数题

    由于$\mu(i)$,因此每一个素数最多存在1次,当$k=0$答案必然为0 根据莫比乌斯和欧拉函数的积性,答案与对素数的划分无关,仅与每一个素数是否出现有关,换言之枚举素数出现的集合$P'$,答案即为 ...