一、绪论
1.1 概述
随着公司上ERP项目,为统一开发技术规范,缩短开发周期,进一步提高项目质量,降低后期维护难度,迫切需要一个更完善、专业、有效的开发规范。
本规范的目的是使本科室JAVA开发能以统一、标准的、规范的方式设计和编码。通过建立开发规范,使每个开发人员养成良好的开发风格和习惯;提高程序的可靠性、可读性、可维护性和一致性等,提高程序员的开发水平,增进团队间的交流,并保证软件产品的质量。
1.2 适用范围
本规范适用于本公司所有JAVA软件项目、产品等的设计、开发以及维护等。所有JAVA软件开发人员在整个软件开发过程中必须遵循此规范。
二、总体框架
2.1 框架概述
本公司JAVA开发的软件产品多为B/S结构,涉及多个层面的开发,为便于逻辑分离及项目分工,开发的软件产品应当符合MVC设计模式,基础框架使用SSH(spring+hibernate+struts2)MVC基础框架。
2.2 框架规范
旧框架中Servlet层应当仅负责宏观层面的业务逻辑,不进行具体的数据访问,新框架中Action组件负责事务同旧框架中的Servlet层组件。Model由开发人员自己实现。hibernate是将原来的 DAO部分,就是数据库部分,进行数据持久化,可以理解为数据库的接口和对数据库的操作之一。spring是管理容器的角色,降低耦合度,方便管理。
2.2.1 Hibernate DAO规范
DAO为数据访问组件,用于访问持久性数据,例如为关系型数据库。本规范要求DAO对象必须直接或间接继承数据访问组件的基础类com.yonggang.framework.hibernate.HibernateDAOSupport ,该基类已经实现了hibernate通用的查询,更新,插入,删除,分页查询等操作,业务类继承该类后即可使用HibernateDAOSupport提供的hibernate数据库操作方法。
DAO处理完正常逻辑后设置本次处理后用于界面提示的消息。禁止DAO类依赖于request等Web对象,便于DAO类可以脱离于Web应用。
2.2.2业务处理类BO规范
在BaseBO当中,提供了业务开发常用方法,比如采用Hibernate方式的普通查询、分页查询、对象的保存与更新,还提供了Jdbc方式的普通查询、分页查询、数据更新等。开发当中可以创建一类业务处理的“BaseBO”,比如“WorkflowBO”,该BO扩展自“com.yonggang.framework.base.BaseBO”,项目当中工作流业务模块皆要扩展这个新创建出来的WorkflowBO。具体的业务模块当中就可以扩展这个WorkflowBO,编写相关的业务方法。
其中的业务方法如果需要事务包裹,要以update、delete、save、process、execute开头,并且配置将该BO配置到Spring当中时,Bean的命名要以BO结尾。
编写好业务类之后,我们需要将其配置到spring的配置文件当中,通常情况下,我们建议您在您的模块的src目录下创建一个configs目录,在其下放置您的spring配置文件,这样,因为是分模块配置对应的spring配置文件,所以即使在多人开发的场景下也不会产生配置文件编辑的冲突问题。下面表格当中向我们展示了TestBO在Spring配置文件中的配置情形。
从上面的配置当中可以看到,我们建议您在Spring当中配置您的BO的时候,bean的ID命名方式采用模块名+“.”+类名(首字母小写)的方式,如上面的bean的名字为“modulea.testBO”,这里的modulea是模块名称,testBO是类名(首字母小写)。通过这种命名方式,我们从Bean名称上就可以看出Bean的作用,同时这种命名方式还可以防止重名。
2.2.3 Action规范
新框架以Action层组件代替Servlet层组件。此处,Action组件将主要负责业务逻辑开发、消息设置、页面导航设置,不再需要管理资源释放(如数据库连接的释放)。
Action类都必须直接或间接继承类com.opensymphony.xwork2.ActionSupprot与DAO的理由一致,每一套应用也应当定义自己的Action入口,此处假定其名称为AppAction。
2.2.4 角色权限用户验证规范
使用spring security3作为本框架的安全验证,使用SpringSecurity可以与spring无缝集成,扩展性很强。下面简单说明下spring security 的业务流程:
1)容器启动(MySecurityMetadataSource:loadResourceDefine加载系统资源与权限列表)
2)用户发出请求
3)过滤器拦截(MySecurityFilter:doFilter)
4)取得请求资源所需权限(MySecurityMetadataSource:getAttributes)
5)匹配用户拥有权限和请求权限(MyAccessDecisionManager:decide),如果用户没有相应的权限,执行第6步,否则执行第7步。
6)登录
7)验证并授权(UserDetailServiceImpl:loadUserByUsername)
8)重复4,5。
该框架中已经实现了基于SpringSecurity的角色权限验证。
2.2.5工作流引擎规范
项目中如果需要使用到工作流引擎,则使用JBPM作为工作流引擎,需要在项目目录下WEB-INF\config\spring\applicationContext.xml中如图:
把 注释释放掉即可。框架JBPM4做了封装和扩展,使用工作流时,写工作流业务类需要继承工作流程业务基类WorkflowBO后通过getWorkflowService()方法获取工作流操作方法实现工作流引擎操作。定义完业务类需要将其配置到spring的配置文件当中,如图: 三、Java开发规范 本部分着重B/S结构中Server端Java代码的规范,同样适用于基础库开发。公用功能的程序由公司基础库提供。基础库应当在实际项目中提炼,采用共同讨论,专人维护的方式进行。基础库生成JavaDOC文档,开发人员应当仔细阅读,利于应用开发。 3.1 风格规范 3.1.1 风格概述 实际的开发中,由于项目期限等原因,尽管已经有初步的开发规范,但在项目后期常常失控,为了赶进度,开发人员逐渐养成了一些不良的习惯。命名随意,汉语拼音英文混合、注释不清晰、导入不使用的类、定义不使用的变量、方法存在不需要的参数、方法命名与方法实现功能不一致、程序缩进不一致等。这些都是需要规范的地方。 好的程序书写规范比随意的书写规范更清晰、错误更少、更易修改。所以,一开始就要注意使用好的编写风格。好的程序设计风格就如同好的文章,不仅要求语句顺畅,而且段落分明,结构紧凑。不仅排版要清晰,标点符号正确使用,而且重点要突出,中心明确。 让我们从这些基本的编程技术基础上入手,改正以前的不良习惯,逐步提高应用交付的质量。 3.1.2 类(包)导入规范 在import需要用到的类时,尽量少用import *;而应当具体指明需要导入的类,利于代码阅读,知道用到了具体的什么类。导入需要用到的类应当按照一定的顺序导入,不能随便写,此处规定,导入顺序如下,且前后类别之间以空行隔开: Java标准包类 Java扩展包类 第三方组件包类 自行开发基础库包类 业务系统自身基础包类 3.1.3 缩进规范 源码缩进不仅仅使程序更美观,而且也使程序结构更清晰、易读。采用统一缩进4个空格方式。在类的定义、方法体的开始以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。 3.1.4 表达式和语句规范 表达示和语句是程序中使用最多的基本语法,也是构成程序逻辑的基本要素,它们的不合理使用很大地影响了程序的清晰性、简洁性。 3.1.5 括号规范 在表达示中,因为算术运算符,关系运算符和逻辑运算符的优先级别一般很难记清,因此规定采用括号“()”显式划分计算的优先级,排除二义性。 在条件判断中,无论执行语有几条,都应当以大扩号“{}”括起来。 3.1.6 空格规范 关键词和操作符之间加空格; 方法名之后不要留空格,紧跟左括号“(”,以与关键字区别; 方法中参数之间夹空格; 赋值操作符、比较操作符、算术操作符、逻辑操作符、位与操作符,如“=”、“+=” “>=”、“<=”、“+”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格; 一元操作符如“!”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空格; 对于表达式比较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格,如for (i=0; i<10; i++)和if ((a<=b) && (c<=d))。 3.1.7 空行规范 包命名的行和后续导入的类(包)之间加一个空行; 按3.1.2规范导入的类(包)之间加空行; 在导入类和类注释之间加空行; 方法和方法之间加空行; 相对的程序块与块之间加空行; 较长的语句、表达式等要分成多行书写; 划分出的新行要进行适当缩进,使排版整齐,语句可读。 长表达式要在低优先级操作符处划分新行,操作符放在新行之首; 循环、判断等语句中若有较长的表达式或语句,则要进行适当划分; 方法参数较长,进行适当的划分; 不允许把多个短语句写在一行中,即一行只写一条语句; 方法或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格。 程序的分界符“{”和“}”应独占一行并且位于同一列,同时与引用它们的语句左对齐; 3.1.8 注释规范 为便于维护,对程序应当给出适当的注释。 类(接口)注释 对类和接口应当加以注释,对该类作一个简单功能描述,同时还可以标注其他内容:如公司名称,开始编写日期等,但作者必须标注上,方便在出现问题时由原作者负责解释。 方法注释 应当对方法进行注释。注释必须含“功能”描述,参数描述,返回值描述。如果参数较为复杂,或者怕遗忘,则详细说明每个参数的作用、取值范围及相互间的关系。 3.2 模块划分 合理的模块划分能提高项目的效率。在一个项目开始之前,应当进行合理的模块划分。划分之后任一模块的业务代码应当仅依赖于下述包(或类): Java标准包 Java扩展包 第三方组件包 业务系统基础包 除此之外,不应该再导入其他类(包),如有导入,则说明模块划分可能不够合理。设计人员在设计之初应当对此进行全局考虑。 3.3 包存放规范 尽管Java支持未命名包,但为让程序显得美观、清晰直观,程序应当放到相应的包下。开发的程序应当放到com.yonggang包或其子目录下。 此处规定,禁止写未命名包的程序,希望大家遵守。 3.4 命名规范 命名采用英文命名,禁止采用中文汉语拼音缩写命名,命名采用大小写混合,提高可读性。命名应当能顾名思义,能够正确表达出想要表达的意思。 3.4.1 包命名规范 包表示一对类的共同含义,可以对应应用开发的模块,必须以名词(或动名词)命名,必须全部采取小写字母形式,并具备规定的层次。 如com.yonggang.ygoa.report包表示出现在该包内的类都是为报表服务的。 3.4.2 类(接口) 命名规范 类和接口表示一类对象,必须以名词命名。类名的第一个字母必须大写,类名如由多个单词(或缩写)构成,则每个单词(缩写)的头一个字母必须大写。如消息管理器命名为MessageManager。 为统一起见,对我司的框架中出现的四种类做出进一步规定,如下: DAO类 DAO类必须以“DAO”三个大写字母结尾,如AmsAssetsCheckHeaderDAO; Servlet类 Servlet类必须以“Servlet”结尾,如AmsAssetsCheckHeader Servlet。 类(接口)名和表名的对应关系为:表名第一个字母大写不变,后续字母变为小写,直到遇到下划线“_”,下划线“_”不出现在类名中,下划线“_”紧跟的字母保持大写不变,后续字母又变为小写,以此类推。 对于不需要单独维护或查询表,不需要写对应的Servlet类,但其他三类应当提供,由其他的DAO类调用。 3.4.3 方法命名规范 方法表示一次操作,因此必须以动词形式命名。方法名第一个字母采取小写形式,其余字母同类(接口)的命名规则。 3.5 方法编写规范 3.5.1 基本原则 方法是Java的基本功能单元,一个方法应当只完成一项功能。对于公用接口外的方法,应当尽可能缩小其可见性,避免用一个类实例去访问其静态变量和方法。当一个方法被调用之后,方法所在类应当反馈出本次调用是成功还是失败,如果被调用方法不能反馈结果,则同一类中其他方法应当提供。 3.5.2 参数规范 禁止方法提供超过四个的参数。如果确实需要更多参数,则用参数建立新的值对象,以此对象做参数。参数类型和返回值尽量接口化,以屏蔽具体的实现细节,提高程序的可扩展性。在方法的入口处对参数进行有效性检查。很多程序错误是由非法参数引起的。良好的编程典范规定:当编写一个方法时,必须验证所有传递进来的参数,如果任何一个参数不合乎要求,就应当明确地引发一个异常。boolean参数不应当检查。 3.5.3 出口规范 对于有返回值的方法,禁止提供多个出口,而只能提供一个出口。 3.5.4 注意事项 方法的规模尽量在200行以内。超过200行则多半存在可以的逻辑单元,则可以将其抽取出去另写方法; 一个方法仅完成一件功能; 为简单功能编写方法; 方法的功能应该是可预测的,也就是只要输入数据相同就应产生同样的输出; 尽量不要编写依赖于其他方法内部实现的方法; 避免设计多参数方法,不使用的参数从接口中去掉;参数多时将之作为新对象的字段,以对象形式传入; 用注释详细说明每个参数的作用、取值范围及相互间的关系; 检查所有参数输入的有效性; 检查所有非参数输入的有效性,如数据文件、公共变量等。 方法名应准确描述方法的功能; 方法的返回值要清楚、明了,让使用者不容易忽视错误情况。 减少方法本身或方法间的递归调用; 3.6 语句选择规范 3.6.1 分支语句 分支语句有if,switch两种。if语句多用于分支较少的情况,switch语句正好相反。当分支较多时,采用if语句显得冗长,建议采用switch语句。 3.6.2 循环语句 Java循环语句中,for语句使用频率最高,while语句其次,do语句很少用,可根据自己熟悉程度选用,但应当考虑效率问题。在循坏次数不太多时,三种语句循环效率无明显差别;当循环次数较大时,效率最高的是do循坏,其次是for循坏,最后是while循坏。 多重循环效率问题 在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。 循环内逻辑判断问题 如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体外面。 特殊规定 如无必要,不应该在for 循环体内修改循环变量,防止for 循环失去控制。 3.7 异常处理与资源回收 3.7.1 异常处理 异常处理的基本思想是只对错误进行处理,如数据库操作、文件操作中的错误以及有限性资源耗尽等。 捕捉异常是为了处理它,不要捕捉后却不做任何处理。如果不想处理,则应当申明方法抛出相应异常,由调用者处理。禁止使用一个catch语句处理多个异常,应当分别捕捉并处理。 一个方法申明抛出的异常个数应当最小化,最好只抛出一个异常。如果确实要捕捉处理多个异常,可记录下非申明异常的错误信息,并将之转化为申明异常抛出。 捉到的异常应当记录下来,记录由基础库提供的日志工具完成。禁止将异常直接输出到控制台。 经常发生的可预计事件不进行异常捕捉及处理,方法已申明抛出的异常不需捕捉。禁止使用异常实现逻辑控制。 应当在本地进行安全性检查,而不是让程序的调用者完成。 3.7.2 资源回收 有限性资源使用完毕后,应当立即释放。如数据库连接,I/O操作等。无论程序是否发生异常,资源都应当得到回收。 回收资源的代码应当位于finally子句内,以保证资源得到释放,禁止与正常的业务处理代码混在一块。 如果类中有限性资源是全局性共享资源,则类还应当提供finalize方法,由JVM在资源回收的时候调用finalize方法,做最后释放。 3.8 性能与安全 3.8.1 基本原则 程序在满足功能的情况下,应当尽量提高运行性能。程序的运行性能很大程度上由SQL语句决定,SQL语句的在编写时在满足功能要求前提下需要提高SQL运行效率。 3.8.2 减少重复计算 如果一个计算或查询多次出现,那么就只在一个地方实现,并记录结果。这样会避免无谓的重复计算与查询工作,计算越复杂性能牺牲就越大。 3.8.3 可变字符串 处理可变字符串时,尽量使用StringBuffer类而非String类。由 StringBuffer对象完成大部分工作,完成后将之转换为需要的String对象。在1.5及以上的JDK版本中可以选中使用StringBuilder类,其效率比String更高。 3.8.4 集合实现 禁止使用Vector和HashTable等旧集合实现,在新的系统设计中应当分别使用ArrayList和HashMap代替。 数组的性能比Vector和ArrayList高,如果元素个数不变,尽量使用数组。 在使用集合类时,变量的定义以及参数的接收应当使用接口,而非具体实现类。 3.8.5 对象创建与释放 禁止在循环中频繁构建和释放对象;不再使用的对象应当及时销毁;如无必要,不要序列化对象。对于频繁使用的对象,可将其缓存起来,下次使用时直接从缓存中获取对象。 3.8.6 代码同步 在不需要同步操作时禁止使用同步操作;尽量少用同步方法,避免使用太多的 synchronized 关键字。 确需使用同步时,尽量将同步代码的范围最小化。 四、WEB开发规范 本部分着重B/S系统开发中的JSP编写规范。 4.1 目录规范 4.1.1 一般原则 Web程序要按照一定的目录存放。建立积累Web基础库,目前主要指Javascript和CSS,今后随发展积累进一步提取,以促进开发应用的成熟度。从Web应当用的根目录算起,应当用目录不应超过三层。目录名称建议也采用Java命名规范。 4.1.2 根目录 J2EE平台上,包含“/WEB-INF”目录的目录称作根目录。 应用本身的基础性文件必须位于Web根目录下。 与具体业务相关的页面不能直接位于根目录下,必须位于根目录下相应模块的子目录下。 4.1.3 公用资源目录 Web基础库作为公用资源,供每套应用使用。在Web根目录下建立/styles /js目录和/styles/css目录,分别存放Javascript函数库和样式表文件。 除此之外,图片文件也作公用资源看待。在根目录下建立/images目录,其下直接存放整套应用需要使用的图片资源文件。在/images目录下以模块名建立子目录,用于存放每个模块需要用到的图片文件。其他目录不应当再存在图片文件。 建立public目录,用于存放其他公用性强的文件,包含各业务模块下公用性强的文件。 4.1.4 业务模块目录 根目录下以业务模块名称建立子目录,用于存放各自的文件。如一个模块过大或有部分功能,可在其下再建立一层子目录。 4.1.5 文件引用规范 由于常采用servlet的forward的形式进行请求的转发,文件之间以“相对目录”的形式引用常常出错。为此规定,在Web应用中,任何文件的应用都应当采用绝对目录(此处决对目录指相对于Web根目录而言)。 我司开发的应用,目前文件间的引用都是采用的绝对目录。 但目前我司开发的应用还存在一个缺陷,当Web应用配置的虚拟目录不为空时,文件间的应用会出错,即找不到引用的资源。此处规定,在今后的Web开发中,在根目录“/”前加上虚拟目录,在JSP中以request.getContextPath()获取。示例如下: /images/news/Styleb1_1.gif”> 4.1.6 配置文件目录 配置文件可以提高灵活性,以适应相应的变化。位于/WEB-INF/目录下的web.xml是符合J2EE规范的标准配置文件,任何符合J2EE规范的应用服务器必须能正确解析该文件。其他配置文件也应当由该配置文件引导加载。 最好的应用是在web.xml文件中只指定一个加载入口,而不应当加入其他的具体配置。 提供的配置文件位于/WEB-INF/config目录下。 配置文件项目负责人安排专人统一设置。 表4.1:Web应用目录结构示例 通常由于浏览器的容错功能太强,即使编写不规范的页面浏览器也能解析。但我们写的程序不仅需要浏览器能识别,更大程度上需要人能识别,符合一定的规范代码更以维护。为此规定以下相关事项。 4.2.1 页面规范 所有标记均为小写; 标记属性均为小写,属性值必须以双引号括起来; 编辑页面的文本输入框必须指定“maxlength”属性值,以免插入数据库中长度越界; HTML代码必须以开头,结尾; 所有的Script及其外部引用、CSS 及其外部引用均放入 所有HTML页面必须在 从菜单栏目链接打开的页面标题必须与菜单栏目描述一致; 4.2.2 元素name命名规范 表单域元素必须命名,且必须与DTO字段名一致。 4.2.3 元素id命名规范 尽管元素的id属性不是后台servlet所必需的,但为了页面Javascript操作的方便,id属性也应当命名,名称必须以双引号引起来。 4.3 JSP规范 4.3.1 JSP页面规范 JSP页面必须指定页面的编码,且放在第一行的位置,编码全部采用“UTF-8”; JSP页面引用类的导入规范同3.1.2部分的Java导入规范; 禁止在页面导入Java.sql包中的任何类; JSP页面不需要对会话进行判断,由基础库提供的filter统一完成; JSP页面不需要写缓存清除代码,由基础库提供的filter统一完成; 禁止JSP页面直接提交给JSP页面,必须提交给控制器Servlet转发处理; 4.3.2 JSP编码规范 禁止JSP出现过多Java代码; 禁止在JSP页面出现数据库连接Connection 禁止在JSP页面写公共方法; JSP页面中的Java脚本代码必须位于“<%”和“%>”之间,且“<%”和“%>”必须各自占一行,“<%”和“%>”必须位于一行的开头;示 JSP页面连续的Java代码不能之间有多余的“<%”和“%>”jsp JSP页面尽量使用标签 4.3.3 列表记录页面规范 查询页面都是以列表的形式显示数据记录,这也是绝大部分应用系统展示数据的方式。要求处理界面,风格统一。 页面布局规范 此处做如下规定: ⏹ 按钮应当在查询条件的左边出现。按从左至右的顺序,“只读类”按钮应当先出现,“编辑类”按钮紧跟其后。如“查 询”、“导 出”、“新 增”、“删 除”、“失 效”; ⏹ 列表显示数据的页面均采用个表格; ⏹ 文本字符左对齐,如果确定本列文本长度一致,则应当居中对齐; ⏹ 日期字符、以及其他等长文本字符居中对齐; ⏹ 数字靠右对齐; 4.3.4 数据有效性验证 数据编辑页面(含新增,修改,删除数据)提交的数据,必须进行有效性验证。有效性验证分为两类:字面格式的验证和业务逻辑的验证。除了必须有后台数据参与才能完成验证的以外,字面格式的验证以及简单的业务逻辑验证,应当在JSP页面完成,减轻服务器负载。 有效性验证由公司的Javascript基础库完成,不能完成的,如果该验证功能是通用性需求,则扩充基础库功能,否则由该模块开发人员自行开发javascript方法完成。 4.4 安全验证 Web应当中,除个别jsp页面或servlet外,其它Web页面或servlet都应当是受保护的资源,对Web页面的访问必须由安全验证程序进行验证。验证通过后方可访问。 安全验证包含会话有效性验证和权限验证。 禁止会话验证代码散布在JSP页面或Servlet中,会话验证程序由基础库统一提供。 权限验证程序由基础库统一提供。如个别模块有特殊权限需求,则相应当模块的应当用程序自行验证相应权限。 五、附录下载本文
配置示例
配置示例
4.2 HTML规范目录名称 用途 备注 /styles/css/ 存放所有CSS文件 存放公共的css文件 / styles/js/ 存放所有公用JS文件 存放公共的js文件 /styles/js/moduleName 存放特定模块使用到的JS文件 如果特定模块没有专用JS文件,则不需创建对应目录。 /images/ 存放公用图片文件 /images/moduleName/ 存放特定模块使用到的专用图片文件 如果特定模块没有专用图片文件,则不需创建对应目录。 /moduleName/ 存放各模块JSP文件 每个应用建立单独的目录,如果应用模块较大,可在下建立子目录,子目录名为子模块名 以下目录从/WEB-INF/classes/开始计算 /com/yonggang/projectName/moduleName/dao/ 存放特定模块数据访问组件DAO目录 /com/yonggang/projectName/moduleName/model/ 存放SQL构造程序 /com/yonggang/projectName/moduleName/assistant/ 存放特定模块辅助类 /config/spring/applicationContext.xml spring配置文件集合文件 以下xml配置文件需在此配置文件中配置 /config/spring/projectName-base-context.xml 数据源、spring基本配置 src/configs/config.xml 业务类在spring中注入初始化配置文件。 /config/logging/log4j.properties 日志记录配置文件