JSP & Servlet学习笔记(第2版)(无赠送光盘)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-08-29 06:49:20

点击下载

作者:林信良

出版社:清华大学出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

JSP & Servlet学习笔记(第2版)(无赠送光盘)

JSP & Servlet学习笔记(第2版)(无赠送光盘)试读:

第2版序

“序”应该表达些什么?写一本书的动机?写一本书的过程?写完一本书的感想?

在本书第1版手稿完成后,思考着如何写序的那几天,在整理旧书时从一本书中掉出了一张车票,于是我写了一张车票引发一连串回忆的故事。在本书第2版手稿完成后,思考着如何写序的这几天,我回顾改版的这段漫长日子,想着一脚踏入陌生领域、探索一切未知的过程。

现在的你,也许在某个领域有擅长的事务,有没有想过,或许哪天,你会接触另一个完全未知的世界,到时候,你会怎么办?

我在信息领域的知识,大多都是自学而来,对于信息领域知识的搜寻、过滤、验证与实践,自认为颇有心得,改版过程中,乍然面对一切毫无所知的世界,也曾一度乱了手脚。某个下午带着慌乱的心路过了书局,突然心里有了答案:“我一直认为收集与过滤是我最大的能力,不用在这个时候,那要用在什么时候?”

你有没有听过类似的事呢?某人拥有高学历,却在生完小孩之后,毅然决然在家带小孩,某人在某领域拥有很好的经历,却在大家觉得他即将迈向巅峰时,投入另一个领域重新开始。像这类的情况,旁人通常都会为他们可惜。

我面对着完全未知的世界,开始发挥大量阅读的能力,极尽可能地寻找相关的书籍,在网络上搜寻各种相关资料,逐步勾勒出这个世界应有的方向,就如同当初从电机转换入信息,一切从未知开始累积,一切从头开始建立基础,既然是初学者,那就一切从头开始建构。

高学历带小孩不好吗?也许是自愿或被迫这么做,但如果可以发挥出高学历下该有的学习态度,好好学习如何让小孩子健康、快乐成长,那不也是件好事吗?放弃原有领域的经历不好吗?把建立原有领域经历的方式应用在新领域经历的建立,因此而有所成就的案例也不在少数!

一切都是动心转念之间,无论如何,保有一颗初学者的心,保有一颗赤子之心,放下熟悉领域拥有的一切,重新出发,方向就会逐步建立,所有的基础,后续的成就,就交由时间慢慢验证。林信良2011年5月26日

第1版序

在完成本书之前,意外翻出了这张车票,94.08.15从高雄到台北的座位证!一时之间还想不起这张车票是哪里来的,反倒是我老婆提醒了我,不过我却想起了更久之前的事情……

大学时代参加的社团是社会服务团,寒、暑假时会到一些地方举办营队,在学期中,即将参与营队的队友们必须负责各自的课程、准备教材、设计教具、验收教案等,出营队时则上台实行课程。

除了社团之外,自己平常也爱写些东西。大学时代正值WWW兴起之时,自己学会如何写HTML,也常将学计算机时的心得写下来放到Web上,像如何安装Apache、CGI留言版之类的,说来写作的习惯应该是从那时养成的。

在大学最后一年考完硕士研究生入学考试之后,我在BBS的Job版上发现了几个短期打工需求,有一天接到一个电话,问我想不想写书。虽然主题只是网页制作,但第一次要写完整的一本书,合同载明页数必须有400页以上,着实有很大的压力,甚至还因此失眠了好几次,所幸在当兵前夕完成了这本书,成了我的第一本著作。事后在市面上发现,这本书重印了4次,心里还蛮感到安慰的。

当兵期间所属的单位是学校,平时除了连队勤务或卫哨之外,所做的事就是协助教官编写教材、教案、上课担任助教等。退伍后的第一份工作是在高雄,公司的业务之一是出版计算机图书,因为早有写作及出版图书的经验,自然也在公司的名义之下写了几本书。

2003年3月底,开始将一些东西以“良葛格学习笔记”的名称放在网络上,随着时间的累积,伴随着网络传播的力量,越来越多人的知道了这个网站的存在,我也在网络上结交了许多朋友,并因此得以在Javaworld@TW前站长林上杰(Browser)先生的介绍下,认识了碁峰编辑江佳慧(Novia)小姐,出版了第二本有个人名号的书籍。

想到这里,发现在我过去的经验中,怎么都跟上台、写作、课程有关?还有一点不知道是否也有相关,我岳父岳母也都是老师……

这就是看到94.08.15从高雄到台北的座位证时,突然涌出的一连串回忆……

1994年8月15日是什么日子?隔两天就是“2005 Java TWO社区大会”!这张车票是为了参加Java TWO大会而买的。这是我第一次参加Java TWO大会,目的之一是想看看许多网络上认识的但未曾谋面的朋友,还有一个原因是碁峰也在大会上设摊,其中有卖我的书,想去看看反应如何……在大会上,碰到了王森(Moli)先生,他跟我说:“想要请你帮忙写个教材……”,不过那时场面很混乱,反正就是一堆人哈啦来哈啦去的,话题很难继续,直到后来出现了Moli先生想加我的MSN,哈啦过后,才确定这件事是真的!

之后又因为一连串的因缘机会,开始了我江湖卖艺……呃……讲课的日子!时光匆匆,岁月如梭……转眼来到了2009年3月,Novia小姐问我有没有新的写作计划?我想了一下,这些日子以来,许许多多的授课经验积累了不少的想法,也了解了不少学员在实际学习时所遇到的问题,不如写下来吧!而这些写下来的东西就成了你眼前的这本书(篇幅有限,这本书只针对Servlet/JSP)!

我不太知道人有没有宿命,但回首时总会发现许多的巧合,过去的种种经验,好像是在为了将来的某个事件而准备似的。当然,你也可以说,这是因为回忆是选择性地挑选拼凑而成的。无论如何,这些事情过去总得发生过,未来的你才有的拼凑。

一张车票引发了一连串回忆,也终于知道要怎么写这本书的序了,这本书就是这么来的……林信良2009年5月26日

导读

这份导读可以让你了解如何使用本书。字体

本书内文中与代码相关的文字,都用等宽字体来加以呈现,以与一般名词相区别。例如,JSP是一般名词,而HttpServlet类为代码相关文字,使用了等宽字体。程序范例

本书中许多范例都使用完整的程序实现来展现,如果是用以下方式示范程序代码:

范例开始的左边名称为FirstServlet,表示可以在本书配套光盘的samples文件夹中查找相应章节目录,即可找到对应的FirstServlet项目,而右边名称为HelloServlet.java,表示可以在项目中找到HelloServlet.java文件。如果代码中出现标号与提示文字,表示后续的内文中会有对应于标号及提示的更详细说明。

原则上,建议每个项目范例都亲自动手编写,但如果由于教学时间或实现时间上的考量,本书有建议进行的练习,如果在范例开始前有个图示,表示建议动手实践,而且在本书配套光盘的labs文件夹中会有练习项目的基础,可以导入项目后,完成项目中遗漏或必须补齐的代码或设定。

如果文中使用以下的代码形成呈现,则表示它是一个完整的程序内容,不是项目的一部分,主要用来展现一个完整的文件如何编写:

如果文中使用以下的代码形式呈现,则表示它是一个程序代码片段,主要展现程序编写时需要特别注意的片段:

由于受书籍页面宽度的限制,有些过长的程序代码可能会在一行容纳不下,不得不隔行表示,此时会使用箭头符号表示两行实际上是必须连接在一起的。例如:

在上面的程序代码片段中,在url属性的设定中,完整的设置其实是jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF8,当中不可以中断。操作步骤

本书将IDE设定的相关操作步骤,也作为练习的一部分,你会看到如下的操作步骤说明:(1) 选择File/New/Dynamic Web Project命令,在出现的New Dynamic Web Project对话框的Project name文本框中输入FirstServlet。(2) 确定Target runtime为刚才设置的Apache Tomcat v7.0,单击Finish按钮。(3) 展开新建项目中的Java Resources节点,在src上单击鼠标右键,从弹出的快捷菜单中选择New/Servlet命令。(4) 在弹出的Create Servlet对话框的Java package文本框中输入cc.openhome,在Class name文本框中输入HelloServlet,单击Next按钮。(5) 选择URL mappings中的HelloServlet,单击右边的Edit按钮,将Pattern改为/hello.view后,单击OK按钮。(6) 单击Create Servlet对话框中的Finish按钮。

如果操作步骤旁有个图示,表示光盘的videos文件夹中对应的章节文件夹有操作步骤的录像,可打开观看以更了解实际操作过程。特殊段落

在本书中会出现以下特殊段落:提示

针对课程中提到的概念,提供一些额外的资源或思考方向,暂时忽略这些提示对课程进行并没有影响,但有时间的话,针对这些提示多作阅读、思考或讨论是有帮助的。注意

针对课程中提到的概念,以特殊段落方式特别呈现出必须注意的一些使用方式、陷阱或避开问题的方法,看到这个特殊段落时请集中精神阅读。综合练习

本书以“微博”项目作为范例贯穿全书,随着每一章的进行,都会在适当的时候将新学习到的技术,应用至“微博”程序之中并作适当的修改,以了解完整的应用程序基本上是如何建构出来的。附录

本书配套光盘中包括本书所有的范例,提供Eclipse范例项目,附录A说明如何使用这些范例项目,本书也说明如何在Web应用程序中整合数据库,范例中使用的数据库为MySQL;附录B包括了MySQL的入门简介。关于认证

本书涵盖了Oracle Certified Professional, Java Platform, Enterprise Edition JavaServer Pages and Servlet Developer考试范围,也就是原Sun Certified Web Component Developer(SCWCD),不过第9章整合数据库与第11章JavaMail入门不在考试范围,只是为了Web应用程序相关技术范围完整性而作介绍。

关于Java认证介绍,建议直接参考Oracle University网站上的认证介绍:

http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=140

每章最后的“重点复习”是针对该章的重要提示,可作为考前复习时使用。每章都会有“课后练习”,与认证相关的是选择题,分为单选、复选题两种形式,实训题是与每个章节相关的程序练习。联系作者

若有勘误反馈等相关书籍问题,可通过网站与作者联系:

http://openhome.ccChapter 1 Web应用程序简介学习目标:

■ 认识HTTP基本特性

■ 了解GET、POST使用时机

■ 了解何为URL/URI编码

■ 认识Web容器角色及其重要性

■ 初步了解Servlet与JSP的关系

■ 初步认识MVC/Model 21.1 Web应用程序基础知识

在正式学习Servlet/JSP相关技术之前,要先花点时间了解一些Web应用程序基础知识,这些知识虽然基础,但却很重要。在我这几年的教学中,发现有些学员并不具备这些基础,或者忽略了这些基础中的一些细节,如HTML(HyperText Markup Language)、HTTP(HyperText Transfer Protocol)、URL(Uniform Resource Locator)甚至文字编码的问题等。

当然,谈这些东西并不是要求你成为这几个名词的专家,而是在以后学习Servlet/JSP相关技术时,若有这些基础,就能真正理解相关技术背后的原理,而不会沦落到死背API(Application Programming Interface)的窘境。

这里先从HTML开始……1.1.1 关于HTML

本书介绍的Web应用程序,是由客户端(Client)与服务器端(Server)两个部分组成的,客户端基本是浏览器(Browser),服务器端则是HTTP服务器,浏览器会请求服务器上放置的文件或资源。对本书来说,服务器上的文件或资源必须产生HTML。

HTML是以标签(Tag)的方式来定义文件结构。例如,一个简单的HTML范例如下所示:

HTML文件的标签通常是成对的,有开头标签与结尾标签(但少数标签例外)。例如,整份HTML文件的定义编写在与标签之间。在文件开始呈现之前,浏览器必须先处理编写在与标签之间的元素。显示在浏览器窗口上的标题,就是编写在HTML中的标签之间的内容。

浏览器若要针对文件内容绘制画面与定义行为,相关的信息是定义在标签之中。例如,
告诉浏览器换下一行后再继续绘制文件内容,范例文件中有个代表图片的标签,告诉浏览器要读取指定的图形文件并绘制在画面上。HTML标签可以拥有属性(attribute),定义该标签的额外信息,如图片来源(src属性)。

标签定义了一个窗体,窗体用来让用户填写一些将送至服务器的信息,其中还使用了标签分别定义了一个输入字段及发送按钮。

简而言之,当浏览器从服务器取得这份HTML文件之后,就可以按照其中的结构等信息进行画面的绘制。图1.1所示为大致的HTML标签与对应的画面呈现。图1.1 浏览器按HTML的结构等信息进行画面绘制

以上描述是对你的一种测试,如果连以上的基本HTML都不甚了解,建议先寻找HTML相关的文件或书签作大致的了解,w3schools(http://w3schools. com)的HTML Tutorial是不错的快速入门文件,足以应付阅读本书所需的HTML基础,网址是:

http://www.w3schools.com/html/default.asp1.1.2 URL、URN与URI

既然Web应用程序的文件等资源是放在服务器上,而服务器是因特网(Internet)上的主机,当然必须要有个方式,告诉浏览器到哪里取得文件等资源。通常会听到有人这么说:“你要指定URL”,偶而会听到有人说:“你要指定URI”。那么到底什么是URL、URI?甚至你还听过URN。首先,三个名词都是缩写,其全名分别为:

■ URL:Uniform Resource Locator

■ URN:Uniform Resource Name

■ URI:Uniform Resource Identifier

从历史的角度来看,URL的标准最先出现,早期U代表Universal(万用),标准化之后代表着Uniform(统一)。正如名称所指出,URL的主要目的,是以文字方式来说明因特网上的资源如何取得。一般而言,URL的主要格式为:

<协议>:<特定协议部分>

协议(scheme)指定了以何种方式取得资源。一些协议名的例子有:

■ ftp(文件传输协议,File Transfer Protocol)

■ http(超文本传输协议,Hypertext Transfer Protocol)

■ mailto(电子邮件)

■ file(特定主机文件名)

协议之后跟随冒号,特定协议部分的格式则为://<用户>:<密码>@<主机>:<端口号>/<路径>

举例来说,若资源放置在HTTP服务器上,如图1.2所示。图1.2 HTTP服务器上的资源

若主机名为openhome.cc,要以HTTP协议取得Gossip目录中index.html文件,端口号8080,则必须使用以下URL(如图1.3所示):

http://openhome.cc:8080/Gossip/index.html图1.3 以URL指定资源位置等信息

又假设想取得计算机文件系统中C:\workspace下的jdbc.pdf文件,则可以指定如下URL格式:

file://C:/workspace/jdbc.pdf

简而言之,URL代表资源的地址信息,URN则代表某个资源独一无二的名称。举例来说,“JSP & Servlet学习笔记(第2版)”的国际标准书号(International Standard Book Number,ISBN)为ISBN 978-7-302-28366-9,这就是URN的一个例子。

由于URL或URN的目的,都是用来标识某个资源,后来的标准制定了URI,而URL与URN成为URI的子集。在一些标准机构,如W3C(World Wide Web Consortium)文件中,后来就也多使用URI这个名词,不过许多人已习惯用URL,所以URL这个名称仍广为使用,程序员口语交谈也多见使用 URL 这个旧称,所以书中还是称 URL。

如果想对URL、URI与URN的历史演进与标准发布作更多的了解,可以参考Wikipedia(http://www.wikipedia.org/)的Uniform Resource Identifier:

http://en.wikipedia.org/wiki/Uniform_Resource_Identifier1.1.3 关于HTTP

先前一直提到HTTP,这是一种通信协议,指架构在TCP/IP之上应用层的一种协议。通信协议基本上就是两台计算机间对谈沟通的方式,例如客户端要跟服务器请求联机,假设就是跟服务器说声CONNECT,服务器响应PASSWORD表示要求密码,客户端再进一步跟服务器说声PASSWORD 1234,表示这是所需的密码,诸如此类,如图1.4所示。图1.4 通信协议是计算机间沟通的一种方式

按不同的联机方式与所使用的网络服务而定,会有不同的通信协议。例如,发送信件时会使用SMTP(Simple Mail Transfer Protocol),传输文件时会使用FTP,下载信件时会使用POP3(Post Office Protocol 3)等,而浏览器跟Web服务器之间使用的沟通方式,则是HTTP,它有两个基本但极为重要的特性:■ 基于请求(Request)/响应(Response)模型■ 无状态(Stateless)通信协议

HTTP是一种基于请求/响应的通信协议,客户端对服务器发出一个取得资源的请求,服务器将要求的资源响应给客户端,每次的联机只作一次请求/响应,是一种很简单的通信协议,没有请求就不会有响应。

在HTTP协议之下,服务器端是个健忘的家伙,服务器响应客户端之后,就不会记得客户端的信息,更不会去维护与客户端有关的状态,因此HTTP又称为无状态(Stateless)的通信协议,如图1.5所示。图1.5 HTTP是一种基于请求/响应的无状态通信协议

明白HTTP这两个基本特性很重要,这样才知道Web应用程序可以做到什么,又有哪些做不到,才能知道之后要介绍的MVC模式(Model-View-Controller Pattern)为何要作变化而成为Model 2模式,之后谈到会话管理(Session management)时,才能知道会话管理的基本原理,并针对需求采取适当的会话管理机制。

浏览器在使用HTTP发出请求时,可以有几种请求方法,如GET、POST、HEAD、PUT、DELETE等。对于编写Servlet或JSP而言,最常接触的就是GET与POST(绝大多数情况下,只会用到这两个方法)。下面分别介绍GET与POST的使用方法。1.GET请求

GET请求,顾名思义,就是向服务器取得(GET)指定的资源,在发出GET请求时,必须一并告诉服务器所请求资源的URL,以及一些标头(Header)信息。例如,一个GET请求的发送范例如图1.6所示。图1.6 HTTP GET请求范例

HTTP所有的通信数据都是使用“字符”来进行协议交换,如果可以使用Telnet软件连接上HTTP服务器,以字符方式输入要求的协议内容,就可以取得指定的资源。

在图1.6中,请求标头的内容是给服务器参考的额外信息,服务器可以选择性地使用这些信息来做适当的响应处理。例如,服务器可以从User-Agent中得知用户使用的浏览器种类与版本,从Accept-Language中了解浏览器可以接收哪些语系的内容响应等。

请求参数通常是用户发送给服务器的必要信息,这个信息通常是利用窗体来进行发送,服务器必须有这些信息才可以进一步针对用户的请求作出正确的响应。请求参数是在URL之后跟随一个问号(?),然后是请求参数名称(name)与请求参数值(value),中间以等号(=)表示成对关系。若有多个请求参数,则以&字符连接。使用GET方式发送请求,浏览器的地址栏上也会出现请求参数信息,如图1.7所示。图1.7 GET的请求参数会出现在地址栏上

GET请求可以发送的请求参数长度有限(这个长度根据浏览器版本而有所不同),对于太大量的数据并不适合用GET方式来进行请求,这时可以改用POST。2.POST请求

POST请求,顾名思义,就是在请求时发布(POST)信息给服务器,对于大量或复杂的信息发送(如文件上传),基本上会采用POST来进行发送。一个POST发送的范例如图1.8所示。图1.8 HTTP POST请求范例

表面上看起来,POST只是将请求参数移至最后的信息体(Message body)之中,由于信息体的内容长度不受限制,所以大量数据的发送都会使用POST方法,而由于请求参数移至信息体,地址栏上也就不会出现请求参数。对于一些较敏感的信息,即使长度不长,通常也会改用POST的方式发送。3.如何选用GET或POST?

GET请求与POST请求是使用Servlet/JSP时最常接触的两个请求方式。除了长度过长的请求数据之外,许多请求既可以使用GET也可以使用POST,那么何时该选用GET而何时该选用POST呢?

从功能面上,可以用以下方式来决定该选用GET或POST:

■ GET请求跟随在URL之后的请求参数长度是有限的,过长的请求参数,或如文件上传这类的大量数据,就不适合用GET请求,而应该改用POST请求。

■ GET请求的请求参数会出现在地址栏上,敏感性或有安全性考虑的请求参数(如信用卡号码、用户名、密码等),就不应该使用GET请求来发送。

■ POST请求的请求参数不会出现在地址栏上,所以无法加入浏览器的书签(Bookmark)之中,如果有些页面是根据请求参数来作不同的画面呈现(如论坛的文章发表),而你希望可以让用户设定书签,以便日后可以直接点击书签浏览,则应该使用GET请求。

■ 有些浏览器会依网址来缓存(Cache)数据,如果网址是相同的URL,则会直接从浏览器缓存中取出数据,而不会真正发送请求至服务器上查询最新的数据。如果不希望服务器状态改变了,而浏览器仍从缓存中取得旧的资料,则可以改用POST请求(使用GET请求也可以避免缓存,例如在网址上附加时间戳,让每次GET请求的网址都不相同)。

另外,还有另一个非功能面上的考虑,但其实也是HTTP当初在设计时区分GET与POST的目的之一,就是按请求是否为等幂(idempotent)操作来决定使用GET或POST。所谓是否为等幂操作,就是请求的操作是否改变服务器状态,同一个操作重复多次,是否传回同样的结果。

■ GET请求应该用于等幂操作。GET请求纯粹取得资源,而不改变服务器上的数据或状态。GET的请求参数,只是用来告知服务器,必须进一步根据请求参数(而不只是URL)来标识出要响应的内容(例如查询数据库的数据),同样的GET请求且使用相同的请求参数重复发送多次,都应该传回相同的结果。

■ POST请求应该用于非等幂(non-idempotent)操作。POST请求发送的数据,可能会影响服务器上的数据或状态,例如修改(增、删、更新)数据库的内容,或是在服务器上保存文件。你的请求若会改变服务器的状态,则应改用POST请求。

就窗体发送而言,可以通过

的method属性来设定使用GET或POST方式来发送数据,通常若不设定method属性,默认会使用GET:1.1.4 有关URL编码

刚刚谈到了HTTP请求参数,必须使用请求参数名称与请求参数值,中间以等号(=)表示成对关系,现在问题来了,如果请求参数值本身包括“=”符号怎么办?又或许你想发送的请求参数值是http://openhome.cc这个值呢?假设是GET请求,则不能直接这么在地址栏上输入:

http://openhome.cc/addBookmar.do?url=http://openhome.cc1.保留字符

在URI的规范中定义了一些保留字符(Reserved character),如“:”、“/”、“?”、“&”、“=”、“@”、“%”等字符,在URI中都有它的作用。如果要在请求参数上表达URI中的保留字符,必须在%字符之后以十六进制数值表示方式,来表示该字符的八个位数值。

例如,“:”字符真正储存时的八个位为00111010,用十六进制数值来表示则为3A,所以必须使用“%3A”来表示“:”;“/”字符储存时的八个位为00101111,用十六进制表示则为2F,所以必须使用“%2F”来表示“/”字符,所以若发送的请求参数值是http://openhome.cc,则必须使用以下格式:

http://openhome.cc/addBookmar.do?url=http%3A%2F%2Fopenhome.cc

这是URI规范中的百分比编码(Percent-Encoding),也就是俗称的URI编码或URL编码。如果想知道某个字符的URL编码是什么,在Java中可以使用java.net.URLEncoder类的静态encode()方法来做这个编码的动作(相对地,要译码则使用java.net.URLDecoder的静态decode()方法)。例如:

String text = URLEncoder.encode("http://openhome.cc ", "ISO-8859-1");

知道这些有什么用?例如,你想给某人一段URL,让他直接单击就可以连到你想要让他看到的网页,你给他的URL在请求参数部分就要注意URL编码。

不过在URI之前,HTTP在GET、POST时也对保留字作了规范,这与URI规范的保留字有所差别。其中一个差别就是在URI规范中,空格符的编码为%20,而在HTTP规范中空白的编码为“+”,java.net.URLEncoder类的静态方法encode()产生的字符串,空格符的编码就为“+”。2.中文字符

另一个差别就是,URI规范的URL编码,针对的是字符UTF-8编码的八个位数值,如果请求参数都是ASCII字符,那没什么问题,因为UTF-8编码与在ASCII字符的编码部分是兼容的,也就是使用一个字节,编码方式就如先前所述。

但在非ASCII字符方面,如中文,在UTF-8编码下,会使用三个字节来表示。例如,“林”这个字在UTF-8编码下的三个字节,对应至十六进制数值表示就是E6、9E、97,所以在URI规范下,请求参数中要包括“林”这个中文,表示方式就是“%E6%9E%97”。例如:

http://openhome.cc/addBookmar.do?lastName=%E6%9E%97

有些初学者会直接打开浏览器输入图1.9所示内容,告诉我:“URL也可以直接打中文啊!”图1.9 浏览器地址栏真的可以输入中文

不过你可以将地址栏复制,粘贴到纯文本文件中,就会看到URI编码的结果,这其实是现在的浏览器很聪明,会自动将上述的URI编码显示为中文。无论如何,在URI规范上若如以上方式发送请求参数,服务器端处理请求参数时,必须使用UTF-8编码来取得正确的“林”字符。

然而在HTTP规范下的URL编码,并不限使用UTF-8,例如在一个BIG5网页中,若窗体使用GET发送“林”这个中文字,则地址栏中会出现:

http://openhome.cc/addBookmar.do?lastName=%AA%4C

这是因为“林”这个中文字的BIG5编码为两个字节,若以十六进制表示,则分别为AA、4C。如果通过窗体发送,由于网页是BIG5编码,则浏览器会自动将“林”编码为“%AA%4C”,服务器端处理请求参数时,就必须指定BIG5编码,以取得正确的“林”汉字字符。

若使用java.net.URLEncoder类的静态encode()方法来作这个编码的动作,则可以像下面这样得到“%AA%4C”的结果:

String text = URLEncoder.encode("林 ", "BIG5");

同理可推,如果网页是UTF-8编码,而你通过窗体发送,则浏览器会自动将“林”编码为“%E6%9E%97”。若使用java.net.URLEncoder类的静态encode()方法来作这个编码的动作,则可像下面这样得到“%E6%9E%97”的结果:

String text = URLEncoder.encode("林", "UTF-8");

知道这些要作什么?你应该感觉到了:“我们会发送中文”。中文是如何编码的?到服务器端后又是如何译码的?这些问题必须先搞清楚。随便问个“为什么我收到的是乱码?”、“为什么数据库中是乱码?”,往往解决不了问题。如果具备这些基础,之后说明Servlet/JSP中如何接收包括中文字符的请求参数时,你才能理解,如何使用某些API进行正确的编码转换动作。1.1.5 动态网页与静态网页

很可惜,现在这个世界通常不会只使用单一技术来完成一个Web应用程序,因此在谈到何为动态网页、静态网页时,必须作个厘清。

本书所谓“静态网页”,指的是请求服务器上的网页时,服务器不对网页文件作任何处理,读取文件之后就直接当作响应传给浏览器。而本书所谓“动态网页”,指的是服务器在响应之前,可能先依客户端的请求参数、标头或实际服务器上的状态,以程序的方式动态产生响应内容,再传回给用户。

举例来说,下面是个JSP的例子(见图1.10),当浏览器请求这个JSP时,会根据服务器上的时间产生响应内容:图1.10 动态网页会根据请求的数据作处理后再传回

所以,动态网页实际上会再经过服务器上的程序处理,再传回实际的响应内容,这类处理动态网页的技术有CGI(Common Gateway Interface)、PHP(Hypertext Preprocessor)、ASP(Active Server Pages)等,以及本书介绍的Servlet/JSP (JavaServer Pages)。

之所以要先作这样的理清,是因为在以上的定义中,未经服务器端程序处理的纯HTML网页文件属于本书所谓的静态网页,但如果这个HTML中包括JavaScript程序代码,HTML中的JavaScript程序代码会被“浏览器”执行(而不是服务器端程序),这在专门介绍JavaScript的书中会被定义为该书所谓动态网页的范畴。

其实这纯粹只是静态网页、动态网页两个名词在不同书中的定义。这里真正想理清的,其实是客户端程序与服务器端程序的差别。

大多数分不清楚客户端程序与服务器端程序差别的学习者,通常都分不清楚JavaScript与JSP的关系,由于JSP中可以编写Java程序代码,而JSP文件中又可以编写JavaScript,而JavaScript当初命名时,又套上了个Java的名字在前头,让许多学习JavaScript或JSP的人,误以为JavaScript与JSP(或Java)有直接的关系。事实上,并没有这回事。

如同前面所讲的,Servlet/JSP是服务器上的一个技术,客户端通过HTTP协议和网络传送请求给Servlet/JSP,服务器上的Servlet/JSP经过运算处理后再将响应(包括HTML与JavaScript)传回给客户端,所有一切程序的处理都是在服务器上发生的。

JavaScript则是执行于客户端浏览器中,可以让你与浏览器沟通,操作浏览器中的网页画面与行为,也可以通过JavaScript来要求浏览器发出请求给服务器。

所以客户端程序与服务器端程序,或说Servlet/JSP与JavaScript,两者根本是执行于不同的内存地址空间(Address space),两者无法作直接的互动,而必须通过网络通过HTTP来进行互动、数据交换或请求、响应,如图1.11所示。

图1.11 Servlet/JSP程序与JavaScript程序是执行于不同的地址空间

在今后学习或应用JSP的过程中,也会在JSP网页中写一些内嵌的(Inline)JavaScript,这些JavaScript并不是在服务器上执行的,服务器会如同处理那些HTML标签一样,将这些JavaScript原封不动地传给浏览器,浏览器收到响应后再处理标签与执行JavaScript。

对处理JSP内容的服务器端而言,内嵌的JavaScript跟静态的HTML标签没有两样,如果了解两者的差别,就不会有所谓“可以直接让JavaScript取得request中的属性吗?”、“为什么JSP没有执行JavaScript?”或“可以直接用JavaScript取得JSTL中标签的test属性吗?”这样的问题。1.2 Servlet/JSP简介

在学习Java程序语言时,有个重要的概念就是:“JVM(Java Virtual Machine)是Java程序唯一认识的操作系统,其可执行文件为.class文件。”基于这样的概念,编写Java程序时,就必须了解Java程序如何与JVM这个虚拟操作系统进行通信,JVM如何管理Java程序中的对象等问题。

在学习Servlet/JSP时,也有个重要概念:“Web容器(Container)是Servlet/JSP唯一认得的HTTP服务器。”如果希望用Servlet/JSP编写的Web应用程序可以正常运作,就必须知道Servlet/JSP如何与Web容器沟通,Web容器如何管理Servlet/JSP的各种对象等问题。1.2.1 何谓Web容器

对于Java程序而言,JVM是其操作系统,.java文件会编译为.class文件,.class对于JVM而言,就是其可执行文件。Java程序基本上只认得一种操作系统,就是JVM。

当开始编写Servlet/JSP程序时,必须开始接触容器(Container)的概念,容器这个名词也用在如List、Set这类的Collection上,也就是用来持有、保存对象的集合(Collection)对象。对于编写Servlet/JSP来说,容器的概念更广,它不仅持有对象,还负责对象的生命周期与相关服务的连接。

在具体层面,容器说穿了,其实就是一个用Java写的程序,运行于JVM之上,不同类型的容器会负责不同的工作,若以Servlet/JSP运行的Web容器(Web Container)来说,也是一个Java写的程序。将来编写Servlet时,会接触HttpServletRequest、HttpServletResponse等对象,想想看,HTTP那些文字性的通信协议,如何变成Servlet/JSP中可用的Java对象,其实就是容器为你剖析与转换。

在抽象层面,可以将Web容器视为运行Servlet/JSP的HTTP服务器。就如同Java程序仅认得JVM这个操作系统,Servlet/JSP程序在抽象层面上,也仅认得Web容器这个概念上的HTTP服务器,只要写的Servlet/JSP符合Web容器的标准规范,Servlet/JSP就可以在各种不同厂商实现的Web容器上运行,而不用理会底层真正的HTTP服务器是什么。

本书将会使用Apache Tomcat(http://tomcat.apache.org)作为范例运行的Web容器。若以Tomcat为例,容器的角色位置可以用图1.12来表示。图1.12 从请求到Servlet处理的线性关系

就如同JVM介于Java程序与实体操作系统之间,Web容器是介于实体HTTP服务器与Servlet之间,也正如编写Java程序必须了解 JVM与应用程序之间如何互动,编写Servlet/JSP也必须知道Web容器如何与Servlet/JSP互动,如何管理Servlet 等事实(JSP最后也是转译、编译、加载为Servlet,在容器的世界中,真正负责请求、响应的是Servlet)。

下面是一个请求/响应的基本例子:(1)客户端(大部分情况下是浏览器)对Web服务器发出HTTP请求。(2)HTTP服务器收到HTTP请求,将请求转由Web容器处理,Web容器会剖析HTTP请求内容,创建各种对象(如HttpServletRequest、HttpServletResponse、HttpSession等)。(3)Web容器由请求的URL决定要使用哪个Servlet来处理请求(事先由开发人员定义)。(4)Servlet根据请求对象(HttpServletRequest)的信息决定如何处理,通过响应对象(HttpServletResponse)来创建响应。(5)Web容器与HTTP服务器沟通,Web服务器将响应转换为HTTP响应并传回客户端。

以上是了解Web容器如何管理Servlet/JSP的一个例子。不了解Web容器行为容易产生问题,举例来说,Servlet是执行在Web容器之中,Web容器是由服务器上的JVM启动,JVM本身就是服务器上的一个可执行程序,当一个请求来到时,Web容器会为每个请求分配一个线程(Thread),如图1.13所示。图1.13 每个请求由Web容器分配一个线程

如果有多次请求进来,就只是启动多个线程来进行处理,而不是重复启动多次JVM。线程就像是进程(Process)中的轻量级流程,由于不用重复启动多个进程,可以大幅减轻性能负担。

然而要注意的是,Web容器可能会使用同一个Servlet实例来服务多个请求。也就是说,多个请求下,就相当于多个线程在共享存取一个对象,因此得注意线程安全(Thread-safe)的问题,避免引发数据错乱,如A用户登录后看到B用户的数据这类问题。

其实不仅是使用Servlet/JSP要了解Web容器,Java各平台的解决方案,其实都对底层作了抽象化,在各平台上都会有对应的容器解决方案。编写EJB就要理解EJB容器的行为,编写Applet就要理解Applet容器的行为,容器是各解决方案面对的平台,不理解容器的行为就容易引发程序面的各种问题。图1.14所示是摘自Java EE 6 Tutorial中Java EE 6 APIs文件的容器示意。图1.14 摘自http://download.oracle.com/javaee/6/tutorial/doc/bnacj.html提示

Java EE 6 Tutorial也是学习Java EE时不错的在线参考文件:http://download. oracle.com/javaee/6/tutorial/doc/1.2.2 Servlet与JSP的关系

本书从开始到现在一直在谈Servlet,但你可能关心的是怎么写JSP。因为你急着想在上面输入HTML然后看看效果。事实上,JSP会被Web容器转译为Servlet的“.java”源文件、编译为“.class”文件,然后加载容器之中,所以最后提供服务的还是Servlet实例(Instance)。这也是为什么到现在一直在谈Servlet的原因,“要能完全掌握JSP,也必须先对Servlet有相当程度的了解”,才不会一知半解,遇到错误无法解决。

先来看一个基本的Servlet长什么样子。

先别管这个程序中有太多细节是你还没看过的,目前只要注意两件事。第一件事是一个Servlet类必须继承HttpServlet,第二件事就是要输出HTML时,必须通过Java的输入输出功能(在这里是从HttpServletResponse取得PrintWriter),并使用Java程序取得服务器上的时间,再用加号(+)运算符来串接为字符串进行输出。

再来看一个产生同样结果的JSP该如何编写:

如果从网页编辑者的角度来看待这个功能的编写,我相信你会选择JSP的编写方式。事实上,JSP的功能角色,本来就是从网页编辑者的角度、方便设计网页画面来解决问题。Servlet主要从事Java程序逻辑的定义,应该避免直接在Servlet中产生画面输出(如直接编写HTML)。如何适当地分配JSP与Servlet的职责,需要一些经验与设计,而这也是本书之后章节会有所介绍的部分。

前面说过,JSP网页最后还是成为Servlet。以上面这个JSP为例,若使用Tomcat作为Web容器,最后由容器转译后的Servlet类别如下所示:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载