Java 编程经验(牛人写的) 下

 原文链接 http://blog.sina.com.cn/s/blog_530abec50100i1f0.html

Java杂谈(五)


本来预计J2se只讲了第四篇就收尾了,可是版主厚爱把帖子置顶长期让大家浏览让小弟倍感责任重大,务必追求最到更好,所以关于J2se一些没有提到的部分,决定再写几篇把常用的部分经验全部写出来供大家讨论切磋。这一篇准备讲一讲Xml解析包和JavaSwing,然后下一篇再讲java.security包关于Java沙箱安全机制和RMI机制,再进入J2ee的部分,暂时就做这样的计划了。如果由于实习繁忙更新稍微慢了一些,希望各位见谅!

1. Java关于XML的解析
相信大家对XML都不陌生,含义是可扩展标记语言。本身它也就是一个数据的载体以树状表现形式出现。后来慢慢的数据变成了信息,区别是信息可以包括可变的状态从而针对程序硬编码的做法变革为针对统一接口硬编码而可变状态作为信息进入了XML中存储。这样改变状态实现扩展的唯一工作是在XML中添加一段文本信息就可以了,代码不需要改动也不需要重新编译。这个灵活性是XML诞生时候谁也没想到的。

当然,如果接口要能提取XML中配置的信息就需要程序能解析规范的XML文件,Java中当然要提高包对这个行为进行有利支持。笔者打算讲到的两个包是 org.w3c.dom和javax.xml.parsers和。(大家可以浏览一下这些包中间的接口和类定义)

Javax.xml.parsers包很简单,没有接口,两个工厂配两个解析器。显然解析XML是有两种方式的:DOM解析和SAX解析。本质上并没有谁好谁不好,只是实现的思想不一样罢了。给一个XML文件的例子:
<?xml version=”1.0” encoding=”UTF-8”>
<root >
<child name=”Kitty” >
ACat
</child>
</root >

所谓DOM解析的思路是把整个树状图存入内存中,需要那个节点只需要在树上搜索就可以读到节点的属性,内容等,这样的好处是所有节点皆在内存可以反复搜索重复使用,缺点是需要消耗相应的内存空间。

自然SAX解析的思路就是为了克服DOM的缺点,以事件触发为基本思路,顺序的搜索下来,碰到了Element之前触发什么事件,碰到之后做什么动作。由于需要自己来写触发事件的处理方案,所以需要借助另外一个自定义的Handler,处于org.xml.sax.helpers包中。它的优点当然是不用整个包都读入内存,缺点也是只能顺序搜索,走完一遍就得重来。

大家很容易就能猜到,接触到的J2ee框架用的是哪一种,显然是DOM。因为类似Struts,Hibernate框架配置文件毕竟是很小的一部分配置信息,而且需要频繁搜索来读取,当然会采用DOM方式(其实SAX内部也是用DOM采用的结构来存储节点信息的)。现在无论用什么框架,还真难发现使用 SAX来解析XML的技术了,如果哪位仁兄知道,请让笔者也学习学习。

既然解析方式有了,那么就需要有解析的存储位置。不知道大家是否发现org.w3c.dom这个包是没有实现类全部都是接口的。这里笔者想说一下Java 如何对XML解析是Jdk应该考虑的事,是它的责任。而w3c组织是维护定义XML标准的组织,所以一个XML结构是怎么样的由w3c说了算,它不关心 Java如何去实现,于是乎规定了所有XML存储的结构应该遵循的规则,这就是org.w3c.dom里全部的接口目的所在。在笔者看来,简单理解接口的概念就是实现者必须遵守的原则。

整个XML对应的结构叫Document、子元素对应的叫做Element、还有节点相关的Node、NodeList、Text、Entity、 CharacterData、CDATASection等接口,它们都可以在XML的语法中间找到相对应的含义。由于这里不是讲解XML基本语法,就不多介绍了。如果大家感兴趣,笔者也可以专门写一篇关于XML的语法规则帖与大家分享一下。

2. Java Swing
Swing是一个让人又爱又恨的东西,可爱之处在于上手很容易,较AWT比起来Swing提供的界面功能更加强大,可恨之处在于编复杂的界面工作量实在是巨大。笔者写过超过3000行的Swing界面,感觉用户体验还不是那么优秀。最近又写过超过6000行的,由于功能模块多了,整体效果还只是一般般。体会最深的就一个字:累!所以大家现在都陆续不怎么用Swing在真正开发的项目上了,太多界面技术可以取代它了。笔者去写也是迫于无奈组里面大家都没写过,我不入地域谁入?

尽管Swing慢慢的在被人忽略,特别是随着B/S慢慢的在淹没C/S,笔者倒是很愿意站出来为Swing正身。每一项技术的掌握绝不是为了流行时尚跟风。真正喜欢Java的朋友们还是应该好好体会一下Swing,相信在校的很多学生也很多在学习它。很可能从Jdk1.1、1.2走过来的很多大学老师可能是最不熟悉它的。
Swing提供了一组轻组件统称为JComponent,它们与AWT组件的最大区别是JComponent全部都是Container,而 Container的特点是里面可以装载别的组件。在Swing组件中无论是JButton、JLabel、JPanel、JList等都可以再装入任何其他组件。好处是程序员可以对Swing组件实现“再开发”,针对特定需求构建自己的按钮、标签、画板、列表之类的特定组件。

有轻自然就有重,那么轻组件和重组件区别是?重组件表现出来的形态因操作系统不同而异,轻组件是Swing自己提供GUI,在跨平台的时候最大程度的保持一致。
那么在编程的时候要注意一些什么呢?笔者谈谈自己的几点经验:

a. 明确一个概念,只有Frame组件才可以单独显示的,也许有人会说JOptionPane里面的静态方法就实现了单独窗口出现,但追寻源代码会发现其实现实出来的Dialog也需要依托一个Frame窗体,如果没有指定就会默认产生一个然后装载这个Dialog显示出来。

b. JFrame是由这么几部分组成:
最底下一层JRootPane,上面是glassPane(一个JPanel)和layeredPane(一个JLayeredPane),而layeredPane又由contentPane(一个JPanel)和menuBar构成。我们的组件都是加在 contentPane上,而背景图片只能加在layeredPane上面。至于glassPane是一个透明的覆盖了contentPane的一层,在特定效果中将被利用到来记录鼠标坐标或掩饰组件。

c. 为了增强用户体验,我们会在一些按钮上添加快捷键,但Swing里面通常只能识别键盘的Alt键,要加入其他的快捷键,必须自己实现一个ActionListener。

d. 通过setLayout(null)可以使得所有组件以setBounds()的四个参数来精确定位各自的大小、位置,但不推荐使用,因为好的编程风格不应该在Swing代码中硬编码具体数字,所有的数字应该以常数的形式统一存在一个静态无实例资源类文件中。这个静态无实例类统一负责Swing界面的风格,包括字体和颜色都应该包括进去。

e. 好的界面设计有一条Golden Rule: 用户不用任何手册通过少数尝试就能学会使用软件。所以尽量把按钮以菜单的形式(不管是右键菜单还是窗体自带顶部菜单)呈现给顾客,除非是频繁点击的按钮才有必要直接呈现在界面中。

其实Swing的功能是相当强大的,只是现在应用不广泛,专门去研究大概是要花不少时间的。笔者在各网站论坛浏览关于Swing的技巧文章还是比较可信的,自己所学非常有限,各人体会对Swing各个组件的掌握就是一个实践积累的过程。笔者只用到过以上这些,所以只能谈谈部分想法,还望大家见谅!
###################################################################################################################
Java杂谈(六)


这篇是笔者打算写的J2se部分的最后一篇了,这篇结束之后,再写J2ee部分,不知道是否还合适写在这个版块?大家可以给点意见,谢谢大家对小弟这么鼓励一路写完前六篇Java杂谈的J2se部分。最后这篇打算谈一谈Java中的RMI机制和JVM沙箱安全框架。

1. Java中的RMI机制
RMI的全称是远程方法调用,相信不少朋友都听说过,基本的思路可以用一个经典比方来解释:A计算机想要计算一个两个数的加法,但A自己做不了,于是叫另外一台计算机B帮忙,B有计算加法的功能,A调用它就像调用这个功能是自己的一样方便。这个就叫做远程方法调用了。

远程方法调用是EJB实现的支柱,建立分布式应用的核心思想。这个很好理解,再拿上面的计算加法例子,A只知道去call计算机B的方法,自己并没有B的那些功能,所以A计算机端就无法看到B执行这段功能的过程和代码,因为看都看不到,所以既没有机会窃取也没有机会去改动方法代码。EJB正式基于这样的思想来完成它的任务的。当简单的加法变成复杂的数据库操作和电子商务交易应用的时候,这样的安全性和分布式应用的便利性就表现出来优势了。

好了,回到细节上,要如何实现远程方法调用呢?我希望大家学习任何技术的时候可以试着依赖自己的下意识判断,只要你的想法是合理健壮的,那么很可能实际上它就是这么做的,毕竟真理都蕴藏在平凡的生活细节中。这样只要带着一些薄弱的Java基础来思考RMI,其实也可以想出个大概来。

a) 需要有一个服务器角色,它拥有真正的功能代码方法。例如B,它提供加法服务
b) 如果想远程使用B的功能,需要知道B的IP地址
c) 如果想远程使用B的功能,还需要知道B中那个特定服务的名字

我们很自然可以想到这些,虽然不完善,但已经很接近正确的做法了。实际上RMI要得以实现还得意于Java一个很重要的特性,就是Java反射机制。我们需要知道服务的名字,但又必须隐藏实现的代码,如何去做呢?答案就是:接口!
举个例子:
public interface Person(){
public void sayHello();
}

Public class PersonImplA implements Person{
public PersonImplA(){}

public void sayHello(){ System.out.println(“Hello!”);}
}

Public class PersonImplB implements Person{
public PersonImplB(){}

public void sayHello(){ System.out.println(“Nicetomeet you!”);}
}

客户端:Person p = Naming.lookup(“PersonService”);
p.sayHello();

就这几段代码就包含了几乎所有的实现技术,大家相信么?客户端请求一个say hello服务,服务器运行时接到这个请求,利用Java反射机制的Class.newInstance()返回一个对象,但客户端不知道服务器返回的是 ImplA还是ImplB,它接受用的参数签名是Person,它知道实现了Person接口的对象一定有sayHello()方法,这就意味着客户端并不知道服务器真正如何去实现的,但它通过了解Person接口明确了它要用的服务方法名字叫做sayHello()。

如此类推,服务器只需要暴露自己的接口出来供客户端,所有客户端就可以自己选择需要的服务。这就像餐馆只要拿出自己的菜单出来让客户选择,就可以在后台厨房一道道的按需做出来,它怎么做的通常是不让客户知道的!(祖传菜谱吧,^_^)

最后一点是我调用lookup,查找一个叫PersonService名字的对象,服务器只要看到这个名字,在自己的目录(相当于电话簿)中找到对应的对象名字提供服务就可以了,这个目录就叫做JNDI(Java命名与目录接口),相信大家也听过的。

有兴趣的朋友不妨自己做个RMI的应用,很多前辈的博客中有简单的例子。提示一下利用Jdk的bin目录中rmi.exe和 rmiregistry.exe两个命令就可以自己建起一个服务器,提供远程服务。因为例子很容易找,我就不自己举例子了!

2. JVM沙箱&框架
RMI罗唆得太多了,实在是尽力想把它说清楚,希望对大家有帮助。最后的最后,给大家简单讲一下JVM框架,我们叫做Java沙箱。Java沙箱的基本组件如下:
a) 类装载器结构
b) class文件检验器
c) 内置于Java虚拟机的安全特性
d) 安全管理器及Java API

其中类装载器在3个方面对Java沙箱起作用:
a. 它防止恶意代码去干涉善意的代码
b. 它守护了被信任的类库边界
c. 它将代码归入保护域,确定了代码可以进行哪些操作

虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。

我们常说的包(package)是在Java虚拟机第2版的规范第一次出现,正确定义是由同一个类装载器装载的、属于同一个包、多个类型的集合。类装载器采用的机制是双亲委派模式。具体的加载器框架我在Java杂谈(一)中已经解释过了,当时说最外层的加载器是AppClassLoader,其实算上网络层的话AppClassLoader也可以作为parent,还有更外层的加载器URLClassLoader。为了防止恶意攻击由URL加载进来的类文件我们当然需要分不同的访问命名空间,并且制定最安全的加载次序,简单来说就是两点:

a. 从最内层JVM自带类加载器开始加载,外层恶意同名类得不到先加载而无法使用
b. 由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。

附:关于Java的平台无关性,有一个例子可以很明显的说明这个特性:
一般来说,C或C++中的int占位宽度是根据目标平台的字长来决定的,这就意味着针对不同的平台编译同一个C++程序在运行时会有不同的行为。然而对于 Java中的int都是32位的二进制补码标识的有符号整数,而float都是遵守IEEE754浮点标准的32位浮点数。

PS: 这个小弟最近也没时间继续研究下去了,只是想抛砖引玉的提供给大家一个初步认识JVM的印象。有机会了解一下JVM的内部结构对今后做Java开发是很有好处的。
####################################################################################################################
Java杂谈(七)--接口& 组件、容器

终于又静下来继续写这个主题的续篇,前六篇主要讲了一些J2se方面的经验和感受, 眼下Java应用范围已经被J2ee占据了相当大的一块领域,有些人甚至声称Java被J2ee所取代了。不知道大家如何来理解所谓的J2ee (Java2EnterpriseEdition),也就是Java企业级应用?

笔者的观点是,技术的发展是顺应世界变化的趋势的,从C/S过渡到B/S模式,从客户端的角度考虑企业级应用或者说电子商务领域不在关心客户端维护问题,这个任务已经交给了任何一台PC都会有的浏览器去维护;从服务器端的角度考虑,以往C/S中的TCP/IP协议实现载体ServerSocket被WebServerContainer所取代,例如大家都很熟悉的Tomcat、JBoss、WebLogic等等。总之一切的转变都是为了使得Java技术能更好的为人类生产生活所服务。

有人会问,直接去学J2ee跳过J2se行否?笔者是肯定不赞成的,实际上确实有人走这条路,但笔者自身体会是正是由于J2se的基础很牢固,才会导致在J2ee学习的道路上顺风顺水,知识点上不会有什么迷惑的地方。举个简单的例子吧:

笔者曾经跟大学同学讨论下面这两种写法的区别:
ArrayList list=new ArrayList();//笔者不说反对,但至少不赞成
List list=new ArrayList();//笔者支持
曾经笔者跟同学争论了几个小时,他非说第一种写法更科学,第二种完全没有必要。我无法完全说服他,但笔者认为良好的习惯和意识是任何时候都应该针对接口编程,以达到解耦合和可扩展性的目的。下面就以接口开始进入J2ee的世界吧:

1. J2ee与接口

每一个版本的J2ee都对应着一个确定版本的JDK,J2ee1.4对应Jdk1.4,现在比较新的是JDK5.0,自然也会有J2EE5.0。其实笔者一直在用的是J2EE1.4,不过没什么关系,大家可以下任何一个版本的J2eeapi来稍微浏览一下。笔者想先声明一个概念,J2ee也是源自Java,所以底层的操作依然调用到很多J2se的库,所以才建议大家先牢牢掌握J2se 的主流技术。

J2ee api有一个特点,大家比较熟悉的几个包java.jms、javax.servlet.http、javax.ejb等都以interface居多,实现类较少。其实大家真正在用的时候百分之六十以上都在反复的查着javax.servlet.http这个包下面几个实现类的api函数,其他的包很少问津。笔者建议在学习一种技术之前,对整体的框架有一个了解是很有必要的,J2ee旨在通过interface的声明来规范实现的行为,任何第三方的厂商想要提供自己品牌的实现前提也是遵循这些接口定义的规则。如果在从前J2se学习的道路上对接口的理解很好的话,这里的体会将是非常深刻的,举个简单的例子:

public interface Mp3{
public void play();
public void record();
public void stop();
}

如果我定义这个简单的接口,发布出去,规定任何第三方的公司想推出自己的名字为Mp3的产品都必须实现这个接口,也就是至少提供接口中方法的具体实现。这个意义已经远远不止是面向对象的多态了,只有厂商遵循J2ee的接口定义,世界上的J2ee程序员才能针对统一的接口进行程序设计,最终不用改变代码只是因为使用了不同厂商的实现类而有不同的特性罢了,本质上说,无论哪一种厂商实现都完成了职责范围内的工作。这个就是笔者想一直强调的,针对接口编程的思想。

接口到底有什么好处呢?我们这样设想,现在有AppleMp3、SonyMp3、SamsungMp3都实现了这个Mp3的接口,于是都有了play、 record、stop这三个功能。我们将Mp3产品座位一个组件的时候就不需要知道它的具体实现,只要看到接口定义知道这个对象有3个功能就可以使用了。那么类似下面这样的业务就完全可以在任何时间从3个品牌扩展到任意个品牌,开个玩笑的说,项目经理高高在上的写完10个接口里的方法声明,然后就丢给手下的程序员去写里面的细节,由于接口已经统一(即每个方法传入和传出的格式已经统一),经理只需关注全局的业务就可以天天端杯咖啡走来走去了,^_^:
public Mp3create();
public void copy(Mp3 mp3);
public Mp3 getMp3();

最后用一个简单的例子说明接口:一个5号电池的手电筒,可以装入任何牌子的5号电池,只要它符合5号电池的规范,装入之后任何看不到是什么牌子,只能感受到手电筒在完成它的功能。那么生产手电筒的厂商和生产5号电池的厂商就可以完全解除依赖关系,可以各自自由开发自己的产品,因为它们都遵守5号电池应有的形状、正负极位置等约定。这下大家能对接口多一点体会了么?

2. 组件和容器
针对接口是笔者特意强调的J2ee学习之路必备的思想,另外一个就是比较常规的组件和容器的概念了。很多教材和专业网站都说J2EE的核心是一组规范与指南,强调J2ee的核心概念就是组件+容器,这确实是无可厚非的。随着越来越多的J2ee框架出现,相应的每种框架都一般有与之对应的容器。

容器,是用来管理组件行为的一个集合工具,组件的行为包括与外部环境的交互、组件的生命周期、组件之间的合作依赖关系等等。J2ee包含的容器种类大约有 Web容器、ApplicationClient容器、EJB容器、Applet客户端容器等。但在笔者看来,现在容器的概念变得有点模糊了,大家耳熟能详是那些功能强大的开源框架,比如 Hibernate、Struts2、Spring、JSF等,其中Hibernate就基于JDBC的基础封装了对事务和会话的管理,大大方便了对数据库操作的繁琐代码,从这个意义上来说它已经接近容器的概念了,EJB的实体Bean也逐渐被以Hibernate为代表的持久化框架所取代。

组件,本意是指可以重用的代码单元,一般代表着一个或者一组可以独立出来的功能模块,在J2ee中组件的种类有很多种,比较常见的是EJB组件、DAO组件、客户端组件或者应用程序组件等,它们有个共同特点是分别会打包成.war,.jar,.jar,.ear,每个组件由特定格式的xml描述符文件进行描述,而且服务器端的组件都需要被部署到应用服务器上面才能够被使用。

稍微理解完组件和容器,还有一个重要的概念就是分层模型,最著名的当然是MVC三层模型。在一个大的工程或项目中,为了让前台和后台各个模块的编程人员能够同时进行工作提高开发效率,最重要的就是实现层与层之间的耦合关系,许多分层模型的宗旨和开源框架所追求的也就是这样的效果。在笔者看来,一个完整的 Web项目大概有以下几个层次:

a) 表示层(Jsp、Html、Javascript、Ajax、Flash等等技术对其支持)
b) 控制层(Struts、JSF、WebWork等等框架在基于Servlet的基础上支持,负责把具体的请求数据(有时卸载重新装载)导向适合处理它的模型层对象)
c) 模型层(笔者认为目前最好的框架是Spring,实质就是处理表示层经由控制层转发过来的数据,包含着大量的业务逻辑)
d) 数据层(Hibernate、JDBC、EJB等,由模型层处理完了持久化到数据库中)

当然,这仅仅是笔者个人的观点,仅仅是供大家学习做一个参考,如果要实现这些层之间的完全分离,那么一个大的工程,可以仅仅通过增加人手就来完成任务。虽然《人月神话》中已经很明确的阐述了增加人手并不能是效率增加,很大程度上是因为彼此做的工作有顺序上的依赖关系或者说难度和工作量上的巨大差距。当然理想状态在真实世界中是不可能达到的,但我们永远应该朝着这个方向去不断努力。最开始所提倡的针对接口来编程,哪怕是小小的细节,写一条Listlist== newArrayList()语句也能体现着处处皆使用接口的思想在里面。Anyway,这只是个开篇,笔者会就自己用过的J2ee技术和框架再细化谈一些经验
####################################################################################################################
Java杂谈(八)--Servlet/Jsp


终于正式进入J2ee的细节部分了,首当其冲的当然是Servlet和Jsp了,上篇曾经提到过J2ee只是一个规范和指南,定义了一组必须要遵循的接口,核心概念是组件和容器。曾经有的人问笔者Servlet的Class文件是哪里来的?他认为是J2ee官方提供的,我举了一个简单的反例:稍微检查了一下Tomcat5.0里面的Servlet.jar文件和JBoss里面的Servlet.jar文件大小,很明显是不一样的,至少已经说明了它们不是源自同根的吧。其实Servlet是由容器根据J2ee的接口定义自己来实现的,实现的方式当然可以不同,只要都遵守J2ee规范和指南。

上述只是一个常见的误区罢了,告诉我们要编译运行Servlet,是要依赖于实现它的容器的,不然连jar文件都没有,编译都无法进行。那么Jsp呢? JavaServerPage的简称,是为了开发动态网页而诞生的技术,其本质也是Jsp,在编写完毕之后会在容器启动时经过编译成对应的Servlet。只是我们利用Jsp 的很多新特性,可以更加专注于前后台的分离,早期Jsp做前台是满流行的,毕竟里面支持Html代码,这让前台美工人员可以更有效率的去完成自己的工作。然后Jsp将请求转发到后台的Servlet,由Servlet处理业务逻辑,再转发回另外一个Jsp在前台显示出来。这似乎已经成为一种常用的模式,最初笔者学习J2ee的时候,大量时间也在编写这样的代码。

尽管现在做前台的技术越来越多,例如Flash、Ajax等,已经有很多人不再认为Jsp重要了。笔者觉得Jsp带来的不仅仅是前后端分离的设计理念,它的另外一项技术成就了我们今天用的很多框架,那就是Tag标签技术。所以与其说是在学习Jsp,不如更清醒的告诉自己在不断的理解Tag标签的意义和本质。

1. Servlet以及Jsp的生命周期
Servlet是Jsp的实质,尽管容器对它们的处理有所区别。Servlet有init()方法初始化,service()方法进行Web服务, destroy()方法进行销毁,从生到灭都由容器来掌握,所以这些方法除非你想自己来实现Servlet,否则是很少会接触到的。正是由于很少接触,才容易被广大初学者所忽略,希望大家至少记住Servlet生命周期方法都是回调方法。回调这个概念简单来说就是把自己注入另外一个类中,由它来调用你的方法,所谓的另外一个类就是Web容器,它只认识接口和接口的方法,注入进来的是怎样的对象不管,它只会根据所需调用这个对象在接口定义存在的那些方法。由容器来调用的Servlet对象的初始化、服务和销毁方法,所以叫做回调。这个概念对学习其他J2ee技术相当关键!

那么Jsp呢?本事上是Servlet,还是有些区别的,它的生命周期是这样的:
a)一个客户端的Request到达服务器->
b) 判断是否第一次调用 -> 是的话编译Jsp成Servlet
c) 否的话再判断此Jsp是否有改变 -> 是的话也重新编译Jsp成Servlet
d) 已经编译最近版本的Servlet装载所需的其他Class
e) 发布Servlet,即调用它的Service()方法

所以Jsp号称的是第一次Load缓慢,以后都会很快的运行。从它的生命的周期确实不难看出来这个特点,客户端的操作很少会改变Jsp的源码,所以它不需要编译第二次就一直可以为客户端提供服务。这里稍微解释一下Http的无状态性,因为发现很多人误解,Http的无状态性是指每次一张页面显示出来了,与服务器的连接其实就已经断开了,当再次有提交动作的时候,才会再次与服务器进行连接请求提供服务。当然还有现在比较流行的是Ajax与服务器异步通过 xml交互的技术,在做前台的领域潜力巨大,笔者不是Ajax的高手,这里无法为大家解释。

2. Tag标签的本质
笔者之前说了,Jsp本身初衷是使得Web应用前后台的开发可以脱离耦合分开有效的进行,可惜这个理念的贡献反倒不如它带来的Tag技术对J2ee的贡献要大。也许已经有很多人开始使用Tag技术了却并不了解它。所以才建议大家在学习J2ee开始的时候一定要认真学习Jsp,其实最重要的就是明白标签的本质。

Html标签我们都很熟悉了,有<html><head> <body> <title>,Jsp带来的Tag标签遵循同样的格式,或者说更严格的Xml格式规范,例如 <jsp:include><jsp:useBean> <c:if> <c:forEach>等等。它们没有什么神秘的地方,就其源头也还是Java Class而已,Tag标签的实质也就是一段Java代码,或者说一个Class文件。当配置文件设置好去哪里寻找这些Class的路径后,容器负责将页面中存在的标签对应到相应的Class上,执行那段特定的Java代码,如此而已。
说得明白一点的话还是举几个简单的例子说明一下吧:

<jsp:include>去哪里找执行什么class呢?首先这是个jsp类库的标签,当然要去jsp类库寻找相应的class了,同样它也是由Web容器来提供,例如 Tomcat就应该去安装目录的lib文件夹下面的jsp-api.jar里面找,有兴趣的可以去找一找啊!

<c:forEach>又去哪里找呢?这个是由Jsp2.0版本推荐的和核心标记库的内容,例如<c:if> 就对应在页面中做if判断的功能的一断Java代码。它的class文件在jstl.jar这个类库里面,往往还需要和一个standard.jar类库一起导入,放在具体Web项目的WEB-INF的lib目录下面就可以使用了。

顺便罗唆一句,WebProject的目录结构是相对固定的,因为容器会按照固定的路径去寻找它需要的配置文件和资源,这个任何一本J2ee入门书上都有,这里就不介绍了。了解Tag的本质还要了解它的工作原理,所以大家去J2ee的API里找到并研究这个包:javax.servlet.jsp.tagext。它有一些接口,和一些实现类,专门用语开发Tag,只有自己亲自写出几个不同功能的标签,才算是真正理解了标签的原理。别忘记了自己开发的标签要自己去完成配置文件,容器只是集成了去哪里寻找jsp标签对应class的路径,自己写的标签库当然要告诉容器去哪里找啦。

说了这么多,我们为什么要用标签呢?完全在Jsp里面来个<%%> 就可以在里面任意写Java代码了,但是长期实践发现页面代码统一都是与html同风格的标记语言更加有助于美工人员进行开发前台,它不需要懂Java,只要Java程序员给个列表告诉美工什么标签可以完成什么逻辑功能,他就可以专注于美工,也算是进一步隔离了前后台的工作吧!

3. 成就Web框架
框架是什么?曾经看过这样的定义:与模式类似,框架也是解决特定问题的可重用方法,框架是一个描述性的构建块和服务集合,开发人员可以用来达成某个目标。一般来说,框架提供了解决某类问题的基础设施,是用来创建解决方案的工具,而不是问题的解决方案。

正是由于Tag的出现,成就了以后出现的那么多Web框架,它们都开发了自己成熟实用的一套标签,然后由特定的Xml文件来配置加载信息,力图使得Web 应用的开发变得更加高效。下面这些标签相应对很多人来说相当熟悉了:
<html:password>
<logic:equal>
<bean:write>
<f:view>
<h:form>
<h:message>

它们分别来自Struts和JSF框架,最强大的功能在于控制转发,就是MVC三层模型中间完成控制器的工作。Struts-1实际上并未做到真正的三层隔离,这一点在Struts-2上得到了很大的改进。而Jsf向来以比较完善合理的标签库受到人们推崇。

今天就大概讲这么多吧,再次需要强调的是Servlet/Jsp是学习J2ee必经之路,也是最基础的知识,希望大家给与足够的重视!
######################################################################################################################
Java杂谈(九)--Struts

J2ee的开源框架很多,笔者只能介绍自己熟悉的几个,其他的目前在中国IT行业应用得不是很多。希望大家对新出的框架不要盲目的推崇,首先一定要熟悉它比旧的到底好在哪里,新的理念和特性是什么?然后再决定是否要使用它。

这期的主题是Struts,直译过来是支架。Struts的第一个版本是在2001年5月发布的,它提供了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值