[转载]CSS未知高度垂直居中

mikel阅读(1146)

[转载]CSS未知高度垂直居中 – Ruby’s Louvre – 博客园.

最近群里这个问题比较热门,决定把我收藏的方法分享大家。在开始时,我们先看一下万能的table实现。

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta content="IE=8" http-equiv="X-UA-Compatible"/>
<title>司徒正美 CSS垂直居中</title>
<style type="text/css">
.container{
width:500px;/*装饰*/
height:500px;
background:#B9D6FF;
border: 1px solid #CCC;
}
</style>
</head>
<body>
<h1>垂直居中 (table)</h1>
<div class='container'>
<table width="100%" height="100%">
<tr>
<td align="center" valign="middle">
</td>
</tr>
</table>
</div>
</body>
</html>

好了,我们看其CSS实现。凡是table能做到的,CSS都能做的,但各浏览器在CSS的差异比较大,因此要兼容它们难度很大。这涉及许多细节, 各种流啊,display的表现效果与CSS hack,IE早些年搞了大堆的私有属性,这也有待我们深一步挖掘。我们先看最简单的实现,背景图片法——

背景图片法

CSS表达式法

绝对定位法

display:inline-block法

writing-mode法

记得淘宝也搞一个font-size法,但我觉得上下差异比较大,就不收录了。怿飞的博客亦提到过一韩国人有个巧妙的实现,但日久链接失效了,谁收 藏了也请提供一下。

[转载]一篇UI规范文件

mikel阅读(1064)

[转载]一篇UI规范文件 – 笑破天的博客 – 博客园.

这是一个UI模板规范,在做B/S版应用程序时比较适用,其实这样的东西算不上什么正规的规范,只是为了适应我 们现在面对的开发环境和组织流程做的一些权宜的努力,和解决了一些与程序沟通和接口的问题,尽量避免误会和摩擦。

一 适用环境和对象
二  必要性
三 技术原则
四 代码编写规范
五 页面模版使用规范

一 适用环境和对象
本规范适用基于浏览器的B/S版软件项目开 发工作。开发流程中的模版页面编写和模版文件套用工作必须遵照此规范执行。适用对象为开发编码人员、UI设计人员、模版编写人员、界面测试人员等。
基 于客户端的C/S版软件开发工作不适用本技术规范。

二 必要性
本规范旨在制订开发编码人员和UI模版编写人员之间在工作交叉部分的技术标准,使他们遵循同 一操作规范,利于交叉工作的平缓顺利交接。以标准化方式,提高沟通和技术协作的水平,提高工作效率。减少和改变责任不明,任务不清,和由此产生的信息沟通 不畅、反复修改、重复劳动、效率低下的现象。

三 技术原则
代码规范化书写
代码规范化书写实现了脚本整体风格的一致,保证了同一个人不同时期 写的脚本风格保持一致,以及同一个工作组中不同的开发人员编写的脚本风格保持一致。因为开发不可能在孤立中进行,所以代码规范化书写是项目组人员合作沟通 的前提。

数据层、结构层、表现 层分离
数据内容就是页面实际要传达的真正信息,包含数据、文档或者图片等。这里强调的“真正”,是指纯粹的数据信息本身。把信息内容以一种合适的 方式格式化,简言之就是页面排版,例如:分成标题、作者、章、节、段落和列表等,使内容更加具有逻辑性,条理清晰易读易懂,叫做“结构 (Structure)” 虽然定义了结构,但是内容还是相同的样式没有改变,例如标题字体没有变大,正文的颜色也没有变化,没有背景,没有修饰。所有这些用来改变内容外观的东西, 称之为“表现(Presentation)” “表现”的作用使内容看上去漂亮、赏心悦目、打动人心!

所有HTML和XHTML页面就是由“结构、表现和行为”这三方面 组成的。抽象一点理解,内容是基础层,然后是附加上去结构层和表现层,人对页面内容的交互及操作效果叫做“行为(Behavior)”,

对于数据、结构与表现 相分离,最早是在软件开发架构理论中提出来的。UI设计师设计出页面模版,程序员负责内容数据的嵌入,数据可能是从数据库中提取出来,也可能是静态写入的 提示性文字,最后形成一个新的页面展示给软件操作者。模版文件的结构利用HTML+XHTML标签来定义,而所有涉及表现的东西通通剥离出来,把它放到一 个单独的文件里,这个单独的文件就是CSS。

数据、结构与表现相分离的好处是:
程序员不需要过多的思考页面显示问题,而只需要根据模版效果把数 据放入模版相应的位置。界面的结构和表现由UI设计师负责。填入结构的数据自觉套用设计好了的表现效果。最后呈现一个实现功能的完整界面。
表现层 的分离保持整个软件界面视觉的一致性,使改版也变得非常简单,修改样式表就可以了;
由于结构清晰,数据层相对独立,对数据的集成、更新、处理和再 利用也更加方便灵活;

四 代码 编写规范

(一)目录结构及命名 规则

目录结构规范
1、 目录建立的原则:以最少的层次提供最清晰简便的访问结构。
2、根目录一般只存放index.htm以及其他必须的系统文件
3、在根目录中 原则上应该按照系统的栏目结构,给每一个栏目开设一个目录,根据需要在每一个栏目的目录中开设一个images 和media 的子目录用以放置此栏目专有的图片和多媒体文件,如果这个栏目的内容特别多,又分出很多下级栏目,可以相应的再开设其他目录。根目录下的images用于 存放各页面都要使用的公用图片,子目录下的images目录存放本栏目页面使用的私有图片
4、所有JS,ASP,PHP等脚本存放在根目录下的 scripts目录
5、所有CGI程序存放在根目录下的cgi-bin目录
6、所有CSS文件存放在根目录下style目录
7、 每个语言版本存放于独立的目录。例如:简体中文gb
8、所有flash, avi, ram, quicktime 等多媒体文件存放在根目录下的media目录
9、temp 子目录放客户提供的各种文字图片等等原始资料,以时间为名称开设目录,将客户陆续提供的资料归类整理。

文件和目录命名规范
1、文件命名的原则:以最少的字母达到最容 易理解的意义。
2、每一个目录中包含的缺省html 文件,文件名统一用index.htm
3、文件名称统一用小写的英文字母、数字和下 划线的组合,不得包含汉字、空格和特殊字符
4、尽量按单词的英语翻译为名称。例如:feedback(信息反馈),aboutus(关于我们) 不到万不得已不要以拼音作为目录名称
5、多个同类型文件使用英文字母加数字命名,字母和数字之间用_分隔。例如:news_01.htm。注意, 数字位数与文件个数成正比,不够的用0补齐。例如共有200条新闻,其中第18条命名为news_018.htm

图片的命名规范
1、 名称分为头尾两两部分,用下划线隔开。
2、头部分表示此图片的大类性质。例如: 放置在页面顶部的广告、装饰图案等长方形的图片我们取名:banner ;标志性的图片我们取名为:logo ;在页面上位置不固定并且带有链接的小图片我们取名为button ;在页面上某一个位置连续出现,性质相同的链接栏目的图片我们取名:menu ;装饰用的照片我们取名:pic ;不带链接表示标题的图片我们取名:title 依照此原则类推。
3、尾部分用来表示图片的具体含义,用英文字 母表示。例如:banner_sohu.gif banner_sina.gif menu_aboutus.gif menu_job.gif title_news.gif logo_police.gif logo_national.gif pic_people.jpg pic_hill.jpg.

4、有onmouse效果的图片,两张分别在原有文件名后加”_on”和”_off”命名

其它文件命名规范
1、 js的命名原则以功能的英语单词为名。例如:广告条的js文件名为:ad.js
2、所有的CGI文件后缀为cgi。所有CGI程序的配置文件为 config.cgi

(二)  html编写规则

一般原则
1、在编写模版文件,排布结构表格之前,要思考一个最佳方案,表格的嵌套尽量控制在三层以内;要考 虑程序套用的可实现性、通用性、灵活性、预见性,所有内容均采用积木式组织,可替换和删除,并对总体结构不会造成破坏性影响
2、尽量避免 <colspan> <rowspan> 两个标记,经验表明,这两个标记会带来许多麻烦
3、一个网页要尽量避免用整个 一张大表格,所有的内容都嵌套在这个大表格之内。因为浏览器在解释页面元素时,是以表格为单位逐一显示,如果一张网页是嵌套在一个大表格之内,那么很可能 造成的后果就是,当浏览者敲入网址,他要先面对一片空白很长时间,然后所有的网页内容同时出现。如果必须这样做,请使用 <tbody>标记,以便能够使这个大表格分块显示
4、排版中经常会遇到需要进行首行缩进的处理,不要使用全角空格来达到效果,规范 的做法是在样式表中定义 p { text-indent: 2em; } 然后给每一段加上 <p> 标记,注意,一般情况下,请不要省略 </p> 结束标记
5、原则上,我们禁止用 <img width=? height=?> 来人为干预图片显示的尺寸,而且建议 <img> 标签中不要带上width 和height 两个属性,这是因为制作过程中,图片往往需要反复的修改,这样可以避免人为干预图片显示的尺寸,尽可能的发挥浏览器自身的功能;但是这样的一个副作用是当 网页还未加载图片时,不会留出图片的站位大小,可能会造成网页在加载过程中抖动(如果图片是插在一个固定大小的表格里的,不会有这个现象),尤其是当图片 的尺寸较大时,这种现象会很明显,所以当预料到这种会明显导致网页抖动的情况会发生时,务必在最后给 <img>附上 width 和 height 属性
6、为了最大程度的发挥浏览器自动排版的功能,在一段完整的文字中尽量不要使用<br> 来人工干预分段
7、 不同语种的文字之间应该有一个半角空格,但避头的符号之前和避尾的符号之后除外,汉字之间的标点要用全角标点,英文字母和数字周围的括号应该使用半角括号
8、 为贯彻结构层和表现层分离的原则,严禁使用传统的HTML3.2/4.0控制表现的标签,例如<font>,<b>,还有本意用 于结构后来被滥用于控制表现的标签,例如:<h1>,<table>等。所有的字号都应该用样式表来实现,禁止在页面中出现 <font size= > 标记,<b> </b> <h1> </h1>标记,严禁在结构页面写表现标签
9、不要在网页 中连续出现多于一个的也尽量少使用全角空格(英文字符集下,全角空格会变成乱码),空白应该尽量使用 text-indent, padding, margin, hspace, vspace 以及透明的gif 图片来实现。
10、中英文混排时,我们尽可能的将英文和数字定义为 verdana 和arial 两种字体
11、行距建议用百分比来定义,常用的两个行距的值是line-height:120%/150%
12、 系统中的路径全部采用相对路径
13、为保证系统和浏览器的兼容性,当设置背景图片时,要坚持用双引号。
14、“网页大小”为网页的所有文 件大小的总和,包括HTML文件和所有的嵌入的对象。页面大小保持在34K以下为合适

代码规则
head区标识(head区是指首页HTML代码的<head> 和</head>之间的内容)
1、公司版权注释
<!–
Generator: 中软融鑫
Creation Data: 2005-8-1
Original Author: 张三
–>

2、网页显示字符集
简体中文:
<META. HTTP-EQUIV=”Content-Type” CONTENT=”text/html; charset=gb2312″>
繁体中 文:
<META. HTTP-EQUIV=”Content-Type” CONTENT=”text/html; charset=BIG5″>
英 语:
<META. HTTP-EQUIV=”Content-Type” CONTENT=”text/html; charset=iso-8859-1″>
?
3、简介
<META. NAME=”DESCRIPTION” CONTENT=”这里填您网站的简介”>?

4、网页的css文件定义,所有css文件尽量采用外部调用
<LINK href=”style/style.css” rel=”stylesheet” type=”text/css”>

5、网页标题
<title> 这里是你的网页标题</title>

6、所有的JavaScript脚本尽量采取外部调用
<SCRIPT. LANGUAGE=”JavaScript” SRC=”script/xxxxx.js”></SCRIPT>

head区可以选择加 入的标识
7、设定网页的到期时间。一旦网页过期,必须到fwq上重新调阅。
<META. HTTP-EQUIV=”expires” CONTENT=”Wed, 26 Feb 1997 08:21:57 GMT”>

8、禁止浏览器从本地 机的缓存中调阅页面内容。
<META. HTTP-EQUIV=”Pragma” CONTENT=”no-cache”>

9、用来防止别人在框 架里调用你的页面。
<META. HTTP-EQUIV=”Window-target” CONTENT=”_top”>

10、自动跳转。
<META. HTTP-EQUIV=”Refresh” CONTENT=”5;URL=http://www.yahoo.com”>
5指时间停留 5秒。

11、网页搜索机器人 向导.用来告诉搜索机器人哪些页面需要索引,哪些页面不需要索引。
<META. NAME=”robots” CONTENT=”none”>
CONTENT的参数有all,none,index,noindex,follow,nofollow。 默认是all。

12、收藏 夹图标
<link rel = “Shortcut Icon” href=”favicon.ico”>

13、搜索关键字
<META. NAME=”keywords” CONTENT=”关键字1,关键字2,关键字3,…”>

head区以下的标记
1、body标记
为了保证浏 览器的兼容性,必须设置页面背景
<body bgcolor=”#FFFFFF”>

2、table标记
在写 <table> 互相嵌套时,严格按照的规范,对于单独的一个<table>来说,<tr>,<td>各缩进两个半角空格,结束标记 和开始标记平齐。<td> 中如果还有嵌套的表格,<table>也缩进两个半角空格,如果<td>中没有任何嵌套的表格,</td> 结束标记应该与 <td> 处于同一行,不要换行。
正确写法:
a\
<table width=”100%”? border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td>
<table width=”100%”? border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>

b\
<td><img src=”../images/sample.gif”></td>

错误写法
a\
<table width=”100%”? border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td><table width=”100%”? border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>

b\
<td><img src=”../images/sample.gif”>
</td>
这是因为浏览器认为换行相当于一个半角空格,以 上不规范的写法相当于无意中增加一个半角空格,如果确实有必要增加一个半角空格,也应该这样写:
<td><img src=”../images/sample.gif”> </td>

于同一个级别的 <table> 一定是左首对齐的,另外不允许没有任何内容的空的单元格存在,高度大于等于12px 的单元格应该 在 <td> 和 </td> 之间写一个&nbsp;,如果高度小于12px, 则应该 在 <td> 和 </td> 之间插入一个1*1 大小的透明的gif 图片,这是因为某些浏览器认为空单元格非法而不会予以解释。如果代码顺序较乱,在DW中可以通过command->apply souce formatting进行重新整理!

3、Width 和height标记
一般情况下只有一列的表格,width 写在<table> 的标签内,只有一行的表格,height 写在 <table> 的标签内,多行多列的表格,width 和height 写在第一行或者第一列的 <td> 标签内。总之遵循一条原则:不出现多于一个的控制同一个单元格大小的height 和width, 保证任何一个width 和height 都是有效的,也就是改动代码中任何一个width 和height 的数值,都应该在浏览器中看到变化。
a、只一列的表格的width标记
<table width=”100%”? border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
</table>
b、 只一行的表格的height标记
<table width=”100%” height=”30″? border=”0″ cellpadding=”0″ cellspacing=”0″>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
c、 多行多列表格的width和height标记
<table border=”0″ cellpadding=”0″ cellspacing=”0″>
<tr>
<td width=”100″ height=”30″>&nbsp;</td>
<td width=”200″>&nbsp;</td>
<td width=”300″>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>

4、table的 width属性

为遵循页面 结构灵活性、通用性原则,table的width属性原则上全部写成100%或者不写width属性,不推荐写成其他非100%宽度属性。留空显示效果通 过其给外部td施加style的padding属性实现。

<table width=”100%”? border=”1″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td width=”200″ bgcolor=”#FF0000″ style=”padding:20px; “>
<table width=”100%” border=”1″ cellpadding=”0″ cellspacing=”0″ bgcolor=”#FFFFFF”>
<tr>
<td>table宽度 100%</td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
</table>
</td>
<td>&nbsp;</td>
</tr>
</table>

需要说明的是这里td的style虽然是css的写法,但不属于表现层的内容,而是属于结构层 的内容,所以可以直接写在html标记中间。

5、数据列表表格代码写法
表格外加上一个<div>,并对<div>赋一个 id,即<div id =list>,然后通过样式表对这个id下的所有html元素进行控制,
用<th>表示表头
设 置每列宽度的位置在表头对应的<th>中,其中列表项中,字数最多或者字数不定的一项不设置宽度。
宽度的值依据列表项内容的多少来 定,2个字的30px,三个字40px,时间、年月日(比如2004-11-11)80-120px,
类似于标题的列表项,表格对齐方式为左对齐 (align=left),时间,人名一般居中对齐,数据一般右对齐(align=right)。
对齐页面内容时不要用div来对齐,直接在td 或th中写align=…
表头文字一般不折行,方法是在<th>中加上nowrap,或者通过样式表来控制

<table width=”100%” border=”0″ cellspacing=”0″ cellpadding=”0″>
<tr>
<th width=”30″ nowrap>选择</th>
<th align=”left” nowrap>标题</th>
<th width=”80″ nowrap>发表人</th>
<th width=”120″ nowrap>时间</th>
<th width=”40″ nowrap>大小</th>
</tr>
<tr>
<td>&nbsp;</td>
<td align=”left”>&nbsp;</td>
<td align=”center”>&nbsp;</td>
<td align=”center”>&nbsp;</td>
<td align=”right”>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td align=”left”>&nbsp;</td>
<td align=”center”>&nbsp;</td>
<td align=”center”>&nbsp;</td>
<td align=”right”>&nbsp;</td>
</tr>
</table>

(三)  css编写规则

css文件 调用写法
1、所有的CSS的尽量采用外部调用,特殊情况才允许使用内置html写法。
<LINK href=”style/style.css” rel=”stylesheet” type=”text/css”>

css文件结构组织
1、 文件提头,css文件名称、时间、作者

2、 将不同目的和效果的CSS选择符分别编组,编组分层级使结构清晰,便于查对。并恰当地成块注释,注释要说 明施加的页面文件的对象。顶级注释用*TOP*打头,次级注释不用。

.headtext {
font-size: 14px;
color: #ffffff;
font-weight: bold;
}?
.headtext a:link {
color: #ffffff;
text-decoration: none;
}
.headtext a:visited {
color: #ffffff;
text-decoration: none;
}
.headtext a:hover {
color: FED078;
text-decoration:none ;
}

#clientcard {
align:left;
}
#clientcard th {
height:20;
font-size: 12px;
color: #737373;
padding-left:10;
font-weight: bold;
background-attachment: fixed;
background:url(images/dot2.gif)

background-repeat: no-repeat;
background-position: left center;
}
#clientcard td {
height:20;
font-size: 12px;
color: #FD783A;
padding-right:25;
}

3、选择符分组的顺序是重定义的最先,伪类其次,自定义最后。便于自己和他人阅读。
例 如:

BODY {
margin-left: 0px;

}

TD {
font-size: 12px;

}

a:link {
color:?#484848;
text-decoration: none;
}
a:visited {
color: #484848;
text-decoration: none;
}
a:hover {
color:#BD0800;
text-decoration: underline;
}

.ltreename {
font-size: 14px;

}

类和ID命名规则
1、 以功能和定义对象的位置,而不是外观为类和ID命名。例如创建了一个 .smallblue 类,后来打算将文字改大,颜色变为红色,这个类名就不再有任何意义了。所以,用更有描述性的名字如 .copyright 和.info-list更加合适。

单位
1、0不用单位
2、非零值要指明单位,指定字体、边距或大小时,必须指明所用的单位
例 如: padding: 0 2px 0 1em;
3、特例:line-height不需要单位

字号大小
1、为了保证不同浏览器上字号保持一致,字号像素px 来定义,一般使用中文宋体12px 和14.7px 这是经过优化的字号,黑体字或者宋体字加粗时,一般选用14.7px 的字号比较合适
例如: font-size: 12px;

顺序
1、a:link a:visited a:hover a:actived 要按照规范顺序写
2、 边框(border)、边距(margin)和补白(padding)的简写次序为:顺时针方向从上开始,即 Top, Right, Bottom, Left。
例如: margin: 0 1px 3px 5px;表示上边距为零,右边距为1px,依此类推。

组合选择符
1、 保持CSS短小对减少下载时间非常重要。尽量为选择符分组、利用继承(inheritance)以及使用简写(shorthand)来减少冗余。

使用图片
1、 css中经常遇到使用图片的情况, 图片的路径一律采用相对路径。
例如:

.hurdlename {
font-size: 14px;
color: #0B43C2;
height:25px;
font-weight: bold;
background-image: url(images/rbar_bg.gif);
background-repeat: repeat-y;
text-indent: 12px;
}

.but1{
background-image: url(../images/but1.gif);
font-size: 12px;
color: #000000;
border: 0;
width:85px;
height:26px;
cursor: hand;
}

2、使用图片替换技术时要考虑与系统和文件结构的亲和力。如果引用css的所有文件不在同一级相对路径,就会出 现css指定的图片无法显示的问题。在这种情况下不支持使用图片技术。建议采用filter技术
例如:

input.buttton {
filter:progid:DXImageTransform.Microsoft.Gradient(gradienttype=0, startcolorstr=#CFD1CF, endcolorstr=#EFEFEF);
border: #B5B6B5 1px solid;
font-size: 12px;
color: #000000;
cursor: hand;
height:24px;
background:#ffffff;
}

五 页面模版使用规范

页面模版使用规范的目 的是统一和约定UI设计、界面工程师与不同的程序编码人员的行为方式,光有了书写代码的规范还不能完全解决界面套用的统一性问题。因为不同的编码人员对同 一个模版的理解有可能不同,再加上个人工作习惯的不同,界面套用的结果往往很容易出现差异。哪怕是每人一点点差异,都可能使软件的质量收到很大的影响。

责任分工明确
1、 UI设计、界面工程师负责界面风格的设计和软件模版的编写,并监督界面套用的效果。对软件最终的界面负责。
2、 编码工程师负责软件业务逻辑的实现,软件模版的套用。对软件的数据和程序负责。
3、现实的情况是个别编码工程师在模版套用出现偏差后,在界面工程 师提出修改意见的时候拒绝修改,以开发进度、时间不够为由搪塞,甚至主观认为“这个(界面)不重要”致使界面工程师的作用得不到应有的发挥,影响软件产品 质量。
4、 解决办法是各负其责。界面问题提高重视程度,并纳入开发流程和进度管理之中。

界面模版交界过程
1、 模版文件制作完成后,在提交给编码工程师时,要简要说明模版的文件的使用说明和提醒。
2、 编码工程师和界面工程师密切合作,完全理解模版使用说明。
3、对界面结构层html的table嵌套关系理解清楚并明确和程序结合的用意。有和程 序不相配合的情况,进一步和界面工程师讨论,获得解决方案。不得在界面工程师不知情的情况下随意修改table结构、定位属性和嵌套关系。这样做的坏处是 虽然一个人解决了暂时的显示问题,但和其他编码工程师套用的结果出现不同。也不利于界面工程师控制总体界面。
4、 对表现层的界面元素和css文件选择符的对应关系。做到心中有数,理解一个模版文件,到套用其他文件时就能够举一反三。

5、编码工程师完全 理解了界面模版后,就能够顺畅的把数据层的内容放到结构层合适的位置,并指定表现层合适的选择符属性。完成界面套用工作。

模版说明的内容
1、 总体的界面结构
2、 页面板块的布局和定位table的写法
3、 table嵌套的方式的理由
4、 不同功能的界面显示单元说明和使用方法
5、 css文件中选择符的使用说明,一般的都能理解,个别特殊的要着重说明。

Css文件的版本控制
Css 文件应引入版本控制的机制,项目组中应指定专人负责css文件的上传和修改。fwq的css文件和界面工程师的css文件应该同步更新。不支持编码工程师 随意添加选择符修改css文件。谁都可以改就没有标准,没有版本控制就做很难做到界面统一

[转载]NVelocity的宏使用

mikel阅读(1005)

[转载]NVelocity的宏使用 – ∠角络 – 博客园.

一、NVelocity使用参数
示例:
1.建立宏
#macro( test $range $arrayList )

#end
2.调用宏
#test([-9,-1] [“favorite”, “color”])
通过以上示例,你只需要一个为每一个需要传递的参数提供了名称的#macro指令,这些参数用空 格进行分隔。如上例中#macro( test $range $arrayList )“test”是宏名,$range $arrayList是参数。用”#”+宏名(参数1,参数2…)来调用宏。

二、NVelocity递归调用

嵌套,最简单的情况就是在NVelocity 中用到macro里调用另外一个macro,这是在实际代码开发中使用得最频繁的一种。递归,是一种特殊类型的嵌套,它是在NVelocity中的 macro里调用自身,但这种情况并不太常见。

#macro( recurs $depth )
进入第 $depth 层<br/>

#set( $depth = $depth – 1 )

#if ( $depth > 0 )

#recurs( $depth )

#end

#set( $depth = $depth + 1 )

进入第 $depth 层<br/>

#end
#recurs( 3 )

执行结果:
进入第 3 层
进入第 2 层
进 入第 1 层
进入第 1 层
进入第 2 层
进入第 3 层
注:在递归调用时,注意 通常不要把一个对象的属性传为参数递归调用,上例中,如果$depth是一个对象的话,那么用#recurs( $depth.attribute)话,模板输出时候往往有问题,而且又查不出来,这里记录一下,忘以后不要出现这样的错误。究其原因,我想是由于是 object类型,往往在调用时认不出对象的类型吧(暂时只能这样去理解了,没深层次去研究过)。

[转载]让ajax更加友好,实时显示后台处理进度。

mikel阅读(1176)

[转载]让ajax更加友好,实时显示后台处理进度。 – BearRui(AK-47) – 博客园.

ajax应用越来越多,大部分ajax处理都是在前台显示1个”loading…”,然后把数据提交给服务器进行处理,处理完毕后显示”处理完 毕”。我们能否让ajax更加友好点,实时显示服务器处理的进度了?这在一些长时间的请求中尤其重要,比如上传文件、发送邮件、批量处理数据。答案当然是 可以的,不然就不会写这个了,对吧,^_^。

存在的问题:

要解决实现上面的功能,需要解决下面几个问题:

1. 服务器如何在处理一部分数据后传递部分response到浏览器。

2、浏览器如何能处理服务器传递过来部分数据,并保持http连接直到处理完全完毕。

要解决第1个问题,使用flush让response分块进行呈现就可以了,具体请参考我另一遍随笔”flush让页面分块,逐步呈现“;

第2个问题,则需要用到XMLHttpRequest的readyState状态,w3c对 readyState 定 义如下几个值:

UNSENT = 0; // 没有发送请求

OPENED = 1;    // 已经打开http连接

HEADERS_RECEIVED = 2; // 接收到response header

LOADING = 3;          // 真正接收response body

DONE = 4;             // 请求接收完毕

相信状态4大家是天天在用,而我们这里需要用到就是状态3。

实例:

废话少说,代码实例比什么文字解释都管用。我们这里假设服务器的1个处理需要6秒种,每秒种处理1条记录,总共处理6条记录,我们需要服务器每处理完1条 数据,客户端则显示处理进度(包括文字和进度条)。

服务器端代码(下面JSP代码):

01 <%
02 // 下面设置Content-Type:application/x-JavaScript 是为了适应Webkit的浏览器(chrome,safari)
03 response.setHeader("Content-Type","application/x-JavaScript");
04 int count = 6; //  处理6条数据
05 for(int i=0;i<count;i++){
06 // 处理完毕一条,输出结果到客户端
07 out.println(i+1);
08 out.flush();
09 // 这里假设每条数据处理时间为1秒
10 Thread.currentThread().sleep(1000);
11 }
12 %>

html代码:

01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml">
03 <head>
04 <style>
05 #divProgress{width:300px;height:24px;position:relative;}
06 #divProgress div{position:absolute;left:0;top:0;height:24px;}
07 #progressBg{background-color:#B9F8F9;z-index:10;}
08 #progressText{z-index:15;text-align:center;width:100%;}
09 </style>
10 </head>
11 <body>
12 <div id="divProgress">
13 <div id="progressBg"></div>
14 <div id="progressText"></div>
15 </div>
16 <br />
17 <button onclick="send()">提交数据</button>
18 <script>
19 var t = document.getElementById("progressText");
20 var bg = document.getElementById("progressBg");
21 function send(){
22 t.innerHTML = "loading...";
23 bg.style.width = "0px";
24
25 var xhr = new window.XMLHttpRequest();
26 if(!window.XMLHttpRequest){
27 try {
28 xhr = new window.ActiveXObject("Microsoft.XMLHTTP");
29 } catch(e) {}
30 }
32 var oldSize=0;
33 xhr.onreadystatechange = function(){
34 if(xhr.readyState > 2){
35 var tmpText = xhr.responseText.substring(oldSize);
36 oldSize = xhr.responseText.length;
37 if(tmpText.length > 0 ){
38 // 设置文本
39 t.innerHTML = tmpText + "/6";
40 // 设置进度条
41 var width = parseInt(tmpText)/6*300;
42 bg.style.width = width+"px";
43 }
44 }
45 if(xhr.readyState == 4){
46 // 请求执行完毕
47 t.innerHTML = "执行完毕";
48 bg.style.width = "300px";
49 }
50 }
51 xhr.send(null);
52 }
53 </script>
54 </body>
55 </html>

运行效果图:

缺点:

看到这里或许你已经蠢蠢欲动,想自己动手试试了。但是注意上面的方法虽好,但也有个缺点,就是浏览器的支持问题。目前IE所有版本的浏览器都不支持 xhr.readyState == 3状态,IE浏览器不支持在response响应完毕前读取responseText属性。  具体可查看MSDN :  XMLHttpRequest Object

基于Webkit的浏览器支持的不是很好,需要设置Content-Type:application/x-JavaScript才行(经测试发现 Content-Type:text/html在有些情况下正常,有些情况下又不正常,而用application/x-javascript都正常)。

看到了缺点后是否又打击了你的积极性了,其实针对IE,我们不需要做太多处理,IE不支持,就不会显示进度,就变成跟传统的ajax请求一样,一直显示1 个loading直到请求完毕。我们只需要加1个简单的判断,判断如果是ie则不执行xhr.readyState > 2中的代码,如果不加判断,IE下会报JS错误.

DEMO:

demo服务器不太好,而且在国外,随时可能会点击不了,而且有时候运行效果不是很好,大家知晓下,最好是把代码copy到本地进行测试.

请使用firefox或chrome查看demo,ie查看的效果跟一般的ajax没什么不一样.

http://213.186.44.204:8080/ChunkTest/index.html

[作者]:BearRui(AK-47)
[博客]: http://www.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.

[转载]名站技术分析 - 浅谈tudou.com首页图片延迟加载的效果

mikel阅读(1484)

[转载]名站技术分析 – 浅谈tudou.com首页图片延迟加载的效果 – BearRui(AK-47) – 博客园.

经常上tudou网,发现tudou首页加载图片的功能很有意思,tudou首页从”娱乐”这个板块往下的所有视频的缩略图并不是在页面打开后就加载 的,而是当用户拖动滚动条到了”娱乐”这个板块,才开始加载图片的。这样做的好处当然是如果有用户不需要查看下面的内容,则免去了下面所有图片的请求,这 对减少服务器的压力还是很有帮助的。

实现:

其实tudou的实现原理很简单,

1.先把所有需要延迟加载的图片的src都设置成同1个小图片的连接(sprite.gif),把真真图片的连接放进图片的alt属性中,look下代 码:

<a class=”inner” target=”new” title=”史上最重街舞选手和最柔软街舞选手” href=”http://www.tudou.com/programs/view/Utmt1_6Z-lU/”>

<img width=”120″ height=”90″ class=”pack_clipImg lazyImg” alt=”http://i01.img.tudou.com/data/imgs/i/051/720/095/p.jpg” src=”http://css.tudouui.com/skin/__g/img/sprite.gif” coords=”_DAA”/>

</a>

2. 绑定window.scroll事件,在该事件里面的重设所有class为lazyImg的图片的src值,在土豆首页找到如下JS:

var o=function(){

var s=TUI.pos.scrollTop(),q=c;

if(q.box[0]){

var r=q.box.offset().top;

if(r-s>0&&r-TUI.pos.windowHeight()<s){

q.init()

}else{

q.stop()

}

}

if(!h||s<590){return true}

TUI.widget.quickPlaylist.load();

h=false

};

o();

$(window).bind(“scroll”,o);

我没有去跟入查看TUI.widget.quickPlaylist.load()方法的实现,tudou的JS都是压缩混淆的,看起来挺累,不过大家知 道原理就可以了。

实例:

上面说了那么多,最后还是来个实例比较实际点,毕竟眼见为实嘛。

01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml">
03 <head>
04 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
06 </head>
07 <body>
08 能 看的见到图片:<img src="http://at-img4.tdimg.com/board/2010/5/tylc-115X55.jpg"/>
09
10 <div id="lazyBox" style="margin-top:100px;">
11 一开始看不到的图片:
12 <img width="120" height="90" style="border:1px solid blue;" class="lazyImg" alt="http://i01.img.tudou.com/data/imgs/i/051/720/095/p.jpg" src="http://css.tudouui.com/skin/__g/img/sprite.gif" coords="_DAA"/>
13 <img width="120" height="90" style="border:1px solid blue;" class="lazyImg" alt="http://i01.img.tudou.com/data/imgs/i/051/871/396/m20.jpg" src="http://css.tudouui.com/skin/__g/img/sprite.gif" coords="_DBA"/>
14 </div>
15 <div style="height:1000px;">
16
17 </div>
18 <script type="text/JavaScript">
19 var hasShow = false;
20 $(window).bind("scroll",function(){
21 if(hasShow==true){
22 $(window).unbind("scroll");
23 return;
24 }
25 var t = $(document).scrollTop();
26 if(t>50){
27 // 滚动高度超过50,加载图片
28 hasShow = true;
29 $("#lazyBox .lazyImg").each(function(){
30 $(this).attr("src",$(this).attr("alt"));
31 });
32 }
33 });
34 </script>
35 </body>
36 </html>

把上面代码copy到本地运行下就可以看到效果了。

[作者]:BearRui(AK-47)
[博客]: http://www.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.

[转载]名站技术分析 — facebook奇特的页面加载技术

mikel阅读(1108)

[转载]名站技术分析 — facebook奇特的页面加载技术 – BearRui(AK-47) – 博客园.

没事使用代理上了下facebook,注册进入个人首页后,习惯性的查看源代码,发现了1个很有意思的现象,首页内容不少,但源代码中HTML 的代码却很少,但去多出了很多段的JavaScript代码,这些js代码都是用于动态生成html的,facebook为什么需要这样做了?出于职业习 惯,研究研究:

一、html代码。

先看看首页查看的源代码,因为源代码比较大,所以把图片压缩了下,可能看不太清楚,只需要注意图中红色是html代码,其余黑压压一片的就全部是JS代 码:

二、JS代码

看到黑压压的JS代码是不是被吓一跳,下面就截取一段JS来分析(其余段的JS都是类似的),facebook源代码中充斥了类似于下面的JS代码:

01 <script>
02 big_pipe.onPageletArrive({
03 "id":"pagelet_welcome_box","phase":1,"is_last":false,"append":false,"bootloadable":[],
04 "css":["lDRwi","eon+N"],
05 "js":["F+B8D","IdQlc"],
06 "resource_map":[],"requires":[],"provides":[],
07 "onload":["window.__UIControllerRegistry[\"c4c13a3ed2dd1e0e349b72\"] = new UIPagelet(\"c4c13a3ed2dd1e0e349b72\", \"\\\/pagelet\\\/generic.php\\\/WelcomeBoxPagelet\\\/\", {}, {});; ;"],
08 "onafterload":[],"onpagecache":[],"onafterpagecache":[],"refresh_pagelets":[],"invalidate_cache":[],
09 "content":{
10 "pagelet_welcome_box":"<div id=\"c4c13a3ed2dd1e0e349b72\"><div class=\"UIImageBlock clearfix fbxWelcomeBox\"> ...这里省略N多HTML"
11 },
12 "page_cache":true
13 });
14 </script>

让我们再看看big_pipe.onPageletArrive函数到底做了什么了?我们只关注参数中的id,js,css,content4个参数,可 以看出js和css都是进行过编码,下面是解码后我们关注的代码:

01 <script>
02 big_pipe.onPageletArrive({
03 "id":"pagelet_welcome_box",
04 "css":{
05 name: "css/c5mv8gd5gwoc4kk0.pkg.css"
06 permanent: true
08 type: "css"
09 },
10 "js":{
11 name: "js/19khsprwvtvokwow.pkg.js"
12 permanent: false
14 type: "js"
15 },
16 "content":{
17 "pagelet_welcome_box":"<div id=\"c4c13a3ed2dd1e0e349b72\"><div class=\"UIImageBlock clearfix fbxWelcomeBox\"> ...这里省略N多HTML"
18 }
19 });
20 </script>

看到还原后的JS,你应该猜出onPageletArrive函数是干嘛的吧,其实onPageletArrive最主要实现就是把”content”中 的html内容插入到对应id(上面的”pagelet_welcome_box”)的html元素中,并下载对应的css和JS。

三、chunk、flush

看到上面的分析后,大家一定奇怪,facebook为什么要生成那么多段JS,再用js去动态插入html代码,这不是脱了裤子放屁,多此一举吗?还不 如直接生成html代码了。facebook当然不会那么笨了,让我们先监控下facebook的http请求,监控图如下:

注意上图中红色部分,原来facebook使用了chunk对页面进行分块输出。这就比较容易理解了,facebook首页的js代码段不是1次就全部 输出的,而是一段一段进行输出的。

什么是chunk和如何使用chunk,请参考我的另1篇博文:flush让页面分块,逐步呈现

总结

facebook使用chunk技术让页面分块输出成很多JS段,这样做的好处就是服务器和客户端可以并行进行处理,不用等服务器全部处理完毕,客户端才 进行处理。

举个博客园首页的列子,博客园首页分为下面几块(“推荐博客排行”,”首页随笔列表”,”最新新闻”…),

我们一般对该http请求处理如下:

1. 浏览器发送http请求

2. 服务器处理请求(从缓存读取前50个推荐博客,从数据库读取”首页随笔列表”,从数据库读取”最新新闻”),生成首页的html代码。

3. 服务器发送html代码给客户端

4、浏览器接收到响应,处理html(下载css,js,image,执行js等等)

可以看出传统的http请求4个过程中,每个过程都必须等待前1个过程完成后才能执行,这样就存在很大的资源浪费。

facebook的对该http请求的处理如下:

1. 浏览器发送http请求

2. 服务器处理请求(从缓存读取前50个推荐博客,生成”推荐博客”的js代码段,flush输出该代码段,

服务器继续读取”首页随笔列表”,并生成输入js代码段。

服务器继续读取”最新新闻”,并生成输入js代码段。

3. 浏览器接收到js代码段,下载该代码段所需的js和css。插入html代码。

在这个处理流程中,最大的特点就是2,3是并行进行处理的,服务器处理完一部分数据就把已经处理好的数据交给浏览器进行呈现处理,自己再继续处理其他的数 据。

PS:文章看完了,有些同学可能会想,为什么不像博客园一样,前台全 部用ajax来异步读取”推荐博客” ,“最新新闻”的数据了,这样做就不会出现因为要处理太多数据而让客户端等待太久的问题了。我觉得对于facebook这种并发量巨大的网站,使用这种方 法无疑会产生太多的请求,比如facebook首页用了14个chunk,如果使用ajax,则需要多14个request请求,这将增加不少服务器的压 力吧。

相关文章: 名 站技术分析 — 浅谈tudou.com首页图片延迟加载的效果

[作者]:BearRui(AK-47)
[博客]: http://www.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.

[转载]web高性能开发系列随笔

mikel阅读(1051)

[转载]web高性能开发系列随笔 – BearRui(AK-47) – 博客园.

在BlogJava里写了一些关于高性能WEB开发的随笔,因为都是跟前端技术相关(html,http,js,css等),所以也贴到博客园来,吸收下 人气。
1、 HTTP服务器.

2、性能测试工具推荐

3、 图 片篇.

4、 如何加载JS,JS应该放在什么位置.

5、 为什么要减少请求数,如何减少请求数.

6、 减少请求,响应的数据量.

7、JS、 CSS的合并、压缩、缓存管理

8、页 面呈现、重绘、回流。

9、该 如何加载google-analytics(或其他第三方)的JS.

10、疯 狂的HTML压缩.

11、flush 让页面分块,逐步呈现

12、了 解CSS的查找匹配原理,让CSS更简洁、高效

[作者]:BearRui(AK-47)
[博客]: http://www.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.

[转载]高性能WEB开发(11) - flush让页面分块,逐步呈现

mikel阅读(1097)

[转载]高性能WEB开发(11) – flush让页面分块,逐步呈现 – BearRui(AK-47) – 博客园.

在处理比较耗时的请求的时候,我们总希望先让用户先看到部分内容,让用户知道系统正在进行处理,而不是无响应。一般大家在处理这种情况,都使用 ajax,先把html输出到客户端,然后再用ajax取加载比较耗时的资源。用ajax麻烦的地方是增加了请求数,而且需要写额外的js代码、和js调 用的请求接口。

正对这种情况,还有一种处理方法,就是让response分块编码进行传输。response分块编码,可以先传输一部分不需要处理的html代码到客 户端,等其他耗时代码执行完毕后再传输另外的html代码。

分块编码(chunked encoding)

chunked encoding 是http1.1 才支持编码格式(当然目前没有哪个浏览器不支持1.1了),chunked encoding 与一般的响应区别如下:

正常的响应:

HTTP/1.1 200 OK

Cache-Control: private, max-age=60

Content-Length: 75785

Content-Type: text/html; charset=utf-8

..其他response headers

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

chunked encoding 响应:

HTTP/1.1 200 OK

Cache-Control: private, max-age=60

Content-Length: 75785

Content-Type: text/html; charset=utf-8

Transfer-Encoding: chunked

..其他response headers

chunk #1(这里通常是16进制的数字,标志这个块的大小)

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”….

chunk #2

<div …..

chunk #3

….</body></html>

实例(JSP)

一个简单的页面,分为头部(header)和内容(部分),假设内容部分需要读取数据库,花费3秒时间,然后显示csdn的logo。header部分显 示cnblogs的logo。代码如下:

01 <body>
02 <div id="head" style="border:1px solid #ccc;">
03 cnblogs logo <img src="http://images.cnblogs.com/logo_small.gif" />
04 </div>
05 <br />
06 <div id="content" style="border:1px solid blue;">
07 <%
08 // 睡眠3秒
09 Thread.currentThread().sleep(3000);
10 %>
11 csdn logo<br />
13 </div>
14 </body>

演示地址:http://213.186.44.204:8080/ChunkTest/nochunk.jsp (服务器比较差,请大家温柔点)

打开这个演示地址发现很正常的页面,在3秒后才开始下载显示2个logo,资源加载瀑布图如下:

现在把代码改成如下,加上flush,让response把之前的html分块输出:

<div id=”head” style=”border:1px
solid #ccc;”>

01 cnblogs logo <img src="http://images.cnblogs.com/logo_small.gif" />
02 </div>
03 <%
04 out.flush(); // flush response,分块输出
05 %>
06 <br />
07 <div id="content" style="border:1px solid blue;">
08 <%
09 // 睡眠3秒
10 Thread.currentThread().sleep(3000);
11 %>
12 csdn logo<br />
14 </div>

演示地址:http://213.186.44.204:8080/ChunkTest/chunk.jsp

打开这个演示地址,是不是发现cnblogs logo先下载显示出来,3秒后csdn logo才显示,资源加载图如下:

从这个图发现,cnblogs的logo在jsp页面还没执行完就开始下载了,这就是分块输出的效果。

监控工具:

如何知道我们是否成功使用了chunk encoding了 ,只要用工具查看response header 中是否包含了Transfer-Encoding: chunked,如果包含了,则是分块了。但要想监控分块的详细信息,据我所知,目前只有httpwatch支持,可以查看我们到底分了多少块,但是数量 好像都多显示了1个,如下图:

有需要请查看:高性能WEB开发系列

[作者]:BearRui(AK-47)
[博客]: http://www.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.

[转载][原创].NET 业务框架开发实战之六 DAL的重构

mikel阅读(1058)

[转载][原创].NET 业务框架开发实战之六 DAL的重构 – ASP.NET 架构 – 博客园.

.NET 业务框架开发实战之六 DAL的重构
前言:其实这个系列还是之前的”.NET 分布式架构开发实战 “,之所以改了名字,主要是因为文章的标题带来了不少的歧义:系列文章中本打算开发一个简化业务发的流程的Framework,然后用这个 Framework再来实战,开发一个分布式的应用。改了名字。给大家带来了不便,敬请见谅。

本篇的议题如下:
1. 确定DAL的接口的定义。

之前在开发DAL中,提出了一些思想,也设计了一些接口。现在就把DAL的一些设计完善起来。说是“完善”,并不是说把所有的代码都实现,而是把该定 义的接口,方法敲定下来。Richard认为,设计一个架构或者Framework的时候,开始是接口的定义,定义好各层之间交互的接口,然后才是具体代 码的实现。
因为在设计Framework的时候,首先要考虑这个Framework的使用者是谁,希望他们怎么样来使用开发出来的这个 Framework。在这里,Richard很明白:Framework的使用者就是自己公司里的开发人员。而且还要使得开发的使用尽量的方便,不要到处 去配置一些文档,最好就是把Framework引入进来,稍微配一下就使用。

在Richard设计的Framework中,就DAL而言,如果希望DAL返回DataTable,DataReader等给BLL,那么需 要配置的仅仅只是指明数据库的连接字符串;如果希望DAL返回的数据实体给BLL,那么就得把一张张的表映射成为实体,然后让这些实体继承 IDataEntity接口就行了(生成实体可以用ORM工具,或者自己手写代码)。

Richard思考了之前对DAL的设计,在此他做了一些改进。
首先就是对于IDataContext的重新设计和理解:之前的设计是定义了IDataContext,然后用不同的方式实现这个接 口,如LinqDataContext.Provider就是用Linq的方法来返回结果(DataResult)。现在Richard认为 IDataContext其实就是用来操作数据库的,所以返回的结果就应该是操作数据之后的结果,如Update操作就返回受影响的行数或者是否更新成 功。至于是否要把一些额外的信息包装返回给BLL,就不是IDataContext的实现者的事情了。而且Richard还考虑到了需要在一定程度上支持 原生的ADO.NET,起码给ADO.NET预留接口。

基于此,Richard就把IDataContext定义为一个接口声明,然后再定义了IDataEntityContext,和 IDataTableContext来继承IDataContext,他们的关系图如下:

其中IDataEntityContext使用Linq和Entity Framework来实现,而IDataTableContext就是用ADO.NET的方式来实现。

IDataEntityContext接口的和系列文章中定义的一些方法差不多,但是做了修改。其中有一点要提的就是:ICriteria就是所有条 件对象要实现的接口(查询对象也是条件对象的一种)。例如,可以根据相应的条件删除,更新数据。

代码

/// <summary>
/// 所有的 数据实体执行者实现这个借口
/// </summary>
public interface IDataEntityContext:IDataContext
{
TEntity Add
<TEntity>(TEntity entity) where TEntity : IDataEntity;
List
<TEntity> Add<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;

bool Update<TEntity>(TEntity entity) where TEntity : IDataEntity;
bool Update<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;
bool Update(ICriteria condiftion, object value);

bool Delete<TEntity>(TEntity entity) where TEntity : IDataEntity;
bool Delete<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;
bool Delete(ICriteria condition);

int GetCount(ICriteria condition);
List
<TEntity> Query<TEntity>(ICriteria condition);
List
<TEntity> Query<TEntity>(ICriteria condition, int pageIndex, int pageSize, ref int entityCount) where TEntity : IDataEntity;
List
<object> Query(ICriteria condiftion);
}

另外就是多了一个 List<object> Query(ICriteria condiftion);方法,之所以有这个方法,Richard考虑到,可能开发人员想要直接自己写SQL语句去执行,如select avg(Count),sum(Name) from Customer…,开发人员可以写任意的语句,所以返回一个实体类不现实,就返回一个List<object>。

还有一点就是关于查询对象的改进:以前仅仅只是定义了查询对象的接口,现在用ICriteria 接口中定义来条件对象,而且还可以在条件对象声明是在对数据操作是否采用事务或者缓存。

代码

/// <summary>
/// 所有的 条件对象都要从这个接口继承
/// </summary>
public interface ICriteria
{
string Name { get; set; }
bool IsCache { get; set; }
bool IsTransaction { get; set; }
}

之后Richard又定义了一个IDataProvider,接口,声明如下 :

代码

/// <summary>
/// 数据提 供者要实现的借口
/// </summary>
public interface IDataProvider
{
DataResult
<TEntity> Add<TEntity>(TEntity entity) where TEntity : IDataEntity;
DataResult
<TEntity> Add<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;

DataResult<TEntity> Update<TEntity>(TEntity entity) where TEntity : IDataEntity;
DataResult
<TEntity> Update<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;
bool Update(ICriteria condiftion, object value);

DataResult<TEntity> Delete<TEntity>(TEntity entity) where TEntity : IDataEntity;
DataResult
<TEntity> Delete<TEntity>(List<TEntity> entityList) where TEntity : IDataEntity;
bool Delete(ICriteria condiftion);

int GetCount(ICriteria condition);

DataResult<TEntity> GetOne<TEntity>(ICriteria condition) where TEntity : IDataEntity;
DataResult
<TEntity> GetList<TEntity>(ICriteria condition) where TEntity : IDataEntity;
DataResult
<TEntity> GetPageData<TEntity>(ICriteria condition, int pageIndex, int pageSize, ref int entityCount) where TEntity : IDataEntity;
List
<object> GetCustomData(ICriteria condiftion);
}

之所以要定义这个接口,其实 Richard就是想让实现了IDataContext的类踏踏实实的去做底层的数据操作,至于数据操作之后的结果以什么形式给BLL,不用 IDataContext的实现者来关心,而是用IDataProvider的实现者来关心。
在IDataProvider的实现者在底层就是调用了IDataContext的实现者的方法,然后在IDataProvider 中,对外提供了一些更加友好和方便使用的方法,最后在BLL中直接依赖的就是IDataProvider,而不是IDataContext。
另外,对于IDataProvider返回的DataResult也做了一些修改:如果返回的是数据实体,即 使用的是IDataEntityContext来提供底层的数据操作,那么DataResult<TEntity>是没有问题的;但是如果使 用的是IDataTableContext,那么返回DataResult<TEntity>就不行了,因为 IDataTableContext查询方法可能返回的DataTable,或者DataReader.所以,在设计中叶预留了一个接口:让 IDataProvider返回的结果实现IDataResult接口,那么ataResult<TEntity>继承这个接口,主要用来返 回数据实体,如下:

DAL的设计就到这里,下一篇文章就开始讲述对业务层的一些思考。

版权为小洋和博客园 所有,转载请标明出处给作者。

http://www.cnblogs.com/yanyangtian

代码下载

[转载]在线视频聊天(客服)系统开发那点事儿

mikel阅读(1189)

[转载]在线视频聊天(客服)系统开发那点事儿 – 菩提树下的杨过.Net – 博客园.

07年的时候,我所在的公司有一个(在业内游戏开发方面有些名气的)Flash程序员应公司要求,利用FMS开发了一套在线视频导购系统,当时我觉 得很牛叉,用户不用安装任何插件,也不用安装什么聊天软件,就可以直接跟销售员在线交流,遇到对产品不清楚的地方,直接让销售员通过摄像头演示一下产品的 用法,沟通ok后,就直接确定购买。

当时我完全不懂flash,而且微软的silverlight也推出了,我一直希望MS能推出更牛叉更容易的解决方案,让我不用学习新语言也能做出 这样类似的应用(当时SL还不支持摄像头),但是一直等啊等(等到花儿也谢了),SL到4.0才支持摄像头,但却没有推出服务端的解决方案,所以目前在这 方面貌似仍然是Adobe领先。

后来换了一家公司也有同类应用(是用As2.0开发的),正好去年底Flash开发人员有事离开了公司,于是在没人接手的情况下,我被迫开始学习 As3.0和FMS,因为As3.0与As2.0几乎完全不兼容(以前的AS2.0代码基本上全看不懂),于是我尝试用As3.0把这套系统重新写了一 遍。

下面是基本结构图,其实说穿了这玩意儿也极其简单

大致原理:

需要做二个flash:一个用于“视频导购员”,即下图中的ChatServer.swf(以下称为服务端),另一个是给“普通访客”用的,即下图 中的ChatClient.swf(以下称为客户端)

二个flash运行时,都先连接到FMS服务器,同时”服务端flash”将用户名等认证信息传输到FMS服务器,FMS服务器再通过ASPX去请 求数据库查询,以验证”导购(客服)员”的信息是否有效,验证通过后FMS服务器允许连接,此时导购员可将自己的的视频与音频向所有连接到自己的访客广 播。

访客可以发送文字信息给导购员,导购员可以通过语音或文字回复。

注:之所以不让访客也能使用摄像头或耳麦,是为了防止有些BT客户播放一些恶作剧的声音或者做一些不雅的动作干扰导购员。同时这样也节省了带宽,否 则的话,就变成一个单纯的视频多人聊天室了 (再演化下去就变成前些年曾盛极一时的~裸~聊@系$统了,呵呵,当然我们都是走正道的人,这种事儿咱不干, 所以我把这个用于电子商务购物平台上的在线视频导购)

这是运行中的基本界面(尚未美化,难看了一点):

这类系统的基本功能:
01.服务端(Flash)能推送摄像头视频和麦克风音频到客户端(Flash).
02.服务端能显示访客列 表,并能从列表中选择需要交谈的对象,实现一对一的视频/语音广播(当然技术上也可以让所有客户听到导购员的声音,这样显得更真实,会让导航员看上去确实 比较忙,能造点气氛,呵呵)
03.服务端能同时接受所有访客的文字消息及系统消息.
04.服务端对指定访客要有屏蔽(黑名单)功能(防止 恶意骚扰)
05.服务端允许设置快速回复,以提高工作效率。

06.服务端允许暂停视频/音频直播,方便偶尔离开的情况,休息回来后,可继续直播。
06.客户端能调节音频的音量大小.
07.客 户端能在线直接截取视频图象并保存.
08.客户端能随时发送文字消息给服务端(前提是未被列为黑名单的情况下)

09.客户端能显示所有在线的导购员列表,并能切换选择不同的导购员视频/音频。

10.客户端能随时接收系统广播。

另外,对了方便运营商管理和监控,以避免发生一些不良现象(比如个人素质不好的导购员,可能会做出一些不雅的动作或姿态),还需要另做一个管理端 Flash,用于实时监控所有在列的导购员视频(就象小区门卫的监控窗口一样),如果发现不良行为,可以强制让导购员下线。

如果需要保存文字聊天记录或记录导购员及访客的登录时间,也可以在FMS服务器上保存每一条详细记录。

主要技术要点:

1.FMS开发中,Application目录下每一个文件夹即为一个应用,所以最简单的解决办法:有多少个导购员,就建多少个文件夹。

2.多个访客连接某一位导购员,其实就是让这些访客与导购员都连接到FMS的某一个文件夹(应用),只不过main.asc中根据不同的身份做出不 同的反馈;访客切换不同的导购员,相当于重新连接新的Application.

3.服务端文本聊天记录的保存,其实只要把每次发送的文字消息trace一下,就会自动记录在FMS的log记录中。

4.导购在线时间的统计,其实也是在main.asc的onConnect、disConnect事件中可以处理。

5.管理端对所有导购员的监控,其实就是在一个Flash中同时创建N个connection,每个conn连接到对应的导购员应用(文件夹)。

6.黑名单或强制下线功能,其实就是在fms服务端disconnect相应的client连接.

7.FMS与数据库的交互可以通过ASP.NET来完成,鉴于as对xml的支持程度极为友好,我个人倾向于让fms去加载一个RESTful的 wcf来获取数据(wcf返回xml格式),需要保存数据时,也可以让fms把数据post或get到某一个RESTful风格的wcf即可.

可能存在的问题:

在某些情况下,管理层可能需要对导购员在线的时间做统计,把这个做为考核绩效的一项指标。这样就存在一个问题,导购员可以一直把摄像头开着,然后人 跑掉了(或者在线看电影而不是在工作),但系统仍然在不停的计时。

为了解决这个bug,可以在服务端Flash中利用Camera的onActivity事件做一些处理,每当摄像头有活动时,该事件会被触发,如果 长时间画面未动,多半就是人跑掉了,可以向FMS服务器自动发送指令,停止计时。如果要做得更精确,flash社区里有一些很NB的大牛们,创造了视频像 素追踪技术,可以检测某个小范围内的像素(BitmapData)变化情况,感兴趣的朋友可以百度,google.

性能及扩展问题:

windows系统下,如果某个目录下的子文件夹数量过多(比如1w个),将会严重影响IO性能(最典型的表现就是进入该目录时,系统响应极慢), 也就是说如果导购员很多,就得分到不同的服务器,这个其实很好解决,多架设几台服务器分散即可,比如1-100个导购员,放在1号服务器,101-200 个导购员放在2号服务器…,当然如果您的money足够多,业内有很多专业做cdn加速和负载均衡的公司,可以实现集群/CDN的的解决方案(不过那 花费可就hign了去了)。

另外,Adobe官方也有相应的集群解决方案:http://files.cnblogs.com/yjmyzz/Flash%2bMedia%2bServer%2b3%e6%8a%80%e6%9c%af%e6%8c%87%e5%8d%97.pdf 这 是“Flash+Media+Server+3技术指南”,里面有一部分提到了集群部署问题,感兴趣的朋友可以下回去研究。

相关基础技术可参见下面的文章:

Flash/Flex学习笔记(10):FMS 3.5之Hello World!

Flash/Flex学习笔记(12):FMS 3.5之如何做视频实时直播

Flash/Flex学习笔记(53):利用FMS快速创建一个文本聊天室

另外FMS3.5安装以后的文档也是极好的参考资料.

后记:

在评论中看到有部分朋友对于这种架构的开发成本(主要是FMS产品的费用)有所担心,其实我很奇怪:大家都在用D版的windows Xp/win7,D版的Office,D版的vs.net,D版的TFS,甚至D版的SQLServer… 好象很少有人担心微软上门来收费,为何就一个FMS,就担心成这样? 🙂

好吧,我承认FMS是收费软件,这确实不能算是这种架构的优势,但其实Adobe是很开放的(不象某水果公司讲的那样),很多标准和协议都是公开 的,所以开源界根据这些标准也有人推出了FMS的替换产品RED5,以下是百度知道上摘抄过来的:

Red5的主要功能和Macromedia公司的FMS类似,提供基于Flash的流媒体服务的一款基于Java的开源流媒体服务器。它由 Java语言编写,使用RTMP作为流媒体传输协议,这与FMS完全兼容。它具有流化FLV、MP3文件,实时录制客户端流为FLV文件,共享对象,实时 视频播放、Remoting等功能。用Red5替换FMS后,客户端不用更改可正常运行。

注意高亮部分,也就是说,如果你拿fms的免费版本做开发,技术成熟以后,如果出于成本考虑,换成red5,flash端是不用做任何修改的,仅服 务端可能需要重新做些调整即可。

另外关于开发工具的选择,其实flash有很多第三方的开发工具,都不要钱的,并非只有Flash CS与Flex Builder/Flash Builder可选。

Flash不仅仅只是一个嵌在网页中的小动画,其实…它也是一个很舞台很大的平台。

作 者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。