学习日记网站动态导航技术探索

littlebat慎重声明:此文的内容基于我3年以前的一个不成熟的甚至是错误的设计思路所写(具体原因请参见本文后面我的后续补充评论批注),并且本文所属的“Java学习日记开源项目”也于2006年停止并删除,不再对外公布代码,此文留存于此仅供资料备查及供朋友一种动态导航的参考,请浏览者注意鉴别。
2009年5月23日 littlebat

版权声明:本文章为JAVA学习日记网站(http://java.learndiary.com)littlebat版权所有,以“Creative Commons License”http://creativecommons.org/licenses/by/2.0/方式授权。欢迎转载,但请注明文章原始出处(http://java.learndiary.com/disDiaryContentAction.do?searchDiaryID=&goalID=1255&naviStr=a10a2167)。

提纲:

一、背境;

二、需求分析:

1、学习日记网站的主要功能页面结构;

2、需要进行动态导航的主要模块;

3、需求的提出:

1)、层次导航的需求;

2)、同一列表中帖子间的导航(即上一条,下一条类似的导航);

3)、父帖与子帖列表的双向导航;

三、具体实现过程:

1、层次导航的实现过程:

1)列出导航功能需求列表,看都有哪些导航路径;

2)分析定位特定类型的页面所需的参数;

3)确定层次导航的实现方法;

4)进行层次导航系统的设计:

(1)、进行页面节点导航封装字符串格式的设计;

(2)、页面完整导航字符串的设计;

(3)、将封装的导航字符串还原为显示在页面上的URL地址导航条;

(4)、在页面上显示层次导航的URL字符串;

2、同一列表中帖子间的导航(即上一条,下一条类似的导航)的实现过程:

1)列出导航需求列表;

2)分析实现上一条、下一条导航所需的参数;

3)确定实现上一条、下一条导航的实现方法;

4)进行上一条、下一条导航的设计:

(1)、根据层次导航的导航字符串确定上一条、下一条导航所在的层次导航位置;

(2)、确定在哪几个Struts的Action中需要处理上一条、下一条导航;

(3)、在页面上显示上一条、下一条导航的URL字符串;

3、父帖与子帖列表的双向导航的实现过程:

1)列出导航需求列表;

2)分析实现双向导航所需的参数;

3)确定实现方法;

4)进行双向导航的设计:

(1)、确定在哪几个Struts的Action中需要处理双向导航;

(2)、在页面上显示双向导航的URL字符串;

四、总结:

1、心得;

2、优点;

3、缺点;

4、愿望;

五、联系方式;

六、附件(附学习日记V0.9.0.4和学习日记系统ArgoUML建模(学习日记V0.9.0.4反向工程类图) );

七、附图

关键词:学习日记 Struts 动态导航 学习日记动态导航技术(简称:LDDN技术 ) 学习日记开发小组(简称:LDDG )

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

正文

一、背境:

JAVA学习日记(http://java.learndiary.com )网站是采用Struts框架的开源项目learndiary(http://develop.learndiary.com )的实际运行示范站点。目前由学习日记开发小组进行开发,致力于以JAVA技术构建一个普遍适用的开源网络学习交流平台。为了改善用户的浏览体验,故提出导航系统的改善计划。已经包含了这个导航系统的的最新版本为learndiaryV0.9.0.4。本文所提到的程序均可以在本站的下载菜单中获取:http://java.learndiary.com/download/download.html 。本文希望起到一个抛砖引玉的作用,引发一场关于java技术构建的web系统的导航系统设计的讨论。

二、基本思路:

1、学习日记网站的主要功能页面结构:

核心为:目标列表-》目标内容及评论-》目标下的日记列表-》日记内容及评论

示意图:(图1 学习日记网站的主要功能页面结构)

2、需要进行动态导航的主要模块:

需要进行动态导航的主要模块有3个,见学习日记网站的菜单栏:

1)、所有目标:http://java.learndiary.com/index0Action.do?pageNum=1&naviStr=a10 (显示学友提出的所有学习目标列表 )

2)、检索:http://java.learndiary.com/toSearchAction.do?naviStr=a10ac0 (检索本站的所有学习目标和学习日记 )

3)、您的目标:http://java.learndiary.com/processGoalAction.do?currentGoalState=1&pageNum=1&naviStr=a10a60 (学友自己的学习目标归类:包括:进行中的目标、退出的目标、已完成的目标 )

3、需求的提出:

1)、层次导航的需求:

我们想建成一个导航系统,它可以跟踪用户在系统中浏览页面的过程,每浏览到一个新的页面,就在导航条中加入这个页面的URL,于是,当用户浏览到别的页面,可以点击返回系统导航条中的前面浏览过的页面;当浏览一个页面是与导航条中已经存在的页面类型一致时,就截去导航条中此类型页面后面的导航URL。

征对这个需求,我大概看了一下动网的实现方式和phpWind论坛的实现方式,他们用的导航基本上是静态的,也就是说,一种页面上的导航条是固定的,例如:显示一条帖子的内容,他们的方式是:论坛首页-》论坛版块-》主题内容。

而我们的需求是,例如:显示一篇日记的内容:

在所有目标模块中,导航条为:所有目标>>日记列表>>日记内容;

图例:(图2 所有目标模块中显示一篇日记的内容)

在检索模块中,导航条为:所有目标>>检索>>检索日记列表>>日记内容;

图例:(图3 检索模块模块中显示一篇日记的内容)

在您的目标中,导航条为:所有目标>>我进行中的目标>>本目标我的日记列表>>日记内容;

图例:(图4 您的目标模块中显示一篇日记的内容)

2)、同一列表中帖子间的导航(即上一条,下一条类似的导航 ):

另外,除了上面层次导航的需求,同一列表中帖子间的导航(即上一条,下一条类似的导航 ),我们也想在网上一般的导航系统的基础有所改良。例如:在一般的导航系统中,如果你在检索结果的列表中点击查看一篇帖子,然后,你再点击这篇帖子的上一条和下一条链接,新点开的页面不是检索结果列表中的上一篇或下一篇帖子,而是这条帖子所有的版块的上一条和下一条帖子。

我们需要在检索结果列表中,点击检索到的一篇日记中的“上一条”和“下一条”链接时,显示的是检索结果列表中本日记的上一条和下一条日记。

例如,我们以“中文显示”为关键字检索日记得到一个检索结果列表:

图例:(图5 检索结果列表层次导航)

当我点击查看“解决:jsp页面中文显示问题”这篇日记中的下一条链接时,我们需要打开检索结果列表的下一篇日记:“问题:jsp中文显示,<c:set>的值可否是对象?me ”:

图例:(图6 检索结果列表层次导航2)

,而不是“解决:jsp页面中文显示问题”这篇日记所在的目标中的下一篇日记。

在“您的目标”这个模块中的“上一条”和“下一条”的导航同样存在在检索页面中点击“上一条”和“下一条”链接的问题。

3)、父帖与子帖列表的双向导航:

学习日记征对自身的功能结构特点,还需要实现:“目标<──>目标下的所有日记列表”的双向导航和“目标<──>目标下我的日记列表”的双向导航:显示目标内容

图例:(图7 双向导航显示目标内容)

,您可以看到页面右边中上有两个链接分别是:“查看所有日记”和“查看我的日记”,点击“查看所有日记”链接出现的是页面

图例:(图8 双向导航查看所有日记)

,点击“查看我的日记”链接出现的是页面

图例:(图9 双向导航查看我的日记)

;后面这两个页面的右中上部又都有到日记所在的目标中的链接:“查看目标内容”。

以上总结了学习日记需要实现的导航系统的三个方面的需求,征对这个需求,我看了一些论坛,均没有现存的东西可以参考,于是,我们决定探索一种能够实现上面动态导航需求的方法。因为我们实现的导航系统是动态变化的,故把这种实现的方法称之为“学习日记动态导航技术”(简称:LDDN技术 )。下面把我们的具体设计过程总结一下。

三、具体实现过程:

具体的设计分析过程我已经在进行的过程中记录在日记中了,所以,如果你要详细的了解我的分析设计过程的话,可以去看这两篇日记:

第一篇日记:“提高学习日记导航能力的思路”(http://java.learndiary.com/disDiaryContentAction.do?searchDiaryID=&goalID=1128&naviStr=a10a2506ah1167 ),主要记录的是我在对层次导航部分的分析设计过程;

第二篇日记:“分析学习日记横向导航及开几个窗口的思路”(http://java.learndiary.com/disDiaryContentAction.do?searchDiaryID=&goalID=1167&naviStr=a10a2506ah1128 ),主要记录的是我在对“上一条”和“下一条”导航部分的分析与设计过程。

当然,细节总是太烦琐和令人不愉快的,我把大概的设计过程总结如下:

1、层次导航的实现过程:

1)列出导航功能需求列表,看都有哪些导航路径,例如:

(5)所有目标列表->相关日记列表->显示日记内容->编辑评论;

(14)所有目标列表->进行中的目标列表->您的日记列表->显示日记内容->编辑评论;

(21)所有目标列表->检索页面->搜索结果日记列表->相关日记列表->显示日记内容->撰写评论;

全部列表请见我上面提到的第一篇日记中的“一、学习日记导航路径列举:”(您可以在页面中搜索位置,前后的双引号除外,下同 )。

2)分析定位特定类型的页面所需的参数(这样,就可以根据页面类型和参数唯一的确定一个页面了 ):

经过分析,唯一定位一个页面所需要的参数变为:

1》页面类型;

2》参数ID;

其中参数ID分为下面几种情况:

1》列表:需要列表的parentID;

2》单个条目:需要它的ID;

3》用户的进行、完成等目标列表:什么都不需要,用户ID在Session中;

4》用户的进行、完成等目标的用户日记列表;目标ID,所需的用户ID在Session中;

5》搜索列表:什么都不需要,因为搜索条件字符串已保留在全局Session中了;

具体的分析过程请见我上面提到的第一篇日记中的“(2 )、如何唯一的定位一个特定的页面呢? ”

3)确定层次导航的实现方法:

当点击一个新的页面时,就把定位这个页面所需的参数加入到层次导航的参数链表中(链表的一个节点储存的是一个新的页面的定位参数 ),这时链表变长;当点击一个在链表中已经存在这种类型的页面(例如:显示一篇日记的内容的页面 )时,就把在导航链表中这个节点及后面的节点删除,再加上这个点击的页面的定位参数。

实现这种层次导航的需求有两种方法:

(1)、为每条导航路径在session中设置一个层次导航所需的属性,在这条路径上导航链表的增长和缩短信息就由这个属性来维持;

(2)、把这个链表封装成字符串,这个字符串在访问不同的页面时,会根据上面的思路不断增长和缩短。把这个封装的字符串连同用户新请求的页面的定位参数节点字符串一起传给请求这个页面前的Struts的action,形成新的页面上导航条所需的编码字符串,然后把这个编码字符串保存在request中,供请求的页面中的下一个链接使用;并同时由action把这个形成的编码导航字符串解码处理成用户请求的页面上需要的导航字符串。

经过分析,我决定采用第(2 )种方法来实现层次导航。

具体的分析过程请见我上面提到的第一篇日记中的“我知道有2种方法可以解决这个问题 ”。

4 )进行层次导航系统的设计:

(1)、进行页面节点导航封装字符串格式的设计:

分隔符(用'a'作分隔符 )+页面节点类型(用一位字符代表,封装成一个页面类型常量类,用字符1-9,英文字符b-z和A-Z表示 )+页面参数ID(如显示目标的日记列表所需的目标ID,显示日记内容所需的日记ID )。如显示一篇日记的页面类型常量为字符:‘h’,那么,显示“解决:jsp页面中文显示问题”这篇日记内容(ID为292 )这一页面的封装字符串为:ah292;

(2)、页面完整导航字符串的设计:

在下面的讨论中会用到的相关源文件:

负责封装学习日记所需导航的页面的类型常量(/WEB-INF/src/com/learndiary/website/PageTypeConsts.java );

负责导航字符串封装的方法(/WEB-INF/src/com/learndiary/website/util/Pager.java中的public static String encodeNaviStr(String naviStr, char toPageType, String parameter) );

当用户提出一个新的页面请求,把当前页面中的完整的导航封装字符串和新的页面的类型和新请求页面的参数ID传给处理新页面显示前的Struts中的Action中,由Action调用一个方法,负责把这些参数组装成下一新页面所需的导航字符串。如:当前正显示的页面是“系统导航:所有目标>>我进行中的目标>>目标:一起学习Struts(MVC)我的日记列表”中的“目标:一起学习Struts(MVC)我的日记列表”

图例:(图10 我的日记列表)

,你可以看到当点击显示日记“解决:jsp页面中文显示问题 (0篇) ”的URL中的导航字符串为:“naviStr=a10a60a0167”(图例中左下方红圈中 ),把这个字符串和请求的显示日记的页面类型(日记为:‘h’ )和显示这篇日记所需的ID(292 )传给显示日记内容前的Action中(disDiaryContentAction.do,源文件为:/WEB-INF/src/com/learndiary/website/action/disgoal/DisGoalContentAction.java ),由负责导航字符串封装的方法(源文件为:/WEB-INF/src/com/learndiary/website/util/Pager.java中的public static String encodeNaviStr(String naviStr, char toPageType, String parameter) )进行处理,处理流程为:以显示日记这个页面的类型ID为‘h’搜索已有导航字符串,没有相同的页面,于是就把这个页面导航字符串节点(ah292 )加到完整的导航字符串(a10a60a0167)后面得到新的导航字符串(a10a60a0167ah292 ),

见例图:(图11 我的日记列表2)

,你可以看到当点击“日记:解决:jsp页面中文显示问题”这篇日记中的“我要评论”的URL中的导航字符串为:“naviStr=a10a60a0167ah292”(图例中左下方红圈中 );

当点击当前页面中的回到上级导航节点的链接时,如:“系统导航:所有目标>>我进行中的目标>>目标:一起学习Struts(MVC)我的日记列表”中的“我进行中的目标”,这时显示“我进行中的目标”页面的类型代码是‘6’,参数ID是“0”,那么以新页面的节点字符串(a60 )的类型代码‘6’搜索已有导航字符串,已经存在相同的类型代码,于是,就把导航字符串中这个节点和后面的所有节点删除得到字符串“a10”,再加上新页面的节点字符串为“a60”,得到显示“我进行中的目标”页面的导航字符串为“a10a60”,

见例图:(图12 我进行中的目标)

,你可以看到当点击“一起学习Struts(MVC) (19篇)”这篇目标的URL中的导航字符串为:“naviStr=a10a60”(图例中左下方红圈中 );

详细分析设计过程我上面提到的第一篇日记中的“2、设计中用到的方法: ”;

(3)、将封装的导航字符串还原为显示在页面上的URL地址导航条:

同样用上面的显示在“我进行中的目标”中目标“一起学习Struts(MVC)我的日记列表”中的日记“解决:jsp页面中文显示问题”来进行说明,也就是说:如何把导航封装字符串“a10a60a0167ah292”转换成字符串“系统导航:<a href="/learndiary/indexAction.do?searchDiaryID=&pageNum=1&naviStr=a10a60a0167ah292">所有目标</a>>><a href="/learndiary/processGoalAction.do?searchDiaryID=&currentGoalState=1&pageNum=1&naviStr=a10a60">我进行中的目标</a>>><a href="/learndiary/myDiaryAction.do?searchDiaryID=&pageNum=1&goalID=167&naviStr=a10a60a0167ah292">目标:一起学习Struts(MVC)我的日记列表</a>>>日记:解决:jsp页面中文显示问题<p>”,

使它在页面上显示导航条为“系统导航:所有目标>>我进行中的目标>>目标:一起学习Struts(MVC)我的日记列表>>日记:解决:jsp页面中文显示问题”?

见图例:(图13 我的日记列表2)

解决这个问题我用两步走的方法:

<1>、用一个方法可以把每一个导航节点的封装字符串转换为导航URL字符串。主要是根据需要显示的页面类型和参数ID来进行转换,实现过程比较简单,请查看源文件中负责解封导航节点封装字符串的方法(/WEB-INF/src/com/learndiary/website/util/Pager.java中的public static String decodeNodeStr(String naviStr, String nodeNaviStr, HttpServletRequest request, boolean ifLast) throws Exception );

<2>、把每个节点封装的字符串联接在一起,形成完成的页面层次导航所需的URL字符串。根据惯例,当前(也就是最后一个节点的导航URL灰化,无链接 )。具体实现请查看源文件中负责解封整个导航封装字符串的方法(/WEB-INF/src/com/learndiary/website/util/Pager.java中的public static String decodeNaviStr(String naviStr, HttpServletRequest request) throws Exception );

具体的分析设计过程请见我上面提到的第一篇日记中的“把封装的字符串转化为下一个页面显示导航条所需要的字符串”。

(4)、在页面上显示层次导航的URL字符串

在需要层次导航的页面上,把从request中获得的属性“navigation”显示在页面的左上部,并把从request中获得的相应的封装导航字符串naviStr作为参数附在每一个URL的后面就行了。

至此,学习动态导航系统中的层次导航部分已经设计完成,下面继续进行显示“上一条”和“下一条”的水平导航部分的探索。

2、同一列表中帖子间的导航(即上一条,下一条类似的导航 )的实现过程:

1)列出导航需求列表:

(1)、在所有目标列表中:

1>目标内容;

2>目标的日记列表(上一条:在这里即上一目标的日记列表);

3>日记列表中的日记内容;

(2)、在检索结果页面中:

1>检索目标列表:

<1>目标内容;

<2>目标的日记列表;

<3>日记列表中的日记内容;

2>检索日记列表:

<1>日记内容;

<2>所在目标的日记列表中的日记内容;

(3)、您的进行中的目标列表:

1>目标内容;

2>目标的全部日记列表;

3>目标的我的日记列表;

4>目标的全部日记列表中的日记;

5>目标的我的日记列表中的日记;

2)分析实现上一条、下一条导航所需的参数:

因为是实现同一列表中的同一级别的帖子之间的导航,所以只需要得到需要导航的条目的ID就行了,其它所有参数都不必改变。

3)确定实现上一条、下一条导航的实现方法:

现在的问题是:如何根据当前条目的ID,得到上一条目和下一条目的ID呢?

答案是:条目的列表,条目在列表中的排序方式,当前条目的ID。为了在查询结果集中得到当前条目的前后条目的ID,可以有下面的方法:

(1)在一个直接操纵数据库的方法中从查询结果集中取出每个ID(整型)后,保存在数组中,马上关闭数据库连接,减少数据库连接开销。然后在同个方法中取得前面、当前、后面记录的ID,只返回这3个元素的数组给Pager类(负责产生页面导航所需要的URL字符串的工具类)处理,这样,可以保证每条数据都是最新的,但是要不停的开启和关闭数据库连接;

(2)把查询结果产生的数组全部存在session中,Pager在session中取数据。这样,可以减少数据库的查询,但是存在两个问题,那个比较长的数组在session中始终占用内存,还有,取出的数据的排序关系可能是过期的(这时,有人往数据库中增加或修改了数据)。

我觉得第一种方法可以减轻对网站虚拟主机资源的压力,决定采用第一种方法。

另外,在直接操纵数据库产生的结果集中查询邻近的ID会出现几种结果呢?

这里用“-1”表示没有相应的帖子。

1>在用户查看帖子期间,这篇帖子被删除了,结果返回:{-1,-1,-1};

2>只有一篇符合要求的帖子,结果返回:{-1,当前帖子ID,-1};

3>当前帖子是第一篇帖子,结果返回:{-1,当前帖子ID,下一条帖子ID};

4>当前帖子是最后一篇帖子,结果返回:{上一篇帖子ID,当前帖子ID,-1};

5>当前帖子前后都有帖子,结果返回:{上一篇帖子ID,当前帖子ID,上一篇帖子ID};

现在,就可以把这个含有前一条、当前、后一条帖子ID的整型数组传给Pager类中的产生上一条、下一条导航URL字符串的相应方法进行处理了。

下面是上一条、下一条导航的具体设计。

4)进行上一条、下一条导航的设计:

(1)、根据层次导航的导航字符串确定上一条、下一条导航所在的层次导航位置:

进行上一条、下一条的导航需要知道被导航的帖子所在的层次导航的位置。例如:显示一篇日记的内容:

在所有目标模块中,导航条为:所有目标-》日记列表-》日记内容;

图例(图14 层次导航路径1):

在检索模块中,导航条为:所有目标>>检索>>检索日记列表>>日记内容;

图例(图15 层次导航路径2):

在您的目标中,导航条为:所有目标>>我进行中的目标>>本目标我的日记列表>>日记内容;

图例(图16 层次导航路径3):

在上一条、下一条的导航中,层次导航条除了上一条目和下一条目内容的改变,其余是不会变的;而且,要得到当前条目的前后条目的ID,在不同的层次导航中是不同的。例如:在上面的路径1中,得到日记列表的查询条件是本目标下的所有日记;在路径2中,得到日记列表的查询条件是检索页面的条件组合;在路径3中,得到日记列表的查询条件是本目标下的用户的所有日记。而且,在学习日记的设计中,这三种情况的排序方式是分开的,可以由用户在浏览时自选的。

为了得到不同层次导航下的上一条、下一条URL导航字符串,我在页面导航URL字符串产生工具类Pager((/WEB-INF/src/com/learndiary/website/util/Pager.java)中用了3个重载的、用于产生上一条、下一条导航URL字符串的方法来征对不同的三种情况(与前面说的3种路径不是一一对应的),分别是:

1>、(包括对这一路径下的目标列表中目标的浏览和目标的日记列表的浏览,和检索目标列表中目标的浏览,和检索日记列表中日记的浏览):public static String getPreNextNaviStr( char toPageType, String url, HttpServletRequest request, String naviStr, int currentID, String condition,int orderType, int direction) throws Exception。输入参数是:toPageType-请求的页面类型,url-请求的页面的“/***Action.do”路径,request-请求对象,naviStr-当前页面的导航封装字符串,currentID-当前条目的ID,condition-查询的where子句,orderType-排序类型,direction-排序方向。为了分离数据库访问的代码,在这个方法中调用了一个直接访问数据库的类(/WEB-INF/src/com/learndiary/website/db/PageDB.java)中的方法(public int[] getAdjacentIDs(String tableName, int currentID, String condition, int orderType, int direction) throws Exception )来得到含有前一条、当前、后一条帖子ID的数组;

2>、(包括对检索日记列表的日记所在目标、日记所在目标下的日记列表的浏览):public static String getPreNextNaviStr(String url, HttpServletRequest request, String naviStr, int searchDiaryID, String condition,int orderType, int direction) throws Exception。输入参数是:url-请求的页面的“/***Action.do”路径,request-请求对象,naviStr-当前页面的导航封装字符串,searchDiaryID-搜索日记列表中当前日记的ID,condition-查询的where子句,orderType-排序类型,direction-排序方向。为了分离数据库访问的代码,在这个方法中调用了一个直接访问数据库的类(/WEB-INF/src/com/learndiary/website/db/PageDB.java)中的方法(public int[] getAdjacentIDs(String tableName, int currentID, String condition, int orderType, int direction) throws Exception )来得到含有前一条、当前、后一条帖子ID的数组;

3>、(包括对进行中的目标、退出的目标、完成的目标列表中目标的浏览):public static String getPreNextNaviStr(String url, HttpServletRequest request, String naviStr, int userID, int currentID, int myGoalTypeFlag, int orderType, int direction) throws Exception。输入参数是:url-请求的页面的“/***Action.do”路径,request-请求对象,naviStr-当前页面的导航封装字符串,userID-当前用户ID,currentID-当前条目的ID,myGoalTypeFlag-用户目标的类型(进行、退出、或者完成),orderType-排序类型,direction-排序方向。为了分离数据库访问的代码,在这个方法中调用了一个直接访问数据库的类(/WEB-INF/src/com/learndiary/website/db/PageDB.java)中的方法(public int[] getAdjacentIDs(int userID,int currentID, int myGoalTypeFlag, int orderType, int direction) throws Exception)来得到含有前一条、当前、后一条帖子ID的数组;

现在的问题是怎么样来区别上面1>、2>、3>中列出的各种情况,并调用对应的“getPreNextNaviStr”方法来产生正确的上一条、下一条的URL导航字符串呢?

我的答案是根据当前页面的封装导航字符串来确定,我通过分析上面1>、2>、3>中列出的各种情况的导航字符串的特征码,然后在程序中通过检索特征码来确定当前页面的层次导航位置(对应于上面不同的几种情况),这是一个烦琐的过程,这里仅列举一二:

例如:在检索目标的列表中的目标页面中的封装导航串一定会含有“ae”两个字符,且帖子类型为“目标”;在检索日记的列表中的日记页面中的封装导航串一定会含有“ad”两个字符,且帖子类型为“日记”。

(2)、确定在哪几个Struts的Action中需要处理上一条、下一条导航:

1)、首先,需要导航的地方有三种情况:

1>、目标内容

2>、日记内容

3>、目标的日记列表

2)、

1>、1)的1>和2>需要放在DisGoalContentAction.java(/WEB-INF/src/com/learndiary/website/action/disgoal/DisGoalContentAction.java)中处理;

2>、1)的3>需要分在几个地方处理,分别是:

1>检索目标的日记列表,所有目标的日记列表,进行、完成、退出的日记列表:在DiaryAction.java(/WEB-INF/src/com/learndiary/website/action/disdiary/DiaryAction.java)中处理;

2>进行、完成、退出的我的日记列表:在MyDiaryAction.java(/WEB-INF/src/com/learndiary/website/action/mydiaries/MyDiaryAction.java)中处理;

(3)、在页面上显示上一条、下一条导航的URL字符串;

在需要上一条、下一条导航的页面上,把从request中获得的属性“preNextNavigation”显示在页面的右上部和右下部就行了。

上一条、下一条导航完整的设计分析过程见我上面提到的第二篇日记:“分析学习日记横向导航及开几个窗口的思路”(http://java.learndiary.com/disDiaryContentAction.do?searchDiaryID=&goalID=1167&naviStr=a10a2506ah1128 )。

3、父帖与子帖列表的双向导航的实现过程:

1)列出导航需求列表:

(1)“目标<──>目标下的所有日记列表”的双向导航;

(2)“目标<──>目标下我的日记列表”的双向导航;

2)分析实现双向导航所需的参数:

只需要目标的ID或日记列表的目标ID和导航封装字符串;

3)确定实现方法:

直接在Action中得到当前目标的ID或日记列表的目标ID和导航封装字符串,附在“***Action.do?”的后面就行了。

4)进行双向导航的设计:

(1)、确定在哪几个Struts的Action中需要处理双向导航:

1>、在“目标──>目标下的所有日记列表”和“目标──>目标下我的日记列表”的导航,需要放在DisGoalContentAction.java(/WEB-INF/src/com/learndiary/website/action/disgoal/DisGoalContentAction.java)中处理;

2>、在“目标下的所有日记列表──>目标”的导航,需要放在DiaryAction.java(/WEB-INF/src/com/learndiary/website/action/disdiary/DiaryAction.java)中处理;

3>、在“目标下的我的日记列表──>目标”的导航,需要放在在MyDiaryAction.java(/WEB-INF/src/com/learndiary/website/action/mydiaries/MyDiaryAction.java)中处理;

(2)、在页面上显示双向导航的URL字符串:

在需要“目标──>目标下的所有日记列表”和“目标──>目标下我的日记列表”的导航的页面上,把从request中获得的属性“jumpToViewDiaries”显示在页面的右上部和右下部;在“目标下的所有日记列表──>目标”和“目标下的我的日记列表──>目标”的导航中,把从request中获得的属性“jumpToViewGoal”显示在页面的右上部和右下部就行了。

四、总结:

1、心得:

1)、编码前的分析设计是非常重要的,这一步工作做好了,编码就很容易了(但我还做得不够,如下面的第3)条心得。可是,也许是我的水平有限,有些应该放在设计时的工作不到编码的时候就是想不到,还望大家给予指点);

2)、Struts框架把程序的逻辑实现代码和页面显示部分能比较好的分离,有利于功能模块的新增和程序的后期维护;

3)、在进行类和类的方法的设计时(如前面提到的Pager类和PageDB类),没有先进行完整的高层设计,是采用边编码边设计的方式,致使类的设计不够面向对象,给后期的理解和维护会造成困难;

4)、如果这种导航设计思路真的有用,有必要把它进行精心的设计,做成插件的形式,这样可以把它方便的应用于需要这种动态导航的各种java的web程序中;

2、这种动态导航的优点:

1)、能够极大的提高用户的浏览体验,使网站的导航更符合逻辑和人们的思维习惯;

2)、能够无限的进行需要导航的页面的增加和减少,后期的维护代码少量增加就行了;

3、这种动态导航的缺点:

1)、实现过程较为复杂,牵涉的页面和逻辑代码较多,权衡实现的代价和收到的效果,真的值得吗?;

2)、动态导航能被用户的使用习惯接受吗?这是一个未知数;

3)、还有什么缺点呢?暂时还没有想出来,大家帮我们想一想吧。

4、愿望:

1)、希望朋友们能够对学习日记开发小组提出的这种动态导航技术展开充分的讨论,论证这种导航方式的可行性;

2)、希望与软件相关(尤其是java )、学习相关(尤其是计算机软件自学 )、开源相关(尤其是java开源 )的网站结为友站关系并交换网站链接,共谋发展。我们的链接代码(请直接复制代码,我们的新logo正在酝酿中 ):图片链接:“<a href="http://java.learndiary.com" target=_blank><img border=0 src="http://java.learndiary.com/pictures/learndiarylink.gif</img>" alt="JAVA学习日记:分享目标,分享快乐。"></a>”,文字链接:“<a href="http://java.learndiary.com" target=_blank title="JAVA学习日记:分享目标,分享快乐。">JAVA学习日记</a>”。如果,你愿意与我们交换链接,请把你的链接代码发至:“mdx-xx@tom.com”。

五、联系方式:

1、在学习日记网站对这篇文章进行评论(建议注册登录后再评论,否则是以guest身份评论):http://java.learndiary.com/disDiaryContentAction.do?searchDiaryID=&goalID=1255&naviStr=a10a2167

2、在学习日记网站留言(不需登录,但留言内容只有本站管理员才能查看与回复):http://java.learndiary.com/toWriteMessageAction.do?typeID=4&goalID=0&naviStr=a10af0

3、电子邮件:mdx-xx@tom.com

4、QQ:81251712

六、附件

1、学习日记V0.9.0.4,简介:http://java.learndiary.com/disDiaryContentAction.do?goalID=1245&naviStr=a10a21

下载地址:http://java.learndiary.com/download/learndiaryV0.9.0.4.war

2、学习日记系统ArgoUML建模(学习日记V0.9.0.4反向工程类图),下载地址:http://java.learndiary.com/download/learndiaryV0.9.0.4.zargo

用ArgoUML V0.20.alpha2打开,ArgoUML下载地址:http://argouml-downloads.tigris.org/nonav/argouml-0.20.ALPHA_2/ArgoUML-0.20.ALPHA_2.zip )。

-全文完

作者:JAVA学习日记 http://java.learndiary.com littlebat )

2005年11月25日下午

七、附图

********************************************************************************************

图1 学习日记网站的主要功能页面结构

********************************************************************************************

图2 所有目标模块中显示一篇日记的内容

********************************************************************************************

图3 检索模块模块中显示一篇日记的内容

********************************************************************************************

图4 您的目标模块中显示一篇日记的内容

********************************************************************************************

图5 检索结果列表层次导航

********************************************************************************************

图6 检索结果列表层次导航2

********************************************************************************************

图7 双向导航显示目标内容

********************************************************************************************

图8 双向导航查看所有日记

********************************************************************************************

图9 双向导航查看我的日记

********************************************************************************************

图10 我的日记列表

********************************************************************************************

图11 我的日记列表2

********************************************************************************************

图12 我进行中的目标

********************************************************************************************

图13 我的日记列表2

********************************************************************************************

图14 层次导航路径1

********************************************************************************************

图15 层次导航路径2

********************************************************************************************

图16 层次导航路径3

(转帖)使用 UTF-8 对 XML 文档进行编码

       中国 [ 选择]      使用条款

  

 

 

    dW 全部内容 -----------------   DB2   Lotus   Tivoli   WebSphere -----------------   Java 技术   Linux   Open source   Security   SOA & Web services   Web architecture   Wireless   XML ----------------- IBM 全部内容            

 

 

      首页       产品       服务与解决方案       支持与下载       个性化服务       

 

 

 

developerWorks

中国

本文内容包括:

 每个人都能使用 UTF-8

 专家们的说法

 中文、日文和韩文

 健壮性

 结束语

 参考资料 

 关于作者

 对本文的评价

 

相关链接

 XML 技术文档库

 

 

 

developerWorks 中国  >  XML  >

使用 UTF-8 对 XML 文档进行编码

(提示:文档大小与 UTF-8 无关)

 

 

  文档选项

   将此页作为电子邮件发送

 

 

对此页的评价

  帮助我们改进这些内容

 

 

 

级别: 中级

Elliotte Harold , 副教授, Polytechnic University

2005 年 9 月 26 日

Unicode 是目前世界上所有其他主要计算机字符集的超集。UTF-8 是 Unicode 字符集特有的二进制编码。本文解释了为何所有 XML 文档都应当使用 UTF-8 生成的原因。结果是更健壮、更具互操作性的文档世界。

Google 的 Sitemap 服务最近在 XML 社区引起了一些波澜,它要求发布的所有站点地图必须采用 Unicode 的 UTF-8 编码。Google 甚至不允许其他 Unicode 编码(如 UTF-16),更不用说 ISO-8859-1 这样的非 Unicode 编码了。从技术上说,这意味着 Google 使用的是非标准 XML 解析器,因为 XML Recommendation 特别要求“所有 XML 处理程序必须接受 Unicode 3.1 的 UTF-8 和 UTF-16 编码”,但这确实是一个大问题吗?

每个人都能使用 UTF-8

普遍性是选择 UTF-8 的第一个也是最有说服力的理由。它可以处理目前世界上使用的每一种文字。虽然还有少数空白,但是越来越不明显,被逐渐填平了。没有纳入的文字通常也没有其他任何字符集实现过,即使有也不能在 XML 中使用。最好的情况下,这些文字通过字体借用转嫁到 Latin-1 这样的单字节字符集。对这类稀有文字的真正支持可能最先来自 Unicode,而且可能只有 Unicode 支持它们。

但这仅仅是使用 Unicode 的一个理由。为什么选择 UTF-8 而不是 UTF-16 或者其他 Unicode 编码呢?最直接的原因之一是广泛的工具支持。基本上所有可能用于 XML 的主要编辑器都能处理 UTF-8,包括 JEdit、BBEdit、Eclipse、emacs 甚至 Notepad。在 XML 和非 XML 工具中,没有其他 Unicode 编码拥有这样广泛的工具支持。

对于其中一些编辑器,如 BBEdit 和 Eclipse,UTF-8 并不是默认的字符集。现在有必要改变默认设置了,所有工具出厂的时候都应该选择 UTF-8 作为默认编码。除非这样,否则当文件跨越国界、平台和语言传递的时候,我们就会陷入不能互操作的泥潭。不过在所有程序都把 UTF-8 作为默认编码之前,自己修改默认设置也很容易。比如在 Eclipse 中,图 1 所示的“General/Editors”首选项面板允许指定所有文件都使用 UTF-8。您可能注意到 Eclipse 希望默认值为 MacRoman,但是如果这样,当把文件传递给使用 Microsoft® Windows® 的程序员或者美国和西欧之外的计算机时将无法编译。

图 1. 改变 Eclipse 的默认字符集

当然,要让 UTF-8 其作用,开发人员交换的文件也都必须使用 UTF-8,但这不成问题。与 MacRoman 不同,UTF-8 不局限于少数文字或者个别平台。任何人都能用 UTF-8。而 MacRoman、Latin-1、SJIS 和其他各种遗留的国家字符集都不能做到。

UTF-8 在不支持多字节数据的工具中也能正常工作。其他 Unicode 格式如 UTF-16 往往包含很多零字节。很多工具将这些字节解释为文件尾或者其他某种特殊的分界符,造成不希望的、未曾预料到的、常常是不愉快的结果。比方说,如果 UTF-16 数据原样加载到 C 字符串中,字符串可能从第一个 ASCII 字符的第二个字节截断。UTF-8 文件仅在确实表示 null 的地方包含 null。当然,不应该选择这么天真的工具来处理 XML 文档。但是,遗留系统中文档常常在奇怪的地方结束,没有人真正认识到或者理解那些字符序列仅仅是旧瓶装新酒。与 UTF-16 或其他 Unicode 编码相比,对于不支持 Unicode 和 XML 的系统,UTF-8 更不容易造成问题。

 

 回页首

 

专家们的说法

XML 是第一个全面支持 UTF-8 的重要标准,但这仅仅是开始。各标准组织都在逐渐推荐 UTF-8。比如,包含非 ASCII 字符的 URL 是长期困扰 Web 的一个问题。在 PC 机上工作的包含非 ASCII 字符的 URL 不能用于 Mac,反之亦然。万维网联盟(W3C)和 Internet 工程任务组(IETF)最近同意所有 URL 都必须采用 UTF-8 编码而不能是其他编码,从而解决了这一问题。

W3C 和 IETF 对最先、最后还是偶尔使用 UTF-8 变得越来越强硬。The W3C Character Model for the World Wide Web 1.0: Fundamentals 指出,“如果必须选择一种字符编码,则必须是 UTF-8、UTF-16 或 UTF-32。US-ASCII 对 UTF-8 向上兼容(US-ASCII 字符串也是 UTF-8 字符串,参见 [RFC 3629]),因此如果需要与 US-ASCII 保持兼容,UTF-8 非常合适。”事实上,与 US-ASCII 兼容如此重要,几乎是必需的。W3C 明智地解释说,“其他情况下,如对于 API,UTF-16 或 UTF-32 可能更合适。选择一种编码的原因可能包括内部处理的效率以及与其他进程的互操作性。”

我同意内部处理的效率这条理由。比如,Java™ 语言中字符串的内部表示采用 UTF-16,因此对字符串的索引更快。不过,Java 代码永远不会把这种内部表示向与它交换数据的程序公开。相反,对于外部数据交换,要使用 java.io.Writer,明确地指定字符集。选择的时候,强烈推荐 UTF-8。

IETF 甚至更加明确。The IETF Charset Policy [RFC 2277] 指出,在没有不确定性的语言中:

协议必须能够使用 UTF-8 字符集,它由 ISO 10646 编码集和 UTF-8 字符编码方法组成,全文参见 [10646] Annex R(修正版 2 中发布)。

此外,协议可以规定如何使用其他 ISO 10646 字符集和字符编码方案,如 UTF-16,但是不能使用 UTF-8 是对本策略的违反,这种违反在进入或者提升到标准跟踪过程时,需要经过变更程序([BCP9] 第 9 节),并在协议规范文档中提出明确、可靠的理由。

现有的协议或者从已有数据存储转移数据的协议,可能需要支持其他数据集,甚至使用 UTF-8 之外的默认编码。这是允许的,但是必须能够支持 UTF-8。

要点:今后一段时间,对遗留协议和文件的支持可能要求接受 UTF-8 之外的字符集和编码,但是如果必须如此我会非常小心。每种新的协议、应用程序和文档都应该使用 UTF-8。

 

 回页首

 

中文、日文和韩文

一种常见的误解是认为 UTF-8 是一种压缩格式。其实并非如此。与其他 Unicode 编码特别是 UTF-16 相比,在 UTF-8 中 ASCII 字符占用的空间只有一半。不过一些字符的 UTF-8 编码占用的空间要多出 50%,特别是中文、日文和韩文(CJK)这样的象形文字。

但即使用 UTF-8 编码 CJK XML,实际的大小可能也比 UTF-16 小。比如,中文的 XML 文档包含大量 ASCII 字符,如 <、>、&、=、"、' 和空格。这些字符的 UTF-8 编码要比 UTF-16 小。具体的压缩/膨胀因素因文档而异,但不论哪种情况,差别都不可能很明显。

最后,值得一提的是中文和日文这类象形文字,与 Latin、Cyrillic 这类字母文字相比,用字往往更少。由于字符的绝对量很大,要求每个字符使用三个或更多字节才能完全地表达这些文字,就是说,与英文或俄文相比,同样的词语或句子,这些语言可以用更少的字表达。比如,“tree”在日文中用“木”表示(非常像一棵树)。 用 UTF-8 表示需要三个字节,而英文单词“tree”包含四个字母,需要四个字节。日文中的“grove(小树林)”是“林”(两棵树靠在一起)。用 UTF-8 编码需要三个字节,而英文单词“grove”有五个字母,需要五个字节。日文中的“森”(三棵树)仍然需要三个字节。而对应的英文字“forest”需要六个字节。

如果确实需要压缩,则使用 zip 或 gzip。压缩后,UTF-8 和 UTF-16 的大小差不多,不论原始大小相差多少。无论哪种编码,原始大小越大,压缩算法去掉的冗余就更多。

 

 回页首

 

健壮性

真正的优势在于设计,与以前和以后设计的其他任何文本编码相比,UTF-8 是一种更健壮、更容易解释的格式。首先,与 UTF-16 相比,UTF-8 没有 endianness 问题。UTF-8 用 Big-endian 和 little-endian 来表示都是一样的,因为 UTF-8 是按 8 位字节而不是 16 位字定义的。UTF-8 没有字节序的不确定性问题,后者必须通过字节序标志或其他试探手段来解决。

UTF-8 更重要的一个特征是无状态性。UTF-8 流或序列中的每个字节都是明确的。在 UTF-8 中总是可以知道所处的位置,就是说给定一个字节,马上就能确定它是一个单字节字符、双字节字符的第一个字节、双字节字符的第二个字节,或者三字节/四字节字符的第二个、第三个或第四个字节(当然还有其他可能性,但明白这个意思就行)。在 UTF-16 中,就不能确定字节“0x41”是不是字母“A”。有时候是,有时候不是。必须记录足够的状态才能确定在流中的位置。如果损失了一个字节,此后的数据就全部无法用了。在 UTF-8 中,丢失或者破坏的字节很容易确定,也不会影响其他数据。

UTF-8 并非是万能的。需要随机访问文档特定位置的应用程序使用 UCS2 或 UTF-32 这类固定宽度的编码可能操作起来更快。(如果考虑到替换对,UTF-16 是一种变长字符编码。)但是,XML 处理不属于这类应用程序。XML 规范特别要求解析器从 XML 文档的第一个字节开始解析直到最后一个字节,所有现有的解析器都是这样操作的。更快的随机访问对 XML 处理没有什么帮助,虽然对于数据库或其他系统使用不同的编码这可能是一个很好的理由,但不适用于 XML。

 

 回页首

 

结束语

在越来越国际化的世界中,语言和政治边界日渐模糊,依赖于地域的字符集不再适用了。Unicode 是惟一能够跨越很多地域互操作的字符集。UTF-8 是最好的 Unicode 编码:

广泛的工具支持,包括与遗留 ASCII 系统最佳的兼容性。

处理起来简单而高效。

抗讹误。

平台独立。

该停止关于字符集和编码的争论了,选择 UTF-8,结束纷争。

 

 回页首

 

参考资料

学习

您可以参阅本文在 developerWorks 全球站点上的 英文原文。

看看引起这场争论的 Google Sitemap 需求。

Unicode 联盟在 The Unicode Standard 4.0 的 第 3.9 节 发布了 UTF-8 的正式定义。

请访问 Wikipedia,其中提供了很好的 关于 UTF-8 的文章。

请阅读 W3C Character Model for the World Wide Web 1.0: Fundamentals。

IETF Policy on Character Sets and Languages 是作为 RFC 2277 和 BCP 18 发布的。

在 developerWorks XML 专区 可以找到更多 XML 参考资料。

了解如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。

 

 回页首

 

关于作者

 

 Elliotte Harold 出生在新奥尔良,现在,他还定期回老家喝一碗美味的秋葵汤。不过目前他与妻子 Beth 定居在纽约临近布鲁克林的 Prospect Heights,与他们住在一起的还有猫咪 Charm(取自夸克)和 Marjorie(按照他岳母的名字)。他是 Polytechnic 大学计算机科学的副教授,讲授 Java 技术和面向对象编程。他的 Cafe au Lait 网站是 Internet 上最受欢迎的独立 Java 站点之一,姊妹站点 Cafe con Leche 是最受欢迎的 XML 站点之一。他的著作包括 Effective XML、Processing XML with Java、Java Network Programming 和 The XML 1.1 Bible。他目前在研究处理 XML 的 XOM API、Jaxen XPath 引擎和 Jester 测试覆盖工具。

 

 

 回页首

 

对本文的评价

 

太差! (1) 需提高 (2) 一般;尚可 (3) 好文章 (4) 真棒!(5)

建议?

 

 

 回页首

 

 

 

    关于 IBM      隐私条约      联系 IBM

 

应该加入给注册用户发系统公告的功能

  学习日记发新版了,却不能通知在学习日记注册的朋友们,看来应该考虑怎么样把通告发给朋友们。

  1、一个简单的办法是把公告这条目标都加为用户的订阅目标。这样每发一个公告,就当作一个目标下日记更新发给用户了。但是,这样一次连续的发几百上千个公告,虚拟空间的服务器支持吗?发送邮件的邮件服务器支持吗?怎么样确保公告都成功的发给了每个注册用户呢?

  征对前一个问题,我可以问一下虚拟空间的提供商;后一个问题可以看邮件服务器的资料。

  2、另一个方法是专门写一个发消息给所有注册用户的action,这样就可以灵活的处理上面有可能的问题。

  但是,如果第一种方法能满足我的需要,我又何必去费心写多余的代码呢:)

我们写代码一定要遵守代码规范,完善文档

  文档现在在我的心里越来越重要,学习日记不完善的文档成了我心里的一个疙瘩,文档不完善,学习日记的继续向前发展将岌岌可危。主要是:

  1、大家难以交流;

  2、设计思路没有整理,有的代码实现日后再看将是一头雾水,成为向前的羁绊。

  不管是否立刻开始新系统的设计,还是继续完善学习日记现有的一些网友早就提出的紧要问题,把学习日记的文档完善成了一个很大的挑战摆在了我的眼前。

  怎么办?To be or not to be?

mysql数据库的导出和导入

  用图形工具是比较方便的,比如我用的:SQLyog。

  在命令行中的方式为:

  1、把整个数据库导出为一个sql文件:用:mysqldump dbname > c:\mydb.sql

  2、把sql文件导入数据库:用mysql命令进入mysql,在mysql>提示符下输入:

  1)创建数据库:create database newdb;

  2)使用当前数据库:use newdb;

  3)导入sql文件中的数据:source c:\mydb.sql(无分号)

  这样,就把mydb.sql中的数据导入到新的数据库newdb了。

学习日记V0.9.0.4正式推出!

  学习日记V0.9.0.4正式推出!下载地址:http://www.learndiary.com/download/learndiaryV0.9.0.4.war。在learndiaryV0.9.0.3的基础上,有如下主要的变化:

  1)、完善网站的动态导航系统;

  2)、根据功能拆分原来的数据库存取对象,但这不是一个真正的DAO方案;

  3)、初步改善登录模式;

  4)、数据库改为utf-8编码,你可以用任意语言书写自己的学习日记;

  5)、修复了一些bug。

  最新的源代码在我们开发社区的CVS库中随时更新(地址:http://learndiary.tigris.org/source/browse/learndiary/old)。欢迎有志于开源事业的Java爱好者加入到我们的开发队伍。

  我们将本着应用为先,用户至上的原则继续向前发展,为最终实现建设一个具有普遍适用性的开源网络学习交流平台而努力。

struts国际化问题(转贴,如有侵权,请告知)

放在这里备忘。

>> 欢迎您,客人: 登录 | 注册 | 忘记密码 | 在线 | 搜索 | 帮助    |  

 

论坛全文检索:    

 

  【ChinaJavaWorld.com技术论坛】

 『 Struts 及 MVC Framework论坛 』   [返回]

   [原创]"struts中文问题&quo ...  

标记论坛所有内容为已读  

>> 『 Struts 及 MVC Framework论坛 』  欢迎您的到来 << 

    ◆您是本帖第 257 个阅读者◆        

 

  * 贴子主题: [原创]"struts中文问题","struts国际化问题"——终极解决方案                 

 

 

  baozitou007     

 

 

信息:    

威望: 0

来自: 湖北鄂州 

总发贴数: 35 篇

注册日期: 2004/01/17

 

 消息 查看 搜索 好友 邮件 QQ 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  引文

----------------------------------------

----------------------------------------

说实话,你们的方法都做的复杂了,Java本身就支持多国语言编码,不需要写任何程序,可以很简单的

实现。

秘诀就是两点:

1、所有HTML/JSP页面全部采用UTF-8编码

2、客户端浏览器完全支持UTF-8编码

步骤:

1、首先把所有的HTML/JSP的ContentType都设为UTF-8

2、然后对于JSP程序中的非ASCII码提示信息都不应该写在程序里面,都应该放在

application.properties里面统一管理。

3、对HTML用native2ascii工具统一做一次处理,把HTML中的非ASCII码都转换为Unicode编码。

4、针对不同的语言,写不同的application.properties,比如说简体中文是

application_zh_CN.properties,繁体中文是application_zh_TW.properties这样,然后对这些配置信

息文件同样用native2ascii工具处理一次,把非ASCII码统统转为Unicode编码。

5、在Servlet的request.getCharacterEncoding()获得客户端的操作系统默认编码,然后set到Struts

的HTTPSession的Locale中。

OK!现在不同的客户访问,就会显示不同的语言版本了。你可以看看此时你的浏览器的字符集,就是

UTF-8。现在你的网站和Google一样了,嘿嘿,其实你有心的话,看看你的浏览器访问Google的时候是

什么字符集吧

切记:所有的HTML/JSP都要设为UTF-8编码,所有的文件中的非ASCII码字符都要用native2ascii工具转

为用ASCII表示的Unicode编码。

----------------------------------------

----------------------------------------

原创

----------------------------------------

上面所述是我从网上下的一篇于中文问题的解决方案,确切的说应该是关于Struts的国际化问题,下面我结合我的实践谈谈具体如何实现Struts的国际化问题,我对理论不是非常精通,我只能完全凭自己的理解和实践来讲述,所以下面讲的内容可能不是非常正确,还请大家原谅。但有一点可以肯定,我通过自己的努力解决了Struts的中文问题,并实现Struts的国际化,其实一切并不复杂,下面是具体步骤:

  0.遇到的问题(这些问题也许不会同时出现)

    a.中文数据从数据库中到jsp中后就变成了"????"

    b.做好的中文properties文件,其中的中文value在页面显示乱码

    c.jsp文件中的中文到浏览器后显示时也是乱码(建议不要在jsp文件中输入中文,尽量放在properties文件中)

    d.由jsp传给bean的中文值,再由bean传回页面又是乱码

    e.当更换本地浏览器的语言选项时,Web应用程序不能自动根据你的locale选择合适的*.properties文件。导致Web应用程序不能国际化。

  1.环境:

      Web服务器: Tomcat 5.0.19

       操作系统: Win2000 Server

         JVM   : jdk 1.4

       数 据 库: Oracle 8.1.7

       开发工具: struts studio 5.2 pro   for  eclipse

  2.先将所有*.jsp 网页中开头处加入

    <%@ page language="java" contentType="text/html; charset=utf-8" %>

     再设置<html:html locale = "true">

  3.然后编辑好两个*.properties文件,放在classes文件夹下你指定的地方,这里是放在/web-inf/classes/com/wiley 下,它们分别是:

    ApplicationResources.properties  (英文资源文件)

    ApplicationResources_zh.properties (中文资源文件)

    随便用什么工具编写都行啊!

  4.将ApplicationResources_zh.properties转码成gb2312。上面引文说要转成UTF-8,结果我试了,不行。转成gb2312就行了,操作是。

    将ApplicationResources_zh.properties更名为ApplicationResources_xx.properties

    在DOS命令行进入ApplicationResources_xx.properties所在的文件夹

    使用命令:native2ascii -encoding gb2312 ApplicationResources_xx.properties ApplicationResources_zh.properties(至于你为什么会出现“native2ascii不是内部命令”,,请查其它资料,可能你要设置环境变量,因为他是jdk的文件夹bin下的一个应用程序)

   5.接下来配置struts-config.xml,很简单,我们加入:

   <message-resources parameter="com.wiley.ApplicationResources"/>  就行了;

   到此已能解决大多数中文问题。如上面所说的a,b,e 现在打开浏览器,选择菜单:工具》internet选项》语言,将“中文-中国[zh-cn]”删掉,添加一个“英语-英国[zh-gb]”确定后,重启Tomcat,输入网址你就会发现,你的页面的文本信息就会用的是ApplicationResources.properties  (英文资源文件)中的内容。如果换回“中文-中国[zh-cn]”,它就会显示ApplicationResources_zh.properties (中文资源文件)中的中文内容。

  至于问题“c.jsp文件中的中文到浏览器后显示时也是乱码” 你就要用与第4步类似的方法来重新对*.jsp 文件编码,这时-encoding的参数就要用UTF-8了,如果你用的也是struts studio 5.2 pro   for  eclipse工具,这一步就免了。它会自动用UTF-8的格式存储。

  至于问题“d.由jsp传给bean的中文值,再由bean传回页面又是乱码”的解决,我只是加了个过滤器。

你可以现在web.xml中加入:

<filter>

<filter-name>Set Character Encoding</filter-name>

<filter-class>com.wiley.SetCharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>utf-8</param-value> 

</init-param>

<init-param>

<param-name>ignore</param-name>

<param-value>true</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>Set Character Encoding</filter-name>

<servlet-name>action</servlet-name>

</filter-mapping>

  然后在你指定的包内加个java文件 我放在了/web-inf/classes/com/wiley 里,下面是源代码:

/*

* XP Forum

*

* Copyright (c) 2002-2003 RedSoft Group. All rights reserved.

*

*/

package com.huahang.tj.struts.filters;

import javax.servlet.*;

import java.io.IOException;

/**

* <p>Filter that sets the character encoding to be used in parsing the

* incoming request, either unconditionally or only if the client did not

* specify a character encoding. Configuration of this filter is based on

* the following initialization parameters:</p>

* <ul>

* <li><strong>encoding</strong> - The character encoding to be configured

* for this request, either conditionally or unconditionally based on

* the <code>ignore</code> initialization parameter. This parameter

* is required, so there is no default.</li>

* <li><strong>ignore</strong> - If set to "true", any character encoding

* specified by the client is ignored, and the value returned by the

* <code>selectEncoding()</code> method is set. If set to "false,

* <code>selectEncoding()</code> is called <strong>only</strong> if the

* client has not already specified an encoding. By default, this

* parameter is set to "true".</li>

* </ul>

*

* <p>Although this filter can be used unchanged, it is also easy to

* subclass it and make the <code>selectEncoding()</code> method more

* intelligent about what encoding to choose, based on characteristics of

* the incoming request (such as the values of the <code>Accept-Language</code>

* and <code>User-Agent</code> headers, or a value stashed in the current

* user's session.</p>

*

* @author <a href="mailto:jwtronics@yahoo.com">John Wong</a>

*

* @version $Id: SetCharacterEncodingFilter.java,v 1.1 2002/04/10 13:59:27 johnwong Exp $

*/

public class SetCharacterEncodingFilter implements Filter {

// ----------------------------------------------------- Instance Variables

/**

* The default character encoding to set for requests that pass through

* this filter.

*/

protected String encoding = null;

/**

* The filter configuration object we are associated with. If this value

* is null, this filter instance is not currently configured.

*/

protected FilterConfig filterConfig = null;

/**

* Should a character encoding specified by the client be ignored?

*/

protected boolean ignore = true;

// --------------------------------------------------------- Public Methods

/**

* Take this filter out of service.

*/

public void destroy() {

this.encoding = null;

this.filterConfig = null;

}

/**

* Select and set (if specified) the character encoding to be used to

* interpret request parameters for this request.

*

* @param request The servlet request we are processing

* @param result The servlet response we are creating

* @param chain The filter chain we are processing

*

* @exception IOException if an input/output error occurs

* @exception ServletException if a servlet error occurs

*/

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain)

throws IOException, ServletException {

// Conditionally select and set the character encoding to be used

if (ignore || (request.getCharacterEncoding() == null)) {

String encoding = selectEncoding(request);

if (encoding != null)

request.setCharacterEncoding(encoding);

}

// Pass control on to the next filter

chain.doFilter(request, response);

}

/**

* Place this filter into service.

*

* @param filterConfig The filter configuration object

*/

public void init(FilterConfig filterConfig) throws ServletException {

this.filterConfig = filterConfig;

this.encoding = filterConfig.getInitParameter("encoding");

String value = filterConfig.getInitParameter("ignore");

if (value == null)

this.ignore = true;

else if (value.equalsIgnoreCase("true"))

this.ignore = true;

else if (value.equalsIgnoreCase("yes"))

this.ignore = true;

else

this.ignore = false;

}

// ------------------------------------------------------ Protected Methods

/**

* Select an appropriate character encoding to be used, based on the

* characteristics of the current request and/or filter initialization

* parameters. If no character encoding should be set, return

* <code>null</code>.

* <p>

* The default implementation unconditionally returns the value configured

* by the <strong>encoding</strong> initialization parameter for this

* filter.

*

* @param request The servlet request we are processing

*/

protected String selectEncoding(ServletRequest request) {

return (this.encoding);

}

}//EOC

   到此我遇到的中文问题已全部得到解决,并从中理解到struts的国际化的深刻含义。

我个人觉得struts作为一个功能强大的应用框架,应该早就考虑到它的国际化问题,并在实际应用中不会很复杂,只要我们遵循一些规则,就可以尽情享受struts给我们带来的无穷乐趣。希望以上所述对大家有所帮助。

 

 

 

 

--------------------------------------------------------------------------------

  2004/03/30 09:36am IP: 已设置保密  

 

 

 

  风行天下     

 

 

信息:    

威望: 0

来自: 北京 

总发贴数: 59 篇

注册日期: 2003/04/28

 

 消息 查看 搜索 好友 邮件 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  thanks very much

 

 

 

--------------------------------------------------------------------------------

  2004/03/30 12:07pm IP: 已设置保密  

 

 

 

  zhushilin     

  kopf43

 

信息:   

威望: 0

来自: 上海 

总发贴数: 43 篇

注册日期: 2002/07/24

 

 消息 查看 搜索 好友 邮件 QQ 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  好文章,长见识了

 

 

 

--------------------------------------------------------------------------------

  2004/03/30 01:17pm IP: 已设置保密  

 

 

 

  iamisabird     

 

 

信息:  

威望: 0

来自: 保密 

总发贴数: 17 篇

注册日期: 2004/02/21

 

 消息 查看 搜索 好友 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  我想问一下,在步骤2中提到的“非ASCII码提示信息“是指哪些东西

 

 

 

--------------------------------------------------------------------------------

  2004/03/30 11:36pm IP: 已设置保密  

 

 

 

  baozitou007     

 

 

信息:    

威望: 0

来自: 湖北鄂州 

总发贴数: 35 篇

注册日期: 2004/01/17

 

 消息 查看 搜索 好友 邮件 QQ 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  这里说的“非ASCII码提示信息”说的是在你的jsp文件中输入不是a,b,c,d......r等ASCII码表中的字符,比如说“中文”,或者是“韩文”等,这都是非“非ASCII码提示信息”例如:

    <html:html xhtml="true" locale="true">

<head>

   <title>

      <bean:message key="app.title" />

   </title>

</head>

<body>

    看来UTF-8是个好东西!

<table width="500" border="0" cellspacing="0" cellpadding="0">

  <tr>

    <td> </td>

  </tr>

  <tr bgcolor="#36566E">

    <td height="68" width="48%">

----------------------------------

其中“看来UTF-8是个好东西!”就是我们说的“非ASCII码提示信息”

 

 

 

--------------------------------------------------------------------------------

  2004/03/31 09:19am IP: 已设置保密  

 

 

 

  momocha     

 

 

信息: 

威望: 0

来自: 保密 

总发贴数: 59 篇

注册日期: 2003/06/26

 

 消息 查看 搜索 好友 邮件 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  切记:所有的HTML/JSP都要设为UTF-8编码,所有的文件中的非ASCII码字符都要用native2ascii工具转

为用ASCII表示的Unicode编码。

问个问题,你所说的这一步不太明白,是不是每一个包含非ascii的jsp/html文件都要用这个工具转换一个,能说说这个工具吗,谢谢了!!

 

 

 

 

--------------------------------------------------------------------------------

  2004/03/31 03:03pm IP: 已设置保密  

 

 

 

  baozitou007     

 

 

信息:    

威望: 0

来自: 湖北鄂州 

总发贴数: 35 篇

注册日期: 2004/01/17

 

 消息 查看 搜索 好友 邮件 QQ 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  native2ascii -encoding gb2312 jspname.jsp newjspname.jsp

  native2ascii这个工具是jdk自带的一个东东,所以如果path都设定正确就可以直接运行了,你可以在$java_home$/bin下找到他。

  所以你要设一下系统环境变量:C:\jdk\bin

 

 

 

 

--------------------------------------------------------------------------------

  2004/04/01 10:01am IP: 已设置保密  

 

 

 

  sdyjmc   头衔: 飞天

 

 

信息:   

威望: 0

来自: 其它大洋洲 

总发贴数: 886 篇

注册日期: 2001/12/21

 

 消息 查看 搜索 好友 主页 QQ ICQ 复制 引用 回复   加到"个人收藏夹"

--------------------------------------------------------------------------------

  不知数据库中的编码,在datasource中怎么解决?能够建立pool的时候指定编码?

<set-property property="weblogic.codeset" value="GBK" />

 

 

 

 

--------------------------------------------------------------------------------

  2004/04/01 04:54pm IP: 已设置保密  

 

 

 

 该主题只有一页  跳转论坛至... ╋Java 2 Platform, Standard Edition (J2SE) 与Java核心技术论坛 |-『 Java语言*初级版 』 |-『 Java语言*高级版 』 |-『 JavaGUI设计 』 |-『 Java安全版块 』 |-『 Java工具安装、配置与使用 』 |-『 Java新技术,新闻,应用与资源等 』╋Java 2 Platform, Enterprise Edition (J2EE) 技术论坛 |-『 JSP/Servlets/JSF 』 |-『 JDBC,JDO 』 |-『 EJB 』 |-『 其他J2EE技术 』╋Java 2 Platform, Micro Edition (J2ME)技术论坛 |-『 J2ME 技术论坛 』╋J2EE 应用服务器 技术论坛 |- 『 BEA WebLogic Platform 技术论坛 』 |-『 IBM WebSphere 技术论坛』 |-『 其他应用服务器技术论坛 』  ╋Web Services和XML技术 |-『 Web Services 技术论坛 』 |-『 XML技术论坛 』╋Apache Jakarta Project技术论坛 |-『 Tomcat技术论坛』   |-『 Struts 及 MVC Framework论坛 』  ╋软件过程管理,建模等 |-『 设计模式 』 |-『 UML 』 |-『 软件测试 』 |-『 软件工程,过程及项目管理 』╋Java相关认证论坛系列 |-『 SCJP认证论坛 』 |-『 Java其他认证 』╋数据库技术 |-『 Oracle&PostgreSQL技术论坛 』╋其他软件开发技术 |-『 C#和.Net技术论坛 』╋操作系统 |-『 操作系统论坛 』╋其他 |-『 休闲乐园 』 |-『 英语学习论坛 』 |-『 求职与招聘 』 |-『 广告论坛 』╋站务建设区 |-『 站务建设 』 |-『 版主专区 』   |-『 论坛公告区 』 |-『 帖子讨论专区 』╋ChinaJavaWorld服务专栏 

   快速回复主题: [原创]"struts中文问题","struts国际化问题"——终极解决方案

输入用户名和密码: 用户名:  没有注册? 密码:  忘记密码?

上传附件或图片 (最大容量 300KB)   支持类型:----------gifjpgbmpzippngswfdoctxthtmhtmlgzrartarsxw

选项

使用 LB5000 标签?

显示您的签名?

有回复时使用邮件通知您?

 

   [使用 Ctrl+Enter 直接提交贴子] 

 

 顶端 加到"个人收藏夹" 主题管理: 总固顶 | 取消总固顶 | 区固顶 | 取消区固顶 | 固顶 | 取消固顶 |

精华 | 取消精华 | 提升 | 锁定 | 解锁 | 删除 | 删除回复 | 移动 | 

  

--------------------------------------------------------------------------------

© 中文版权所有: Java开发者  版本: LB5000MX 2.00

程序版权所有: CGI 编程者之家    程序编制: 山鹰(糊)、 花无缺

本论坛言论纯属发表者个人意见,与 【ChinaJavaWorld.com技术论坛】 立场无关

 

基础问题出错:String的split(String str)方法用法

  如果一行只有一个回车换行符,那么这行用这个方法分开得到是一个0长度字符串,

下面这一句:

        if (charArray[0] != ' ') {

        sB.append(lineStr);

        sB.append("<br>");

      }

  就会出现indexOutOfBoundary这样的错误。

    //replace space at beginning and add "<br>" at end of every line

    String[] strArray = tempStr.split("\n");

    StringBuffer sB = new StringBuffer();

    for (int i = 0; i < strArray.length; i++) {

      String lineStr = strArray[i];

      //System.out.println(i +" : lineStr is: " + lineStr+"ok");

      char[] charArray = lineStr.toCharArray();

 

      //if no any char in this line,then add a <br> to the end of sB,

      //continue loop(don't excute the code behind continue in this loop).

      if (charArray.length == 0){

        sB.append("<br>");

        //System.out.println("come here.");

        continue;

      } 

     

      if (charArray[0] != ' ') {

        sB.append(lineStr);

        sB.append("<br>");

      }

完整代码:

package com.learndiary.website.util;

//import com.learndiary.util.*;

public class Util {

   

  public static String htmlFormat(String source) {

    //if (source==null) return null;//WHEN the source is "",run at line 33,will happen ArrayIndexOutOfBoundsException.

    //because char[0] don't exist a charactor.

    if ((source==null)||(source.length()==0)) return "";

    //replace "<>"

    String tempStr = source.replaceAll("<", "<").replaceAll(">", ">");

   

    //replace space at beginning and add "<br>" at end of every line

    String[] strArray = tempStr.split("\n");

    StringBuffer sB = new StringBuffer();

    for (int i = 0; i < strArray.length; i++) {

      String lineStr = strArray[i];

      //System.out.println(i +" : lineStr is: " + lineStr+"ok");

      char[] charArray = lineStr.toCharArray();

 

      //if no any char in this line,then add a <br> to the end of sB,

      //continue loop(don't excute the code behind continue in this loop).

      if (charArray.length == 0){

        sB.append("<br>");

        //System.out.println("come here.");

        continue;

      } 

     

      if (charArray[0] != ' ') {

        sB.append(lineStr);

        sB.append("<br>");

      } else {

      for (int j = 0; j < charArray.length; j++) {//if the first char of this String is space,need convert the first space to " "

        if (charArray[j] == ' ')//if there are several spaces at the begin of this String,need convert every space to " ".

          sB.append(" ");  

          else {//once meet a char isn't a space,then every space after this char needn't to be converted to " " in this string.

                //we can add the all charaters after this char,then ,add "<br>" to the end of this String.

            sB.append(charArray, j, charArray.length - j);

            //sB.append("<br>");

            break;

          }

        }

        sB.append("<br>");//need add " " to the end of this string.why put this sentence at here?

                          //if every character is space in this string,it also needs adding "<br>" at the end of this string.

      }

    }

   

    String resultTemp = sB.toString();

    String result = resultTemp.substring(0, resultTemp.length() - 4);       

    return result;

    //replaceAll(" ", " ").

  } 

 

  // Simple test:

  /* 

  public static void main(String[] args) throws Exception {

    String file = TextFile.read("gb5.txt");

    System.out.println("file is: \n" + file);

    String result = htmlFormat(file);

    System.out.println("result is \n" + result);

    write("test.txt", file);

    TextFile text = new TextFile("test.txt");

    text.write("test2.txt");

  }

   */

}

jdk1.4的文档:(还没有看懂,记在这里,慢慢看)

split

public String[] split(String regex,

                      int limit)

Splits this string around matches of the given regular expression.

The array returned by this method contains each substring of this string that is terminated by another substring that matches the given expression or is terminated by the end of the string. The substrings in the array are in the order in which they occur in this string. If the expression does not match any part of the input then the resulting array has just one element, namely this string.

The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.

The string "boo:and:foo", for example, yields the following results with these parameters:

Regex Limit Result

: 2 { "boo", "and:foo" }

: 5 { "boo", "and", "foo" }

: -2 { "boo", "and", "foo" }

o 5 { "b", "", ":and:f", "", "" }

o -2 { "b", "", ":and:f", "", "" }

o 0 { "b", "", ":and:f" }

An invocation of this method of the form str.split(regex, n) yields the same result as the expression

Pattern.compile(regex).split(str, n)

Parameters:

regex - the delimiting regular expression

limit - the result threshold, as described above

Returns:

the array of strings computed by splitting this string around matches of the given regular expression

Throws:

PatternSyntaxException - if the regular expression's syntax is invalid

Since:

1.4

See Also:

Pattern

--------------------------------------------------------------------------------

split

public String[] split(String regex)

Splits this string around matches of the given regular expression.

This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array.

The string "boo:and:foo", for example, yields the following results with these expressions:

Regex Result

: { "boo", "and", "foo" }

o { "b", "", ":and:f" }

Parameters:

regex - the delimiting regular expression

Returns:

the array of strings computed by splitting this string around matches of the given regular expression

Throws:

PatternSyntaxException - if the regular expression's syntax is invalid

Since:

1.4

See Also:

Pattern

改變學習日記的字符集總結,查詢utf數據庫?

版权声明:本文章为学习日记网站(http://www.learndiary.com )版权所有,以<a href="http://creativecommons.org/licenses/by/2.0/">Creative Commons License</a>方式授权。欢迎转载,但请注明文章原始出处(http://www.learndiary.com/disDiaryContentAction.do?goalID=1242 )。

 

  1、想在学习日记中(http://www.learndiary.com)贴繁体字的文章,结果是乱码;

  2、先改为GBK,可是不知道为什么,用GBK写到数据库中和页面上的字符都自动加了转义符了(\),如:(")变成了 (\"),还有,原来,文本里的回车换行都被加上了转义,于是,在网页上连换行都不行了,如:(\r\n)自动变成了(\\r\\n)。到现在,我也不知道这是什么原因,先放在这里,等以后再学习;

  3、看了jive3论坛,发现程序使用的字符集与mysql使用的默认字符集好像是无关的(究竟有没有关,还须进一步学习:),学习日记虚拟主机空间默认使用的是gb2312;于是,试着在数据库连接字符串用utf-8的characterEncoding=UTF-8;结果成功可以使用;

  4、原来数据库中的数据是gb2312编码的,必须转成utf-8。我用了一个笨办法,先把数据中的数据导出成sql文件,把sql文件全部用ultraedit(旧版本的不行,我下了一个最新的 11烈火版)转成utf-8格式;

  5、但是把转换后的sql文件重新导入数据库中出错,不知道为什么,偶然发现在用ultraedit转成的sql文件中的两个字段间缺了一个单引号',前一个字段后有一个?号,像:本该是这样的('学习','日记'),变成了('学?,'日记'),我想这是转码过程中出现的问题,问题是怎么一回事?现在还不清楚,以后学习;

  6、用ultraedit查找替换掉错误的地方,导入成功;

  7、导入后的数据有的被截掉了尾巴,原来是在utf-8编码中,一个汉字是3个字节,一个英文字符是1个字节,于是,原来的数据库字段长就不合适了;

  8、修改字段长度,然后把sql文件像上面那样转码、修改、导入。

  9、完成,可以用繁体字写日记了。

  10、缺陷:无法在数据库中直接用中文关键字执行查询了,也不能直接看到数据库中的内容了,不知道怎么解决这个问题?以后再学习。

的用法

忘性真大,一段時間不用,這些簡單的東西又要翻書了,看來,3天不用手生,3天不說口生。的確不假呀。

<html:text>和<html:textarea>标记分别HTML文本框和文本区,属性如下:

属性 描述

Property 定义当表单被提交时送回到服务器的请求参数的名称,或用来确定文本元素当前值的bean的属性名称

Name 属性被查询的bean的名称,它决定了文本框和文本区的值。如果没有设置,将使用与这个内嵌表单相关的ActionForm的名称

<html:text>标记还有以下属性:

属性 描述

Maxlength 能够输入的最大字符数

Size 文本框的大小(字符数)

(补充:这里的字符数是不论是汉字还英文,一个汉字和一个英文字符都算一个字符;与UTF-8对比为:一个汉字3个英文字符;与java中的对比:一个汉字1个英文;与gb2312对比:一个汉字2个英文字符(即2个字节))

例如:<html:text property="articleName" maxlength="50" size="50"/>