|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
Java的B/s开发是通常是javaweb开发,又叫J2EE开发,J2SE是手机开发。C#的C/s和B/s开发是说.net和Asp开发。。u在这里说明一点;资深一点的Java和C#程序员都明白一点servlet今天的Java开辟甚么样?
(神仙掌事情室 2001年06月19日14:44)
和以后的Servlet2.2标准比拟,Servlet2.3倡议终极草案(PFD)最年夜的分歧的地方在于把filter(过滤器)和event(事务)到场了Servlet模子。过滤器供应了一种让使用程序在任何Servlet运转之前或运转以后实行尺度举措的办法。很长工夫以来,Servlet标准中都没有事务。事务供应的是特定举措的关照,出格是使用程序的启动/停止预会话的启动/停止,使得使用程序可以举行某些一次性的初始化/清算操纵。
事务句柄
在很多场所,使用程序一启动就必需举行一些初始化操纵。比方,创立和初始化JDBC毗连时,大概创立JDBC毗连池时,大概读取在使用程序的全部性命周期内都要用到的资本时,大概举行复杂的反省以确保使用程序要用到的某些资本的确存在时,这类情形城市产生。在服从2.2标准的容器上,使用程序没有包管可以实行这类初始化操纵的举措。
在2.2标准中,部署Servlet时能够在web.xml文件中设置<load-on-startup>项目。这个元素应当包括一个负数,它决意了Servlet启动的序次,有关该标志的更多申明,请拜见Servlet标准中的web.xmlDTD申明。接纳这类计划有几个成绩。起首,Servlet标准说:“load-on-startup元素暗示该Servlet应当(should)在Web使用程序启动的时分装进。”Servlet容器开辟者大概把它了解成“应当装进,但不是必需装进”(因而,当使用程序启动时Servlet大概没有被装进)。别的一个成绩在于,我们是在用一种与Servlet计划企图分歧的体例利用Servlet。
Servlet有一个“哀求”级的感化局限。也就是说,依照计划,Servlet关于每一个客户真个哀求实行一次。但在这里,Servlet有了“使用”级感化局限,它实行一次然后就挂起。
在2.2标准中,Servlet还能够被卸载――容器反省初始化Servlet,判别出Servlet在一段工夫内已没有利用,因而就卸载它。假如这个Servlet“占有”了一些启动的时分它初始化的资本,那末它应当开释这些资本。可是,Servlet不会原告知使用程序甚么时分停止。Servlet的撤除办法会在使用程序封闭的时分被挪用,但它没法晓得是不是一切其他Servlet也被卸载。当其他Servlet被卸载时,它们大概必要用到由初始化Servlet创立的资本。假如先卸载的是初始化Servlet,那末其他Servlet的处境就不妙了。
利用会话的时分也会呈现完整一样的成绩,由于使用程序完整有来由在创建/撤除每个会话的时分,做一些初始化大概清算事情。
为懂得决这些成绩,Servlet2.3标准引进了事务句柄的观点。事务句柄是一些回应和处置由容器初始化的特定事务的代码。Servlet2.3标准界说了两品种型的事务:使用程序事务,会话事务。关于一切这两种事务范例,事务句柄可以捕捉启动和停止事务,可以捕捉属性改动事务。
我们将把注重力次要会合到使用程序的启动和停止事务上,但关于其他事务范例来讲,代码也是类似的。
我们来看看事务句柄的代码。使用程序的事务句柄必需扩大javax.servlet.ServletContextListener接口。这个接口有两个办法,即contextDestroyed()和contextInitialized()。两个办法都有一个ServletContextEvent参数。正如你能够料想到的,contextInitialized()办法在使用程序启动的时分被挪用,contextDestroyed()办法在使用程序停止的时分被挪用。ServletContextEvent类有一个办法,它可以前往正在被创立或撤除的ServletContext的援用。
举例来讲,假定你正在计划一个基于Web的复杂白页(WhitePage)使用。在这个使用中,用户经由过程email查找姓名和地点,如Listing1所示。这个例子在一个Hashtable(散列表)中保留白页的内容,散列表必需在使用程序启动的时分创立,并且它必需保留到使用程序的ServletContext。
【Listing1】
importjavax.servlet.ServletContextListener;
publicclassWhitePagesListenerimplementsServletContextListener{
HashtablewhitePages;
publicWhitePagesServletListener(){
whitePages=newHashtable();
}
publicvoidcontextDestroyed(ServletContextEventsce){}
publicvoidcontextInitialized(ServletContextEventsce){
System.out.println("contextInitialized");
WhitePageEntrywpe=newWhitePageEntry("KevinJones","555-1234");
whitePages.put("kev@dev.com",wpe);
wpe=newWhitePageEntry("SimonHorrell","555-8765");
whitePages.put("simon@dev.com",wpe);
wpe=newWhitePageEntry("DonBox","555-2137");
whitePages.put("don@dev.com",wpe);
//把散列表保留到ServletContext
sce.getServletContext().setAttribute("addrbook",whitePages);
}
}
代码十分复杂。WhitePagesListener类完成了ServletContextListener。散列表由类的机关办法创立。contextDestroyed()办法甚么事变也不错,由于使用程序是被完整卸载,我们不必要清算历程。使人感乐趣的部分是在contextInitialized()办法内。这个办法把我们必要的数据保留到散列表,然后把散列表保留到ServletContext。当contextInitialized()被挪用时,它的参数中传进了一个对ServletContextEvent对象的援用。ServletContextEvent类有一个getServletContext()办法,它前往的是对以后使用程序的ServletContext的援用。取得ServletContext的援用以后,散列表就被保留到了ServletContext当中。
使用程序必需经由设置才干利用这个事务句柄,详细经由过程修正使用程序的部署形貌器(即web.xml文件)完成:
<web-app>
<listener>
<listener-class>
WhitePagesListener
</listener-class>
</listener>...
用这类办法能够设置恣意数目的监听器(Listener)。挪用监听器的序次就是它们在部署形貌器中呈现的序次。监听器属于Singleton,开辟者必需卖力举行同步。这一点关于本例来讲不是出格主要,但关于一切别的范例的使用来讲,它大概很主要。
过滤器
过滤器是Servlet2.3标准中最次要的新增功效。过滤器使得Servlet开辟者可以在哀求抵达Servlet之前截取哀求,在Servlet处置哀求以后修正应对。正如我们行将看到的,过滤器的创立和安装都很复杂。
一切的过滤器完成javax.filter.Filter接口。这个接口有三个办法:setFilterConfig()办法,在最初的标准中,这个办法极可能被两个办法代替,代替的办法多是init(Filterconfigconfig)和destroy();getFilterConfig()办法,在标准的稍后版本中这个办法大概消散;doFilter()办法。setFilterConfig()办法在第一次创立过滤器实例和从挪用链删除过滤器时被挪用。创立实例时,传进过滤器的参数是一个非null的FilterConfig对象。这个对象使得过滤器可以会见它的名字和以后的ServletContext。初始化参数能够作为过滤器设置的一部分指定,这些参数也能够经由过程FilterConfig会见。当过滤器被删除时,传进setFilterConfig()的是一个值为null的FilterConfig。
设置过滤器时,我们能够把过滤器联系关系到一个大概多个Servlet上。只需哀求传送到了与某个过滤器联系关系的Servlet上,该过滤器就会实行。过滤器以挪用链中一部分的情势实行,实行序次由过滤器在部署形貌器(即web.xml文件)中的序次决意。容器经由过程挪用过滤器的doFilter()办法实行过滤器。doFilter()办法的参数包含一个ServletRequest对象、一个ServletResponse对象、一个javax.servlet.FilterChain对象。
FilterChain只要一个办法doFilter(),过滤器经由过程挪用该办法把哀求和应对持续向挪用链的下一环传送。固然这也意味着,过滤器能够不再向挪用链传送它,从而堵塞挪用。此时,以后过滤器必需卖力天生符合的应对内容。
举一个例子,我们来看一个在调试Servlet时很有效的Servlet,如Listing2所示。这个过滤器将输入“下流”Servlet和过滤器设置的HttpRequest头和HttpResponse头。假如让这个过滤器成为挪用链中的第一个过滤器,它大概可以让我们捕捉一切的应对头,不外容器大概决意以过滤器永久不克不及懂得的体例设置应对头:
【Listing2】上面清单中的Servlet将输入由“下流”Servlet和过滤器设置的HttpRequest头和HttpResponse头
publicclassDumpHeadersimplements
javax.servlet.Filter{
privateFilterConfigfc;
privateServletContextctx;
......
publicFilterConfiggetFilterConfig(){
returnfc;
}
publicvoidsetFilterConfig(FilterConfigfilterConfig){
fc=filterConfig;
if(fc!=null)ctx=fc.getServletContext();
}
}
这个过滤器完成了javax.servlet.Filter接口,以是它必需依照后面所显现的完成setFilterConfig()和getFilterConfig()。setFilterContext()保留了一个对ServletContext的援用以便今后利用。
doFilter()办法的完成必要一点技能。doFilter()的第一部分很复杂:猎取request对象,剖析HTTP办法和查询字符串,然后列举哀求头。代码如Listing3所示。
【Listing3】上面显现了doFilter()第一部分的完成,它猎取request对象,剖析HTTP办法和查询字符串。
publicvoiddoFilter(
ServletRequestrequest,
ServletResponseresponse,chain)
throwsjava.io.IOException,
ServletException{
//取得request对象
HttpServletRequestreq=(HttpServletRequest)request;
//从头机关HTTP哀求行
Stringtemp;
temp=req.getMethod()+req.getRequestURI();
if(req.getQueryString()!=null)
temp+="?"+req.getQueryString();
temp+=""+req.getProtocol();
//用ServletContext纪录HTTP哀求行
ctx.log(temp);temp="";
//列举哀求头
Enumerationnames=req.getHeaderNames();
while(names.hasMoreElements()){
Stringname=(String)names.nextElement();
temp+=name+":";
Enumerationvalues=req.getHeaders(name);
while(values.hasMoreElements()){
Stringvalue=(String)values.nextElement();
temp+=value+"";
}//纪录ctx.log(temp);temp="";
}
但处置应对对照庞大,并且它触及到Servlet的一个新观点――封装request和response对象。在Servlet标准之前的版本中,挪用任何一个请求有[Http]ServletRequest或[Http]ServletResponse的办法时,你必需把传送给Servletservice办法的request和response对象传送给该办法。最分明的例子就是分拨哀求的时分:
RequestDispatchrd=getServletContext().getRequestDispatcher("foo");rd.forward(request,response);//orrd.include(request,response);
假定你想实行一个包括操纵,然后,在把应对发送给客户端之前又要对它举行处置,大概在把应对发送给客户端之前从RequestDispatcher.forward()检察应对。在之前的Servlet标准中,这是不成能的。但在Servlet2.3标准中这统统都成为大概。
新的标准界说了两个新类,即javax.servlet.http.HttpServletRequestWrapper和javax.servlet.http.HttpServletResponseWrapper(这两个类从它们各自的非HTTP版本承继)。这两个类的机关办法以下:
HttpServletRequestWrapper(HttpServletRequestrequest)HttpServletResponseWrapper(HttpServletResponseresponse)
在这些类中,这两个办法的默许举动是把挪用传送给它们所封装的对象。利用这些类的时分,你一样平常要派生这些类并掩盖那些感乐趣的办法。关于本文的过滤器,我们必需创立一个应对封装器,纪录对addXXXHeader()办法和setXXXHeader()办法的挪用。别的,我们还想要捕捉对setStatus()、setContentLength()、setContentType()和setLocale()办法的挪用。代码如Listing4所示,它复杂地纪录了对各个办法的挪用。
【Listing4】应对封装器。上面的代码为过滤器机关了一个应对封装器,它将纪录对addXXXHeader()和setXXXHeader()办法的挪用。别的,它还要捕捉对setStatus()、setContentLength()、setContentType()和setLocale()办法的挪用。
classHeaderResponseWrapperextends
HttpServletResponseWrapper{
ServletContextctx;
publicHeaderResponseWrapper(
HttpServletResponseresponse,
ServletContextctx){
super(response);
this.ctx=ctx;
}
publicvoidaddCookie(Cookiecookie){
ctx.log("Set-Cookie:"+cookie.getName()+":"+cookie.getValue());
super.addCookie(cookie);
}
publicvoidaddHeader(Stringname,Stringvalue){
ctx.log(name+":"+value);super.addHeader(name,value);
}
publicvoidaddIntHeader(Stringname,intvalue){
ctx.log(name+":"+value);super.addIntHeader(name,value);
}
publicvoidaddDateHeader(Stringname,longvalue){
ctx.log(name+":"+value);super.addDateHeader(name,value);
}
publicvoidsetHeader(Stringname,Stringvalue){
ctx.log(name+":"+value);super.setHeader(name,value);
}
publicvoidsetIntHeader(Stringname,intvalue){
ctx.log(name+":"+value);super.setIntHeader(name,value);
}
publicvoidsetDateHeader(Stringname,longvalue){
ctx.log(name+":"+value);super.setDateHeader(name,value);
}
publicvoidsetStatus(intsc){
ctx.log("status:"+sc);super.setStatus(sc);
}
publicvoidsetStatus(intsc,java.lang.Stringsm){
ctx.log("status:"+sc);super.setStatus(sc,sm);
}
publicvoidsetContentLength(intlen){
ctx.log("Content-Length:"+len);super.setContentLength(len);
}
publicvoidsetContentType(java.lang.Stringtype){
ctx.log("Content-Type:"+type);super.setContentType(type);
}
publicvoidsetLocale(java.util.Localeloc){
ctx.log("locale:"+loc);super.setLocale(loc);
}
}
在过滤器中,我们依照以下体例利用这个对象:
HttpServletResponseresp=(HttpServletResponse)response;
HeaderResponseWrapperhrespw=newHeaderResponseWrapper(resp,ctx);
System.out.println("********");
chain.doFilter(request,hrespw);
注重创立好封装器以后chain.doFilter()办法就被挪用。
界说好过滤器以后就应当安装它。为此,web.xml中应当界说一个filter元素:
<filter>
<filter-name>
HeadersFilter
</filter-name>
<filter-class>
DumpHeaders
</filter-class>
<!-optional<init-params>->
</filter>
完成这一步以后,你还要把过滤器和你想要过滤的资本联系关系起来。这时候你有两种选择:在web.xml中,把过滤器联系关系到单个定名的Servlet,大概把过滤器联系关系到一个URL。以下所示:
<filter-mapping>
<filter-name>
HeadersFilter
</filter-name>
<servlet-name>
AddressBookServlet
</servlet-name>
</filter-mapping>
大概:
<filter-mapping>
<filter-name>
HeaderFilter
</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
输入的哀求头以下所示:
GET/AddressBook/Browse.jspHTTP/1.1
accept:*/*
referer:http://localhost/AddressBook/
accept-language:en-gb
accept-encoding:gzip,deflate
user-agent:Mozilla/4.0(compatible;MSIE5.5;WindowsNT5.0)
host:localhost
connection:Keep-Alive
cookie:JSESSIONID=E0F9646772F4448004C16122020664F1
输入的应对头以下所示:
Content-Type:text/html;charset=8859_1Content-Type:text/plain
假如举行收集跟踪,你会发明这里少了一些工具。比方,形态代码没有显现,这是由于有一些应对头由容器在过滤器链实行之前或以后设置。
过滤器有良多用处,好比考证、转换、加密/解密。但有一点必需注重:你能够把过滤器联系关系就任意资本,而不单单是Servlet。假如你利用的是一个拔出到其他Web服务器的Servlet引擎,Web服务器极可能会不依附于Servlet容器自力地供应服务。在这类情形下,Servlet容器将吸收不到一切的哀求,以是过滤器也就不会老是被实行。
JSP1.1中有一个成绩触及到哀求分拨。假如你有一个页面实行include操纵,jsp:include有一个必需设置为true的强迫性flush(革新)属性:
<jsp:includepage="somePage"flush="true"/>
这个属性强迫容器把以后缓冲区内容革新到客户端。如许,JSP页面不克不及再设置恣意HTTP应对头。JSP1.2标准已修改这个成绩,jsp:include标志中如今已能够指定flush="false"。
C++编译的是本地码,优点是启动快,而且可以精确控制资源因此可以开发很高效的程序.缺点是编程麻烦,而且容易留下安全隐患.跨平台靠源代码在各个平台间分别编译(一处编写到处编译) |
|