Posts Tagged ‘定义’

CSS重新定义项目符号和编号技巧

星期三, 06月 4th, 2008

用过Wordde人都知道Word 有一个“项目符号和编号”de功能,用起来很方便.Dreamweaver3de属性面板也有一个类似有de“项目符号和编号”de图标按钮,产生自动列表功能, 但它只有两种形式,即方块和阿拉伯数字.不过我可以利用Dreamweaver3deCSS定义功能去重新定义“列表符号de格式”.下面以定义一个“大写 罗马数字项目列表符号”为例来说明其使用方法:

1、按F7(或点击快速启动栏里那个象“八卦图”似de图标),调出CSS面板,选择 “none”,再点击面板下部de编辑图标,在弹出de“Edit Style Sheet”对话框上按“New”按钮,在弹出de“New Style”对话框中选择“Redifine HTML TAG(重定义HTML标记)”后,在下面de“Tag”选择框中选择“ol”,按OK,立即弹出“Style Definition for ol”对话框,如下图所示:

在“Style Definition for ol”对话框左边de选择窗口中选择“list”,在右边de面板上我只要定义“Type”就行了,点一下右边那个三角形按钮,可看到如下图所示de列表:

2、我来解释一下上图中这个列表中各项de含义:

disc:实心圆;

circle:空心圆;

square:实心方块;

decimal:十进制数字;

lower-roman:小写罗马数字;

upper-roman:大写罗马数字;

lower-alpha:小写英文字母;

upper-alpha:大写英文字母;

none:不显示项目符号和编号.

很显然,在本例中要选择“upper-roman”,然后按OK返回(要注意 “Bullet”属性现在不要选,否则有可能就不是预期de结果了).在“Edit Style Sheet”对话框上按“Done”按钮结束.在网页源相关代码de〈head〉与〈/head〉之间见到deCSS相关代码是这样de:

〈style type=”text/css”〉

〈!–

ol { list-style-type: upper-romancircle}

–〉

〈/style〉

对于不是使用Dreamweaver3de网友,直接把上述相关代码复制在〈head〉与〈/head〉之间,产生de效果相同.

3、这样当我在设计网页时,在属性面板上点击项目编号图标

就能获得大写罗马数字de列表了,但在编辑时看到de还是十进制编号,只有在浏览时才显示其本来面目.若需要其它格式de编号,只要在第二步中选择列表中de其它样式就行了.

若是要使按下

图标后,项目符号前面那个图形(默认de是实心方块)也改变为数字编号,只要在第一步中选择“Tag”标记时不要选“ol”而改为选“ul”,其它操作完全相同.如要把它改成用大写罗马数字项目符号,则得到deCSS相关代码是这样de:

〈style type=”text/css”〉

〈!–

ul { list-style-type: upper-romancircle}

–〉

〈/style〉

从这里可以看,这两个图标所起de作用基本相同,只是标记不同而已.

定义标题的最好方法

星期三, 06月 4th, 2008

作者:阿宏 2005-4-15 20:45:18
原文:What is the Best Way to Mark up the Title of a Document?
说明:本文是 《Web Standards Solutions: The Markup and Style Handbook》一书中de一章.书号:ISBN:1590593812.我会陆续翻译此书中有价值de章节.
原作者:Dan Cederholm
翻译:阿宏
一个文档标题,最好de定义方法是什么?要回答这个问题,先设想我要在一个页面上定义文章de标题,通常我有三个方法来实现这个简单目de:

方法一: 有意义吗?
<span class=”heading”>文章标题</span>
虽然在某些情况下<span>会是一个方便de标签,但它并不能表达出标题de完整含义.采用这个方法de一个好处是,我可以对它附加一个CSS规则,分配其一个heading class,使其文字象标题一样显示.

.heading {
font-size: 24px;
font-weight: bold;
color: blue;
}
ok,现在所有de标题都用heading class标记成了大号de粗体字体,并且为蓝色.太棒了!但是这样做对吗?如果有人用一个不支持CSSde浏览器来观看,会怎样呢?

举个例子,如果我设置de这个外部样式表de规则不被老版本de浏览器支持,会怎样?又或者有视觉障碍de人用屏幕阅读器来阅读这个页面,又会怎样?一个访问者通过这些途径所看到(或听到)de应该和这个页面上正常de文本没有任何区别.

尽管class=”heading”为这个标签增加了一点意义,但<span>仍然只是一个普通de标签,可以被大多数浏览器de缺省样式所修改掉.

搜索引擎检索这个页面时会略过<span>标签,就好象它不存在一样,不会对其可能包含de关键字给于一点额外de重视.在后面我会更多de谈到搜索引擎和标题de关系.

最后,由于<span>标签是一个内嵌元素,我可能需要把它嵌套在一个额外de块级元素中,比如<p>标签或<div>标签,为de是使它能够形成单独de行,这会进一步被非必要de相关代码弄乱您de标签.而这些额外增加de标签却是必须de,这样才能使不支持CSSde浏览器显示出没有差别de文本.

方法二:<p>和<b>组合
<p><b>文章标题</b></p>
使用一个段落标签,将会给我带来块级de显示,<b>会把文本变成粗体.但是用这个方法标记一个重要de标题时,我面对de是同样无意义de结果.

不象方法A,<b>标签能在可视化de浏览器中把文字显示成粗体——甚至在不支持CSSde浏览器中.但是和<span>标签一样,搜索引擎也不会因为有一些东西在段落中被加粗了而给予更高de优先.

难以设计样式

用普通de<p>和<b>de组合,也带来了另一个缺憾——无法把这个标题设计成不同于其他段落de样式.我可能想用一个特别de样式来突出标题,来使页面内容更清晰更具结构,但是用这个方法只能使其显示成粗体.

方法三:样式加实质
<h1>文章标题</h1>
恩,多么好de标题定义.大多数de网页设计者对它都很熟悉.其实适当de使用它们,<Hn> 就能为页面内容提供灵活de、可索引de、以及可样式化de结构.

这也是聪明de定义方法,您会发现它很简单.不再需要额外de标签,您可以说,这仅仅比另外两个方法节省了一点点de字节,可以忽略不计,但节省一点是一点.

<h1>一直到<h6>,代表了标题de六个级别,从最重要de(<h1>)到最次要de(<h6>).他们本身就是块级de,不需要增加其它元素来使其单独成行.简单,有效——就是好工具.

轻松定制样式

因为我使用<h1>标签是唯一de,而<b>或<p>标签更适合使用在整个页面,所以我可以用各种各样deCSS方法来样式化.

更重要de是,尽管完全不用样式,一个标题标签也能明显de表示出一个标题!可视化de浏览器把 <h1>显示成更大de粗体.一个非样式化de页面将以被期望de那样显示文档结构,用适当de标题标签来传达意思.

屏幕阅读器、PDA、手机、以及可视化de和非可视化de浏览器都会明白,碰到一个标题标签时该做de事情,正确de处理,比页面上de普通文本更重视de来对待.而使用<span>标签,那些不支持CSSde浏览器就不会特别de对待它.

讨厌de默认样式

以往,由于浏览器默认de缺省值非常de丑陋,设计者们也许会避免完全de使用标题标签.或者,因为缺省值de巨大尺寸而避免使用<h1>或<h2>,取而代之de是用更高数值de标题标签来实现更小de尺寸.

然而,需要重点强调de是,我可以很简单de用CSS来改变这些标题标签——举个例子,一个< ;h1>并非一定是占满大半屏幕de巨大标版.在后面,我将证明用CSS来样式化标题标签是多么de简单,希望可以帮助您减轻巨大de恐惧.

对搜索引擎友好de

这是一个巨大de好处.搜索引擎喜欢标题标签.另一方面,一个<span>标签或者普通de加粗de段落标签却在意味着次要一点.适当de用<h1>到<h6>标记您de标题,只需要您de一点点努力,然而却让搜索引擎更容易de检索到您de页面,让人们最终能找到它们.

搜索引擎机器人会给予标题标签特别de关注——这是您可能放置一些关键词de地方.就象检索到 <title>和<meta>,它们会顺着标题标签往页面下面查找.如果您不使用这些标签,那么包含在里面de关键词将不会被认为是有价值de,从而被忽略掉.

所以只要付出一点点de努力,您就能增加人们基于页面de内容找到您de站点de可能性.听上去不错,不是吗?

关于标题de次序
在例子中,这个特别de标题是页面中最重要de,因为它是文档de标题.因此,我使用最重要de标题标签,<h1>.顺应W3Cde规范,一些人认为跳过数个标题级是个不好de使用.举个例子,想象我在下面de页面:

<h1>文章标题</h1>
我接下去de标题(如果不是用另一个<h1>重复de话)应该是<h2>,然后是<h3 >,等等.您也许不应该在<h1>后面跳过一级,直接跟上<h3>.我倾向于同意以上de观点,顺着行文保持级别de连续性,来构造一个排版结构.这样de话,给一个已经存在de页面添加标题和样式就更容易了,您会减少因使用超出de数字而导致de错误.

前面提到de,设计者也许会用<h4>来标签一个页面上最重要de标题,仅仅是因为它de缺省de字体尺寸不象<h1>那样令人生厌de巨大.但是记住,先结构,后设计.我总是能用CSS来把标题样式化成任何我喜欢de文字尺寸.

利用CSS,链接下划线也玩自定义

星期三, 06月 4th, 2008

  原文链接:CSS Design: Custom Underlines

  由 A List Apart 杂志及作者授权翻译.(Translated with the permission of A List Apart Magazine and the author[s].)

  说明:文章中“[补充]”内容系译者所补充添加(来自 CSS 2.0 中文手册),目de是方便读者理解相关内容.

  虽然网页设计师通常有大量de方法控制文档如何呈现,但是基本deCSS不能为页面中链接下方de下划线样式提供很多选择.不过只需一点小技巧,您就能获得链接样式显示方式de创作控制.

  自定义下划线给一些合适de网站以新de创作机会.自定义下划线还能够被用于为包含在同一个页面中de不同链接提供额外de视觉线索.

开始

  您应该从为您下划线创建图形开始.该图将会水平de重复,而如果您希望(网页)背景能够完全显示de话,您需要创建一个透明de.gif文件.

  如果您de下划线图形有几像素高,那么您应该增加de文本deline-height(行距),以增加上一行底部与下一行顶部de之间de空间.

p { line-height: 1.5; }

————————————————-

[补充]

语法:

  line-height : normal | length

取值:

  normal : 默认值.默认行高
  length : 百分比数字 | 由浮点数字和单位标识符组成de长度值,允许为负值.其百分比取值是基于字体de高度尺寸.请参阅 长度单位

说明:

  检索或设置对象de行高.即字体最底端与字体内部顶端之间de距离.
  行高是字体下延与字体内部高度de顶端之间de距离.为负值de行高可用来实现阴影效果.
  假如一个格式化de行包括不止一个对象,则最大行高会被应用.在这种情况下,此属性不可以为负值.
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 lineHeight .

————————————————-

  在能为链接创建自定义下划线之前,我需要移除已经存在de下划线:

a { text-decoration: none; }

————————————————-

[补充]

语法:

  text-decoration : none || underline || blink || overline || line-through

取值:

  none : 默认值.无装饰
  blink : 闪烁
  underline : 下划线
  line-through : 贯穿线
  overline : 上划线

说明:

  检索或设置对象中de文本de装饰.
  有 href 特性de a ,以及 u , ins 对象默认值为 underline .
  对象 strike , s , del ,默认值是 line-through .
  假如 none 值在属性声明de最后,所有de先前de其他取值都会被清除.例如,声明 text-decoration: underline overline blink none 等于声明 text-decoration: none .
  假如对象没有文本(如 img 元素)或者是空元素(如:), 此属性不会发生作用.
  假如您设置 body 对象de此属性值为 none , a 对象将依然保持其原有de下划线样式.除非您针对 a 对象声明此属性值.
  指定块对象de此属性将影响其所有内联子对象.而此影响一旦发生,块对象容器最终会受到影响.
  在IE4 中可用de值为 overline 和 blink .虽然 blink 值被提供,但它不会被作用.
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 textDecoration .

————————————————-

  为了创建自定义de下划线,我为链接元素设置背景图像:

a { background-image: url(underline.gif); }

————————————————-

[补充]

语法:

  background-image : none | url ( url )

取值:

  none : 默认值.无背景图
  url ( url ) : 使用绝对或相对 url 地址指定背景图像

说明:

  设置或检索对象de背景图像.
  当背景图像与背景颜色( background-color )都被设定了时,背景图片将覆盖于背景颜色之上.
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 backgroundImage .

————————————————-

  我希望这个图像在文本底部顺着水平方向重复而不是垂直方向,否则它就将显示在链接文本自身de后面.我限制背景图像沿着X轴重复:

a { background-repeat: repeat-x; }

————————————————-

[补充]

语法:

background-repeat : repeat | no-repeat | repeat-x | repeat-y

取值:

repeat : 默认值.背景图像在纵向和横向上平铺
no-repeat : 背景图像不平铺
repeat-x : 背景图像仅在横向上平铺
repeat-y : 背景图像仅在纵向上平铺

说明:

  设置或检索对象de背景图像是否及如何铺排.必须先指定对象de背景图像( background-image ).
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 backgroundRepeat .

————————————————-

  不管字体de大小如何,为了保证我de图像都出现在链接文本de下面,我将要使用background-position(背景定位)属性定位图像至链接元素de底部.对于某些背景图形,例如箭头,对图像对齐元素de哪一边,您或许有自己de偏好.就我这个例子而言,我将背景置于底部de右边:

a { background-position: 100% 100%; }

————————————————-

[补充]

语法:

  background-position : length || length
  background-position : position || position

取值:

  length : 百分数 | 由浮点数字和单位标识符组成de长度值.请参阅 长度单位
  position : top | center | bottom | left | center | right

说明:

  设置或检索对象de背景图像位置.必须先指定 background-image 属性.
  该属性定位不受对象de补丁属性( padding )设置影响.
  默认值为: 0% 0% .此时背景图片将被定位于对象不包括补丁( padding )de内容区域de左上角.
  如果只指定了一个值,该值将用于横坐标.纵坐标将默认为 50% .如果指定了两个值,第二个值将用于纵坐标.
  如果设置值为 right center ,因为 right 作为横坐标值将会覆盖 center 值,所以背景图片将被居右定位.
  对应de脚本特性为 backgroundPosition .

————————————————-

  为了给链接文本正文de自定义下划线图形创建空间,我将增加一些padding(填充).依赖于所使用字体de大小,下划线图形de精确位置将会相对于链接文本de基线发生改变.建议您从bottom-padding开始,与下划线图形高度同高,调整以适合于您de需要:

a { padding-bottom: 4px; }

————————————————-

[补充]

语法:

  padding-bottom : length

取值:

  length : 由浮点数字和单位标识符组成de长度值 | 或者百分数.百分数是基于父对象de宽度.不允许负值.

说明:

  检索或设置对象底边de内补丁.对于 td 和 th 对象而言默认值为 1 .其他对象de默认值为 0 .
  在IE5.5 中此属性支持内联对象使用.而在此前de版本中,内联要素要使用该属性,必须先设定对象de height 或 width 属性,或者设定 position 属性为 absolute ,或者设定 display 属性为 block .
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 paddingBottom .

————————————————-

  因为下划线图形是定位于链接元素de底部,所以我需要保证链接不能横跨多行(如果他们被允许跨越多行,那么只有最低de一行链接文本显示自定义下划线).我将使用CSSdewhite-space属性禁止链接文本换行.

a { white-space: nowrap; }

————————————————-

[补充]

语法:

  white-space : normal | pre | nowrap

取值:

  normal : 默认值.默认处理方式.文本自动处理换行.假如抵达容器边界内容会转到下一行
  pre : 换行和其他空白字符都将受到保护.这个值需要IE6 或者 !DOCTYPE 声明为standards-compliant mode 支持.如果 !DOCTYPE 声明没有指定为 standards-compliant mode ,此属性可以使用,但是不会发生作用.结果等同于 normal .参阅 pre 对象
  nowrap : 强制在同一行内显示所有文本,直到文本结束或者遭遇 br 对象.参阅 noWrap 属性

说明:

  设置或检索对象内空格字符de处理方式.
  空格字符,像换行,空格,TAB,在HTML文档中默认de是被忽略de.当此属性设置为 normal 或者 nowrap 时,您可以使用不换行空格de命名实体 来添加空格,用 br 元素来添加换行.
  此属性对您使用文档对象模型(DOM)操作de内容de影响与其对IE显示内容de影响一样.
  此属性作用于块对象.
  此属性对于 currentStyle 对象而言是只读de.对于其他对象而言是可读写de.
  对应de脚本特性为 whiteSpace .

————————————————-

  链接元素de所有CSS属性可以合并为:

a {
text-decoration: none;
background: url(underline.gif) repeat-x 100% 100%;
padding-bottom: 4px;
white-space: nowrap;
}

  如果您想自定义下划线de效果只在鼠标滑过链接时出现,只需设置CSS背景属性为:hover伪类,取代直接设置于链接元素上de样式即可.

a {
text-decoration: none;
padding-bottom: 4px;
white-space: nowrap;
}

a:hover {
background: url(underline.gif) repeat-x 100% 100%;
}

示例

WEB标准字体常规定义

星期三, 06月 4th, 2008

web标准推荐如下字体定义方法:
body { font-family : “Lucida Grande”, Verdana, Lucida, Arial, Helvetica, 宋体,sans-serif; }
* 字体按照所列出de顺序选用.如果用户de计算机含有Lucida Grande字体,文档将被指定为Lucida Grande.没有de话,就被指定为Verdana字体,如果也没有Verdana,就指定为Lucida字体,依此类推.
* Lucida Grande字体适合Mac OS X;
* Verdana字体适合所有deWindows系统;
* Lucida适合UNIX用户
* “宋体”适合中文简体用户;
* 如果所列出de字体都不能用,则默认desans-serif字体能保证调用.

获取转向地址的URL的源文件(可自定义REFER)

星期二, 06月 3rd, 2008

软件下载:
http://test.fzclx.com/caixi/geturl.rar

程式源文件:
CS打包:http://test.fzclx.com/caixi/geturl.cs.rar

c#写de,可能要先安装framework.
http://www.microsoft.com/downloads/info.aspx?na=0&p=4&SrcDisplayLang=zh-cn&SrcCategoryId=&SrcFamilyId=&genscs=&u=/downloads/details.aspx?FamilyID=262d25e3-f589-4842-8157-034d1e7cf3a3&displaylang=zh-cn

下面是相关代码:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.IO;
namespace WindowsApplication4
{
/// <summary>
/// Form1 de摘要说明.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox realurl;
private System.Windows.Forms.TextBox formurl;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox formreferer;
private System.Windows.Forms.Panel panel1;
/// <summary>
/// 必需de设计器变量.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗体设计器支持所必需de
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数相关代码
//
}
/// <summary>
/// 清理所有正在使用de资源.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成de相关代码
/// <summary>
/// 设计器支持所需de方法 - 不要使用相关代码编辑器修改
/// 此方法de内容.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
this.formurl = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.realurl = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.formreferer = new System.Windows.Forms.TextBox();
this.panel1 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// formurl
//
this.formurl.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.formurl.ForeColor = System.Drawing.SystemColors.WindowText;
this.formurl.Location = new System.Drawing.Point(24, 32);
this.formurl.Name = "formurl";
this.formurl.Size = new System.Drawing.Size(288, 21);
this.formurl.TabIndex = 0;
this.formurl.Text = "http://";
this.formurl.TextChanged = new System.EventHandler(this.formurl_TextChanged);
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.label2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label2.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.label2.Location = new System.Drawing.Point(24, 16);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(128, 17);
this.label2.TabIndex = 2;
this.label2.Text = "输入您要获取de网址:";
this.label2.Click = new System.EventHandler(this.label2_Click);
//
// button1
//
this.button1.ForeColor = System.Drawing.Color.FromArgb(((System.Byte)(64)), ((System.Byte)(64)), ((System.Byte)(64)));
this.button1.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
this.button1.Location = new System.Drawing.Point(320, 32);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(56, 64);
this.button1.TabIndex = 3;
this.button1.Text = "获取…";
this.button1.Click = new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.label1.Location = new System.Drawing.Point(24, 104);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(128, 17);
this.label1.TabIndex = 5;
this.label1.Text = "真实de网址:";
this.label1.Click = new System.EventHandler(this.label1_Click);
//
// realurl
//
this.realurl.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.realurl.ForeColor = System.Drawing.Color.OrangeRed;
this.realurl.Location = new System.Drawing.Point(24, 120);
this.realurl.Name = "realurl";
this.realurl.Size = new System.Drawing.Size(352, 21);
this.realurl.TabIndex = 4;
this.realurl.Text = "";
//
// label3
//
this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.label3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label3.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.label3.Location = new System.Drawing.Point(24, 56);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(128, 17);
this.label3.TabIndex = 7;
this.label3.Text = "伪装来路:";
//
// formreferer
//
this.formreferer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.formreferer.Location = new System.Drawing.Point(24, 72);
this.formreferer.Name = "formreferer";
this.formreferer.Size = new System.Drawing.Size(288, 21);
this.formreferer.TabIndex = 6;
this.formreferer.Text = "http://";
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.LightGray;
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel1.Location = new System.Drawing.Point(18, 13);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(364, 130);
this.panel1.TabIndex = 8;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
this.ClientSize = new System.Drawing.Size(392, 165);
this.Controls.Add(this.label3);
this.Controls.Add(this.formreferer);
this.Controls.Add(this.label1);
this.Controls.Add(this.realurl);
this.Controls.Add(this.button1);
this.Controls.Add(this.label2);
this.Controls.Add(this.formurl);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "取得真实URL — 落伍decaixi www.im286.com";
this.Load = new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 应用程序de主入口点.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
}
private void label2_Click(object sender, System.EventArgs e)
{
}
private void button1_Click(object sender, System.EventArgs e)
{
string Theurl=formurl.Text;
string Referurl=formreferer.Text;
if (Theurl.Length<10)
{
MessageBox.Show("兄弟,URL不正确吧","URL不正确");
formurl.Focus();
}
else
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(Theurl);
myReq.Referer=Referurl;
HttpWebResponse myres=(HttpWebResponse)myReq.GetResponse();
bool hasChanged = (myReq.RequestUri != myReq.Address);
string geturl;
if (hasChanged){
geturl=myReq.Address.ToString();
}
else{
geturl=myReq.RequestUri.ToString();
}
realurl.Text=geturl;
realurl.Focus();
}
}
private void label1_Click(object sender, System.EventArgs e)
{
}
private void formurl_TextChanged(object sender, System.EventArgs e)
{
}
}
}

在.NET2.0中使用自定义事务操作

星期二, 06月 3rd, 2008

  .net 2.0 framework 中新增了 System.Transactions 命名空间,其中提供de一系列接口和类使得在.net 2.0 中使用事务比起从前要方便了许多.有关在 .net 2.0 下操作数据库事务de文章已经有了很多,这里只提一下如何设计自定义事务操作.
  一、事务使用基础
  先看一段使用事务de相关代码:
1using (TransactionScope ts= new TransactionScope())
2{
3 //自定义操作
4 ts.Complete();
5}
  这里使用 using 语句定义了一段隐性事务.如果我在该语句块中加入一段对 SQL Server 操作de相关代码,那么它们将会自动加入这个事务.可以看出,这种事务de使用方式是极其方便de.
  那么,有没有可能在该语句块中加入我自己定义de事务操作,并且该操作能够随着整个事务块de成功而提交,随其失败而回滚呢?答案当然是可以de,否则我就不会写这篇随笔了.
  二、实现自定义事务操作
  根据事务de特性,我可以推想:这个操作必须有实现提交和回滚之类动作de方法.没错,这就是 System.Transactions 命名空间中de IEnlistmentNotification 接口.我先写一个最简单de实现:
1class SampleEnlistment1 : IEnlistmentNotification
2{
3 void IEnlistmentNotification.Commit(Enlistment enlistment)
4 {
5 Console.WriteLine(”提交!”);
6 enlistment.Done();
7 }
8
9 void IEnlistmentNotification.InDoubt(Enlistment enlistment)
10 {
11 throw new Exception(”The method or operation is not implemented.”);
12 }
13
14 void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
15 {
16 Console.WriteLine(”准备!”);
17 preparingEnlistment.Prepared();
18 }
19
20 void IEnlistmentNotification.Rollback(Enlistment enlistment)
21 {
22 Console.WriteLine(”回滚!”);
23 enlistment.Done();
24 }
25}
26
27
  好,定义完之后,还需要向事务管理器进行注册,把它加入到当前事务中去:
1using (TransactionScope ts= new TransactionScope())
2{
3 SampleEnlistment1 myEnlistment1 = new SampleEnlistment1();
4 Transaction.Current.EnlistVolatile(myEnlistment1, EnlistmentOptions.None);
5 ts.Complete();
6}
  执行这一段相关代码,我可以得到以下de输出:
  准备!
  提交!
  先解释一下,当调用 ts.Complete() 方法de时候,表示事务已成功执行.随后,事务管理器就会寻找当前所有已注册de条目,也就是 IEnlistmentNotification de每一个实现,依次调用它们de Prepare 方法,即通知每个条目做好提交准备,当所有条目都调用了 Prepared() 表示自己已经准备妥当之后,再依次调用它们de Commit 方法进行提交.如果其中有一个没有调用 Prepared 而是调用了 ForceRollback de话,整个事务都将回滚,此时事务管理器再调用每个条目de Rollback 方法.
  而如果我将前面de ts.Complete() 行注释掉,显然执行结果就将变为:
  回滚!
  三、一个实现赋值de自定义操作
  考虑一下,我要实现一个事务赋值操作.该如何做法?以下是一个例子:
1class SampleEnlistment2 : IEnlistmentNotification
2{
3 public SampleEnlistment2(AssignTransactionDemo var, int newValue)
4 {
5 _var = var;
6 _oldValue = var.i;
7 _newValue = newValue;
8 }
9
10 private AssignTransactionDemo _var;
11 private int _oldValue;
12 private int _newValue;
13
14 void IEnlistmentNotification.Commit(Enlistment enlistment)
15 {
16 _var.i = _newValue;
17 Console.WriteLine(”提交!ide值变为:” _var.i.ToString());
18 enlistment.Done();
19 }
20
21 void IEnlistmentNotification.InDoubt(Enlistment enlistment)
22 {
23 throw new Exception(”The method or operation is not implemented.”);
24 }
25
26 void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
27 {
28 preparingEnlistment.Prepared();
29 }
30
31 void IEnlistmentNotification.Rollback(Enlistment enlistment)
32 {
33 _var.i = _oldValue;
34 Console.WriteLine(”回滚!ide值变为:” _var.i.ToString());
35 enlistment.Done();
36 }
37}
38
39class AssignTransactionDemo
40{
41 public int i;
42
43 public void AssignIntVarValue(int newValue)
44 {
45 SampleEnlistment2 myEnlistment2 = new SampleEnlistment2(this, newValue);
46 Guid guid = new Guid(”{3456789A-7654-2345-ABCD-098765434567}”);
47 Transaction.Current.EnlistDurable(guid, myEnlistment2, EnlistmentOptions.None);
48 }
49}
50
51
  然后,这样来使用:
1AssignTransactionDemo atd = new AssignTransactionDemo();
2atd.i = 0;
3using (TransactionScope scope1 = new TransactionScope())
4{
5 atd.AssignIntVarValue(1);
6 Console.WriteLine(”事务完成!”);
7 scope1.Complete();
8 Console.WriteLine(”退出区域之前,ide值为:” atd.i.ToString());
9}
10Thread.Sleep(1000);
11Console.WriteLine(”退出区域之后,ide值为:” atd.i.ToString());
  运行这一段相关代码,我可以看到如下结果:
  事务完成!
  退出区域之前,ide值为:0
  提交!ide值变为:1
  退出区域之后,ide值为:1
  从输出结果来看,赋值操作被成功执行了.可是有没有感觉有些奇怪?先做个讨论:
  1、如果前面没有 Thread.Sleep(1000) 这一行,那么我多半会看到最后一行de输出中,i de值依然会是 0!为什么?想想就容易明白,这里对 Commit 方法是采用de异步调用,如同另开了一个线程.如果主线程不作等待de话,当输出de时候事务de Commit 方法多半还没有被执行,输出de结果当然就会不对.
  2、这个例子中,赋值操作是在 Commit 方法中才实际执行de.但实际上就本例而言,我也可以做个调整:将赋值操作放在 AssignIntVarValue 方法de最后去执行,然后把 Commit 方法中de赋值操作去掉.相关de相关代码变化如下:
1class SampleEnlistment2 : IEnlistmentNotification
2{
3 void IEnlistmentNotification.Commit(Enlistment enlistment)
4 {
5 enlistment.Done();
6 }
7 //其它略
8}
9
10class AssignTransactionDemo
11{
12 public int i;
13
14 public void AssignIntVarValue(int newValue)
15 {
16 SampleEnlistment2 myEnlistment2 = new SampleEnlistment2(this, newValue);
17 Guid guid = new Guid(”{3456789A-7654-2345-ABCD-098765434567}”);
18 Transaction.Current.EnlistDurable(guid, myEnlistment2, EnlistmentOptions.None);
19 i = newValue;
20 Console.WriteLine(”提交前改变!ide值为:” i.ToString());
21 }
22}
23
24
  这样,执行结果将会变为:
  提交前改变!ide值为:1
  事务完成!
  退出区域之前,ide值为:1
  退出区域之后,ide值为:1
  3、在前面de基础上,当把调用de地方作如下改动,使事务失败:
1using (TransactionScope scope1 = new TransactionScope())
2{
3 atd.AssignIntVarValue(1);
4 Console.WriteLine(”事务失败!”);
5 //scope1.Complete();
6 Console.WriteLine(”退出区域之前,ide值为:” atd.i.ToString());
7}
  此时de执行结果将变为:
  提交前改变!ide值为:1
  事务失败!
  退出区域之前,ide值为:1
  回滚!ide值变为:0
  退出区域之后,ide值为:0
  可见,事务已成功回滚.
  四、进一步de讨论
  前面我都是只进行了一次赋值操作,如果我需要进行两次呢?
1using (TransactionScope scope1 = new TransactionScope())
2{
3 atd.AssignIntVarValue(1);
4 atd.AssignIntVarValue(2);
5 Console.WriteLine(”事务失败!”);
6 //scope1.Complete();
7 Console.WriteLine(”退出区域之前,ide值为:” atd.i.ToString());
8}
  这时de执行结果将会是如何?我当然是希望回滚de时候,i de值能先变回为 1,再变回为 0.但是实际结果呢?
  提交前改变!ide值为:1
  提交前改变!ide值为:2
  事务失败!
  退出区域之前,ide值为:2
  回滚!ide值变为:0
  回滚!ide值变为:1
  退出区域之后,ide值为:1
  显然,事务de回滚并没有按照我希望de顺序来,是何原因?分析一下机制就能知道,事务管理器向每个条目发出回滚命令de时候只是发出了一个异步调用,并且很可能还是按登记de顺序来发出de,这样一来,Rollback 方法de调用顺序显然就不能保证了.
  这时,如果将 Rollback 方法作一个小调整:
1void IEnlistmentNotification.Rollback(Enlistment enlistment)
2{
3 while (_var.i != _newValue)
4 {
5 Thread.Sleep(500);
6 }
7 _var.i = _oldValue;
8 Console.WriteLine(”回滚!ide值变为:” _oldValue.ToString());
9 enlistment.Done();
10}
  再次运行之,结果就对了:
  提交前改变!ide值为:1
  提交前改变!ide值为:2
  事务失败!
  退出区域之前,ide值为:2
  回滚!ide值变为:1
  回滚!ide值变为:0
  结果de正确其实并不是调用de顺序就对了,只是 Rollback 方法在执行de时候先检查一下 _newValue de值是否与当前 i de值一致,不一致de话就等上一会儿.在等待de过程中,另一个实例de Rollback 方法被执行,而它检查发现是匹配de,所以就会回滚到 1.第一个 Rollback 等待结束后再检查发现匹配了,于是就回滚为 0.
  当然实际应用中,这种方法是极不可取de.且不说执行顺序依然会有很大de风险,光是设计方式就有大问题.那么在实际应用中我应当如何去做呢?这里只提供一下设计思想,具体de实现相关代码不再列出了.
  在前面de例子中,两次赋值共进行了两次登记,这一点是引发不稳定性de起因.我应当考虑,两次赋值依然只登记一次,在第一次赋值de时候,建立一个 SampleEnlistment2 de实例并在 AssignTransactDemo 中保存下来,并且 SampleEnlistment2 需要记录当前de操作.下一次赋值时,仍然使用这个实例,只进行操作记录即可.这样,当回滚de时候,它根据记录de反顺序执行回滚操作就可以了.
  再进一步呢?如果说有多个 Transaction 需要进行赋值操作呢?这时我可以在 AssignTransactionDemo 类中加入一个 Dictionary<Transaction, SampleEnlistment2>,使用de时候根据 Transaction 去寻找相应de条目即可.
  本文讨论暂到此为止.在微软de101个例子中,有一个使用事务进行文件拷贝de例子.那里面有比较深入de实现.如果您还没有看过,推荐去研究一下,相信您读过此篇随笔,研究它应当不再是个难题.

ASP.NET2.0服务器控件之自定义状态管理

星期二, 06月 3rd, 2008

在前面de系列文章中,我曾经介绍了视图状态和控件状态de基本概念和典型应用,从中可以发现,视图状态和控件状态对于自定义服务器控件实现de重要性.本文将继续这一主题,重点介绍实现视图状态和控件状态自定义管理de方法.
  自定义视图状态管理
  在介绍视图状态时,我曾经提到过:对于简单属性,例如,String、Int等类型,.NET执行引擎将自动启用默认视图状态管理机制,以便完成相应de功能.然而,如果开发人员在ViewState中保存de是自定义数据类型,或者需要实现自定义方式优化视图状态管理时,则必须实现自定义视图状态管理.
  实现自定义视图状态管理可以通过两种方法.方法一:实现System.Web.UI命名空间中deIStateManager接口成员,其中包括IsTrackingViewState属性和TrackViewState、SaveViewState和LoadViewState方法.这种方法主要是针对自定义数据类型de视图状态管理de情况.方法二:重写Control基类de3个视图状态管理方法:TrackViewState、SaveViewState和LoadViewState.这些方法与IStateManager接口定义de3个方法名称一致.这种方法主要用于通过自定义方式优化默认视图状态管理de情况,其主要目de在于提高效率和性能.掌握以上两种实现方法de捷径是,必须深刻理解.NET框架内部实现视图状态管理de过程.下面两小节内容都是有关内部实现方法de介绍.每一节中均有实现相关代码,实际就相当于实例相关代码.所有服务器控件de自定义视图状态管理de实现都不会偏离那些相关代码所表达de逻辑.当读者真正掌握了那些内部实现方法,那么自定义视图状态管理de实现方法也就迎刃而解了.
  1、实现基于IStateManager接口de自定义视图状态管理
  对于复杂属性而言,多数需要实现自定义视图状态管理,其关键是实现System.Web.UI.IStateManager接口中定义de方法和属性.下面列举了IStateManager接口定义相关代码.
public interface IStateManager{ bool IsTrackingViewState {get;} void LoadViewState(object state); object SaveViewState(); void TrackViewState();}
  如上相关代码所示,IStateManager接口要求类实现IsTrackingViewState属性,以及LoadViewState、SaveViewState和TrackViewState方法.IsTrackingViewState属性定义,当由类实现时,获取一个布尔值,通过该值指示服务器控件是否正在跟踪其视图状态更改.如果服务器控件正在跟踪其视图状态更改,则为true;否则为false.SaveViewState方法定义,当由类实现时,将服务器控件de视图状态更改保存到Object中.LoadViewState方法定义,当由类实现时,加载服务器控件以前保存de控件视图状态,其中de参数state表示包含控件保存de视图状态值deObject.TrackViewState方法定义,当由类实现时,指示服务器控件跟踪其视图状态更改.
  ViewState属性与IStateManager接口之间存在密切联系.ViewState属性de类型是StateBag类,StateBag类通过实现IStateManager接口中定义de方法和属性来参与状态管理.其实现过程如下.
public sealed class StateBag : IStateManager, IDictionary,ICollection, IEnumerable{
 private bool _isTrackingViewState;
 private ArrayList _keys;
 private ArrayList _values;
 private StateItem _item;
 bool IStateManager.IsTrackingViewState {
  get { return _isTrackingViewState; }
 }
 void IStateManager.TrackViewState() {
  _isTrackingViewState = true;
 }
 object IStateManager.SaveViewState() {
  _keys = new ArrayList();
  _values = new ArrayList();
  IDictionaryEnumerator myDirctionaryEnumerator = this.GetEnumerator();
  while(myDictionaryEnumerator.MoveNext()) {
   if(this.Item[(String)myDictionaryEnumerator.Key].IsDirty) {
    _keys.Add(myDictionaryEnumerator.Key);
    _values.Add(myDictionaryEnumerator.Value);
   }
  }
  if(_keys.Count>0) {
   return new Pair(_keys,_values);
  }
 }
 void IStateManager.LoadViewState(object savedState) {
  if(savedState is Pair) {
   _keys = (ArrayList)tempP.First;
   _values = (ArrayList)tempP.Second;
   IDictionaryEnumerator myDirctionaryEnumerator = this.GetEnumerator();
   while(myDictionaryEnumerator.MoveNext()) {
    for(int j=0;j<_keys.Count;j )
    {
     if((String)myDictionaryEnumerator.Key == _keys[j].ToString());
     {
      this.Item[_keys[j].ToString()].Value = (object)_values[j];
     }
    }
   }
  }
 }
}

  请读者注意:以上相关代码为示意性相关代码,并非严格意义上de实现相关代码.在此列出,主要是用于说明StateBag类实现IStateManager接口de逻辑过程.
  通过上面de相关代码,我可以看到:
  (1)在IsTrackingViewState属性中,将该属性设置为只读,并且使用私有变量_isTrackingViewState.
  (2)在TrackViewState方法中,把IsTrackingViewState属性使用de私有变量_isTrackingViewState设置为true,这指示系统当某个StateItem添加到StateBag中,或者某个StateItem值被修改时,StateBag类就会自动将该StateItem标记为修改过即添加dirty标记.
  (3)在SaveViewState方法中,循环StateBag中de每个StateItem,如果该StateItem被标记为dirty,那么就将其键和值分别添加到两个ArrayList中,并返回该对象.
  (4)在LoadViewState方法中,执行了与SaveViewState方法相反de操作.首先将savedState对象分解为两个保存有键和值deArrayList,然后将其中de值加载到相应deStateItem对象中.
  以上就是ViewState属性实现IStateManager接口de基本过程.所有de视图状态管理过程,都要使用以上de实现过程,因此理解以上逻辑对于深入掌握自定义视图状态管理机制具有举足轻重de作用.

JSP教程(三)–JSP中”预定义变量”的使用

星期一, 06月 2nd, 2008

为了简化JSP表达式和scriptlets中de相关代码,提供了8种自动定义de变量,有时称做implicit objects(固有对象).它们是:request,response,out,session,application,config,pageContext,和 page.下面我来详细de了解它们.
  request
  与request相联系de是HttpServletRequest类,使您可以得到requestde参数(通过getParameter方法),request de类型(GET,POST,HEAD,等等),和引入deHTTP头(cookies,Referer,等等).严格来说,request是类ServletRequestde一个子类而不是HttpServletRequest类de,事实上,如果requestde协议不是HTTP,那麽它几乎不会工作.
  response
  对客户端deresponse与HttpServletResponse 相连.请注意,因为输出流是放入缓冲de,所以可以设置HTTP状态码和response头,尽管在标准deservlets中不允许将之发送到客户端.
  out
  这里使用PrintWriter类来发送输出到客户端.然而,为了使response对象有效,可使用一个PrintWrite类de使用缓冲de版本JspWriter.使用sessionde属性page directive,您可以自己定义缓冲de大小,甚至可以在使用了buffer属性后关闭缓冲.也请注意,out仅用于scriptlets之中,因为JSP表达式自动de放入输出流,所以极少需要明确de声明out.
  session
  应用与request相联系deHttpSession类.因为session是自动创建de,即使没有一个引入desession,这种变量仍可绑定.有一个例外是,如果您用page directive关闭session,再试图使用session时将导致错误(在JSP页面向servlet转换时).
  application
  使用ServeletContext类,通过使用getServletConfig().getContext()得到.
  config
  是一个ServletConfig类de对象.
  pageContext
  这是JSP中de一个新de类PageContext,用于精练特定服务器de特点时使用,如提高JspWritersde执行效率.如果您通过这个类访问而不是直接de,您de相关代码将仍然运行在“规则”deJSP /servlet引擎.
  page
  在JAVA中不是很有用,它仅仅是用来保存在脚本de语言不是JAVA时de时间.

JAVA/JSP学习系列之七(Orion下自定义Tag)

星期一, 06月 2nd, 2008

一、前言 (本文译自Orion官方站点)
   本文将一步一步介绍在Orion Application Server下定义自己de标签,然后,实现该标签de功能,最后用一个jsp例子测试.
二、建立标签,实现该标签de功能.
1.命名package为:com.acme.mytags(为了和原文相同,我不做改动)
package com.acme.mytags;
2.import相关class
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
3.实现javax.servlet.jsp.tagext.Tag接口:
public class HelloWorld implements Tag
{
4.定义局部变量
private PageContext pageContext;
private Tag parent;
5.调用标签开始de实现方法
public int doStartTag() throws javax.servlet.jsp.JspException
{
return SKIP_BODY;
}
注意:这个方法返回 SKIP_BODY,就是标签debody为空de时候,将返回这个值,否则将返回:EVAL_BODY_INCLUDE
6.调用标签结束de实现方法
public int doEndTag() throws javax.servlet.jsp.JspException
{
try
{
pageContext.getOut().write("Hello World!");
}
catch(java.io.IOException e)
{
throw new JspException("IO Error: " e.getMessage());
}
return EVAL_PAGE;
}
这样将在jsp文件de自定义标签结束地方输出“Hello World!”
7.还不够,我还要写下面de方法:
public void release() {}
对于本简单de例子,上面de方法不需要任何实现.
8.JSPde容器要调用下面de方法:
public void setPageContext(final javax.servlet.jsp.PageContext pageContext) {
this.pageContext=pageContext;
}
JSP容器通过上面de方法调用标签,而且上面de方法用来设置标签dePageContext.
9.JSPde容器还要调用下面de方法:
public void setParent(final javax.servlet.jsp.tagext.Tag parent)
{
this.parent=parent;
}
JSP容器通过上面de方法设置标签deparent-Tag,因为每个标签dePageContext都要保留它deparent标签.
10.最后,实现方法:
public javax.servlet.jsp.tagext.Tag getParent()
{
return parent;
}
}
11. 编译标签.
三、描叙标签
现在将要写一个描叙文件,描叙该标签.
1.建立一个taglib.tld文件,
2.taglib.tld是一个XML格式de文本文件,XMLde头如下:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
3.描叙标签库
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>mt</shortname> <uri>http://www.orionserver.com/tutorials/tagtut/lesson1/mytags.jar</uri>
<info>My first Tag library</info>
4.描叙标签
<tag>
<name>helloWorld</name>
<tagclass>com.acme.mytags.HelloWorld</tagclass>
<bodycontent>empty</bodycontent>
<info>A Hello world Tag</info>
</tag>
5.结束
</taglib>
四、打包
名称为:mytags.jar
其目录结构为:
com/acme/mytags/HelloWorld.class
META-INF/taglib.tld
五、在jsp文件中使用自定义标签
建立hello.jsp如下:
<%@ taglib uri="mytags.jar" prefix="mt" %>
<HTML>
<HEAD>
<TITLE>Hello World!</TITLE>
</HEAD> <BODY BGCOLOR="#FFFFFF">
<HR>
<mt:helloWorld/>
<HR>
</BODY>
</HTML>
六、测试运行
在orion目录下,建立如下结构,其中,tag是自己建立de,前面de目录是本来就有de.
E:\orion\default-web-app\tag
将jar文件和jsp文件全部放到这个目录下.
然后,访问:
http://localhost:[port]/tag/hello.jsp
将出现:

——————————————————————————–

Hello World! 

——————————————————————————–
七、恭喜,您已经成功了!
附:mytags.jar和hello.jsp 文件本站下载地址:
http://www.wodejia.net/softdownload/java/orion_tag01.zip

十二、脚本元素、指令和预定义变量

星期一, 06月 2nd, 2008

12.1 JSP脚本元素
   JSP脚本元素用来插入Java相关代码,这些Java相关代码将出现在由当前JSP页面生成deServlet中.脚本元素有三种格式:
表达式格式<%= expression %>:计算表达式并输出其结果.
Scriptlet格式<% code %>:把相关代码插入到Servletdeservice方法.
声明格式<%! code %>:把声明加入到Servlet类(在任何方法之外).
   下面我详细说明它们de用法.
   12.1.1 JSP表达式
   JSP表达式用来把Java数据直接插入到输出.其语法如下:
<%= Java Expression %>

   计算Java表达式得到de结果被转换成字符串,然后插入到页面.计算在运行时进行(页面被请求时),因此可以访问和请求有关de全部信息.例如,下面de相关代码显示页面被请求de日期/时间:
Current time: <%= new java.util.Date() %>

   为简化这些表达式,JSP预定义了一组可以直接使用de对象变量.后面我将详细介绍这些隐含声明de对象,但对于JSP表达式来说,最重要de几个对象及其类型如下:
request:HttpServletRequest;
response:HttpServletResponse;
session:和request关联deHttpSession
out:PrintWriter(带缓冲de版本,JspWriter),用来把输出发送到客户端
   下面是一个例子:
Your hostname: <%= request.getRemoteHost() %>

   最后,如果使用XMLde话,JSP表达式也可以写成下面这种形式:
<jsp:expression>
Java Expression
</jsp:expression>

   请记住XML元素和HTML不一样.XML是大小写敏感de,因此务必使用小写.有关XML语法de说明,请参见《XML教程 》
   12.1.2 JSP Scriptlet
   如果您要完成de任务比插入简单de表达式更加复杂,可以使用JSP Scriptlet.JSP Scriptlet允许您把任意deJava相关代码插入Servlet.JSP Scriptlet语法如下:
<% Java Code %>

   和JSP表达式一样,Scriptlet也可以访问所有预定义de变量.例如,如果您要向结果页面输出内容,可以使用out变量:
<%
String queryData = request.getQueryString();
out.println("Attached GET data: " queryData);
%>

   注意Scriptlet中de相关代码将被照搬到Servlet内,而Scriptlet前面和后面de静态HTML(模板文本)将被转换成println语句.这就意味着,Scriptlet内deJava语句并非一定要是完整de,没有关闭de块将影响Scriptlet外de静态HTML.例如,下面deJSP片断混合了模板文本和Scriptlet:
<% if (Math.random() < 0.5) { %>
Have a <B>nice</B> day!
<% } else { %>
Have a <B>lousy</B> day!
<% } %>

   上述JSP相关代码将被转换成如下Servlet相关代码:
if (Math.random() < 0.5) {
out.println("Have a <B>nice</B> day!");
} else {
out.println("Have a <B>lousy</B> day!");
}

   如果要在Scriptlet内部使用字符“%>”,必须写成“%\>”.另外,请注意<% code %>deXML等价表达是:
<jsp:scriptlet>
Code
</jsp:scriptlet>

   12.1.3 JSP声明
   JSP声明用来定义插入Servlet类de方法和成员变量,其语法如下:
<%! Java Code %>

   由于声明不会有任何输出,因此它们往往和JSP表达式或Scriptlet结合在一起使用.例如,下面deJSP相关代码片断输出自从服务器启动(或Servlet类被改动并重新装载以来)当前页面被请求de次数:
<%! private int accessCount = 0; %>
自从服务器启动以来页面访问次数为:
<%= accessCount %>

   和Scriptlet一样,如果要使用字符串“%>”,必须使用“%\>”代替.最后,<%! code %>deXML等价表达方式为:
<jsp:declaration>
Code
</jsp:declaration>

   12.2 JSP指令
   JSP指令影响Servlet类de整体结构,它de语法一般如下:
<%@ directive attribute="value" %>

   另外,也可以把同一指令de多个属性结合起来,例如:
<%@ directive attribute1="value1"
attribute2="value2"

attributeN="valueN" %>

   JSP指令分为两种类型:第一是page指令,用来完成下面这类任务:导入指定de类,自定义Servletde超类,等等;第二是include指令,用来在JSP文件转换成Servlet时引入其他文件.JSP规范也提到了taglib指令,其目de是让JSP开发者能够自己定义标记,但JSP 1.0不支持该指令,有希望它将成为JSP 1.1de主要改进之一.
   12.2.1 page指令
   page指令de作用是定义下面一个或多个属性,这些属性大小写敏感.

import="package.class",或者import="package.class1,…,package.classN":
用于指定导入哪些包,例如:<%@ page import="java.util.*" %>.import是唯一允许出现一次以上de属性.

contentType="MIME-Type" 或contentType="MIME-Type; charset=Character-Set":
该属性指定输出deMIME类型.默认是text/html.例如,下面这个指令:
<%@ page contentType="text/plain" %>.
和下面deScriptlet效果相同:
<% response.setContentType("text/plain"); %>

isThreadSafe="true|false"
默认值true表明Servlet按照标准de方式处理,即假定开发者已经同步对实例变量de访问,由单个Servlet实例同时地处理多个请求.如果取值false,表明Servlet应该实现SingleThreadModel,请求或者是逐个进入,或者多个并行de请求分别由不同deServlet实例处理.

session="true|false"
默认值true表明预定义变量session(类型为HttpSession)应该绑定到已有de会话,如果不存在已有de会话,则新建一个并绑定session变量.如果取值false,表明不会用到会话,试图访问变量session将导致JSP转换成Servlet时出错.

buffer="size kb|none"
该属性指定JspWrite outde缓存大小.默认值和服务器有关,但至少应该是8 KB.

autoflush="true|false"
默认值true表明如果缓存已满则刷新它.autoflush很少取false值,false值表示如果缓存已满则抛出异常.如果buffer="none",autoflush不能取false值.

extends="package.class"
该属性指出将要生成deServlet使用哪个超类.使用该属性应当十分小心,因为服务器可能已经在用自定义de超类.

info="message"
该属性定义一个可以通过getServletInfo方法提取de字符串.

errorPage="url"
该属性指定一个JSP页面,所有未被当前页面捕获de异常均由该页面处理.

isErrorPage="true|false"
该属性指示当前页面是否可以作为另一JSP页面de错误处理页面.默认值false.

language="java"
该属性用来指示所使用de语言.目前没有必要关注这个属性,因为默认deJava是当前唯一可用de语言.
   定义指令deXML语法为:
<jsp:directive.directiveType attribute=value />

   例如,下面这个指令:
<%@ page import="java.util.*" %>

   它deXML等价表达是:
<jsp:directive.page import="java.util.*" />

   12.2.2 include指令
   include指令用于JSP页面转换成Servlet时引入其他文件.该指令语法如下:
<%@ include file="relative url" %>

   这里所指定deURL是和发出引用指令deJSP页面相对deURL,然而,与通常意义上de相对URL一样,您可以利用以“/”开始deURL告诉系统把URL视为从Web服务器根目录开始.包含文件de内容也是JSP相关代码,即包含文件可以包含静态HTML、脚本元素、JSP指令和动作.
   例如,许多网站de每个页面都有一个小小de导航条.由于HTML框架存在不少问题,导航条往往用页面顶端或左边de一个表格制作,同一份HTML相关代码重复出现在整个网站de每个页面上.include指令是实现该功能de非常理想de方法.使用include指令,开发者不必再把导航HTML相关代码拷贝到每个文件中,从而可以更轻松地完成维护工作.
   由于include指令是在JSP转换成Servletde时候引入文件,因此如果导航条改变了,所有使用该导航条deJSP页面都必须重新转换成Servlet.如果导航条改动不频繁,而且您希望包含操作具有尽可能好de效率,使用include指令是最好de选择.然而,如果导航条改动非常频繁,您可以使用jsp:include动作.jsp:include动作在出现对JSP页面请求de时候才会引用指定de文件,请参见本文后面de具体说明.
   12.3 实例:脚本元素和指令de应用
   下面是一个使用JSP表达式、Scriptlet、声明、指令de简单例子.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>JavaServer Pages</TITLE>
</HEAD>
<BODY BGCOLOR="#FDF5E6" TEXT="#000000" LINK="#0000EE"
VLINK="#551A8B" ALINK="#FF0000">
<CENTER>
<TABLE BORDER=5 BGCOLOR="#EF8429">
<TR><TH CLASS="TITLE">
JSP应用实例</TABLE>
</CENTER>
<P>
下面是一些利用各种JSP功能生成de动态内容:
<UL>
<LI><B>表达式.</B><BR>
您de主机名: <%= request.getRemoteHost() %>.
<LI><B>JSP Scriptlet.</B><BR>
<% out.println("查询字符串: "
request.getQueryString()); %>
<LI><B>声明(和表达式).</B><BR>
<%! private int accessCount = 0; %>
服务器启动以来访问次数: <%= accessCount %>
<LI><B>指令(和表达式).</B><BR>
<%@ page import = "java.util.*" %>
当前日期: <%= new Date() %>
</UL>
</BODY>
</HTML>

   12.4 JSP预定义变量
   为了简化JSP表达式和Scriptletde相关代码,JSP提供了8个预先定义de变量(或称为隐含对象).这些变量是request、response、out、session、application、config、pageContext和page.
   12.4.1 request
   这是和请求关联deHttpServletRequest,通过它可以查看请求参数(调用getParameter),请求类型(GET,POST,HEAD,等),以及请求deHTTP头(Cookie,Referer,等).严格说来,如果请求所用de是HTTP之外de其他协议,request可以是ServletRequestde子类(而不是HttpServletRequest),但在实践中几乎不会用到.
   12.4.2 response
   这是和应答关联deHttpServletResponse.注意,由于输出流(参见下面deout)是带缓冲de,因此,如果已经向客户端发送了输出内容,普通Servlet不允许再设置HTTP状态相关代码,但在JSP中却是合法de.
   12.4.3 out
   这是用来向客户端发送内容dePrintWriter.然而,为了让response对象更为实用,out是带缓存功能dePrintWriter,即JspWriter.JSP允许通过page指令debuffer属性调整缓存de大小,甚至允许关闭缓存.
   out一般只在Scriptlet内使用,这是因为JSP表达式是自动发送到输出流de,很少需要显式地引用out.
   12.4.4 session
   这是和请求关联deHttpSession对象.前面我已经介绍过会话de自动创建,我知道,即使不存在session引用,这个对象也是自动绑定de.但有一个例外,这就是如果您用page指令desession属性关闭了会话,此时对session变量de引用将导致JSP页面转换成Servlet时出错.
   12.4.5 application
   这是一个ServletContext,也可以通过getServletConfig().getContext()获得.
   12.4.6 config
   这是当前页面deServletConfig对象.
   12.4.7 pageContext
   主要用来管理页面de属性.
   12.4.8 page
   它是thisde同义词,当前用处不大.它是为了Java不再是唯一deJSP编程语言而准备de占位符.