Java软件开发规范
版本说明
版本 | 作者 | 日期 | 备注 |
征求版 | 杨章云、唐明胜 | 2006-09-05 | 提出初始版本,分发各相关人员 |
修订版 | 唐明胜 | 2006-09-29 | 征求大家意见的基础上,制订的修订版 |
1.0版 | 唐明胜 | 2007-09-18 | 总结前期开发经验,对开发规范进行升级。加粗海绿色为修订内容,蓝色为新增内容。 |
2.0版 | 唐明胜 | 2008-11-18 | 总结前期项目开发经验,对开发规范进行升级完善。本版改动较大,不再以颜色加以区分。 |
1 绪论
1.1 概述
在我司前期完成的软件《河南移动物流平台》、《河南移动集中核算系统》、《移动资产实物管理系统》以及其他一些项目中,本规范得到了较好的贯彻,提高了项目成员开发的规范性,更提升了项目质量。但也存在一些问题:开发规范不够全面;开发人员对规范理解不深;在项目后期,常常存在不遵守规范的失控现象。同时随着公司规模的扩大,项目经验教训总结的增加,为缩短开发周期,进一步提高项目质量,我司迫切需要一个更完善、专业、有效的开发规范。同时,将基础库(含基础框架以及js部分)新增工能纳入。
本规范的目的是使本公司能以标准的、规范的方式设计和编码。通过建立开发规范,使每个开发人员养成良好的开发风格和习惯;提高程序的可靠性、可读性、可维护性和一致性等,提高程序员的开发水平,增进团队间的交流,并保证软件产品的质量。
代码虽然是给机器运行的,但却是给人读的。
最基本的原则是运用常识。当找不到任何规则或指导方针或者规则明显不适用时,运用常识并核实本规范的基本原则。这条规则比其它所有规则都重要,记住一点,常识必不可少。当出现该情况时,应当及时收集并提交,以便完善本规范。
1.2 优良代码的特点
任何的软件设计中,都离不开编程实现。在软件实现中,除了程序架构设计、数据结构设计、算法的设计以外,还有具体的代码的编写规范问题。
好的代码应该具有以下的特征:
Ø 准确性:保证程序运行稳定、正确,不容易出错;
Ø 简单性:程序代码容易管理;
Ø 清晰性:程序容易理解,无论对人还是计算机;
Ø 普遍性:在很广泛的情况下都能工作的很好,也容易做修改以适应新出现的情况;
1.3 适用范围
本规范适用于本公司(思诺博信息技术有限公司、各分公司及办事处)所有软件项目、产品等的设计、开发以及维护、升级等。
本公司所有软件开发人员在整个软件开发过程中必须遵循此规范。
2 总体架构
2.1 框架概述
本公司开发的软件产品多为B/S结构,涉及多个层面的开发,为便于逻辑分离及项目分工,本公司开发的软件产品应当符合MVC设计模式。旧框架由四层相互协作的组件(DTO、DAO、MODEL、SERVLET)构成,新框架同样由相互协作的四层组件(DTO、DAO、MODEL、ACTION)构成。
旧框架如图2.1所示,新框架如图2.2所示略。
图2.1:基础库应用框架(旧)
图2.2:基础库应用框架(新)
基础库提供以上架构的基础框架。
2.2 框架规范
旧框架中Servlet层应当仅负责宏观层面的业务逻辑,不进行具体的数据访问,新框架中Action组件负责事务同旧框架中的Servlet层组件。
上图中各层含义参见《基础库设计与使用说明》,此处制定应用开发中应当遵守的框架规范。
2.2.1 DTO规范
DTO的标志性接口为com.sino.base.dto.DTO,应用开发中要求DTO类一律从直接或间接继承该接口,新框架中提供了功能更强大的CommonRecordDTO类,该类位于com.sino.base.dto包下,在《资产实物管理系统》中已经存在该DTO类,只是为放入基础库包。
特别的,用户对象也是一个DTO,框架要求每个应用的用户类必须继承com.sino.framework.dto. BaseUserDTO类,如《资产实物管理系统》中的SfUserDTO类。
2.2.2 SQLModel规范
SQLModel组件规定必须直接或间接继承BaseSQLProducer类。由于需要用到具体应用的用户类中的各种信息,BaseUserDTO不能提供该信息。因此要求每一套应用应该建立自己的SQLModel入口,如《资产实物管理系统》中的AMSSQLProducer,此处假设名称为AppBaseSQL,在其中定义受保护的用户对象,在构造函数中设置其值,其他业务类继承的AppBaseSQL,可直接使用用户类。AppBaseSQL示例如图2.3所示。
图2.3:AppBaseSQL示例
2.2.3 DAO规范
DAO为数据访问组件,用于访问持久性数据,例如为关系型数据库。由于BaseDAO的一个明显缺陷,initSQLProducer方法需要传递参数,但该参数实际上不需要,因此新提供了抽象类SinoBaseDAO。本规范要求DAO对象必须直接或间接继承数据访问组件的基础类 com.sino.framework.dao. SinoBaseDAO。
理由同上,也要求每一套应用建立自己的DAO入口类,AppBaseDAO示例如图2.4所示。
图2.4:AppBaseDAO示例
DAO处理完正常逻辑后设置本次处理后用于界面提示的消息。
旧框架中Web页面分页查询用的DAO由com.sino.framework.dao. PageQueryDAO统一执行,其它业务逻辑的DAO由具体的DAO负责;新框架已经将二者统一起来,每个DAO类自动具有Web页面分页查询功能。
禁止DAO类依赖于request等Web对象,便于DAO类可以脱离于Web应用。
2.2.4 Servlet规范
应用中的Servlet组件都从com.sino.framework.servlet.BaseServlet开始继承,每个Servlet必须实现方法performTask。
Servlet标准规定,服务器不会为每次请求都产生一个新对象,其全局变量是线程不安全的,因此,除确保不会改变的变量可以作为servlet的全局变量外,禁止使用全局变量。
DAO和SQLModel中的用户都由Servlet获取传递。此处规定采用统一的获取方式,例如在SinoAMS系统中,代码如下:
SfUserDTO userAccount = (SfUserDTO)SessionUtil.getUserAccount(req);
其中使用到的SessionUtil已经由基础库规定。
Servlet必须具有finally模块,“释放数据库连接”、“设置页面消息提示”以及“URL定向”等必须位于其中,以确保资源得到有效释放。
2.2.5 Action规范
新框架以Action层组件代替Servlet层组件。此处,Action组件将主要负责业务逻辑开发、消息设置、页面导航设置,不再需要管理资源释放(如数据库连接的释放),统一由ActionProcessServlet管理。
Action类都必须直接或间接继承类com.sino.framework.action. Action,与SQLModel和DAO的理由一致,每一套应用也应当定义自己的Action入口,此处假定其名称为AppBaseAction,代码示例如图2.5所示。
图2.5:AppBaseAction示例
2.2.6 消息规范
无论旧框架还是新框架,都要用到消息提示。消息提示以属性文件的形式配置。消息配置支持国际化,但首先必须支持默认语言,在中华人民共和国范围内的应用的程序,必须配置简体中文消息文件,消息文件必须以“_zh_CN”结尾。MessageResource.properties和MessageResource_zh_CN.properties配置文件为基础库所需,不能修改。
应用系统中用到的各消息提示在其他文件中定义,如《资产实物管理系统》中提供的AMSMessageResource_zh_CN.properties文件和AMSMessageResource.properties文件。消息定义如图2.6所示。
图2.6:消息定义示例
消息定义注意事项如下:
Ø 一行只能定义一条消息;
Ø 文件中不需要的数据以“#”注释;
Ø 消息由键名和键值构成;
Ø 键名和键值以等号“=”连接,等号前后有空格;
Ø 键值可以含参数,由程序运行时动态设置,参数用大括号“{}”括起来;
Ø 只有定义了消息配置文件,DAO类、Servlet类才能正确显示消息;
3 Java开发规范
本部分着重B/S结构中Server端Java代码的规范,同样适用于基础库开发。
公用功能的程序由公司基础库提供。
基础库应当在实际项目中提炼,采用共同讨论,专人维护的方式进行。
基础库生成JavaDOC文档,开发人员应当仔细阅读,利于应用开发。
3.1 风格规范
3.1.1 风格概述
在我司的实际的开发中,由于项目期限等原因,尽管已经有初步的开发规范,但在项目后期常常失控,为了赶进度,开发人员逐渐养成了一些不良的习惯。命名随意(汉语拼音英文混合、词不达意、动名词不分)、注释不清晰、导入不使用的类、定义不使用的变量、方法存在不需要的参数、方法命名与方法实现功能不一致、程序缩进不一致等。这些都是需要规范的地方。
好的程序书写规范比随意的书写规范更清晰、错误更少、更易修改。所以,一开始就要注意使用好的编写风格。好的程序设计风格就如同好的文章,不仅要求语句顺畅,而且段落分明,结构紧凑。不仅排版要清晰,标点符号正确使用,而且重点要突出,中心明确。
让我们从这些基本的编程技术基础上入手,改正以前的不良习惯,逐步提高应用交付的质量。
3.1.2 类(包)导入规范
在import需要用到的类时,尽量少用import *;而应当具体指明需要导入的类,利于代码阅读,知道用到了具体的什么类。同时,由于我司目前开发的应用为打包,所以还不存在较大问题,今后开发的应用进一步规范化之后,打包时会将*所涉及到的类全部导入。
导入需要用到的类应当按照一定的顺序导入,不能随便写,此处规定,导入顺序如下,且前后类别之间以空行隔开:
Ø Java标准包类
Ø Java扩展包类
Ø 第三方组件包类
Ø 公司基础库包类
Ø 公司框架包类
Ø 业务系统自身基础包类
3.1.3 缩进规范
源码缩进不仅仅使程序更美观,而且也使程序结构更清晰、易读。采用统一的Tab缩进方式。各集成开发工具应当将Tab键设为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 注释规范
为便于维护,对程序应当给出适当的注释。没有注释也就意味着很快就会被抛弃,因为可能没人能懂。注释应当符合JavaDOC的标准,这样编译器不会给出警告,否则有的编译器可能会给出警告。
Ø 类(接口)注释
对类和接口应当加以注释,对该类作一个简单功能描述,同时还可以标注其他内容:如公司名称,开始编写日期等,但作者必须标注上,方便在出现问题时由原作者负责解释。注释示例如图3.1所示。
图3.1:类注释示例
Ø 方法注释
应当对方法进行注释。注释必须含“功能”描述,参数描述,返回值描述。如果参数较为复杂,或者怕遗忘,则详细说明每个参数的作用、取值范围及相互间的关系。方法注释示例如图3.2所示。
图3.2:方法注释示例
3.2 模块划分
合理的模块划分能提高我司按模块提交项目的能力。在一个项目开始之前,应当进行合理的模块划分。划分之后任一模块的业务代码应当仅依赖于下述包(或类):
Ø Java标准包
Ø Java扩展包
Ø 第三方组件包
Ø 公司基础库包
Ø 公司框架包
Ø 业务系统基础包
除此之外,不应该再导入其他类(包),如有导入,则说明模块划分可能不够合理。设计人员在设计之初应当对此进行全局考虑。
3.3 包存放规范
尽管Java支持未命名包,但为让程序显得美观、清晰直观,程序应当放到相应的包下。我司开发的程序应当放到com.sino包或其子目录下。
此处规定,禁止写未命名包的程序,希望大家遵守。
3.4 命名规范
命名采用英文命名,禁止采用中文汉语拼音命名,命名采用大小写混合,提高可读性。命名应当能顾名思义,能够正确表达出想要表达的意思。
3.4.1 包命名规范
包表示一对类的共同含义,可以对应应用开发的模块,必须以名词(或动名词)命名,必须全部采取小写字母形式,并具备规定的层次。
如com.sino.ams.newasset.report包表示出现在该包内的类都是为报表服务的。
3.4.2 类(接口) 命名规范
类和接口表示一类对象,必须以名词命名。类名的第一个字母必须大写,类名如由多个单词(或缩写)构成,则每个单词(缩写)的头一个字母必须大写。如消息管理器命名为MessageManager。
为统一起见,对我司的框架中出现的四种类做出进一步规定,如下:
Ø DTO类
DTO类必须以“DTO”三个大写字母结尾,如AmsAssetsCheckHeaderDTO;
Ø DAO类
DAO类必须以“DAO”三个大写字母结尾,如AmsAssetsCheckHeaderDAO;
Ø SQLModel类
SQLModel类必须以“Model”结尾,如AmsAssetsCheckHeaderModel;
Ø Servlet类
Servlet类必须以“Servlet”结尾,如AmsAssetsCheckHeader Servlet。
上述四个示例类对应《资产实物管理系统》中的表AMS_ASSETS_CHECK_HEADER,类(接口)名和表名的对应关系为:表名第一个字母大写不变,后续字母变为小写,直到遇到下划线“_”,下划线“_”不出现在类名中,下划线“_”紧跟的字母保持大写不变,后续字母又变为小写,以此类推。
对于不需要单独维护或查询表,不需要写对应的Servlet类,但其他三类应当提供,由其他的DAO类调用。
3.4.3 字段命名规范
类中的字段表示类的一个属性或标志,同样也必须以名词命名。字段名的第一个字母必须为小写,其余字母和表字段映射关系同类名和表名的映射关系。如《资产实物管理系统》中的盘点工单表AMS_ASSETS_CHECK_HEADER的字段盘点工单号“TRANS_NO”则在上述四类中都必须以“transNo”出现。
特别规定:Web页面表单域名与DTO对象属性名相同。对应关系定义如表3.1所示:
表3.1:命名示例
表单域名 | DTO属性名 | 数据库字段名 |
transNo | transNo | TRANS_NO |
3.4.4 方法命名规范
方法表示一次操作,因此必须以动词形式命名。方法名第一个字母采取小写形式,其余字母同类(接口)的命名规则。
DTO中方法名和字段名的对应关系为JavaBean中的规则,此处不再赘述。
3.5 方法编写规范
3.5.1 基本原则
方法是Java的基本功能单元,设计的细微缺点很容易导致该方法被错用,所以仅方法功能正确是不够的。
一个方法应当只完成一项功能。
对于公用接口外的方法,应当尽可能缩小其可见性,避免用一个类实例去访问其静态变量和方法。当一个方法被调用之后,方法所在类应当反馈出本次调用是成功还是失败,如果被调用方法不能反馈结果,则同一类中其他方法应当提供。
3.5.2 参数规范
禁止方法提供超过四个的参数。如果确实需要更多参数,则用参数建立新的值对象,以此对象做参数。
参数类型和返回值尽量接口化,以屏蔽具体的实现细节,提高程序的可扩展性。
在方法的入口处对参数进行有效性检查。
很多程序错误是由非法参数引起的。良好的编程典范规定:当编写一个方法时,必须验证所有传递进来的参数,如果任何一个参数不合乎要求,就应当明确地引发一个异常。boolean参数不应当检查。
3.5.3 出口规范
对于有返回值的方法,禁止提供多个出口,而只能提供一个出口,不好的代码如图3.3所示,好的代码如图3.4所示。
图3.3:方法出口错误示例(多出口)
图3.4:方法出口正确示例(单出口)
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跨切循环层的次数。示例3-5的效率比示例3-6的高。
图3.5:效率高的多重循环
图3.6:效率低的多重循环
Ø 循环内逻辑判断问题
如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体外面。示例3-7的程序比示例3-8多执行了N-1次逻辑判断。并且由于前者老要进行逻辑判断,打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。如果N非常大,应当采用示例3-8的写法;如果N非常小,两者效率差别并不明显,采用示例3-7的写法可使程序更加简洁。
图3-7:低效率逻辑判断
图3-8:高效率逻辑判断
Ø 特殊规定
如无必要,不应该在for 循环体内修改循环变量,防止for 循环失去控制。
3.7 异常处理与资源回收
3.7.1 异常处理
异常处理的基本思想是只对错误进行处理,如数据库操作、文件操作中的错误以及有限性资源耗尽等。
捕捉异常是为了处理它,不要捕捉后却不做任何处理。如果不想处理,则应当申明方法抛出相应异常,由调用者处理。禁止使用一个catch语句处理多个异常,应当分别捕捉并处理。
一个方法申明抛出的异常个数应当最小化,最好只抛出一个异常。如果确实要捕捉处理多个异常,可记录下非申明异常的错误信息,并将之转化为申明异常抛出。
捉到的异常应当记录下来,记录由基础库提供的日志工具完成。禁止将异常直接输出到控制台。对于继承自SinoBaseException的异常,基础库提供printLog()方法记录异常,该方法会根据LogConfig.xml文件的配置将异常记录到日志文件或控制台。
经常发生的可预计事件不进行异常捕捉及处理,方法已申明抛出的异常不需捕捉。
禁止使用异常实现逻辑控制。
应当在本地进行安全性检查,而不是让程序的调用者完成。
3.7.2 资源回收
有限性资源使用完毕后,应当立即释放。如数据库连接,I/O操作等。无论程序是否发生异常,资源都应当得到回收。
回收资源的代码应当位于finally子句内,以保证资源得到释放,禁止与正常的业务处理代码混在一块。
如果类中有限性资源是全局性共享资源,则类还应当提供finalize方法,由JVM在资源回收的时候调用finalize方法,做最后释放。
异常处理与资源回收代码示例如图3.9所示。
图3.9:异常与资源释放示例
3.8 性能与安全
3.8.1 基本原则
程序在满足功能的情况下,应当尽量提高运行性能。
程序的运行性能很大程度上由SQL语句决定,SQL语句的编写参见《SQL 语句编写规范》,对于Oracle数据库,优化技能参见《Oracle SQL优化培训》,此处着重Java本身的编写规范。
3.8.2 减少重复计算
如果一个代价昂贵的计算或查询多次出现,那么就只在一个地方实现,并记录结果。这样会避免无谓的重复计算与查询工作。示例3.10枚循环一次都会计算一次size(),而3.11只计算一次,计算越复杂性能牺牲就越大。
图3.11:重复计算示例
图3.12:一次计算示例
3.8.3 可变字符串
处理可变字符串时,尽量使用StringBuffer类而非String类。由 StringBuffer对象完成大部分工作,完成后将之转换为需要的String对象。在1.5及以上的JDK版本中可以选中使用StringBuilder类,其效率比StringBuffer更高,但是线程不安全的。
3.8.4 集合实现
禁止使用Vector和HashTable等旧集合实现,在新的系统设计中应当分别使用ArrayList和HashMap代替。
数组的性能比Vector和ArrayList高,如果元素个数不变,尽量使用数组。
在使用集合类时,变量的定义以及参数的接收应当使用接口,而非具体实现类。
3.8.5 对象创建与释放
禁止在循环中频繁构建和释放对象;不再使用的对象应当及时销毁;如无必要,不要序列化对象。对于频繁使用的对象,可将其缓存起来,下次使用时直接从缓存中获取对象。
3.8.6 代码同步
在不需要同步操作时禁止使用同步操作;尽量少用同步方法,避免使用太多的 synchronized 关键字。
确需使用同步时,尽量将同步代码的范围最小化。
4 WEB开发规范
本部分着重B/S系统开发中的JSP编写规范。
4.1 目录规范
4.1.1 一般原则
Web程序要按照一定的目录存放。公司建立积累Web基础库,目前主要指Javascript和CSS,今后随发展积累进一步提取,以促进公司开发应用的成熟度。
从Web应当用的根目录算起,应当用目录不应超过三层。
目录名称建议也采用Java命名规范。
4.1.2 根目录
J2EE平台上,包含“/WEB-INF”目录的目录称作根目录。
应用本身的基础性文件必须位于Web根目录下。下面以《山西移动资产实物管理系统》为例进行说明。如登陆页面login.jsp、登陆验证后的第一个展示页面mainPage.jsp(该页面是一个框架页面、其涉及到的topPage.jsp、resourceMenu.jsp、home.jsp页面也均位于根目录下)、会话过期展示页面timeOutPage.jsp、无权限时的导向页面noPriviPage.jsp、首次登陆强制操作页面firstLogin.jsp。
与具体业务相关的页面不能直接位于根目录下,必须位于根目录下相应模块的子目录下。
4.1.3 公用资源目录
Web基础库作为公用资源,供每套应用使用。在Web根目录下建立/WebLibary/js目录和/WebLibary/css目录,分别存放Javascript函数库和样式表文件。
除此之外,图片文件也作公用资源看待。在根目录下建立/images目录,其下直接存放整套应用需要使用的图片资源文件。在/images目录下以模块名建立子目录,用于存放每个模块需要用到的图片文件。其他目录不应当再存在图片文件。
建立public目录,用于存放其他公用性强的文件,包含各业务模块下公用性强的文件。
4.1.4 业务模块目录
根目录下以业务模块名称建立子目录,用于存放各自的文件。如一个模块过大或有部分独立功能,可在其下再建立一层子目录。
4.1.5 文件引用规范
由于常采用servlet的forward的形式进行请求的转发,文件之间以“相对目录”的形式引用常常出错。为此规定,在Web应用中,任何文件的应用都应当采用绝对目录(此处决对目录指相对于Web根目录而言)。
我司开发的应用,目前文件间的引用都是采用的绝对目录。
但目前我司开发的应用还存在一个缺陷,当Web应用配置的虚拟目录不为空时,文件间的应用会出错,即找不到引用的资源。此处规定,在今后的Web开发中,在根目录“/”前加上虚拟目录,在JSP中以request.getContextPath()获取。示例如下:
<img src="<%=request.getContextPath()%>/images/news/Styleb1_1.gif”>
4.1.6 配置文件目录
配置文件可以提高灵活性,以适应相应的变化。位于/WEB-INF/目录下的web.xml是符合J2EE规范的标准配置文件,任何符合J2EE规范的应用服务器必须能正确解析该文件。其他配置文件也应当由该配置文件引导加载。
最好的应用是在web.xml文件中只指定一个加载入口,而不应当加入其他的具体配置,目前《资产实物管理系统》的配置是一个非良好应用案例,今后应当杜绝。
我司配置的功能描述见《基础库设计与使用说明》相关部分。
我司自行提供的配置文件位于/WEB-INF/classes/SinoConfig目录下。
配置文件项目负责人安排专人统一设置。
表4.1:Web应用目录结构示例
目录名称 | 用途 | 备注 |
/WebLibary/css/ | 存放所有CSS文件 | 存放公共的css文件 |
/ WebLibary /js/ | 存放所有公用JS文件 | 存放公共的js文件 |
/WebLibarary/js/moduleName | 存放特定模块使用到的JS文件 | 如果特定模块没有专用JS文件,则不需创建对应目录。 |
/images/ | 存放公用图片文件 |
|
/images/moduleName/ | 存放特定模块使用到的专用图片文件 | 如果特定模块没有专用图片文件,则不需创建对应目录。 |
/moduleName/ | 存放各模块JSP文件 | 每个应用建立单独的目录,如果应用模块较大,可在下建立子目录,子目录名为子模块名 |
以下目录从/WEB-INF/classes/开始计算 | ||
/com/sino/ies/moduleName/servlet/ | 存放servlet的目录 | servlet都应当位于相应模块之下,即必须有相应的包名。 |
/com/sino/ies/moduleName/dto/ | 存放特定模块数据传输对象DTO目录 |
|
/com/sino/ies/moduleName/dao/ | 存放特定模块数据访问组件DAO目录 |
|
/com/sino/ies/moduleName/model/ | 存放SQL构造程序 |
|
/com/sino/ies/moduleName/assistant/ | 存放特定模块辅助类 |
|
/SinoConfig/SystemConfig.xml | 配置文件的配置文件 | 以下xml配置文件需在此配置文件中配置 |
/SinoConfig/PoolConfig.xml | 数据库连接池配置文件 |
|
/SinoConfig/LogConfig.xml | 日志记录配置文件 |
|
/SinoConfig/PictureResourceConfig.xml | 图片资源配置文件 | 已经废弃,不再需要 |
/SinoConfig/PrivilegeConfig.xml | 权限管理配置文件 | 已经废弃,不再需要 |
/SinoConfig/UploadConfig.xml | 文件上载配置文件 |
|
/SinoConfig/QueryConfig.xml | 分页查询用配置文件 |
|
/SinoConfig/SmsConfig.xml | 手机短信配置文件 | 具体应用具体配置。 |
/SinoConfig/resource/message | 各消息配置文件 | 消息配置文件可多个,由应用所需支持的语言种类决定,且不需要在总配置文件SystemConfig.xml中配置。 |
4.2 HTML规范
通常由于浏览器的容错功能太强,即使编写不规范的页面浏览器也能解析。但我们写的程序不仅需要浏览器能识别,更大程度上需要人能识别,符合一定的规范代码更以维护。为此规定以下相关事项。
4.2.1 页面规范
Ø 所有标记均为小写;
Ø 标记属性均为小写,属性值必须以双引号括起来;
Ø 编辑页面的文本输入框必须指定“maxlength”属性值,以免插入数据库中长度越界;
Ø HTML代码必须以<HTML>开头,</HTML>结尾;
Ø 所有的Script及其外部引用、CSS 及其外部引用均放入<HEAD></HEAD>中;
Ø <HEAD></HEAD>之间应当设置页面所使用的语言,如
<META http-equiv="Content-Type" content="text/html; charset=GBK">
Ø 所有HTML页面必须在<TITLE></TITLE>中设置标题,禁止出现“UnTitled”或“未命名”标题的页面;
Ø 从菜单栏目链接打开的页面标题必须与菜单栏目描述一致;
4.2.2 元素name命名规范
表单域元素必须命名,且必须与DTO字段名一致。
4.2.3 元素id命名规范
尽管元素的id属性不是后台servlet所必需的,但为了页面Javascript操作的方便,id属性也应当命名,名称必须以双引号引起来。
4.3 JSP规范
4.3.1 JSP页面规范
Ø JSP页面必须指定页面的编码,且放在第一行的位置,编码全部采用“GBK”;
Ø 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脚本代码必须位于“<%”和“%>”之间,且“<%”和“%>”必须各自占一行,“<%”和“%>”必须位于一行的开头;示例代码如图4.1和图4.2所示;
图4.1:JSP代码示例2
图4.2:JSP代码示例2
Ø JSP页面连续的Java代码不能之间有多余的“<%”和“%>”,图4.3为正确的写法,图4.4位错误的写法;
图4.3:正确的JSP代码示例
图4.4:错误的JSP代码示例
4.3.3 单记录页面布局规范
Ø 现存问题
单记录指录入数据、编辑修改数据、记录详细信息等页面。
目前我司开发的各套应用中,对此没有统一的处理风格,界面比较杂乱。主要表现在:
n “文字描述标签”不对齐;
n 同一逻辑信息其“文字描述标签”不一致;如《资产实物管理系统》中,对“资产名称”同一信息存在“资产名称”、“资产描述”、“设备名称”、“名称”等各种描述;
n “文字描述标签”后有跟中文冒号“:”的,也有跟英文冒号“:”的,也有什么也不跟的;
n 文本框占据表格列的宽度长短不一;
n 文本框不对齐;
n 文本框中内容对齐方式太随意;
Ø 页面布局规范
此处做如下规定:
n “文字描述标签”应当靠右对齐,且以中文冒号“:”结束,“标签描述”字符长度应当尽量一致;
n 文本框应当对齐;
n 文本框内容根据内容特性其布局特性不同,大致原则如下:文本字符靠左对齐,如果同一应用中该内容长度一致,则应当居中,如《资产实物管理系统》中的“资产标签”;日期及其他等长度代码居中对齐;数字靠右齐。
单记录页面布局示例如图4.5所示。
图4.5:单记录页面布局示例
4.3.4 列表记录页面规范
Ø 现存问题
我司的查询页面都是以列表的形式显示数据记录,这也是绝大部分应用系统展示数据的方式。目前我司开发的各套应用中,对此没有统一的处理风格,界面比较杂乱。主要表现在:
n 查询按钮、导出按钮、新增、删除按钮等布局太乱;
n 数据列出现的先后顺序太随意,查询相同的数据,不同的页面不一样;
n 上下行数据没有按照统一的方式对齐;
n 数据折行,同一页中数据行的高度不一致;
n 如果同一页数据行过多,则在向下滚动后,表头部分消失,导致用户不知各列数据的具体含义(目前该问题较少);
n 宽屏电脑页面出现空白;
Ø 页面布局规范
此处做如下规定:
n 按钮应当在查询条件的左边出现。按从左至右的顺序,“只读类”按钮应当先出现,“编辑类”按钮紧跟其后。如“查 询”、“导 出”、“新 增”、“删 除”、“失 效”;
n 列表显示数据的页面均采用个表格:一个用于表头部分,一个用于数据展示部分,表头部分代码如图4.6所示,数据展示部分代码如图4.7所示;
n 文本字符左对齐,如果确定本列文本长度一致,则应当居中对齐;
n 日期字符、以及其他等长文本字符居中对齐;
n 数字靠右对齐;
图4.6:表头代码示例
图4.7:数据表代码示例
4.3.5 数据有效性验证
数据编辑页面(含新增,修改,删除数据)提交的数据,必须进行有效性验证。有效性验证分为两类:字面格式的验证和业务逻辑的验证。除了必须有后台数据参与才能完成验证的以外,字面格式的验证以及简单的业务逻辑验证,应当在JSP页面完成,减轻服务器负载。
有效性验证由公司的Javascript基础库完成,不能完成的,如果该验证功能是通用性需求,则扩充基础库功能,否则由该模块开发人员自行开发javascript方法完成。
4.3.6 特别规定
Ø 页面加载规定
在任何一个页面被打开后,用户可能将其最小化,而当用户再次点击相应连接时,该页面总是不弹出。其解决办法是,在每个页面的<body>标签中都加入一个初始化函数,如do_initPage(),该函数至少执行获取焦点的方法window.focus(),可根据需要加入其他功能。
Ø 防止表格撑开的方法
图4.7的代码不能防止表格被撑开。在确认显示数据长度不大的情况下,可以采取上述方式。但当显示数据长度较大时,建议在表格列中增加一个没有名称、不带边框的只读文本框,将要显示的值显示在该文本框中。代码示例如图4.8所示。同时为使表格宽度可自适应调整,应当在上面的do_initPage()方法中加入do_SetPageWidth()方法。该方法由Web基础库提供,可根据屏幕分辨率自适应调整表格宽度。
图4.8:文本框展示数据防止表格被撑开示例
Ø LookUp规范
为方便用户操作和数据的规范性,应用需尽量提供选择的方式录入数据。在我司开发的应用中,常以Select下拉框和LookUp查询方式提供。
当展示的数据条数不多,如100条以内,且用户关心的数据项为1时,可以Select的下拉框形式提供,没必要处处提供LookUp操作;反之则应当提供LookUp查询方式。
公司基础库提供了较为方便的LookUp查询方式,但对页面提出了一定的要求,在此以特别规定的形式描述如下。
n 多数据选择
多数据选择用于选择多条数据的时候。如《资产实物管理系统》中,创建“资产调拨单”时选择资产;创建“资产盘点工单”时选择地点。LookUp会自动创添加的表格行,并将选择的数据自动添加到相应的位置。要完成该功能,JSP页面的数据表格需要满足一些特殊条件,如果是新增数据,则需要具备一个隐藏的空行。数据表格行要求如下:
每个需要显示的列必须具备“name”属性和“id”属性值,“id”属性值以“name”属性值连接数字构成。比如<td name=”userName” id=”userName0”></td>;
如果表格列不具备上述特点,则表格列应当具有表单域,表单域应当具有“name”属性和“id”属性值,“id”属性值以“name”属性值连接数字构成。比如<td width="10%"><input type="text" name="transNo" id="transNo0"></td>;
不能同时具备上述情况;
一个表格列最多只能有一个显示表单域;
如果从LookUp返回的值除了需要显示的以外,还需要其他的值,则均以隐藏域的形式存在于最后一列,且最后一列需要隐藏;
表格具备上述特征后,配合相应的Javascript函数,则可以完成相应的功能了。
列示例代码如图4.9所示,Javascript函数示例如图4.10所示。
图4.9:LookUp数据表空行示例
图4.10:LookUp Javascript示例1
n 单数据选择
单数据选择用于仅选择一条数据的情况。LookUp会自动将选择的数据赋值到相应表单域。这时没有对表格的要求,但执行LookUp的Servlet设置的返回字段必须和页面表单域存在前面描述的命名规范中的对应关系。其Javascript函数示例如图4.11所示。
图4.11:LookUp Javascript示例2
4.4 安全验证
Web应当中,除个别jsp页面或servlet外,其它Web页面或servlet都应当是受保护的资源,对Web页面的访问必须由安全验证程序进行验证。验证通过后方可访问。
安全验证包含会话有效性验证和权限验证。
禁止会话验证代码散布在JSP页面或Servlet中,会话验证程序由基础库统一提供。
权限验证程序由基础库统一提供。如个别模块有特殊权限需求,则相应当模块的应当用程序自行验证相应权限。
5 附录
5.1 消息提示
在《河南移动物流平台》中,消息提示不够规范,且未区分系统级异常和应用级异常。由于消息提示是显示给最终用户看的,因此必须将系统级异常转换为应用级异常,然后提示给用户。系统级异常用日志记录,以备程序维护时检查。
前台数据校验的提示以标准的对话框提示;业务逻辑在后台处理后的提示不再使用对话框,在jsp页面包含统一的servlet,具体指令为:
<jsp:include page="/servlet/com.sino.framework.servlet.MessageProcessServlet" flush="true"/>
基础库提供统一的消息处理程序。
5.2 二维报表
基础库增加了统一的二维报表生成功能:含Web页面二维报表和Excel二维报表。应当能满足大部分需求。具体代码可参考《河南移动物流平台》中的相关程序。
5.3 翻页选择支持
在翻页查询中,对不在同一页的数据进行选择记录。原来只能分次操作,增加了用户操作的烦琐程度。基础库进行了更新,增加了跨页记忆功能。具体程序代码可参考《河南移动物流平台》中的“网优接口”部分的程序。
5.4 动态添加行
动态添加表格行是一个烦琐的工作。目前Js基础库增加了TableProcess.js。结合5.3使用,程序操作更简单。具体程序代码可参考《河南移动物流平台》中的“网优接口”中“物料选择”部分的程序。
5.5 特殊要求
5.5.1 页面传值要求
Form传值必须使用“post”方法;Form应当含有隐藏表单域,统一命名为act,代表本次操作类型;常用操作类型必须使用基础库com.sino.base.constant.web.WebActionConstant常量接口定义的参数,具体应用需要使用的值如果该接口没有,则从该接口扩展。
5.5.2 常用操作类型定义
常用操作类型有特定的含义,不可更改,描述如下:
Ø QUERY_ACTION:进入查询页面,且显示数据
Ø NEW_ACTION:进入新增页面
Ø DETAIL_ACTION:进入详细信息页面
Ø CREATE_ACTION:新增数据
Ø UPDATE_ACTION:更新数据
Ø DELETE_ACTION:删除数据
Ø EXPORT_ACTION:导出数据
Ø SUBMIT_ACTION:提交单据,流程使用
Ø REJECT_ ACTION:单据审批退回,流程使用
Ø APPROVE_ACTION:单据审批通过,流程使用
Ø CLEAR_ACTION:清除数据
Ø TREE_ACTION:树状菜单请求
5.5.3 维护页面个数
页面个数一般根据具体情况确定。但对于维护类页面,一般只需要两张页面即可:翻页查询页面和详细信息页面。新增页面与详细信息页面使用同一页面。
5.5.4 数据保持
在任何一步操作失败时,必须保留用户输入的数据,返回到原页面,并回显数据。
5.6 其它
本规范暂未涉及工作流部分。工作流部分由翁锦兴统一负责。在完成统一的工作流程序后,由汪文斌完善本部分规范。
5.7 错误收集
如果发现基础库错误,请及时与相关作者联系,以便更正。如果发现本规范语意不清或存在错别字等问题,请与唐明胜联系。