久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

CHATPER 12 在Servlets里使用 Velocity - Velocity空間...

 木木的陽(yáng)光 2011-03-23

通過前面章節(jié)的學(xué)習(xí),我們了解到Velocity主要用作MVC框架View組件的腳本語(yǔ)言,。ServletsJavaMVC框架里用得最多的編程方式,。通過把Servlets用作控制器(controller),,Velocity用作顯示層(View),把ServletsJavaBeans作用模型(model),,這樣就創(chuàng)建了一個(gè)理想的Web開發(fā)全面解決方案,。在這一章里,我們將學(xué)習(xí)如何在Servlets里使用Velocity,。

使用Servlets

在開始學(xué)習(xí)這章內(nèi)容之前,,你必須充分理解Servlets是什么?以及它是如何工作的,?如果對(duì)此你已經(jīng)很熟悉了,,那么你可以直接跳到VelocityServlet擴(kuò)展Servlets”節(jié)進(jìn)行深入學(xué)習(xí)。

在動(dòng)態(tài)Web頁(yè)面開發(fā)的早期,,服務(wù)端語(yǔ)言,,比如ASPJSP等主要用于在HTML頁(yè)面里嵌入服務(wù)器端執(zhí)行的代碼,。當(dāng)瀏覽器請(qǐng)求這個(gè)頁(yè)面的時(shí)候,,服務(wù)器立即對(duì)所請(qǐng)求的ASP/JSP頁(yè)面進(jìn)行解析,執(zhí)行里面的語(yǔ)句,,并向用戶返回一個(gè)純粹的HTML頁(yè)面,,有時(shí)還要附帶返回客戶端執(zhí)行的JavaScriptVBScript腳本?;旌?/span>HTML和服務(wù)器端代碼并不容易,,而且,服務(wù)器端腳本語(yǔ)言還要受到一些限制,,比如服務(wù)器平臺(tái)支持,、服務(wù)器支持等比較有限。

Servlets把代碼從HTML中提取出來(lái),,把它放到服務(wù)器上,,這樣,你就可以使用全功能的Java語(yǔ)言進(jìn)行Servlets邏輯開發(fā),。Servlets也能進(jìn)行分布式處理,,而且可以使用模板來(lái)向用戶提供信息顯示。

Servlets的通用格式

在進(jìn)行深入學(xué)習(xí)之前了解傳統(tǒng)的Servlets結(jié)構(gòu)是非常有必要的,。Listing 12.1顯示了一個(gè)簡(jiǎn)單的Servlets,。

import java.io.*;

import java.sql.*;

import javax.servlet.*;

import javax.servlet.http.*;

import javax.naming.*;

public class ViewAccount extends HttpServlet {

public void init() throws ServletException {

}

public void doGet(HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<HTML>");

out.println("</HTML>");

} catch (SQLException e) {

e.printStackTrace();

}

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

Listing 12.1 傳統(tǒng)servlet代碼

當(dāng)有一個(gè)web瀏覽器請(qǐng)求達(dá)到時(shí),一般情況下,,請(qǐng)求的方式為POSTGET,。在上面的代碼中你可以看到,其中有一些方法將用于處理這兩種請(qǐng)求,,分別為doPost()doGet()方法,,其中doPost()方法只是簡(jiǎn)單委派給了doGet()方法,。在doGet()方法內(nèi)部有兩個(gè)重要的變量:requestresponserequest對(duì)象用于把用戶信息轉(zhuǎn)換成servlet能夠理解的信息,。特別的,,用戶在HTML窗體里的輸入將作為文本進(jìn)行處理。response對(duì)象主要負(fù)責(zé)向用戶的瀏覽器返回標(biāo)準(zhǔn)的HTML頁(yè)面,。response對(duì)象返回的信息包括HTML,、XML和圖片。response對(duì)象也可以和PrintWriter對(duì)象一起協(xié)同工作,,以用于寫入信息并返回給用戶,。

Servlets不能使用普通的Web服務(wù)器作為主機(jī),只能使用應(yīng)用程序服務(wù)器(application servers)作為主機(jī),??梢宰鳛?/span>Servlets主機(jī)的軟件有TomcatJBOSS,、Resin,、WEBlogicapusic等,。在很多情況下,,應(yīng)用程序服務(wù)器被用于和Web服務(wù)器一起協(xié)同工作,比如IISApache等,。當(dāng)Web服務(wù)器得到一個(gè)servlet請(qǐng)求時(shí),,這個(gè)請(qǐng)求被移交給應(yīng)用程序服務(wù)器執(zhí)行。應(yīng)用程序服務(wù)器使用java編譯器來(lái)創(chuàng)建一個(gè)可執(zhí)行的Servlets映像,,這個(gè)Servlets映像將在JVM里執(zhí)行,。我們將在下一章演示這個(gè)話題的示例。

VelocityServlet擴(kuò)展Servlets

在某種程度上,,你可以使用Velocity引擎和servlet,,通過Velocity模板語(yǔ)言書寫代碼來(lái)為用戶創(chuàng)建信息輸出。為了讓Servlets的使用更容易,,我們將通過使用一個(gè)名叫VelocityServlet的基類和名叫handleRequest()的方法來(lái)代替?zhèn)鹘y(tǒng)ServletsHttpServletdoGet()/doPost()方法。

handleRequest()方法傳遞三個(gè)參數(shù)HttpServletRequest,、HttpServletResponseContext來(lái)響應(yīng)GET/POST請(qǐng)求,。HttpServletRequestHttpServletResponse對(duì)象和doGet(),、doPost()方法接受的是同一個(gè)對(duì)象(代碼見Listing 12.1),。上下文對(duì)象是一個(gè)用于在Servlets里使用的Velocity引擎的上下文。我們將在上下文對(duì)象里為用于向用戶顯示響應(yīng)的Velocity模板放置信息,。

handleRequest()方法返回一個(gè)模板對(duì)象,,該方法自動(dòng)把傳遞進(jìn)來(lái)的上下文對(duì)象進(jìn)行合并,。因而,在handleRequest()方法里的代碼,,主要完成設(shè)置上下文和合并返回的Velocity對(duì)象等操作,。如果返回的模板對(duì)象為null,這些代碼就不能完成合并操作,。在這種情況下,,和傳統(tǒng)的Servlets代碼一樣,這些代碼將向用戶瀏覽器返回一些放置在response對(duì)象里的PrintWriter對(duì)象里的東西,。

基本的Velocity Servlet代碼

handleRequest()方法示例代碼見Listing 12.2,,用于向?yàn)g覽器簡(jiǎn)單輸出字符串。

import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.Template;

import org.apache.velocity.context.Context;

import org.apache.velocity.servlet.VelocityServlet;

import org.apache.velocity.exception.*;

public class VelocityServletExample extends VelocityServlet {

public Template handleRequest( HttpServletRequest request,

HttpServletResponse response,

Context context ) {

Vector v = new Vector();

v.add("one");

v.add("two");

v.add("three");

context.put("list", v);

Template template = null;

try {

template = getTemplate("displaylist.vm");

} catch( Exception e ) {

PrintWriter out = response.getWriter();

out.println("Error getting template");

}

return template;

}

}

Listing 12.2 A Velocity servlet example.

當(dāng)瀏覽器調(diào)用Listing 12.2里的代碼時(shí),,初始化一個(gè)Velocity對(duì)象,,并在里面放置了三個(gè)字符串對(duì)象。Velocity對(duì)象通過下面的語(yǔ)句被放入上下文中,。

context.put("list", v);

注意,,我們?cè)谏舷挛睦锓胖玫氖?/span>Vector對(duì)象實(shí)體(java.util.Vector)。接著,,聲明了一個(gè)模板對(duì)象,,并使用getTemplate(String)方法來(lái)從服務(wù)器的磁盤上定位和加載模板。如果在獲取模板文件的過程中出現(xiàn)錯(cuò)誤時(shí),,response對(duì)象里的PrintWriter被獲得,,并向其中寫入錯(cuò)誤信息。最后一個(gè)操作是返回模板對(duì)象,。如果某些錯(cuò)誤導(dǎo)致這個(gè)對(duì)象為null,,系統(tǒng)將不能完成合并操作;否則,,從服務(wù)器讀入的模板將和上下文一起被合并,。Listing 12.3為這個(gè)示例所使用的Velocity模板。

<?xml version="1.0" encoding="ISO-8859-1" ?>

<list>

#foreach( $value in $list )

<number>$value</number>

#end

</list>

Listing 12.3 The displaylist.vm Velocity code.

Listing 12.3里的模板不是HTML格式的,,我們使用XML來(lái)演示Velocity模板并不僅限于使用HTML格式,。了解這個(gè)示例是如何執(zhí)行的非常重要。還記得“list”關(guān)鍵字和Vector對(duì)象關(guān)聯(lián),,在模板里的Velocity模板語(yǔ)言代碼通過#foreach循環(huán)指令使用Vector,。回想一下在List對(duì)象(如Vector)里使用#foreach指令的定義我們就可以發(fā)現(xiàn),,迭代器(iterator)自動(dòng)提取并用于獲取所有在List(在這種情況下還可以是Vector)里的獨(dú)立對(duì)象,。

所有來(lái)自Vector的每一個(gè)對(duì)象都被提出并放置到引用$value處。既然字符串不是混合對(duì)象,我們就可以簡(jiǎn)單地輸出它的值(在<number>元素標(biāo)記里),。Figure 12.1演示了執(zhí)行結(jié)果,。


Figure 12.1
Output from the Velocity template.

HttpServletRequestHttpServletResponse對(duì)象被傳遞給Servlets代碼,同時(shí)被放置在兩個(gè)上下文常量對(duì)象中:

VelocityServlet.REQUEST—Stored as req

VelocityServlet.RESPONSE—Stored as res

 

每一個(gè)對(duì)象都能通過直接調(diào)用引用名(reqres)的方式用于Velocity模板中,。

#set($username = $req.getParameter('username'))

創(chuàng)建一個(gè)MVC應(yīng)用程序

我們的第一個(gè)Velocity示例相當(dāng)簡(jiǎn)單,,現(xiàn)在我們來(lái)搞一個(gè)稍復(fù)雜一點(diǎn)的示例。在這一節(jié)里,,你將使用Servlets來(lái)構(gòu)建一個(gè)MVC應(yīng)用程序,,其中:Servlets用作控制器(controller)Velocity模板作用視圖(view),、JavaBeans作用模型(model),。這個(gè)應(yīng)用程序是一個(gè)具有以下四個(gè)功能的CD數(shù)據(jù)庫(kù):

增加一個(gè)CD,同時(shí)返回一個(gè)thank-you響應(yīng)

為特定的CD增加歌曲track,,同時(shí)返回一個(gè)thank-you響應(yīng)

通過特定的藝術(shù)家返回其所有的CD

獲取特定CD的全部歌曲track

Figure 12.2顯示了增加一個(gè)新CD時(shí)的情況,;Figure 12.3顯示了當(dāng)你使用特定的藝術(shù)家搜索CD時(shí)的情況;Figure 12.4顯示了一個(gè)特定CD的所有歌曲時(shí)的情況,。


Figure 12.2
Adding a new CD.


Figure 12.3
Listing all CDs for an artist.

數(shù)據(jù)庫(kù)結(jié)構(gòu)

這個(gè)應(yīng)用程序使用了一個(gè)數(shù)據(jù)庫(kù)來(lái)保存CD和所有歌曲的信息,。在這個(gè)測(cè)試環(huán)境,我們選擇MYSQL數(shù)據(jù)庫(kù)來(lái)存在數(shù)據(jù),,當(dāng)然,,你也可以選擇其他類型的數(shù)據(jù)庫(kù)。下面的SQL建表命令顯示了CD和歌曲表的數(shù)據(jù)結(jié)構(gòu),。

create table cd (

id int not null primary key auto_increment,

title varchar(128),

artist varchar(64),

tracks int);

create table tracks(

id int not null primary key auto_increment,

cd_id int,

name varchar(64),

length varchar(16));


Figure 12.4
Listing all tracks on a CD.

數(shù)據(jù)庫(kù)訪問

我們的模型組件打算使用實(shí)體EJBs來(lái)訪問CD表和歌曲(tracks)表的數(shù)據(jù),,這些beanServlets被用于向用戶提供服務(wù)。在這個(gè)測(cè)試環(huán)境里,,我們使用了Resin應(yīng)用程序服務(wù)器,。EJBs通過JNDI(Java名字和目錄接口)資源引用來(lái)訪問數(shù)據(jù)庫(kù)。Listing 12.4顯示了在應(yīng)用程序服務(wù)器的配置文件中增加的 <resource-ref>元素,。除了數(shù)據(jù)庫(kù)驅(qū)動(dòng)和URL外,,這個(gè)元素使用的是標(biāo)準(zhǔn)規(guī)范。如果你使用的是另外數(shù)據(jù)庫(kù),,你需要改變<init-param>元素以滿足需要,。

<resource-ref>

<res-ref-name>jdbc/ProductsDB</res-ref-name>

<res-type>javax.sql.ConnectionPoolDataSource</res-type>

<init-param driver-name="org.gjt.mm.mysql.Driver"/>

<init-param url="jdbc:mysql://localhost:3306/products"/>

<init-param user=""/>

<init-param password=""/>

<init-param max-connections="20"/>

<init-param max-idle-time="30"/>

<init-param max-active-time="1"/>

<init-param max-pool-time="1"/>

<init-param connection-wait-time="1"/>

</resource-ref>

Listing 12.4 The resin.config resource text.

模型(Model)代碼

在這里,你已經(jīng)創(chuàng)建了一個(gè)數(shù)據(jù)庫(kù),,同時(shí)包含了JNDI引用,,現(xiàn)在,通過JNDI引用,,你就可以訪問數(shù)據(jù)庫(kù)了,。是時(shí)候考慮實(shí)體beans了,我們將把它用于訪問數(shù)據(jù)庫(kù)表里的數(shù)據(jù),。因?yàn)樵谖覀兊挠袃蓚€(gè)數(shù)據(jù)庫(kù)表,,因此就需要構(gòu)建兩個(gè)EJB。為了達(dá)到目的,,讓我們利用Resincontainer-managed persistence (CMP)模式來(lái)創(chuàng)建bean,,同時(shí)主要把精力集中在實(shí)現(xiàn)EJB本地實(shí)例上。意思是我們只處理CMP的本地接口,,而不處理遠(yuǎn)程接口,,因此只需要很少的代碼。由于本書是關(guān)于Velocity的,,故我們只展示這兩個(gè)bean的代碼,,不作更多解釋,你可以在站點(diǎn)http://www./compbooks/gradecki處下載這個(gè)完整的示例代碼,。下面就讓我們來(lái)看一看EJB文件的定義(Listing 12.5),。

<ejb-jar>

<enterprise-beans>

<entity>

<ejb-name>CDRecordBean</ejb-name>

<local-home>cd.CDRecordHome</local-home>

<local>cd.CDRecord</local>

<ejb-class>cd.CDRecordBean</ejb-class>

<prim-key-class>int</prim-key-class>

<primkey-field>id</primkey-field>

<persistence-type>Container</persistence-type>

<reentrant>True</reentrant>

<abstract-schema-name>CDTable</abstract-schema-name>

<sql-table>cd</sql-table>

<cmp-field><field-name>id</field-name></cmp-field>

<cmp-field><field-name>title</field-name></cmp-field>

<cmp-field><field-name>artist</field-name></cmp-field>

<cmp-field><field-name>tracks</field-name></cmp-field>

<query>

<query-method>

<method-name>findByArtist</method-name>

</query-method>

<ejb-ql>SELECT o FROM CDTable o WHERE o.artist like

1</ejb-ql>

</query>

</entity>

<entity>

<ejb-name>TracksRecordBean</ejb-name>

<local-home>cd.TracksRecordHome</local-home>

<local>cd.TracksRecord</local>

<ejb-class>cd.TracksRecordBean</ejb-class>

<prim-key-class>int</prim-key-class>

<primkey-field>id</primkey-field>

<persistence-type>Container</persistence-type>

<reentrant>True</reentrant>

<abstract-schema-name>TrackTable</abstract-schema-name>

<sql-table>tracks</sql-table>

<cmp-field><field-name>id</field-name></cmp-field>

<cmp-field><field-name>cd_id</field-name></cmp-field>

<cmp-field><field-name>name</field-name></cmp-field>

<cmp-field><field-name>length</field-name></cmp-field>

<query>

<query-method>

<method-name>findByCdID</method-name>

</query-method>

<ejb-ql>SELECT o FROM TrackTable o WHERE o.cd_id=?1</ejb-ql>

</query>

</entity>

</enterprise-beans>

</ejb-jar>

Listing 12.5 The CDRecordBean EJB file.

Listing 12.5里的EJB文件展示了這兩個(gè)bean是如何定義的,其中包含了主鍵和每一個(gè)表的字段,。這兩個(gè)實(shí)體bean都包含了一個(gè)<query>元素,,它允許數(shù)據(jù)從表中取出并用于除主鍵以外的字段。為了讓你了解在Resin應(yīng)用程序服務(wù)器里是如何書寫實(shí)體bean的,,讓我們來(lái)看一下Listing 12.6里的CDRecordBean類,。

package cd;

import javax.ejb.*;

public abstract class CDRecordBean

extends com.caucho.ejb.AbstractEntityBean {

public abstract String getTitle();

public abstract String getArtist();

public abstract int getTracks();

public abstract int getId();

public abstract void setTitle(String title);

public abstract void setArtist(String artist);

public abstract void setTracks(int tracks);

public abstract void setId(int id);

public int ejbCreate(String title, String artist, int tracks)

throws CreateException {

setId(0);

setTitle(title);

setArtist(artist);

setTracks(tracks);

return 1;

}

public void ejbPostCreate(String title, String artist, int

tracks) {

// since there are no relations, this is empty.

}

}

Listing 12.6 The CDRecordBean class.

Listing 12.6里的CDRecordBean類繼承自AbstractEntityBean類,AbstractEntityBean類是Resin制造商定義的一個(gè)助手類,。這個(gè)助手類提供了所有的用于讓實(shí)體bean實(shí)現(xiàn)空body的通用方法,。事實(shí)上,把該助手類用于你的bean時(shí),,你只需要提供一個(gè)方法,,從而減少代碼量和代碼混雜。另外,,bean里剩余的代碼被用于定義與這個(gè)bean相關(guān)聯(lián)的表字段,。Listing 12.7顯示了TracksRecordBean類。

package cd;

import javax.ejb.*;

import java.sql.*;

public abstract class TracksRecordBean

extends com.caucho.ejb.AbstractEntityBean {

public abstract int getId();

public abstract int getCd_id();

public abstract String getName();

public abstract String getLength();

public abstract void setId(int id);

public abstract void setCd_id(int cd_id);

public abstract void setName(String name);

public abstract void setLength(String tracks);

public int ejbCreate(int cd_id, String name, String length)

throws CreateException {

setCd_id(cd_id);

setName(name);

setLength(length);

return 1;

}

public void ejbPostCreate(int cd_id, String name, String length) {

// since there are no relations, this is empty.

}

}

Listing 12.7 The TracksRecordBean class.

我們?cè)谥霸?jīng)提及,,你可以為這些實(shí)體bean下載剩余的文件,。所有的實(shí)體文件被放置在Resin 應(yīng)用程序服務(wù)器主機(jī)的/classes目錄下。

The View Code

現(xiàn)在,,你需要考慮一下如何使用Velocity作為你的腳本語(yǔ)言來(lái)進(jìn)行輸出,。這里將是你施展魔法的地方,為用戶提供令人激動(dòng)的輸出,。對(duì)這個(gè)應(yīng)用程序來(lái)說(shuō),,我們需要三個(gè)Velocity模板:

thanks.vm—顯示thank-you信息的普通頁(yè)面

displaycd.vm—向用戶顯示CD列表的頁(yè)面

displaytracks.vm—顯示特定CD內(nèi)所有歌曲的頁(yè)面

首先,,讓我們來(lái)看一下thanks.vm模板,見Listing 12.8

<HTML>

<HEAD>

<TITLE></TITLE>

<link rel="stylesheet" type="text/css" href="defaultpage.css">

</HEAD>

<BODY BGCOLOR="#F79C19" link="ffffff" alink="999999"

vlink="ffffff" topmargin="0" leftmargin="0" marginheight="0"

marginwidth="0">

<BR>

#if ($message)

$message

#end

$thanks

<img src="/images/tune_big.gif" height="250" width=283></td></tr>

</table>

</BODY>

</HTML>

Listing 12.8 The thanks.vm template.

這個(gè)thanks.vm模板事實(shí)上是web框架集的一部分,,它提供了所有可見的邊框,。這個(gè)模板將被放置在main處,或放在body里,,是web框架集的一部分,。在這里,為了讓頁(yè)面更美觀,,你需要提供適當(dāng)?shù)谋尘邦伾蛨D片,。在這個(gè)模板的頂部是頁(yè)面背景的信息,后跟實(shí)際的Velocity元素,。

第一個(gè)元素為帶有$message引用的#if指令,。$message引用用于顯示一個(gè)信息(當(dāng)一個(gè)錯(cuò)誤出現(xiàn)并且你需要讓用戶知道這個(gè)錯(cuò)誤的時(shí)候)。這個(gè)信息只有在錯(cuò)誤發(fā)生時(shí)才會(huì)被寫入上下文中,,因此,,程序沒有發(fā)生錯(cuò)誤的時(shí)候,這個(gè)引用在上下文里是不存在的,。如果我們不用#if指令對(duì)$message進(jìn)行測(cè)試,,那么在輸出中就有可能出現(xiàn)文本字符串“$message”,這看起來(lái)不太好,,因此我們使用$if指令對(duì)$message引用是否包含有值進(jìn)行測(cè)試,,如果$message引用包含有值(意思是在上下文里可以找到這個(gè)引用),那么就顯示$message引用的值,。

在發(fā)生錯(cuò)誤的情況下,,你仍舊想感謝用戶辛苦輸入新的CD或歌曲。這個(gè)輸出就$thanks引用來(lái)產(chǎn)生,。

 

顯示CD

我們的應(yīng)用程序允許用戶通過特定的藝術(shù)家搜索數(shù)據(jù)庫(kù)里所有的CD,,并得到一個(gè)這些CD的列表。在每一次顯示CD列表的時(shí)候都將顯示一個(gè)按鈕,,以方便用戶可以單擊來(lái)列出特定CD的歌曲列表,。Listing 12.9里的displaycd.vm模板用于處理這些顯示任務(wù)。

<HTML>

<HEAD>

<TITLE></TITLE>

<link rel="stylesheet" type="text/css" href="defaultpage.css">

</HEAD>

<BODY BGCOLOR="#F79C19" link="ffffff" alink="999999"

vlink="ffffff" topmargin="0" leftmargin="0" marginheight="0"

marginwidth="0">

<BR><BR>

<font color="ffffff">

#foreach($value in $cds)

<form action="http://localhost:8080/cd/cdVelocityHandler"

method="post">

<b> Title: $value.title </b>

<input type="hidden" name="id" value="$value.id">

<input type="submit" name="submit" value="tracks">

</form>

#end

<BR>

<img src="/images/tune_big.gif" height="250" width="150">

</BODY>

</HTML>

Listing 12.9 The displaycd.vm template.

thanks.vm模板一樣,,在這個(gè)模板的開頭部分包含了一些HTML標(biāo)記,。所有CD的輸出將被顯示在框架集的body內(nèi)。伴隨HTML而來(lái)的是Velocity代碼?,F(xiàn)在讓我們回憶一下需要列表顯示的兩個(gè)部分:顯示某藝術(shù)家的所有CD標(biāo)題和顯示一個(gè)用于列出每個(gè)CD的所有歌曲的按鈕,。

假如你正和你的web開發(fā)者一起工作,你決定讓代碼執(zhí)行一個(gè)操作,,把從數(shù)據(jù)庫(kù)里提出來(lái)的CD放到一個(gè)名叫$cdsCollection對(duì)象里,,并將這個(gè)$cds對(duì)象放入上下文中,。這個(gè)Collection對(duì)象將包含許多基于某特定藝術(shù)家所有CDCDRecordBean對(duì)象。

正如你已經(jīng)看到的,,#foreach指令用于從可用的對(duì)象里提取一個(gè)迭代器(iterator),,Collection類就是這樣的一個(gè)對(duì)象。因此,,每一次循環(huán),$value引用將得到一個(gè)CDRecordBean實(shí)體對(duì)象,。利用beangetter方法,,適當(dāng)?shù)闹祵⒈惶崛〕鰜?lái)。

許多工作都發(fā)生在循環(huán)內(nèi)部,,在這里將從數(shù)據(jù)庫(kù)提取用于顯示的CD標(biāo)題,。注意,一定要用HTML<form>標(biāo)記包圍這個(gè)標(biāo)題,,這個(gè)<form>標(biāo)記用于顯示一個(gè)讓用戶單擊就可以顯示所有這張CD歌曲的按鈕,。

在討論完應(yīng)用程序的需求后,你和web開發(fā)者決定從CD表里提取ID,,用于鏈接歌曲表,。為了實(shí)現(xiàn)這個(gè)想法,你在<form>元素里創(chuàng)建了一個(gè)隱藏的<input>元素,。注意,,這個(gè)隱藏輸入按鈕的值用的是$value.id,意思是你可以向控制器傳遞每一個(gè)CDID,。

顯示歌曲(tracks)

當(dāng)用戶單擊displaycd.vm模板輸出的Tracks按鈕時(shí),,將顯示歌曲的名稱和歌曲長(zhǎng)度。Listing 12.10顯示的displaytracks.vm模板將用于完成這些任務(wù),。這個(gè)模板再次包含了HTML標(biāo)記,,以便更美觀地顯示這個(gè)模板。在HTML標(biāo)記之后,,你將看到另一個(gè)#foreach循環(huán),。

<HTML>

<HEAD>

<TITLE></TITLE>

<link rel="stylesheet" type="text/css" href="defaultpage.css">

</HEAD>

<BODY BGCOLOR="#F79C19" link="ffffff" alink="999999"

vlink="ffffff" topmargin="0" leftmargin="0" marginheight="0"

marginwidth="0">

#if ($message)

$message

#end

<BR>

#foreach($value in $tracks)

<b> Track: $value.name - Length: $value.length</b><BR>

#end

<br>

<img src="/images/tune_big.gif" height="250" width=283></td></tr>

</table>

</BODY>

</HTML>

Listing 12.10 The displaytracks.vm template.

在這里,你的web開發(fā)者已經(jīng)指出了你所需要的另外一個(gè)Collection對(duì)象,,用于存儲(chǔ)某張CD上所有的歌曲,。這個(gè)Collection對(duì)象被命名為$tracks,它通過控制器組件放置在上下文里,。

控制器代碼

你目前已經(jīng)擁有了模型和視圖組件,,現(xiàn)在你需要一個(gè)控制器組件來(lái)把這兩個(gè)組件聯(lián)系在一起,。Listing 12.11顯示了這個(gè)Velocity Servlets,,它將完成這個(gè)工作,。

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

import org.apache.velocity.Template;

import org.apache.velocity.context.Context;

import org.apache.velocity.servlet.VelocityServlet;

import org.apache.velocity.exception.*;

import javax.naming.*;

import javax.ejb.*;

import cd.*;

import org.apache.velocity.app.Velocity;

public class cdVelocityHandler extends VelocityServlet {

private CDRecordHome cdHome = null;

private TracksRecordHome tracksHome = null;

protected Properties loadConfiguration(ServletConfig config )

throws IOException, FileNotFoundException {

Properties p = new Properties();

String path =

config.getServletContext().getRealPath("/");

if (path == null) {

System.out.println("

Unable to get the current webapp root");

path = "/";

}

p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH,

path );

return p;

}

public void init() throws ServletException {

try {

javax.naming.Context cmp = (javax.naming.Context)

new InitialContext().lookup("java:comp/env/cmp");

cdHome = (CDRecordHome) cmp.lookup("CDRecordBean");

tracksHome = (TracksRecordHome)

cmp.lookup("TracksRecordBean");

} catch (NamingException e) {

e.printStackTrace();

}

}

public Template handleRequest( HttpServletRequest req,

HttpServletResponse res, Context context ) {

Template template = null;

if (req.getParameter("submit").equals("new")) {

try {

if (cdHome == null) {

context.put("message", "Sorry we had an error");

} else {

int tracks =

Integer.parseInt(req.getParameter("tracks"));

CDRecord cd =

cdHome.create(req.getParameter("title"),

req.getParameter("artist"), tracks);

if (cd != null) {

context.put("thanks",

"Thank you for the new CD<BR>");

} else {

context.put("thanks",

"We are sorry but your request failed<BR>");

}

try {

template = getTemplate("thanks.vm");

} catch( Exception e ) {

e.printStackTrace();

}

}

} catch(Exception e) {

e.printStackTrace();

}

} else if (req.getParameter("submit").equals("obtain")) {

try {

if (cdHome == null) {

context.put("message", "Sorry we had an error");

} else {

Collection cds =

cdHome.findByArtist(req.getParameter("artist"));

context.put ("cds", cds);

try {

template = getTemplate("displaycds.vm");

} catch( Exception e ) {

e.printStackTrace();

}

}

} catch(Exception e) {

e.printStackTrace();

}

} else if (req.getParameter("submit").equals("tracks")) {

try {

if (tracksHome == null) {

context.put("message", "Sorry we had an error");

} else {

int id = Integer.parseInt(req.getParameter("id"));

Collection tracks = tracksHome.findByCdID(id);

context.put ("tracks", tracks);

try {

template = getTemplate("displaytracks.vm");

} catch( Exception e ) {

System.out.println("Error " + e);

}

}

} catch(Exception e) {

e.printStackTrace();

}

} else if (req.getParameter("submit").equals("addtrack")) {

try {

if (tracksHome == null) {

context.put("message", "Sorry we had an error");

} else {

int id= Integer.parseInt(req.getParameter("id"));

TracksRecord track = tracksHome.create(id,

req.getParameter("name"),

req.getParameter("length"));

if (track!= null) {

context.put("thanks",

"Thank you for the new track<BR>");

} else {

context.put("thanks",

"We are sorry but your request failed<BR>");

}

try {

template = getTemplate("thanks.vm");

} catch( Exception e ) {

e.printStackTrace();

}

}

} catch(Exception e) {

e.printStackTrace();

}

} else {

}

return template;

}

}

Listing 12.11 The controller servlet for the CD example

這個(gè)控制器組件是一個(gè)Velocity Servlets,它使用VelocityServlet類的handleRequest()方法,。在這里有一些讓Servlets訪問Velocity模板和實(shí)體EJB的步驟,。

Velocity模板被放置在Servlets應(yīng)用程序的根目錄,這個(gè)目錄是Servlets必須的,。為了確定Servlets能夠訪問這個(gè)應(yīng)用程序的根目錄,需要為FILE_RESOURCE_LOADER_PATH屬性設(shè)置真實(shí)的目錄,。你可以在loadConfiguration()方法里完成這個(gè)設(shè)置操作,,這個(gè)方法將在handleRequest()方法調(diào)用之前被自動(dòng)調(diào)用。

接著,,你需要獲得實(shí)體EJB home接口的訪問權(quán),,你可以在init()方法里完成這個(gè)任務(wù),init()方法將Servlets第一次執(zhí)行時(shí)被調(diào)用,,這個(gè)方法將為comp/env/cmp JNDI引用獲得一個(gè)naming.Context上下文對(duì)象,。這個(gè)引用將用于在系統(tǒng)里訪問EJB。接下來(lái),,你需要查找每一個(gè)bean,,并從這兩個(gè)bean中返回適當(dāng)?shù)?/span>home對(duì)象。這些home對(duì)象將用于構(gòu)建實(shí)體bean,。

handleRequest()方法里的代碼用于檢查用戶請(qǐng)求的是這四個(gè)操作的哪一個(gè)操作(增加CD,、搜索特定藝術(shù)家、查看某CD的全部歌曲,、為CD增加歌曲),。讓我分別看一下這四個(gè)操作:

增加新CD

當(dāng)用戶為一張新的CD輸入標(biāo)題、藝術(shù)家和該CD的所有歌曲時(shí),,代碼必須能夠完全把這些數(shù)據(jù)放到數(shù)據(jù)庫(kù)表里,。代碼首先確定home接口對(duì)象是有效的,如果該接口無(wú)效,,一個(gè)錯(cuò)誤信息將會(huì)指派給“message”引用,,該引用將增加到上下文中。

如果home接口對(duì)象是有效的,,則從HTML<form>傳遞過來(lái)的歌曲字符串被轉(zhuǎn)換成integer,。接著,,歌曲和從<form>傳遞過來(lái)的值的剩余部分一同被傳遞給CD beanhome接口的create()方法。調(diào)用該方法的結(jié)果有可能是null,,也可能是一個(gè)用于呈現(xiàn)CD表行的新的實(shí)體EJB,。如果該方法的值不是null,那么“thanks”引用被指向一個(gè)文本字符串,,同時(shí)被加入到上下文對(duì)象中,。否則,一個(gè)失敗的信息將會(huì)加入到上下文中,。

在任意一種情況下,,模板對(duì)象都會(huì)被設(shè)置成從getTemplate()方法(使用thanks.vm文件名參數(shù))返回的值。如果沒有異常發(fā)生,,這個(gè)新模板對(duì)象會(huì)從handleRequest()方法返回,同時(shí)用戶會(huì)看到適當(dāng)?shù)妮敵觥?/span>

增加新CD歌曲(Track

增加新CD歌曲的代碼基本上和增加新CD的代碼一樣,,只是接口不同,,在此用的是track接口。在一個(gè)生產(chǎn)型(production)系統(tǒng)里,,你必須確定歌曲應(yīng)該加入到的CD表,,以保證CD和歌曲能夠正確關(guān)聯(lián)。

通過藝術(shù)家搜索CD

通過特定的藝術(shù)家來(lái)獲取CD列表和增加CD只有一小點(diǎn)的不同就是獲取CD列表需要查詢數(shù)據(jù)庫(kù),。你應(yīng)該記得這兩個(gè)實(shí)體EJBEJB文件里都定義了一個(gè)<query>元素,。在CD數(shù)據(jù)表的情況下,我們定義的查詢將返回特定藝術(shù)家所有的CD表行,。

代碼通過findByArtist(String)方法來(lái)調(diào)用這個(gè)查詢,。從這個(gè)方法返回的值是一個(gè)Collection對(duì)象,它包含了從CD數(shù)據(jù)表返回的零到若干個(gè)實(shí)體對(duì)象,。不管有多少個(gè)對(duì)象在collection里,,我們將使用下面的命令把這個(gè)Collection加入到上下文中

context.put ("cds", cds);

當(dāng)Collection對(duì)象被加入到上下文中后,,displaycds.vm模板就從服務(wù)器的磁盤取出,之后,,這個(gè)模板對(duì)象被顯示給用戶。

列出CD歌曲

當(dāng)用戶想顯示特定CD的歌曲時(shí),,代碼將獲取從<form>里的ID變量傳遞過來(lái)的ID,,以及將這個(gè)ID傳遞給findByCdID(int)方法。這個(gè)方法執(zhí)行TracksRecordBeanEJB文件里的<query>元素,,該方法的結(jié)果是一個(gè)Collection對(duì)象,,它包含了這張?zhí)囟?/span>CD的所有歌曲。這個(gè)Collection對(duì)象通過$tracks引用被加入到上下文中,。

高級(jí)Servlet功能

作為VelocityServlet基礎(chǔ)類,,許多附加的方法可以被重載,。這些方法如下:

Properties loadConfiguration(ServletConfig)—一個(gè)允許附加的屬性被加入到Servlets的屬性中的方法。這些目前被定義到Velocity運(yùn)行時(shí)的屬性是:

l         static java.lang.String--COUNTER_INITIAL_VALUE—初始化#foreach指令的計(jì)數(shù)器值

l         static java.lang.String--COUNTER_NAME—初始化#foreach指令的計(jì)數(shù)器名稱

l         static java.lang.String--DEBUG_PREFIX—日志信息前綴

l         static java.lang.String--DEFAULT_RUNTIME_DIRECTIVES—默認(rèn)運(yùn)行時(shí)指令

l         static java.lang.String--DEFAULT_RUNTIME_PROPERTIES—默認(rèn)運(yùn)行時(shí)屬性

l         static java.lang.String--ENCODING_DEFAULT—默認(rèn)編碼類型

l         static java.lang.String--ERROR_PREFIX—錯(cuò)誤信息前綴

l         static java.lang.String--ERRORMSG_END—錯(cuò)誤信息的結(jié)束標(biāo)記,,通過在#include指令里傳遞一個(gè)不允許參數(shù)時(shí)觸發(fā)

l         static java.lang.String--ERRORMSG_START—錯(cuò)誤信息的開始標(biāo)記,,通過在#include指令里傳遞一個(gè)不允許參數(shù)時(shí)觸發(fā)

l         static java.lang.String--FILE_RESOURCE_LOADER_CACHE—FileResourceLoader里打開一個(gè)公用的緩存

l         static java.lang.String--FILE_RESOURCE_LOADER_PATH—FileResourceLoader里設(shè)置一個(gè)公用的路徑

l         static java.lang.String--INFO_PREFIX—消息通知前綴

l         static java.lang.String--INPUT_ENCODING—模板編碼集

l         static java.lang.String--INTERPOLATE_STRINGLITERALS—字符串篡改開關(guān)

l         static java.lang.String--LOGSYSTEM_LOG4J_EMAIL_BUFFER_SIZE--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_EMAIL_FROM--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_EMAIL_SERVER--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_EMAIL_SUBJECT--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_EMAIL_TO--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_FILE_BACKUPS--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_FILE_SIZE--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_PATTERN--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_REMOTE_HOST--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_REMOTE_PORT--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_SYSLOGD_FACILITY--log4J配置

l         static java.lang.String--LOGSYSTEM_LOG4J_SYSLOGD_HOST--log4J配置

l         static int--NUMBER_OF_PARSERS—你想創(chuàng)建的解析器數(shù)量

l         static java.lang.String--OUTPUT_ENCODING—輸出流編碼集

l         static java.lang.String--PARSE_DIRECTIVE_MAXDEPTH—#parse指令允許的最大遞歸深度

l         static java.lang.String--PARSER_POOL_SIZE—解析器在池里的總數(shù)

l         static java.lang.String--RESOURCE_LOADER—用于重新找回資源加載器名稱的關(guān)鍵字

l         static java.lang.String--RESOURCE_MANAGER_CACHE_CLASS—實(shí)現(xiàn)資源管理緩存的類

l         static java.lang.String--RESOURCE_MANAGER_CLASS—實(shí)現(xiàn)資源管理器的類

l         static java.lang.String--RESOURCE_MANAGER_LOGWHENFOUND—用于確定是否對(duì)找到資源進(jìn)行日志

l         static java.lang.String--RUNTIME_LOG—定位Velocity日志文件

l         static java.lang.String--RUNTIME_LOG_ERROR_STACKTRACE—堆棧跟蹤錯(cuò)誤信息輸出

l         static java.lang.String--RUNTIME_LOG_INFO_STACKTRACE—堆棧跟蹤報(bào)告信息輸出

l         static java.lang.String--RUNTIME_LOG_LOGSYSTEM—用于指定外面的日志系統(tǒng)

l         static java.lang.String--RUNTIME_LOG_LOGSYSTEM_CLASS—你想要使用的日志系統(tǒng)類

l         static java.lang.String--RUNTIME_LOG_REFERENCE_LOG_INVALID—非法引用日志

l         static java.lang.String--RUNTIME_LOG_WARN_STACKTRACE—堆棧跟蹤警告信息輸出

l         static java.lang.String--UNKNOWN_PREFIX—未知信息前綴

l         static java.lang.String--VM_CONTEXT_LOCALSCOPE—VM本地作用域開關(guān),默認(rèn)為false

l         static java.lang.String--VM_LIBRARY—本地Velocimacro庫(kù)模板名稱

l         static java.lang.String--VM_LIBRARY_AUTORELOAD—一個(gè)自動(dòng)加載VM資源庫(kù)的開關(guān),,用于開發(fā)階段

l         static java.lang.String--VM_MESSAGES_ON—VM消息開關(guān),,默認(rèn)為true

l         static java.lang.String--VM_PERM_ALLOW_INLINE—布爾值,默認(rèn)為true,,既是否允許內(nèi)聯(lián)(在模板里)宏定義

l         static java.lang.String--VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL—布爾值,,默認(rèn)為false,即是否允許內(nèi)聯(lián)(在模板里)宏定義替換現(xiàn)有的定義

l         static java.lang.String--VM_PERM_INLINE_LOCAL—是否強(qiáng)迫內(nèi)聯(lián)宏為本地的,,默認(rèn)為false

l         static java.lang.String--WARN_PREFIX—警告信息前綴

Context createContext(HttpServletRequest, HttpServletResponse)—該方法允許開發(fā)者創(chuàng)建他們自己的上下文對(duì)象,,可以被用作私有merge()方法。

void setContentType( HttpServletRequest,HttpServletResponse)—默認(rèn)情況下,,handleRequest()方法將輸出HTML格式的文本,,但是,你可以更改成其他格式,,比如XML,,甚至是圖片文件。

void mergeTemplate(Template, Context, HttpServletResponse)—如果你想自己控制輸出來(lái)代替handleRequest()方法,,那么你可以使用createContext()方法得到你自己的上下文,,并且把它們和模板進(jìn)行合并,之后通過handleRequest()方法輸出給response對(duì)象,。mergeTemplate()方法得到所有的三個(gè)對(duì)象,,并且產(chǎn)生輸出。

void requestCleanup(HttpServletRequest, HttpServletResponse, Context)—如果你想自己處理輸出,,你應(yīng)該重載requestCleanup()方法,,來(lái)處理任何最后的結(jié)果。默認(rèn)情況下,,這個(gè)方法并沒有實(shí)現(xiàn),。

protected void error(HttpServletRequest, HttpServletResponse, Exception)—當(dāng)在處理用戶請(qǐng)求發(fā)生一個(gè)異常時(shí),該方法將被調(diào)用,。你可以重載這個(gè)方法來(lái)提供更多高級(jí)的錯(cuò)誤處理能力,。默認(rèn)實(shí)現(xiàn)只是發(fā)送一個(gè)錯(cuò)誤信息和一個(gè)堆棧跟蹤信息給用戶。

增加報(bào)表(report

我們的應(yīng)用程序在此已經(jīng)把注意力集中到產(chǎn)生一個(gè)HTML窗體格式的輸出,。但是,,如果你不想要任何HTML樣式的表,而是只想得到一個(gè)基于文本格式的所有數(shù)據(jù)庫(kù)里CD的報(bào)表該怎么辦?Ok,,現(xiàn)在讓我們考慮一下Listing 12.12里的Velocity模板,。



Listing 12.12 A Velocity template that produces a text report.

Listing 12.12里的Velocity模板用于輸出一個(gè)頁(yè)面的頭部,最多列出50張數(shù)據(jù)庫(kù)里的CD,,之后,,產(chǎn)生另一個(gè)頁(yè)面頭部。在兩個(gè)頭部之間的CD數(shù)量可以改變,,以適應(yīng)于不同的輸出,。為了產(chǎn)生的完整的CD報(bào)表,你需要在主CD index.html頁(yè)面增加一個(gè)按鈕,。下面給出這個(gè)按鈕的代碼:

<h3>Reports</h3>

<form action="http://localhost:8080/cd/cdVelocityHandler" method="post">

<input type="submit" name="submit" value="fullreport"> -

download 'report.txt' to your local system

</form>

這個(gè)新窗體在index頁(yè)面上顯示了一個(gè)名叫FullReport的按鈕,。當(dāng)用戶單擊這個(gè)按鈕的時(shí)候,控件被傳遞到cdVelocityHandler servlet(在Listing 12.11里定義的),。Listing 12.13的代碼將用于處理這個(gè)新按鈕,。

else if (req.getParameter("submit").equals("fullreport")) {

try {

if (cdHome == null) {

context.put("message", "Sorry we had an error");

} else {

Collection cds = cdHome.findAllCDs();

context.put ("cds", cds);

try {

template = getTemplate("fullreport.vm");

} catch( Exception e ) {

e.printStackTrace();

}

}

} catch(Exception e) {

e.printStackTrace();

}

}

Listing 12.13 The control servlet report task.

除了配合CDRecordBean實(shí)體beanfindAllCDs查詢外,這些代碼沒有什么特別的地方,。新報(bào)表的查詢見Listing 12.14,。

<query>

<query-method>

<method-name>findAllCDs</method-name>

</query-method>

<ejb-ql>SELECT o FROM CDTable o</ejb-ql>

</query>

Listing 12.14 The bean query.

新查詢從CDTable數(shù)據(jù)庫(kù)表從提出所有的行。一旦所有的行被提出,,結(jié)果Collection對(duì)象就會(huì)被放入上下文中,。最后,,Velocity模板fullreport.vm被調(diào)用,,用于輸出這個(gè)查詢的結(jié)果。輸出的結(jié)果見Figure 12.5


Figure 12.5
The report output in a browser.

正如你所看見的一樣,,這個(gè)輸出并不像我們希望的一樣,,只輸出文本樣式,而不需要HTML進(jìn)行潤(rùn)色,。如果我們想生成一個(gè)文本格式的文件并可以進(jìn)行下載該怎么做,?讓我們來(lái)考慮一下Listing 12.15里的模板。


Listing 12.15
The Velocity template for text only.

Listing 12.15Velocity模板使用tab占位符來(lái)控制從數(shù)據(jù)庫(kù)生成數(shù)據(jù)的輸出格式,。這也就意味著,,ArtisTitle對(duì)應(yīng)的字符串將擁有一個(gè)適當(dāng)?shù)母袷胶蛯?duì)齊方式,同時(shí)不再顧及這些字符串的長(zhǎng)度,。你肯定不想看到任何參差不齊的行排列樣式,。為了完成這個(gè)任務(wù),在知道Artist的值后,,你必須生成一個(gè)正確的tab個(gè)數(shù),。如果你看一下模板代碼,你將會(huì)看到下面這行:

$value.artist$stringlength.tabs($value.artist)$value.title

這一個(gè)行是由下面三行代碼構(gòu)成的:

$value.artist

$stringlength.tabs($value.artist)

$value.title

$value.artist$value.title命令只簡(jiǎn)單為當(dāng)前行產(chǎn)生將要顯示的artisttitle數(shù)據(jù),。這個(gè)命令里最有趣的部分是$stringlength.tabs($value.artist),。這個(gè)$stringlength引用和一個(gè)放置在上下文的對(duì)象(使用StringLength類)關(guān)聯(lián),。StringLength類代碼見Listing 12.16

public class StringLength {

public StringLength(){}

public String tabs(String st) {

String s = new String();

for (int i=3;i>st.length()/5;i--)

s = s + ""t";

return s;

}

}

Listing 12.16 The StringLength class.

StringLength類只有一個(gè)簡(jiǎn)單的任務(wù):暴露一個(gè)名叫tabs()的方法。這個(gè)方法的作用是計(jì)算并返回一個(gè)確定個(gè)數(shù)的tabs字符串,,以用于排列artisttitle的值,。藝術(shù)家的名稱被傳遞給tabs()方法,之后確定數(shù)量的tabs被返回,。

現(xiàn)在,,你的Velocity模板已經(jīng)能夠返回正確的輸出,OK,,讓我們考慮一下如何讓你的控件Servlets生成一個(gè)文件,,以便用戶下載。Listing 12.17的代碼顯示了Full-Report按鈕的控件Servlets代碼,。

else if (req.getParameter("submit").equals("fullreport")) {

try {

if (cdHome == null) {

context.put("message", "Sorry we had an error");

} else {

Collection cds = cdHome.findAllCDs();

context.put ("cds", cds);

try {

res.setContentType("APPLICATION/OCTET-STREAM");

res.setHeader("Content-Disposition","attachment;

filename=report.txt");

template = getTemplate("fullreport.vm");

} catch( Exception e ) {

e.printStackTrace();

}

}

} catch(Exception e) {

e.printStackTrace();

}

}

Listing 12.17 The servlet code for downloading the report.

正如你所看到的一樣,,findAllCDs查詢被用于從數(shù)據(jù)庫(kù)中提取所有的CD信息,同時(shí),,模板fullreport.vm被用于輸出,。其中增加了兩個(gè)新命令:

res.setContentType("APPLICATION/OCTET-STREAM");

res.setHeader("Content-Disposition","attachment; filename=report.txt");

這兩個(gè)命令用于告訴用戶瀏覽器,從<form>返回的信息是一個(gè)名叫report.txt的文件,,這個(gè)信息將導(dǎo)致出現(xiàn)一個(gè)下載對(duì)話框,,用于用戶下載文件。Figure 12.6顯示了使用這個(gè)應(yīng)用程序產(chǎn)生的文件下載情況,。


Figure 12.6
The report output.

本章小節(jié)和下章介紹

在這一章里,,我們介紹了一種可能對(duì)開發(fā)者有用的混合VelocityServlets的技術(shù)。在下一章里,,我們將演示如何擴(kuò)展Velocity驅(qū)動(dòng)的站點(diǎn),,以適當(dāng)國(guó)際化需要的技術(shù)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多