应用开发部代码开发规范v1.1

文档版本说明
v1.0 基础版本
v1.1 补充规范,增加规范等级

一、代码流程规范


(一) java代码处理

  1. 【强制】java中对象判空必须使用ta3框架提供的ValidateUtil.isEmpty()方法或ValidateUtil.isNotEmpty()方法,不要自己去写,例如写==null等等;
    需要判空的情况:
    • 界面采集到的重要数据,尤其是update的条件数据;
    • service返回的数据;
    • 在对象执行相关方法的时候在为确定对象不为空的情况下都需要判空,如domain.tomap() ,list.size(),obj.equals()等;
  2. 【强制】java代码中使用码值时,必须将码值定义成常量并放到常量文件中。
  3. 【强制】获取当前时间必须使用统一方法从数据库中获取,一般为BaseService中的getSysTimestamp()getSysData()等方法,使用数据库时间作为统一的业务时间,避免直接使用应用系统时间,因为我们无法保证集群环境下,多台应用系统服务器时间的一致性和正确性。
  4. 【强制】序列号必须使用系统统一提供的getSeqence服务或项目自定义的获取序列的方法,不能自行随机产生,更不能简单的用时间做序列号,用随机数和时间在高并发、集群环境下都会很随机的产生碰撞,导致异常。
  5. 【推荐】service中getDao() 可以直接使用dao简写。
  6. 【推荐】善用TODO:在代码中加入//TODO:IDE会帮你提示,让你知道还有什么事没做,例:
if(order.isPaid()){
//TODO:更新订单
}
  1. 【强制】变量和字符串做比较时,必须用"字符串".equals("变量"),如"0".equals(变量),避免变量为空时使用equals方法报空指针错误。
  2. 【强制】禁止使用equals()方法将一个对象与null作比较(obj.equals(null)),如果obj对象为null,程序将抛出NullPointerException异常;如果obj对象不是null,那么该表达式将始终返回false。
  3. 【强制】表达式的计算结果永远为false,表明基于该表达式的代码片段将永远不会被执行,是程序中的死代码或用于调试的代码,这些死代码会增加代码的阅读、理解和维护难度,甚至该段代码还可能指出程序中曾经出现的错误,被其他人利用;检查程序逻辑,如果确定程序中的死代码没有作用,应该将其删除。
  4. 【强制】空的try代码块、if代码块在程序中没有起到任何作用,是程序中的死代码或者是应该被注释掉的调试代码;这些死代码会增加代码的阅读、理解和维护难度;检查程序逻辑,如果确定程序中的死代码没有作用,应该将其删除。
  5. 【强制】禁止在finally语句块中使用return、continue或break返回指令,这会导致try块中抛出的异常丢失及逻辑混乱。
  6. 【强制】自定义类的对象使用 equals()方法时必须重写equals()方法,在没有重写equals()方法的类(或接口)上调用equals()方法,会导致调用继承自java.lang.Object的equals()方法,尽管可以合法的使用Object.equals(),但是Object.equals()将比较两个对象的内存地址,而不是比较对象的成员变量。
  7. 【强制】 类如果重写了equals(),必须同时重写hashCode()方法;Java语言规范规定相等的对象必须具有相同的哈希码,即:如果a.equals(b)==true,那么a.hashCode()==b.hashCode();如果不遵循这个准则,当此类对象存储在一个集合中时,可能就会引发一些问题;如果将这个类的对象用作哈希表的关键值或是插入到一个Map或者Set中,那么相等的对象要具有相等的哈希码,这一点十分重要。
  8. 【强制】启动线程应该调用start()方法,而不是run()方法;用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码;run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
  9. 【强制】不同的操作系统使用不同的字符作为文件分隔符;例如,Windows 系统使用 "",而 UNIX 系统则使用 "/";应用程序需要在不同的平台上运行时,使用硬编码文件分隔符会导致应用程序逻辑执行错误,并有可能导致拒绝服务;
    反例:以下代码使用硬编码文件分隔符来打开文件:
File file = new File(directoryName + "\\" + fileName);

正例:

File file = new File(directoryName + File.separator + fileName);
  1. 【强制】开发人员必须使用框架提供dao对数据库进行操作,禁止使用jdk原始api操作数据库,特殊业务除外。
  2. 【强制】java中杜绝使用java.lang.Runtime.getRuntime().exec(…),该命令会造成恶意用户通过前段传入任意命令操控服务器,从而达到各种攻击的目的;
  3. 【强制】静止私自调用System.runFinalizersOnExit()System.gc()System.exit()Runtime.exit()方法;前者不正确的调用会导致jvm不正常工作,程序频繁调用System.gc()将会降低系统性能,调用System.exit()Runtime.exit()会关闭java虚拟机。
  4. 【强制】框架中Service均是单实例多线程,如果在程序的实现类中定义了存在线程安全问题的变量,可能出现业务经办结果的不确定性;因此在Service中除了定义在配置中注入的变量、以static final定的简单类型(如:int、float、byte等)和不可变类(如:String、Float、Integer等)外,不要额外定义其他变量;正确的定义示例如下:
public class TestServiceImpl extends BaseService implements TestService{
    private ResourceService resourceService;
    private static final String Q_MODE = "01";
    //……
}
  1. 【强制】程序注释中禁止保留密码等敏感信息,将使敏感信息对任何能够获取到该文件的人员可见。
  2. 【强制】程序中禁止重写类的finalize方法并进行调用,该方法用于释放对象占用的存储空间,应由JVM进行调用;如实际业务需要重写类的finalize方法,在重写的finalize()方法时应先调用super.finalize()。
  3. 【强制】开发人员禁止私自在项目中添加第三方jar包,如有实际需要,需向项目经理报备。
  4. 【强制】项目上线时,需将jdbc.properties中的数据库信息去掉,防止黑客获取到数据库连接信息。

(二)数据处理

  1. 【强制】Java中金额相关的对象类型必须使用BigDecimal,以防止计算的不精确、数据过大、过小的越界等
    获取当前登录人员信息必须统一使用dto中的getUserInfo()方法,如:
String userName = dto.getUserInfo().getName();
  1. 【强制】方法的入参和返回参数不要用Object类型。
  2. 【强制】不能将返回结果集放到session中,避免服务器内存消耗而影响整体系统性能,除非设计要求。
  3. 【强制】集合等类型如知道所装对象类型,请使用泛型,如:
List> list = new ArrayList>();

(三)异常处理

  1. 【强制】java里面如需抛异常,异常类型必须为ta3封装的AppException,如:
if(n != 1){
    throw new AppException("修改失败");
}
  1. 【强制】所有Service里面的异常全部抛出,内部实现不要try-catch,有特殊业务需求除外,如使用了try-catch且在catch里使用return语句后,需注意事务问题 ,如
try {
    //a操作
    //b操作
} catch(Exception e) {
    return "";
}

该操作没有将异常抛出,直接在catch里面return,如果b操作失败抛出异常,a操作是不会回滚的

  1. 【强制】action中捕获service中抛出的异常,并将错误信息处理成用户易于理解的方式展示到前台,不要直接将异常信息展示给用户,如:
try {
    //service方法
} catch(Exception e) {
    setMsg("保存失败,请联系管理员!",ERROR);
}

(四)事务控制

  1. 【强制】service事务配置范本
    testService :spring beanID
    transactionProxy:spring事务代理
    dataSource:数据源
  • 带事务的service

    
        
    

  • 不带事务的service
    
  1. 【强制】在配置了多数据源的项目中,事务代理和数据源必须一一对应。
  2. 【强制】同一个service内不同方法的事务传播行为必须一样,否则会造成事务失效的风险(详细解释)
  3. 【强制】查询类操作可以直接在action中进行,不需要事务控制。

(五)sql规范

  1. 【强制】分页查询sql和普通查询sql不能共用,会有缓存风险。
  2. 【强制】在所有用到dao.updatedao.delete对数据的操作,能够根据业务上下文确定影响记录数,必须对dao.updatedao.delete返回值进行判断,例:
    if(1 != dao.update("updateAc01ForKey", mapKey)){
        throw new AppException("xxxxx");
    }
  1. 【强制】update,delete语句不能使用动态where条件,如使用动态where条件,传入参数为空时,则可能造成更新和删除的范围变大的风险,例:
    UPDATE SYSHELP
       SET yxbz = '0'
    
        
           id = #id#
        
        
           name = #name#
        
    

优化为:

    UPDATE SYSHELP
       SET yxbz = '0'
     WHERE id = #id#
       AND name= #name#
  1. 【强制】在Ibatis中的SQL语句不能使用动态$参数,由于$参数是基于字符串的原样替换拼接,如果该参数是来自界面的无效、恶意参数容易导致SQL注入攻击,例:
SELECT aac001
FROM ac01 a
WHERE a.aac001 = #aac001#
AND a.aac008 IN ($aac008$)

假定参数aac008传入为'01' ) OR 'a' IN ('a',该语句最终执行为:

SELECT aac001
FROM ac01 a
WHERE a.aac001 = #aac001#
AND a.aac008 IN ('01' ) OR 'a' IN ('a')

就会导致全表查询,假如该表是千万、或者上亿的数据,则查询可能会导致应用服务器内存溢出、宕机,如必须使用,需向领导报备,并对参数做长度、特殊字符等检查

  1. 【强制】sql中禁止使用truncate、drop命令,删除表数据或删除表。

二、性能规范


(一)java性能

  1. 【强制】String是不可变类,字符串+运算不是直接将字符串在原对象上进行拼接,而是新产生对象,对应用服务器内存和效率都会带来一定影响;因此在循环中进行字符串拼接,必须使用StringBuilder.append或StringBuffer.append来替代+字符串运算;此外,本条也适用于非循环语句下大量字符串连续拼接运算;示例如下:
    String err = "";
    for(int i = 0; i < inputList.size(); i++) {
        //....
        err = err + "第" + i + "行[" + vo.getAac001() + "]重号/n";
        //....
    }

优化为

    StringBuilder err = new StringBuilder();
        for(int i = 0, j = inputList.size(); i < j; i++) {
        //....
        err.append("第").append(i).append("行[").append(vo.getAac001()).append("]重号/n");
        //....
    }
  1. 【强制】在循环时,变量的声明应放到循环外,循环中保持值不变的变量,应在循环外赋值,如:
for (int i = 0; i < list.size() ; i++) {
    Map m = new HashMap();
    //……
}

优化为

Map m = null;
for (int i = 0; i < list.size() ; i++) {
    m = new HashMap();
    // ………
}
  1. 【强制】代码中的System.out.println在功能测试通过后必须删除或注释。
  2. 【强制】删除没有被使用的变量。
  3. 【强制】ta3中批量insert使用框架提供的dao.insertBatch()方法,不要循环调用insert方法,如:
for (Map map : list) {
        dao.insert("test.insert",map);
}

优化为

dao.insertBatch("test.insert",list);
  1. 【推荐】对追求高性能、不需要扩展和继承覆盖的类、方法、变量等使用final修饰符,JVM会对final修饰的类、方法、变量进行运行时缓存和优化,从而提高运行效率。
  2. 【推荐】如需遍历Map尽量用entrySet(),遍历时用entry.getKey() 和 entry.getValue(),该遍历方法效率较高。
  3. 【推荐】在业务代码中尽量减少反射的操作,例如使用get、set方式代替类似BeanUtils.copyProperty这样的反射操作,从而提高代码运行性能。
  4. 【推荐】尽量使用局部变量,调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快;其他变量,如静态变量、实例变量等,都在堆 (Heap)中创建,速度较慢;另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。
  5. 【推荐】程序中采用new Boolean(boolean expression)或new Boolean(String expression)创建对象,该方法产生的额外对象将占用更多空间、降低性能;使用Boolean.valueOf(boolean expression)或Boolean.valueOf(String expression)或Boolean.TRUE、Boolean.FALSE代替new Boolean。
  6. 【推荐】循环中尽可能使用临时变量存储.length() .size() .getClass().getName()等取值方法的返回值,以及存储在一行中多个“.”调用代码的中间值,从而提高效率,例如:
queryDto.getParameter().put("aae041", aae041);
queryDto.getParameter().put("yab003", queryDto.getUserInfo().getOrgId());

修改为:

Map m = queryDto.getParameter();
m.put("aae041", aae041);
m.put("yab003", queryDto.getUserInfo().getOrgId());
  1. 【强制】对时间、时间戳、BigDecimal等类型做整型转换时,用JAVA自带的 API或框架中的工具类,应该避免转换为字符串,然后截取,强转这种方式;
    反例:
int beforeChange = Integer.valueOf(时间戳格式对象.toString().substring(0,4)).intValue();

(二)sql性能

  1. 【强制】对表进行操作时,where条件中必须带上主键或有索引的字段;
  2. 【强制】对带有索引的字段进行like模糊查询时,只能使用keyword%右模糊,使用%keyword%keyword%会使索引失效;

三、代码格式规范


(一)命名规范

  1. 【强制】包(Package)命名
  • 采用完整的英文描述符,应该都是由小写字母组成,并且以com.yinhai开头;
  1. 【强制】类(class)命名
  • jsp,action,service,service实现的命名必须对应,如test.jsp,TestAction.java,TestService.java,TestServiceImpl.java;
  • jsp以小写开头,采用驼峰方式,如testJava.jsp
  • java以大写开头,采用驼峰方式,如TestAction.java
  • 配置文件小写开头,如spring-test.xml
  1. 【强制】静态常量字段(static final)
  • 全部采用大写字母,单词之间用下划线分隔; MIN_BALANCE, DEFAULT_DATE
  1. 【强制】标签变量命名
  • from标签直接定义为from1;
  • 变量名避免使用太长的名字,如长度超过15位,请使用缩写;
  • 如果标签与数据库字段未绑定, 则标签id属性用前缀名+下划+对应的表字段名来描述( 全部小写);
标签 前缀
checkbox cb
radio rd
text txt
selectInput slpt
tree tre
  1. 【强制】按钮命名
按钮 id key hotkey
查询 btnQuery 查询[Q] ctrl+q
删除 btnDelete 删除[D] ctrl+d
增加 btnAdd 增加[A] ctrl+a
修改 btnEdit 修改[E] ctrl+e
重置 btnReset 重置[R] ctrl+r
保存 btnSave 保存[S] ctrl+s
关闭 btnClose 关闭[C] ctrl+c

其他按钮命名以btn开头, 热键不能和已有的重复

  1. 【强制】方法命名
  • 首字母小写,采用驼峰方式,长度过长请使用缩写,如queryEmp()
  1. 【强制】禁止类成员与类同名,变量与方法同名,容易导致程序混乱或产生错误的代码;

(二) 标签格式

  1. 【强制】标签如果没有子标签,后面的结束标签可以简写,如:

优化为:


(三) JS代码格式

  1. 【强制】不能在一行语句定义多个变量,如
var aac001,aac002,aac003;

优化为:

var aac001,//变量注释 
    aac002,//变量注释 
    aac003;//变量注释 

(四) JAVA代码格式

  1. 【强制】删除不用的包导入,在代码提交svn前必须使用快捷键ctrl+shift+o修正导入。
  2. 【强制】大括号的开始在代码块开始的行尾,闭合在和代码块同一缩进的行首,如:
public Object implLog(Map argMap) {
    return dao.insert("compmanage.insertComp_impl_id_log", argMap);
}
  1. 【强制】xml文件里面只能使用空格缩进。
  2. 【强制】xml文件中开始标签和对应的结束标签必须对齐。
  3. 【强制】if-else,for,while等语句,在任何情况下,都应该有“{”,“}”。

(五) 注释

  1. 【强制】类注释:java类必须注释上该类的作用,开发者名字及开发时间
    /**
    *
    * @description 个人差额退补
    * @author wukong,bailongma
    * @Time 2016-03-01 15:02:29
    */
    public class DiffCompensAction extends BusinessBaseAction{}
  1. 【强制】方法注释
    /**
     * @description 保存基金支出信息
     * @param dto
     * @return
     * @throws Exception 
     * @author Administrator
     * @Time 2012-11-20 15:02:29
     */
    public void toSave(List list,ParamDTO dto) throws Exception{};
  1. 【强制】代码块注释
    • 逻辑控制代码块必须有注释
    • 重要的业务节点必须有注释
  2. 【推荐】变量定义后必须加上注释
  3. 【强制】sql注释
    • 查询sql字段的注释
    • sql中的小于符号的转义

四、界面布局规范


(一)表单规范

  1. 【推荐】页面上的经办时间必须带上时分秒。
  2. 【推荐】输入类标签父容器用fieldset
  3. 【推荐】表格类标签父容器用panel
  4. 【推荐】表单输入框按照3列布局。
  5. 【推荐】输入内容较长的标签占2-3列,如:地址、公司名称、备注等。
  6. 【推荐】按钮使用toolbar标签。
  7. 【强制】页面显示内容使用form标签包裹。
  8. 【推荐】表格中较长的数据必须添加showDetail=true属性,如:

  1. 【强制】布局容器同级情况下,只有第一个容器添加fit=true
  2. 【强制】label字数过多时, 被输入框遮挡, 必须设置标签的labelWidth属性设置label的宽度, 但页面上的标签需统一调整, 达到页面统一。
  3. 【强制】在jsp页面title标签中间加上当前页面对应的action名字及功能名称,如:
allpaymentRecheckAction|支付计划
  1. 【强制】所有标签的第一个属性应为id,第二个属性为key(没有key的除外),其他属性依次 往后排,新添加的属性应在最后加,不能在中间添加,规范写法:



  1. 【强制】必须使用框架提供重置按钮

  1. 【推荐】按钮都需要添加快捷键,快捷键为Ctrl+英文字母,且在按钮标题中显示快捷键信息

  1. 【强制】必录项需使用标签的required属性添加红星

  1. 【强制】文本框必须有长度校验, 字符长度不能超过数据库字段长度; 数字输入框要有最大值限制, 数字最大值不能超过数据库字段长度, 最小值依据业务需求而定; 如数据库中字段的类型为number(8,2), 表示范围是8位, 精度为2, 即存6位整数, 两位小数, 那么标签里的max="999999.99"


  1. 【强制】邮政编码,邮箱等必须使用text标签的validType属性校验,具体可校验类型参 照validType属性值


  1. 【推荐】下拉列表的下拉选项只有一个、并且该下拉列表是必录项时,需将该唯一的下拉选项设置为下拉列表的默认值。
  2. 【推荐】表单与datagrid中:文本靠左、数字靠右,datagrid中日期居中。
  3. 【强制】selectinputdatagrid里有码表的必须加collection属性,后台手动设置的除外

  1. 【强制】查询条件至少有一个为必输条件,除特殊要求外;
  2. 【强制】对于结果超过500条数据的查询,应使用分页方式,分页数如果允许修改限制不超过500;
  3. 【强制】表单、表格中的id字段不能直接展示到界面,需隐藏,除业务需要展示的;
  4. 【推荐】默认情况下,表格不能启用通用数据导出功能,避免数据泄露;
  5. 【强制】jsp页面禁止直接写代码访问数据库,禁止在JSP、JS、HTML等前端代码中使用SQLID传到后端执行相应SQL,熟悉系统的恶意攻击者通过更换SQLID伪造关键数据,从而非法执行后台SQL,获取、修改正常数据,给系统带来安全隐患;
  6. 【强制】当关键业务数据出现在URL中时,须进行加密,确保在浏览器地址栏中,或在浏览器开发调试视图、或其他途径看不到关键数据的明码,且当参数被非法修改后不会非法访问业务系统;

(二) JavaScript规范

  1. 【强制】提示信息必须使用Base.alert(),并且必须带上类型(如successerrorwarn),不能使用原生的alert方法
Base.alert("保存成功! ","success");
  1. 【强制】查询操作查询不出信息时需做提示;保存、删除成功后需给出提示信息(成功或下一步操作的提示)。
  2. 【推荐】初始化界面,焦点置于第一个输入框
$(document).ready(function() {
    $("body").taLayout();
    Base.focus("aac001");
});
  1. 【强制】在保存的提交方法里,Base.submit方法的第五个参数设置为true,框架自动调用Base.validateForm对ids对象进行校验,如果校验失败将不再提交,并自动设置不通过的 输入对象为校验失败的样式,同时第一个校验失败元素获取焦点;重要的信息必须自己手 动再调用Base.validateForm检验
Base.submit("form1", "insurTransferApplyAction!toSave.do",null,null,true);
  1. 【强制】身份证有效性校验,如界面存在出生日期、性别字段,必须在录完身份证时自动填写。
  2. 【强制】输入的时间段,需进行校验,结束时间不能早于开始时间。
  3. 【强制】Base.submit提交请求,第一个参数有多个值时,值参数之间不能有包含关系,第一个参数和第三个参数不能有重复的字段
    setReadOnlysetRequiredshowObjsetDisabledsetDisRequiredsetEnable有 多个值时,值用逗号隔开,不能每个值写一行。
  4. 【推荐】Base.submitBase.getJson方法根据业务需求合理选择使用
    • Base.submit:异步请求,在请求还未结束的情况下,后续代码会继续执行;
    • Base.getJson:同步请求(异步中的同步),在请求还未结束的情况下,后续代码不会继续执行;
  5. 【强制】不能使用关键字作为变量名或者键值对中的key,包括(按字母排序):breakcasecatchcontinuedefaultdeletedoelsefinallyforfunctionifininstanceofnewreturnswitchthisthrowtrytypeofvarvoidwhilewith 等;
  6. 【强制】缩进的单位为4个空格;
  7. 【强制】所有的函数在使用前声明;
  8. 【推荐】if、for、while、do、switch、try使用方法如下:
if (condition) {
    statements;
}

if (condition) {
    statements;
} else {
    statements;
}

if (condition) {
    statements;
} else if (condition) {
    statements;
} else {
    statements;
}

//用于已经知道相关参数的数组循环
for (initialization; condition; update) {
    statements;
}

//用户对象中,object原型中的成员会被包含在迭代器中,
for (variable in object) if (filter) {
    statements;
}

while (condition) {
    statements;
}
do {
    statements;
} while ( condition );
switch (expression) {
case expression:
    statements;
default:
    statements;
}
try {
    statements;
} catch(variable) {
    statements;
}
try {
    statements;
} catch(variable) {
    statements;
} finally {
    statements;
}

五、findbugs检查规范


  • 项目代码必须通过FindBugs工具扫描,并100%修复minimum priority to report为Hight的以下几种类型的bug:
  1. 正确性(Correctness):这种归类下的问题在某种情况下会导致bug,比如错误的强制类型转换等;
  2. 最佳实践反例(Bad practice):这种类别下的代码违反了公认的最佳实践标准,比如某个类实现了equals方法但未实现hashCode方法等;
  3. 多线程正确性(Multithreaded correctness):关注于同步和多线程问题;
  4. 性能(Performance):潜在的性能问题;
  5. 安全(Security):安全相关;
  6. 高危(Dodgy):FindBugs团队认为该类型下的问题代码导致bug的可能性很高;
  7. 恶意代码漏洞(malicious code vulnerability):其他恶意代码安全漏洞;

你可能感兴趣的:(应用开发部代码开发规范v1.1)