目录
第一章、概述 4
1.1、目的 4
1.2、范围 4
1.3、文档约定 4
1.4、相关概念及词汇列表 4
1.5、相关角色 5
第二章、协作规范 6
2.1、参与协作开发 6
2.2、进行协作开发 8
2.3、相关规范 12
第三章、设计规范 13
3.1、JAVA存放位置 13
3.2、页面存放位置 14
3.3、配置文件存放位置 14
3.4、业务代码位置 15
3.5、数据库设计 15
3.6、Model规范 16
3.7、Design配置规范 16
3.8、JAVA类规范 17
3.9、JSP界面规范 18
3.10、properties资源文件规范 19
第四章、代码规范 20
4.1、命名规范 20
4.2、风格规范 25
文档授权 30
更多资料请查阅
、目的
对于代码,首要要求是它必须正确,能够按照程序员的真实思想去运行;第二个的要求是代码必须清晰易懂,使别的程序员能够容易理解代码所进行的实际工作。
通过建立开发规范,形成开发小组编码约定,提高程序的可靠性、可读性、可修改性、可维护性、可继承性和一致性,可以保证程序代码的质量,继承软件开发成果,充分利用资源,使开发人员之间的工作成果可以共享。
、范围
1、项目组成员;
2、蓝凌公司相关技术开发人员;
3、其他经公司认可的必要知情的人员。
、文档约定
本文档采用MS Word软件编写,采用统一风格排版,正文风格为:五号中文宋体、五号英文Arial字体、行距1.5行;
针对需要重点注意的段落,采用红色描色。
一般来说,各章内容相对独立,构成全文的有效组成部分。
、相关概念及词汇列表
【同步代码】
在进行开发的过程中将本地的代码和SVN服务器的代码进行同步,在eclipse中的操作叫Synchronize whit Repository。
【合并代码】
在同步的过程中,发现本地的代码和服务器上的代码都有所改变,这个时候会产生冲突,就需要合并代码。
【签入】
在进行开发的过程中将代码放入SVN服务器的操作叫签入(check-in),在eclipse中的操作叫提交。
【签出】
在进行开发的过程中将代码从SVN服务器下载下来的操作叫签入(check-out),在eclipse中的操作叫更新。
、相关角色
【开发人员】
根据开发规范,进行日常开发工作。
【SVN管理员】
管理SVN服务器,包括开通帐号、停止帐号、处理SVN遇到的问题。
开发人员编写程序的过程中,每个程序都会有很多不同的版本,这就需要开发人员很好的管理代码,在需要的时间可以取出需要的版本,并且每个版本都需要一个完成的说明和标记。我们公司采用Sub Version(简称SVN,主要用于定制项目管理)和Rational team concert(简称RTC,主要用于产品管理)做为版本管理工具,在多个开发人员开发同一段代码的过程中,版本的管理和协作规范显得尤为重要。
.1、参与协作开发
如何参与协作开发,具体参考以下文档:
SVN:《蓝凌JAVA产品部SVN使用指南.doc》RTC:《蓝凌JAVA产品部RTC使用指南.doc》 .3、相关规范 开发环境一律使用公司标准开发环境,如使用自己的开发环境,遇到问题则自己行解决;每个开发人员都有自己的帐号和密码,禁止使用其他开发人员的帐号和密码,可以保证每个版本都能找到相应的开发人员,如需开通新帐号密码,请告知SCM管理员;遇到SCM服务器问题,应及时寻找SCM管理员帮助解决,避免自己去尝试解决导致服务器崩溃;发现冲突必须经过手动合并后才能上传到SCM服务器上,不能将其他开发人员的代码直接覆盖,导致代码丢失;上传的代码必须保证是能运行的代码,不能将未经过测试的代码就上传SCM服务器上,导致其他发开人员项目启动不了;每天下班前将当天开发的已完成的代码提交到服务器上;每天早上来到公司应该同步SCM服务器,将最新的代码更新到本地,可以避免服务器崩溃后找不到最新的代码。
注:开发人员必须遵守以上规范,如发现未遵守以上规范,导致代码丢失或者影响其他开发人员正常工作的行为,会给予相应的处罚
开发人员在编程过程代码目录结构、业务逻辑在什么地方、配置文件存放位置等都需要规范,以便其他开发人员快速查找文件,减少开发过程中的沟通,减少维护成本。
.1、JAVA存放位置
src是存放JAVA代码的目录,我们公司所有的项目的包名前面都有com.landray.kmss,后面接的是项目名称,如HR项目就是com.landray.kmss.hr,下面是HR的各个模块,如绩效考核模块:com.landray.kmss.hr.pm。
我们公司采用三层架构(struts、hibernate、spring),JAVA代码分成五个目录存放,目录包括action、form、dao、model、service,还有一个ApplicationResources.properties资源文件文件,每个模块都包含五个目录和一个资源文件。代码结构如下:
com.lanray.kmss.项目名称
—— 模块1
——子模块(如归档模块)
——action
——constant
——dao
——hibernate
——form
——model
——service
——spring
——util
——ApplicationResources.properties
—— 模块2
—— 模块3
例子:
com.landray.kmss.hr.pm.action
com.landray.kmss.hr.pm. archive(绩效考核归档模块)
com.landray.kmss.hr.pm.dao
com.landray.kmss.hr.pm.dao.hibernaete
com.landray.kmss.hr.pm.form
com.landray.kmss.hr.pm.model
com.landray.kmss.hr.pm.service
com.landray.kmss.hr.pm.service.spring
com.landray.kmss.hr.pm.ApplicationResources.properties
.2、页面存放位置
页面文件存放在WebContent目录下面,代码结构如下:
WebContent
——项目名称
——模块1
——模块2
——模块3
例子:
WebContent
——hr
——pm
——hr_pm_action
——hr_pm_angle
——resources(可选)
——retain
——salary
发现多个模块使用的文件的直接存放在模块下
resources存放JS、图片、样式、静态HTML
.3、配置文件存放位置
design、spring.xml等文件应存放WebContent\WEB-INF下的KmssConfig目录下面,代码结构如下:
WebContent
——WEB-INF
——KmssConfig
——项目名称
——模块1
——data-dict
——模块2
例子:
WebContent
——WEB-INF
——KmssConfig
——hr
——pm
——data-dict
——HrPmAction.xml
——design.xml
——spring.xml
——hibernate.xml
——struts.xml
——validation.xml
——enums.xml
——retain
.4、业务代码位置
业务代码均在spring或者dao中开发,action只用于页面的跳转,禁止在action写大量业务代码,禁止对model进行赋值操作,禁止多次调用service的更新操作,禁止直接调用dao
注:开发人员在开发过程中请严格遵循以上代码结构
.5、数据库设计
数据库设计在开发中如有更改,要及时维护PowerDesigner
没有必要情况不要写数据库特性的sql语句,尽量使用HQL语句,如有特殊情况特殊处理
、Model规范
model里面不能使用基础类型,只能使用对象类型,如:double类型、int类型等是不能使用,要使用Double类型、Integer类型等
hbm中String的length大于1500的不能超过5个,否则使用clob属性
针对类似Clob、Blob等大字段类型的字段,必须采用字段延时加载的模式,修改样例如下:
hbm文件:
<property
name="docContent"
column="doc_content"
update="true"
insert="true"
not-null="false"
type="com.mon.dao.ClobStringType"
lazy="true"
length="1000000" />
model类(需实现net.sf.cglib.transform.impl.InterceptFieldEnabled接口):
protected String docContent;
public String getDocContent() {
return (String) readLazyField("docContent", docContent);
}
public void setDocContent(String docContent) {
this.docContent = (String) writeLazyField("docContent",
this.docContent, docContent);
}
、Design配置规范
-design中配置模块首页(homepage)
例如:
<!-- 知识库主页配置 -->
<homePage
urlPrefix="km/doc"
url="/moduleindex.jsp?nav=/km/doc/tree.jsp&main=%2Fkm%2Fdoc%2Fkm_doc_knowledge%2FkmDocKnowledge.do%3Fmethod%3DlistChildren%26s_path%3D%25E6%2589%2580%25E6%259C%2589%25E6%2596%2587%25E6%25A1%25A3"
messageKey="km-doc:kmDoc.tree.title" />
注意:url需要转码,并且不能将s_css=default配置在里面
错误的配置:
<!-- 知识库主页配置 -->
<homePage
urlPrefix="km/doc"
url="/moduleindex.jsp?nav=/km/doc/tree.jsp& main=/km/doc/km_doc_knowledge/kmDocKnowledge.do?method=listChildren&s_path=%E6%89%80%E6%9C%89%E6%96%87%E6%A1%A3&s_css=default"
messageKey="km-doc:kmDoc.tree.title"/>
-design中portlet配置需要添加morlUrl,默认配置为模块首页地址
例如:
moreURL="/km/doc.index"
-有“我的工作”、“系统配置”、“草稿”等属性需要在design中配置myjob、config、darft等treenode
、JAVA类规范不能使用累赘方法(循环嵌套),循环次数不能超过两次,当出现这样的情况,需要抽取成方法,增加代码可读性 void Test(){
for(i=0; i<2; i++){
Test1();
}
void Test1(){
for(i=0; i<2; i++){
Test2();
}
void Test1(){
for(i=0; i<2; i++){
…
}
void Test(){
for (i=0; i<2; i++){
for(j=0; j<2; j++){
for(k=0; k<2; k++){
for….
}
}
}
}
没有使用过的变量需要删除
例如:
-没有使用过的方法需要删除
-已经不需要的代码不要长篇幅的注释放在那里
-方法体需要添加注释
、JSP界面规范
-jsp不允许直接写中文
例如:
if(fdBeforeStartTimeReminds==null||fdBeforeStartTimeReminds==""){
alert("<bean:message key="kmCalendarMain.msg.unableSendRemind.timeError" bundle="km-calendar"/>");
document.getElementById("fdBeforeStartTimeRemind").focus();
return false;
}
错误的写法:
if(fdBeforeStartTimeReminds==null||fdBeforeStartTimeReminds==""){
alert("日程开始前提醒的时间不能为空");
document.getElementById("fdBeforeStartTimeRemind").focus();
return false;
}
例如:
<sunbor:column property="kmCalendarMain.docCreateTime">
<bean:message bundle="km-calendar" key="kmCalendarMain.docCreateTime"/>
</sunbor:column>
错误的写法:
<sunbor:column property="kmCalendarMain.docCreateTime">
创建时间
</sunbor:column>
-单选按钮或多选按钮需要添加<lable></lable>标签,如:
<label><input type=”radio” name=”fdYesNo” value=”true”> 是</label>
<label><input type=”radio” name=”fdYesNo” value=”false”> 否</label>
-jsp中需要import一个jsp时需要在import中指定编码格式UTF-8,避免出现乱码问题
例如:
<c:import url="/sys/bookmark/include/bookmark_bar.jsp" charEncoding="UTF-8">
<c:param name="fdSubject" value="${kmBamDocKnowledgeForm.docSubject}" />
<c:param name="fdModelId" value="${kmBamDocKnowledgeForm.fdId}" />
<c:param name="fdModelName"
value="com.landray.kmss.km.bam.model.KmBamDocKnowledge" />
</c:import>
-js中alert使用的资源文件中若含有双引号,alert必须使用单引号。
例如:
km.doc.subject=当前操作为“修改当前处理人”!
alert('<bean:message key="km.doc.subject">')
错误的写法:
alert("<bean:message key="km.doc.subject">")
、properties资源文件规范
-properties不允许写入含有单引号或双引号的html语句,如必要资源文件需拆语句
例如:
资源文件中
sysNotifyTodo.home.you=您
sysNotifyTodo.home.notHave=没有
sysNotifyTodo.home.todo=待办事宜
jsp中
<bean:message bundle='sys-notify-todo' key='sysNotifyTodo.home.you'/>
<font style="color:#FF6600;"><b>
<bean:message bundle='sys-notify-todo' key='sysNotifyTodo.home. notHave'/>
</font>
<bean:message bundle='sys-notify-todo' key='sysNotifyTodo.home. todo'/>
错误的写法:
资源文件中
sysNotifyTodo.home.havenot=您 <font style="color:#FF6600;"><b>没有</b></font> 待办事宜
jsp中
<bean:message bundle='sys-notify-todo' key='sysNotifyTodo.home.havenot'/>
.1、命名规范数据库设计
表和字段全部小写,用“_”分隔表名或字段名中的多个词
表:[产品简称_模块简称_表简称]
样例:hr_org_dept
每个数据库的主表:表:[产品简称_模块简称_main]
样例:km_review_main
子表名称:[产品简称_模块简称_主表简称_子表简称]
样例:km_review_main_keyword
中间表名称:[产品简称_模块简称_主表简称_字段简称]
样例:km_review_main_post
主键:[fd_id]
外键:[fd_字段名_id]
样例:fd_creator_id
字段:[fd_字段名]
样例:fd_order
字段类型:
主外键:VARCHAR2(36)
布尔:NUMBER(1)
枚举:NUMBER(2)
普通的多行文本:VARCHAR2(1500)或VARCHAR2(2000)
RTF:CLOB
排序号:NUMBER(10)
注:表名长度、字段名长度均不能超过30个字符
JAVA类
类名:[产品简称+模块简称+表内容简称]
样例:HrOrgDept
普通属性:[fd字段名]
样例:fdOrder、docCreator
特殊对象属性:直接属性的类名(首字母小写)
说明:特殊对象指该对象通过类名已经可以明确对象的含义,该对象无二义性,如:hrOrgPostType(岗位性质)。但类似SysOrgElement(组织架构元素)的对象,它既可以表示创建者,也可以表示修改者或其他实际的业务属性,这种情况下,该对象必须以“普通属性”的格式命名,如创建者命名为fdCreator。
样例:hrOrgPostType
普通列表属性:[fd字段名的复数]
样例:fdEditors
特殊列表属性:直接属性的类名的复数
说明:特殊列表属性类似于特殊对象属性,与普通列表属性的区别是该类含义无二义性。
样例:hrOrgPostTypes
常用表名字常用字段
普通类型
内容管理
权限相关
注:创建人、创建时间必须为docCreator和docCreateTime
常用枚举权限命名每个模块必须定义DEFAULT的角色,用于校验模块中未声明的页面以及操作权限,并在该角色的注释中说明DEFAULT所具有的操作权限。模块的基础配置信息(简单配置,如员工管理中的政治面貌、学历等),若无特别业务要求,均采用集中一个角色的方案进行配置。模块中稍微复杂的配置(如:员工信息中的异动流程设置),采用一个角色对应一种配置的方案进行配置。一般的主业务的配置,需要针对“新增、删除、修改、查阅”等操作分别进行配置,其中查阅和修改操作,针对是否有数据过滤,又分为读者/作者(有数据过滤)和阅读/修改(无数据过滤)两种方式设置。对于有数据过滤的模块,不限制list操作。对于组织架构关联很大的主业务的配置,需要进行本部门下的新增/删除/修改权限控制。对于阅读的权限,采用数据过滤的方式,过滤掉非本部门的数据,同样不限制list操作。
默认角色:ROLE_模块名(英文)_DEFAULT
定义于:模块的默认校验
名称:模块名(中文)_默认权限
描述:可访问模块名(中文)中的其他页面以及可以进行模块名(中文)中的其他操作
样例:
角色:ROLE_SYSORG_DEFAULT
名称:组织架构_默认权限
描述:可访问组织架构中的其他页面以及可以进行组织架构中的其他操作
基础信息维护者:ROLE_模块名(英文)_SETTING
定义于:简单的基础信息维护(注意:简单的基础信息一般指单表)
名称:模块名(中文)_维护基础信息
描述:可维护模块名(中文)中的基础信息
样例:
角色:ROLE_SYSORG_SETTING
名称:组织架构_维护基础信息
描述:可维护组织架构中的基础信息
新增角色:ROLE_表名(英文)_CREATE
定义于:表的add、save、saveadd页面
名称:模块名(中文)_新增表名(中文)
描述:可新增模块名(中文)中的表名(中文)信息
样例:
角色:ROLE_SYSORGDEPT_CREATE
名称:组织架构_新增部门
描述:可新增组织架构中的部门信息
删除角色:ROLE_表名(英文)_DELETE
定义于:表的delete、deleteall页面
名称:模块名(中文)_删除表名(中文)
描述:可删除模块名(中文)中的表名(中文)信息
样例:
角色:ROLE_SYSORGDEPT_DELETE
名称:组织架构_删除部门
描述:可删除组织架构中的部门信息
查阅角色:ROLE_表名(英文)_VIEW
定义于:表的view和list页面,注意跟READER的角色区分,一般用于无权限过滤的表
名称:模块名(中文)_查阅表名(中文)
描述:可查阅模块名(中文)中的表名(中文)信息
样例:
角色:ROLE_SYSORGDEPT_VIEW
名称:组织架构_查阅部门
描述:可查阅组织架构中的部门信息
编辑角色:ROLE_表名(英文)_EDIT
定义于:表的edit和update页面,注意跟EDITOR的角色区分,一般用于无权限过滤的表
名称:模块名(中文)_编辑表名(中文)
描述:可编辑模块名(中文)中的表名(中文)信息
样例:
角色:ROLE_SYSORGDEPT_EDIT
名称:组织架构_编辑部门
描述:可编辑组织架构中的部门信息
读者角色:ROLE_表名(英文)_READER
定义于:表Model的数据过滤器,一般用于有权限过滤的表
名称:模块名(中文)_查看所有的表名(中文)
描述:可查看模块名(中文)中的所有表名(中文)信息(无论是否有授权)
样例:
角色:ROLE_SYSORGDEPT_READER
名称:组织架构_查看所有的部门
描述:可查看组织架构中的所有部门信息(无论是否有授权)
读者角色:ROLE_表名(英文)_EDITOR
定义于:表Model的数据过滤器,一般用于有权限过滤的表
名称:模块名(中文)_编辑所有的表名(中文)
描述:可编辑模块名(中文)中的所有表名(中文)信息(无论是否有授权)
样例:
角色:ROLE_SYSORGDEPT_EDITOR
名称:组织架构_编辑所有的部门
描述:可编辑组织架构中的所有部门信息(无论是否有授权)
结合部门的角色:ROLE_表名(英文)_DEPT_OPT
定义于:表的OPT相关页面
名称:模块名(中文)_操作名本部门下的表名(中文)
描述:可操作名模块名(中文)中本部门下的表名(中文)信息
样例:
角色:ROLE_SYSORGDEPT_DEPT_ADD
名称:组织架构_增加本部门下的部门
描述:可增加组织架构中本部门下的部门信息
.2、风格规范基本要求
程序结构清析,简单易懂,单个函数的程序行数避免超过100行,单个类避 免超过1000行。
尽量使用标准库函数和公共函数。
不要随意定义全局变量,尽量使用局部变量。
使用括号以避免二义性,如:if和else
基础数据对象如:Long、Double等不能使用new方法直接初始化,要使用 ValueOf()方法
集合类要声明集合元素的类型,如:Map<String, String> map = new HashMap<String, String>();
文件组织
Java源文件还遵循以下规则:
1.1包和引入语句(Package and Import Statements)
在多数Java源文件中,第一个非注释行是包语句。在它之后可以跟引入语句。例如:
packagecom.mon.actions;
importjava.util.Map;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServletRequest;
importorg.apache.struts.action.ActionMapping;
1.2文件注释(Beginning Comments)
所有的源文件都应该在有一个C语言风格的注释,其中列出该类的使用说明、作者、版本信息、日期:
/**
* Action基类,不建议直接继承,仅当ExtendAction完全无法满足实际业务需求时才继承该类。<br>
* 使用范围:Action层代码,作为基类继承。
*
*@author叶中奇
*@version1.0 -04-02
*/
注释
在处理过程的每个阶段都有相关注释说明,特殊变量(结构、联合、类或对象)定义或引用时,也应写注释,有注释有便于其他开发人员或自己下次查看代码时候能很明白程序的意思,读懂程序,可以减少内部的沟通。
程序可以有4种实现注释的风格:块(block)、单行(single-line)、尾端(trailing)和行末(end-of-line)。
块注释(Block Comments)
块注释通常用于提供对文件,方法,数据结构和算法的描述。块注释被置于每个文件的开始处以及每个方法之前。它们也可以被用于其他地方,比如方法内部。在功能和方法内部的块注释应该和它们所描述的代码具有一样的缩进格式。
块注释之首应该有一个空行,用于把块注释和代码分割开来,比如:
/*
* Here is a block comment.
*/
单行注释(Single-Line Comments)
短注释可以显示在一行内,并与其后的代码具有一样的缩进层级。如果一个注释不能在一行内写完,就该采用块注释(参见"块注释")。单行注释之前应该有一个空行。以下是一个Java代码中单行注释的例子:
if (condition) {
/* Handle the condition. */
...
}
尾端注释(Trailing Comments)
极短的注释可以与它们所要描述的代码位于同一行,但是应该有足够的空白来分开代码和注释。若有多个短注释出现于大段代码中,它们应该具有相同的缩进。
以下是一个Java代码中尾端注释的例子:
if (a == 2) {
return TRUE; /* special case */
} else {
return isPrime(a); /* works only for odd a */
}
行末注释(End-Of-Line Comments)
注释界定符"//",可以注释掉整行或者一行中的一部分。它一般不用于连续多行的注释文本;然而,它可以用来注释掉连续多行的代码段。以下是所有三种风格的例子:
if (foo > 1) {
// Do a double-flip.
...
}
else {
return false; // Explain why here.
}
//if (bar > 1) {
//
// // Do a triple-flip.
// ...
//}
//else {
// return false;
//}
注:代码的注释只能使用单行注释,不能使用块注释
声明
变量的声明应注意其使用范围,不要什么变量都定义为public
推荐一行一个声明,因为这样以利于写注释,如下:
int level; // indentation level
int size; // size of table
int level, size; //最好不要这样声明
定义一个集合,如:map的时候要说明key,value是什么
循环语句
语句是包含在大括号中的语句序列,形如"{ 语句 }"。例如下面各段。
- 被括其中的语句应该较之复合语句缩进一个层次
- 左大括号"{"应位于复合语句起始行的行尾;右大括号"}"应另起一行并与复合语句首行对齐。
- 大括号可以被用于所有语句,包括单个语句,只要这些语句是诸如if-else或for控制结构的一部分。这样便于添加语句而无需担心由于忘了加括号而引入bug,并且方便其他开发人员阅读。
例如:
for(int i =0; i <10; i ++){
i++ ;
if(i==5) break ;
}
if (condition) {
statements;
}
if (condition) {
statements;
} else {
statements;
}
避免为了偷懒写成
if (condition)
statements;
else
statements;
-case语句的结尾需要加break
-switch需要写default分支
例如:
switch (runType) {
case RUNTYPE_ALLNODE:
sysQuartzScheduler.scheduleJob(jobModel);
break;
case RUNTYPE_ALLSERVER:
if (channel.isServerMaster())
sysQuartzScheduler.scheduleJob(jobModel);
break;
default:
sysQuartzScheduler.scheduleJob(jobModel);
break;
}
equals判断
例如:
"failure".equals(para)
集合类需要声明集合元素的类型
例如:
Map<String, String> map = new HashMap<String, String>();
使用常量
例如:
whereBlock = "kmMissiveSendMain.docStatus != "
+ SysDocConstant.DOC_STATUS_DRAFT;
避免为了偷懒写成
whereBlock = "kmMissiveSendMain.docStatus != 10";
注:开发人员在开发过程中请注意按ctrl+shift+o(去除引用多余的包)和ctrl+shift+f(自动排版)
本文档仅供蓝凌内部使用,未经蓝凌许可,不得以任何形式将本文档转发、拷贝给其他方。
[全文完]