综述:Java Servlet是JSP技术的基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。现在许多Web服务器都支持Servlet,即使不直接支持Servlet的Web服务器,也可以通过附件的应用服务器和模块来支持Servlet,这得益于Java的跨平台特性。另外,由于Servlet内部以线程方式提供提供服务,不必对于每个请求都启动一个进程,并且利用多线程机制可以同时为多个请求服务,因此Servlet的效率非常高。

  但它并不是没有缺点,和传统的CGI、ISAPI、NSAPI方式相同,Java Servlet也是利用输出HTML语句来实现动态网页的,如果用它来开发整个网站,动态部分和静态页面的整合过程将变得无法想象。这就是SUN还要推出JSP的原因。

  如何正确理解servlet?

  servlet的基本概念

  一、Servlet的结构

  在具体掌握servlet之前,须对Java语言有所了解。我们假设读者已经具备一定的Java基础。在Servlet API中最重要的是Servlet接口(interface),所有的servlets都必须实现该接口,途径有很多:一是直接实现该接口,二是通过扩展类(class)来实现,如 HttpServlet。 这个Servlet接口提供了servlet与客户端联系的方法。Servlet编写者可以在他们开发 servlet程序时提供更多一些或所有的这样方法。

  当一个servlet接收来自客户端的调用请求, 它接收两个对象:一个是ServletRequest,另外一个是ServletResponse。这个ServletRequest类概括从客户端到服务器之间的联系,而 ServletResponse类概括从servlet返回客户端的联系。

  ServletRequest接口可以获取到这样一些信息,如由客户端传送的阐述名称,客户端正在使用的协议,产生请求并且接收请求的服务器远端主机名。它也提供获取数据流的ServletInputStream, 这些数据是客户端引用中使用HTTP POST 和 PUT 方法递交的。一个ServletRequest的子类可以让servlet获取更多的协议特性数据。例如:HttpServletRequest 包含获取 HTTP-specific头部信息的方法。

  ServletResponse接口给出相应客户端的servlet方法。它允许servlet设置内容长度和回应的mime类型,并且提供输出流ServletOutputStream,通过编写者可以发回相应的数据。ServletResponse子类可以给出更多protocol-specific内容的信息。 例如:HttpServletResponse 包含允许servlet 操作HTTP-specific头部信息的方法。

  上面有关类和接口的描述,构成了一个基本的Servlet框架。HTTP servlets有一些附加的可以提供session-tracking capabilities的方法。servlet编写者可以利用这些API,在有他人操作时维护servlet与客户端之间的状态。


  二、Servlet的接口

  我们编写的Servlet ,一般从Javax包的HttpServlet类扩展而来,在HttpServlet中加入了一些附加的方法,这些方法可以被协助处理HTTP 基本请求的HttpServlet类中的方法service自动地调用。这些方法有:

  · doGet 用来处理HTTP的GET请求。

  这个GET操作仅仅允许客户从HTTP server上取得(GET)资源。重载此方法的用户自动允许支持方法HEAD。这个GET操作被认为是安全的,没有任何的负面影响,对用户来说是很可靠的。比如,大多数的正规查询都没有副作用。打算改变存储数据的请求必须用其他的HTTP方法。这些方法也必须是个安全的操作。方法doGet的缺省实现将返回一个HTTP的BAD_REQUEST错误。

  方法doGet的格式:
  protected void doGet(HttpServletResquest request, HttpServletResponse response)
  throws ServletException,IOException;

  · doPost 用来处理HTTP的POST请求。

  这个POST操作包含了在必须通过此servlet执行的请求中的数据。由于它不能立即取得资源,故对于那些涉及到安全性的用户来说,通过POST请求操作会有一些副作用。

  方法doPost的缺省实现将返回一个HTTP的BAD_REQUEST错误。当编写servlet时,为了支持POST操作必须在子类HttpServlet中实现(implement)此方法。

  此方法的格式:

  protected void doPost(HttpServletResquest request, HttpServletResponse response)
  throws ServletException,IOException;

  · doPut用来处理HTTP的PUT请求。

  此PUT操作模拟通过FTP发送一个文件。对于那些涉及到安全性的用户来说,通过PUT请求操作也会有一些副作用。

  此方法的格式:

  protected void doPut(HttpServletResquest request,HttpServletResponse response)
  throws ServletException,IOException;

  · doDelete用来处理HTTP的DELETE请求。

  此操作允许客户端请求一个从server移出的URL。对于那些涉及到安全性的用户来说,通过DELETE请求操作会有一些副作用。

  方法doDelete的缺省实现将返回一个HTTP的BAD_REQUEST错误。当编写servlet时,为了支持DELETE操作,必须在子类HttpServlet中实现(implement)此方法。

  此方法的格式:

  protected void doDelete (HttpServletResquest request, HttpServletResponse response)
  throws ServletException,IOException;

  · doHead 用来处理HTTP的HEAD请求。

  缺省地,它会在无条件的GET方法执行时运行,但是不返回任何数据到客户端。只返回包含内容信息的长度的header。由于用到GET操作,此方法应该是很安全的(没有副作用)也是可重复使用的。此方法的缺省实现(implement)自动地处理了HTTPDE的HEAD操作并且不需要通过一个子类实现(implement)。

  此方法的格式:

  protected void doHead (HttpServletResquest request,HttpServletResponse response)
  throws ServletException,IOException;

  · doOptions用来处理HTTP的OPTIONS请求。

  此操作自动地决定支持什么HTTP方法。比如说,如果读者创建HttpServlet的子类并重载方法doGet,然后方法doOptions会返回下面的header:

  Allow:GET,HEAD,TRACE,OPTIONS

  一般不需要重载方法doOptions。

  此方法的格式:

  protected void doOptions (HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;

  · doTrace用来处理HTTP的TRACE请求。

  此方法的缺省实现产生一个包含所有在trace请求中的header的信息的应答(response)。在开发servlet时,多数情况下需要重载此方法。

  此方法的格式:

  protected void doTrace (HttpServletResquest request, HttpServletResponse response)
  throws ServletException,IOException;

  在开发以HTTP为基础的servlet中,Servlet开发者关心方法doGet和方法doPost即可。


3.Servlet结束时期
  Servlets一直运行到他们被服务器卸载。在结束的时候需要收回在init()方法中使用的资源,在Servlet中是通过destory()方法来实现的。
public void destroy()
{
//回收在init()中启用的资源,如关闭数据库的连接等。
}

  JSP与servlet之间是怎样的关系?

  JSP主要关注于HTML(或者XML)与Java代码的结合,以及加入其中的JSP标记。如果一个支持JSP的服务器遇到一个JSP页面,它首先查看该页面是否被编译成为一个servlet。由此可见,JSP被编译成servlet,即被转变为纯Java,然后被装载入服务器执行。当然,这一过程,根据不同的JSP引擎而略有不同。

  JSP和servlet在应用上有什么区别

  简单的说,SUN首先发展出SERVLET,其功能比较强劲,体系设计也很先进,只是,它输出HTML语句还是采用了老的CGI方式,是一句一句输出,所以,编写和修改HTML非常不方便。

  后来SUN推出了类似于ASP的嵌套型的JSP,把JSP TAG嵌套到HTML语句中,这样,就大大简化和方便了网页的设计和修改。新型的网络语言如ASP,PHP都是嵌套型的。

  从网络三层结构的角度看,一个网络项目最少分三层:data layer,business layer,,presentation layer。当然也可以更复杂。

  SERVLET用来写business layer是很强大的,但是对于写presentation layer就很不方便。JSP则主要是为了方便写presentation layer而设计的。当然也可以写business layer。写惯了ASP,PHP,CGI的朋友,经常会不自觉的把presentation layer和business layer混在一起。比如把数据库处理信息放到JSP中,其实,它应该放在business layer中。

  根据SUN自己的推荐,JSP中应该仅仅存放与presentation layer有关的部分,也就是说,只放输出HTML网页的部份。而所有的数据计算、数据分析、数据库联结处理,统统是属于business layer,应该放在JAVA BEANS中。通过JSP调用JAVA BEANS,实现两层的整合。

  实际上,微软前不久推出的DNA技术,简单说,就是ASP+COM/DCOM技术。与JSP+BEANS完全类似,所有的presentation layer由ASP完成,所有的business layer由COM/DCOM完成。通过调用,实现整合。

  为什么要采用这些组件技术呢?因为单纯的ASP/JSP语言是非常低效率执行的,如果出现大量用户点击,纯SCRIPT语言很快就到达了他的功能上限,而组件技术就能大幅度提高功能上限,加快执行速度。

  另外一方面,纯SCRIPT语言将presentation layer和business layer混在一起,造成修改不方便,并且代码不能重复利用。如果想修改一个地方,经常会牵涉到十几页CODE,采用组件技术就只改组件就可以了。

  综上所述,SERVLET是一个不完善的产品,写business layer很好,写presentation layer就很逊色许多了,并且两层混杂。所以,推出JSP+BAEN,用JSP写presentation layer,用BAEN写business layer。SUN自己的意思也是将来用JSP替代SERVLET。

  所以,学了JSP,不会用JAVA BEAN并进行整合,等于没学。


如何调用servlet?

  要调用Servlet或Web应用程序,请使用下列任一种方法:由URL调用、在<FORM>标记中调用、在<SERVLET>标记中调用、在ASP文件中调用。

  1.由URL调用 Servlet

  这里有两种用Servlet的URL从浏览器中调用该Servlet的方法:

  (1)指定 Servlet 名称:当用 WebSphere应用服务器管理器来将一个Servlet实例添加(注册)到服务器配置中时,必须指定"Servlet 名称"参数的值。例如,可以指定将hi作为HelloWorldServlet的Servlet名称。要调用该Servlet,需打开http://your.server.name/servlet/hi。也可以指定Servlet和类使用同一名称(HelloWorldServlet)。在这种情况下,将由http://your.server.name/servlet/ HelloWorldServlet 来调用Servlet的实例。

  (2)指定 Servlet 别名:用 WebSphere应用服务器 管理器来配置Servlet别名,该别名是用于调用Servlet的快捷URL。快捷URL中不包括Servlet名称。

  2.在<FORM>标记中指定Servlet

  可以在<FORM>标记中调用Servlet。HTM 格式使用户能在Web页面(即从浏览器)上输入数据,并向Servlet提交数据。例如:

<FORM METHOD="GET" ACTION="/servlet/myservlet">
<OL>
<INPUT TYPE="radio" NAME="broadcast" VALUE="am">AM<BR>
<INPUT TYPE="radio" NAME="broadcast" VALUE="fm">FM<BR>
</OL>
(用于放置文本输入区域的标记、按钮和其它的提示符。)
</FORM>

  ACTION特性表明了用于调用Servlet的URL。关于METHOD的特性,如果用户输入的信息是通过GET方法向Servlet提交的,则 Servlet 必须优先使用doGet()方法。反之,如果用户输入的信息是通过POST方法向Servlet提交的,则 Servlet 必须优先使用doPost()方法。使用GET方法时,用户提供的信息是查询字符串表示的URL编码。无需对URL进行编码,因为这是由表单完成的。然后URL编码的查询字符串被附加到Servlet URL中,则整个URL提交完成。URL编码的查询字符串将根据用户同可视部件之间的交互操作,将用户所选的值同可视部件的名称进行配对。例如,考虑前面的HTML代码段将用于显示按钮(标记为AM和FM),如果用户选择FM按钮,则查询字符串将包含name=value的配对操作为broadcast=fm。因为在这种情况下,Servlet将响应HTTP请求,因此Servlet应基于HttpServlet类。Servlet 应根据提交给它的查询字符串中的用户信息使用的 GET 或 POST 方法,而相应地使用 doGet() 或 doPost() 方法。

   3.在<SERVLET>标记中指定Servlet

  当使用<SERVLET>标记来调用Servlet时,如同使用<FORM>标记一样,无需创建一个完整的HTML页面。作为替代,Servlet的输出仅是HTML页面的一部分,且被动态嵌入到原始HTML页面中的其它静态文本中。所有这些都发生在服务器上,且发送给用户的仅是结果HTML页面。建议在Java服务器页面(JSP)文件中使用 <SERVLET> 标记。

  原始HTML页面中包含<SERVLET> 和</SERVLET> 标记。Servlet将在这两个标记中被调用,且Servlet的响应将覆盖这两个标记间的所有东西和标记本身。如果用户的浏览器可以看到HTML源文件,则用户将看不到<SERVLET>和</SERVLET>标记。要在 Domino Go Webserver 上使用该方法,请启用服务器上的服务器端包括功能。部分启用过程将会涉及到添加特殊文件类型SHTML。当Web服务器接收到一个扩展名为SHTML的Web页面请求时,它将搜索 <SERVLET> 和 </SERVLET> 标记。对于所有支持的Web服务器,WebSphere应用服务器将处理SERVLET标记间的所有信息。下列 HTML 代码段显示了如何使用该技术。

<SERVLET NAME="myservlet" CODE="myservlet.class" CODEBASE="url" initparm1= "value">
<PARAM NAME="parm1" VALUE="value">
</SERVLET>

  使用NAME和CODE属性带来了使用上的灵活性。可以只使用其中一个属性,也可以同时使用两个属性。NAME属性指定了Servlet的名称(使用WebSphere应用服务器管理器配置的),或不带.class扩展名的Servlet类名。CODE属性指定了Servlet类名。使用WebSphere应用服务器时,建议指定NAME和CODE,或当NAME指定了Servlet名称时,仅指定NAME。如果仅指定了CODE,则会创建一个NAME=CODE的Servlet实例。装入的Servlet将假设Servlet名称与NAME属性中指定的名称匹配。然后,其它SHTML文件可以成功地使用NAME属性来指定Servlet的名称,并调用已装入的Servlet。NAME的值可以直接在要调用Servlet的URL中使用。如果NAME和CODE都存在,且NAME指定了一个现有Servlet,则通常使用NAME中指定的Servlet。由于Servlet创建了部分HTML文件,所以当创建Servlet时,将可能会使用HttpServlet的一个子类,并优先使用doGet()方法(因为GET方法是提供信息给Servlet的缺省方法)。另一个选项是优先使用service()方法。另外,CODEBASE是可选的,它指定了装入Servlet的远程系统的URL。请使用WebSphere应用服务器管理器来从JAR文件配置远程Servlet装入系统。

  在上述的标记示例中,initparm1是初始化参数名,value是该参数的值。可以指定多个"名称-值"对的集合。利用ServletConfig对象(被传递到Servlet的init()方法中)的getInitParameterNames()和getInitParameter()方法来查找参数名和参数值的字符串数组。在示例中,parm1是参数名,并在初始化Servlet后被才被设置某个值。因为只能通过使用"请求"对象的方法来使用以<PARAM>标记设置的参数,所以服务器必须调用Servlet service()方法,以从用户处传递请求。要获得有关用户的请求信息,请使用getParameterNames()、getParameter()和getParameterValues()方法。

  初始化参数是持续的。假设一台客户机通过调用一个包含某些初始化参数的SHTML文件来调用Servlet。并假设第二台客户机通过调用第二个SHTML文件来调用同一个Servlet,且该SHTML中未指定任何初始化参数。那么第一次调用Servlet时所设置的初始化参数将一直可用,并且通过所有其它SHTML文件而调用的所有后继Servlet都不会更改该参数。直到Servlet调用了destroy()方法后,才能重新设置初始化参数。例如,如果另一个SHTML文件指定了另一个不同的初始化参数值,虽然已此时已装入了Servlet,但该值仍将被忽略。

   4.在ASP文件中调用Servlet
  如果在Microsoft Internet Information Server(IIS)上有遗留的ASP文件,并且无法将ASP文件移植成JSP文件时,可用ASP文件来调用Servlet。在WebSphere应用服务器中的ASP支持包括一个用于嵌入Servlet的ActiveX控制,下面介绍ActiveX控制AspToServlet的方法和属性。

  该方法说明如下:

  (1)String ExecServletToString(String servletName);执行ServletName,并将其输出返回到一个字符串中。

  (2)ExecServlet(String servletName);执行ServletName,并将其输出直接发送至 HTML 页面。

  (3)String VarValue(String varName);获得一预置变量值(其它格式)。

  (4)VarValue(String varName, String newVal);设置变量值。变量占据的总大小应小于0.5个千字节(Kbyte)。且仅对配置文件使用这些变量。

  其属性如下:

  = Boolean WriteHeaders;若该属性为真,则Servlet提供的标题被写入用户处。缺省值为假。
  = Boolean OnTest;若该属性为真,服务器会将消息记录到生成的HTML页面中。缺省值为假。
  下列ASP 脚本示例是以Microsoft Visual Basic Scripting(VBScript)书写的。

<%
' Small sample asp file to show the capabilities of the servlets and the ASP GateWay ...
%>
<H1> Starting the ASP->Java Servlet demo</H1>
<%
' Create a Servlet gateway object and initialize it ...
Set Javaasp = Server.CreateObject("AspToServlet.AspToServlet")
' Setting these properties is only for the sake of demo.
' These are the default values ...
Javaasp.OnTest = False
Javaasp.WriteHeaders = False
' Add several variables ...
Javaasp.VarValue("gal") = "lag"
Javaasp.VarValue("pico")= "ocip"
Javaasp.VarValue("tal") = "lat"
Javaasp.VarValue("paz") = "zap"
Javaasp.VarValue("variable name with spaces") = "variable value with spaces"
%>
<BR>
Lets check the variables
<%
Response.Write("variable gal = ")
Response.Write(Javaasp.VarValue("gal"))
%>
<BR>
<%
Response.Write("variable pico = " & Javaasp.VarValue("pico"))
%>

<BR>
<HR>
<%
galout = Javaasp.ExecServletToString("SnoopServlet")
If Javaasp.WriteHeaders = True Then
%>
Headers were written <%
Else
%>
Headers were not written <%
End If
Response.Write(galout)
%>
<H1> The End ...</H1>


  如何设置servlet类的路径?

  因为各个服务器对访问servlet的策略不尽相同,所以在设置servlet类路径时应该视情况而定。
对于开发中的servlet,只需确认包含Javax.servlet 的JAR文档在您的类路径中,并运用如Javac的普通开发工具。
  对于 JSDK:JSDK_HOME/servlet.jar
  JSDK_HOME/server.jar
  对于 Tomcat:TOMCAT_HOME/lib/servlet.jar
  对于运行中的servlet,必须为servlet引擎设置类路径,这根据不同的引擎,有不同的配置,如哪些库和目录应包括,哪些不应包括。注:对于servlet的动态加载引擎如JRun, Apache Jserv, Tomcat,包含servlet类文件的目录不应在类路径中,而应在config文件中配置。否则,servlet可以运行,但不能被动态再加载。

  Servlet 2.2 规范认为以下应被容器自动包括,因此您不必把他们手工添加到类路径。

  · 所有的类应放在 webapp/WEB-INF/classes目录下

  · 所有JAR文件放在webapp/WEB-INF/lib 目录下

  · 对webapps的应用体现在文档系统中,对已打包进JAR文档的webapps的应用应放入容器的webapps目录。(例如,TOMCAT_HOME/webapps/myapp.jar)

  另外,由Gene McKenna(mckenna@meangene.com)撰写的"The Complete CLASSPATH Guide for Servlets"详细叙述了如何为JavaWebServer和Jrun设置类路径。

  如何实现servlet与applet的通信?

  这个例子将向读者展示服务器端程序(Servlet)和小应用程序(Applet)之间是如何完成通信活动的。它由三个文件组成,一个是sendApplet.Java文件,用于实现Applet,一个是receiveservlet.Java,用于实现servlet,还有一个是add-servlet.html,用于调用Applet。

  在sendApplet.Java文件中,最重要的要属init()函数和Send()函数,其中init()函数用来生成整个Applet的用户操作界面,包括消息文本框、发送按钮等等。而消息的发送过程则由Send()函数来完成。请仔细阅读下面的代码:

private void Send()
{
message = sendText.getText();
//清除用户的输入信息
sendText.setText("");
showStatus("Message send!");
//把输入的字符串转化为 x-www-form-urlencoded 格式
String queryString = "/servlet/ReceiveServlet?message=" + URLEncoder.encode ( message ) ;
p("Attempting to send:"+message);

//建立与Servlet的联接,并取得Servelt的输出信息
try {
connect = (new URL(chatURL,queryString)).openConnection();
showStatus("open connection!");
//下次连接不用Cache
connect.setDefaultUseCaches(false);
//这次连接也不用Cache
connect.setUseCaches(false);
//打开淂流用于读数据
connect.setDoInput(true);
//不能用于写数据
connect.setDoOutput(false);
//服务器与客户的真正连接
connect.connect();
p("Made connection to "+connect);
showStatus("Open Stream!");
DataInputStream in = new DataInputStream(connect.getInputStream());
showStatus("reading!");
message = in.readLine();
while (message! = null)
{
//在消息文本框显示Servlet生成的信息
messageText.setText(message);
message = in.readLine();
}
}catch(MalformedURLException e2)
{
System.err.println("MalformedURLException!");
e2.printStackTrace(System.err);
showStatus("MalformedURLException!");
}catch(IOException e1)
{
System.err.println("IOException!");
e2.printStackTrace(System.err);
showStatus("IOException");
}
}

  整个Applet的详细代码请见sendApplet.Java。

  当Applet与Servlet建立连接后,工作就可以交给Servlet了,由它来解析客户端的请求,获得参数message的值,然后将适当信息返回给客户端,并由Applet进行显示。完成该功能的是receiveservlet.Java中的service()函数:

public void service (HttpServletRequest req,HttpServletResponse res)
throws ServletException,IOException
{
res.setContentType("text/plain");
ServletOutputStream out = res.getOutputStream();
out.print("receive user message:");
out.print(req.getParameter("message"));
}

  该Servlet的详细源代码请见receiveservlet.Java。
  最后一个文件是add-servlet.html,它用来调用Applet:

<html>
<head>
<title>sendApplet</title>
</head>
<body>
<hr>
<applet code=sendApplet width=400 height=300 ></applet>
<hr>
</body>
</html>

  是不是很简单?


  如何应用应用Servlet进行图象处理?

  我们在处理数据时,有时希望能用图象直观的表述,在这里有一个巧方法,能方便快捷的实现一些简单的图形(不能称之图象),比如条形图,我们不必去用Java来生成并显示图象,(Java生成图象很慢),我们可以这样来作,先用作图工具作一个很小的你需要的图片,再根据你所处理的数据量来实时的加长它,就可以得到所要表述的图例。比如我们在数据库中得到了一组数据,我们从中找出最大的那一个,按比列设定其<img>标签的长度,其它的数据图形则可与它相比,得到<img>的长度,这样,一个简简单单的条形图就出来。但有时一些简单的图形已经不能解决我们实际遇到的情况,比如曲线图就不能用这种方法,这时我们需要生成Java图象,也许大家都用过applet这样的程序吧,若访问量不大,而实时性又很特殊时(比如股票系统),必须这样用它。但事实上,我们web程序大多有前后台之分,前台浏览,后台维护。这样我们可以在后台用servlet实时动态定时地生成图象文件,而前台只是查看静态图片,这比你用applet来动态产生图象的速度快了不知多少倍,因为applet来动态产生图象,有两个地方很费时,一是数据库查询时间,二是applet本身生成图象就很慢。下面以一个简单的例子来说明一下怎样生成并写入图象文件,本例注重的是怎样写入图象文件,相信写过applet的读者会生成更加漂亮的图象。

package test;
import Javax.servlet.*;
import Javax.servlet.http.*;
import Java.io.*;
import Java.util.*;
import Java.awt.image.BufferedImage;
import com.sun.image.codec.jpeg.*;
import Java.awt.image.*;
import Java.awt.*;

public class Servlet2 extends HttpServlet
{
public void init(ServletConfig config) throws ServletException {
super.init(config);
}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String sFileName = "e:/temp/name.jpg";
try{
FileOutputStream fos = new
FileOutputStream(sFileName);
BufferedImage myImage = new BufferedImage(225, 225,BufferedImage. TYPE_INT_RGB);
Graphics g = myImage.getGraphics();
g.setColor(Color.white);
g.fillRect(0,0,225,225);
g.setColor(Color.black);
g.drawString("Finance Balance Summary", 40, 15);
g.drawString("Primary", 90, 30);
g.setColor(Color.darkGray);
g.fillRect(15,193,7,7);
g.setColor(Color.black);
g.drawString("% Operating", 25, 200);
g.setColor(Color.yellow);
g.fillRect(130,193,7,7);
g.setColor(Color.black);
g.drawString("% Term", 140, 200);
g.setColor(Color.lightGray);
g.fillRect(15,213,7,7);
g.setColor(Color.black);
g.drawString("% Mortgage", 25, 220);
g.setColor(Color.green);
g.fillRect(130,213,7,7);
g.setColor(Color.black);
g.drawString("% Lease", 140, 220);
JPEGImageEncoder jpg = JPEGCodec.createJPEGEncoder(fos);
jpg.encode(myImage);
}catch (Exception e)
{
String exceptionThrown = e.toString();
String sourceOfException = " Method";
System.out.println("Origional Exception Thrown: " +exceptionThrown + '/r' + '/n');
System.out.println("Origional SourceOfException: " + sourceOfException +'/r' + '/n');
} // CatchStatementEnd
}
}

  如何通过Servlet调用JavaBean输出结果集

  以此我们通过一个例子进行说明,该例演示了如何通过Servlet调用JavaBean输出结果集,并打印的方法,共由两个文件组成,一个是JavaBean,用于实现对数据库的访问,并获得结果集;另一个是Servlet,主要负责JavaBean的调用,并将结果集发送到客户端。

  在JavaBean中,我们将访问DB2样例数据库(sample)中的STAFF表,至于如何实现对数据库的访问,读者可以参考《JSP与JDBC》一章。此外,读者可以通过修改部分参数,来实现对其他数据库、表的访问,达到举一反三的效果。

  该JavaBean的核心是execute()函数:

public void execute()
{
try {
//装载JDBC驱动程序
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
//建立对数据库的连接
conn = DriverManager.getConnection("jdbc:db2:sample", "db2admin", "db2admin");
stmt = conn.createStatement();
String sql = "SELECT * FROM STAFF WHERE DEPT=20";
//执行查询语句,返回结果集
ResultSet rs = stmt.executeQuery(sql);
setResult(rs);
} catch (SQLException e) {
} catch (IllegalAccessException e2) {
} catch (ClassNotFoundException e3) {
} catch (InstantiationException e4) {}
}

  JavaBean的具体源代码请见Tbean.Java。

  知道数据是如何获取之后,下面我们来看一下Servlet是如何来调用上述JavaBean的。

  同样看service()方法即可(详细源代码请见Tservlet.Java):

public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
try {
//实例化JavaBean
Demo.TBean Javabean = new Demo.TBean();
Javabean.execute();
ResultSet rs1 = Javabean.getResult();
PrintWriter out = res.getWriter();
res.setContentType("text/html");
out.println("<table border=1>"=;
out.println("<H1>Hello World</H1>"=;
out.println("<td>ID</td><td>NAME</td><td>DEPT</td><td>JOB</td><td>YEARS</td><td>SALARY</td><td>COMM</td>"=;
while (rs1.next())
{
out.println("<tr>"=;
for (int i = 1; i <= 7; i++=
out.println("<td>" + rs1.getString(i) + "</td>"=;
out.println("</tr>"=;
}
out.println("</table>"=;
Javabean.Sqlclose();
} catch (SQLException e) {}
}
//运行:在VisualAge for Java 的IBM Websphere Test Environment的环境下:
//http://localhost:8080/servlet/Demo.TServlet

Hello Print ID NAME DEPT JOB YEARS SALARY COMM
10 Sanders 20 Mgr 7 18357.50 null
20 Pernal 20 Sales 8 18171.25 612.45
80 James 20 Clerk null 13504.60 128.20
190 Sneider 20 Clerk 8 14252.75 126.50


  如何用Servlet来中断涉及的多线程

  现在我们已经知道,当服务器要卸载一个Servlet时,它会在所有的service都已经完成后再调用destroy()方法。如果程序的操作运行需要很长时间,destroy()被调用时就可能还有其他线程在运行。Servlet程序员必须保证所有的线程都已经完成。

  长时间运行响应客户端请求的那些Servlet应当保留当前有多少方法在运行的记录。它的long-running方法应当周期性地轮流询问以确保它们能够继续运行下去。如果Servlet被destroy()方法调用,那么这个long-running方法必须停止工作或清除。

  举例,变量serviceCounter用来统计有多少service方法在运行,变量shuttingDown显示这个Servlet是否被destroy。每个变量有它自己的获取方法:

public ShutdownExample extends HttpServlet
{
private int serviceCounter = 0;
private Boolean shuttingDown;

//serviceCounter
protected synchronized void enteringServiceMethod()
{
serviceCounter++;
}
protected synchronized void leavingServiceMethod()
{
serviceCounter--;
}
protected synchronized int numServices()
{
return serviceCounter;
}
//shuttingDown
protected setShuttingDown(Boolean flag)
{
shuttingDown = flag;
}
protected Boolean isShuttingDown()
{
return shuttingDown;
}
这个service方法每次在它进入时要增加,而在它返回退出时要减少:
protected void service(HttpServletRequest req , HttpServletResponse resp)
throws ServletException IOException
{
enteringServiceMethod();
try{
super.service(req , resp);
}
finally {leavingServiceMethod();}
}

  destroy方法应当检查serviceCounter,如果存在长时间方式运行的话,设置变量shuttingDown。这个变量将会让那个正在处理请求的线程知道该结束了。destroy方法应当等待这几个service方法完成,这样就是一个清楚的关闭过程了。

public void destroy()
{
//检查是否有线程在运行,如果有,告诉它们停止
if (numServices() > 0)
{
setShuttingDown(true);
}
//等待它们停止
while(numService() > 0)
{
try{
thisThread.sleep(interval);
}catch(InterruptedException e) {}
}
}
long-running方法如必要应当检查这个变量,并且解释它们的工作:
public void doPost(…)
{

for(i = 0; ((i < lotsOfStuffToDo) && !isShuttingDown()); i++)
{
try{
partOfLongRunningOperation(i);
}catch (InterruptedException e) {}
}
}

  附录:深入理解servlet

  Servlets(Java小服务器程序)是Java中新增加的一个全新功能。一般来说,Servlets是由服务器端调用和执行的任何Java类,浏览器端运行的Java程序叫Applet,Web服务器端运行的Java程序叫做Servlet。自从有了Servlet后,Java的电子商务才真正的开始,之后的JSP又是在Servlet上有了更进一步的发展。了解Servlet的机制也就掌握到了到JSP的实现原理。
  在编写Servlet的时候不需要关心一个Servlet是如何被装载到服务器环境中,只需要调用Java Servlet API编程接口就行了。在使用Servlet API的时候,程序员完全可以不必了解内部运行方式,服务器头、Cookies、会话都可以通过Servlet来处理。但当我们需要一些特殊功能的时候,就需要了解它的一些实现机制了。
  先从Servlet的生命周期说起。一般情况下,可以归纳为几点:
  1.装载Servlets。这项操作一般是动态执行的。有些Server提供了相应的管理功能,可以在启动的时候就装载Servlet;
  2.Server创建一个Servlet实例;
  3.Server调用Servlet的init()方法;
  4.一个客户端的请求到达Server;
  5.server创建一个请求对象;
  6.Server创建一个响应对象;
  7.Server激活Servlet的Service()方法,并传递请求和响应对象;
  8.service()方法获得关于请求对象的的信息、处理请求、访问其他资源、获得需要的信息;
  9.service()方法使用响应对象的方法,将响应传回Server,最终到达客户端。Service()方法可能机或其他方法已处理请求,如doGet()或doPost()或程序员自己开发的方法;
  10.对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此Servlet的service()方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用init()方法。也就是说,Servlet()只初始化一次。
  11.当Server不再需要Servlet时(一般是当Server关闭的时候),Server调用Servlets的destroy()方法。
  从前面我们还可以更进一步得出以下几点:
  Servlet运行时是多线程的,在开发的时候由Servlet API实现,开发人员不需要做特别的处理。Servlet的init()、destroy()的使用就像是一个C++编写的结构、析构函数,要注意前后的一致。比如在init()打开了一个数据库,就要在destroy()中关闭。
  对一些底层的处理,如要控制消息响应的方式,我们就要重载server()方法,并重新编写。
  为便于解释Servlet的实现机制,围绕HttpServlet,用下图描述Javax.Http包中常用到的类之间的关系(除掉了JSP部分),限于篇幅,没有给出每个接口、类的属性和方法。通过图示,我们很容易开发一些较低层次的代码。

  从下图,非常明显的可以看出HttpServlet是从GenericServlet类继承下来的。而事实上,GenericServlet类主要是为了起到三个接口的联合(这个词用得可能不科学):Servlet,ServletConfig,Serializable,以获得系统的支持;除了init()外几乎没有实现方法操作。真正调用系统所支持的各项功能是在HttpServlet类中。

  就HttpServlet的service()方法,一般来说,当它接收到一个OPTIONS请求时,会调用doOptions()方法,当接收到一个TRACE请求时调用doTrace()。doOptions()缺省执行方式是自动决定什么样的HTTP被选择并且返回哪个信息。相关源代码如下:

public void service(ServletRequest req,ServletResponse res)
throws ServletException,IOException
{
HttpServletRequest request;
    HttpServletResponse response;
    try
    {
    request = (HttpServletRequest)req;
      response = (HttpServletResponse)res;
  } catch(ClassCastException _ex)
  {
      throw new ServletException("non-HTTP request or response");
}
service(request, response);
  }
  protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
      String method = req.getMethod();
      if(method.equals("GET"))
      {
        long lastModified = getLastModified(req);
        if(lastModified == -1L)
        {
          doGet(req, resp);
        }
        else
        {
          long ifModifiedSince = req.getDateHeader("If-Modified-Since");
          if(ifModifiedSince < (lastModified / 1000L) * 1000L)
          {
            maybeSetLastModified(resp, lastModified); doGet(req, resp);
          }
          else
          {
            resp.setStatus(304);
          }
        }
      }
      else if(method.equals("HEAD"))
      {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);
      }
      else
      if(method.equals("POST"))
        doPost(req, resp);
      else
      if(method.equals("PUT"))
        doPut(req, resp);
      else
      if(method.equals("DELETE"))
        doDelete(req, resp);
      else
      if(method.equals("OPTIONS"))
        doOptions(req, resp);
      else
      if(method.equals("TRACE")) {
        doTrace(req, resp);
      }
      else
      {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object errArgs[] = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);
        resp.sendError(501, errMsg);
      }
    }
  protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
    {
      Method methods[] = getAllDeclaredMethods(getClass());
      boolean ALLOW_GET = false; boolean ALLOW_HEAD = false;
      boolean ALLOW_POST = false; boolean ALLOW_PUT = false;
      boolean ALLOW_DELETE = false; boolean ALLOW_TRACE = true;
      boolean ALLOW_OPTIONS = true;
      for(int i = 0; i < methods.length; i++)
      {
        Method m = methods[i];
        if(m.getName().equals("doGet"))
        {
          ALLOW_GET = true;
          ALLOW_HEAD = true;
        }
        if(m.getName().equals("doPost"))
        ALLOW_POST = true;
        if(m.getName().equals("doPut"))
        ALLOW_PUT = true;
        if(m.getName().equals("doDelete"))
        ALLOW_DELETE = true;
        }
        String allow = null;
        if(ALLOW_GET && allow == null)
          allow = "GET";
        if(ALLOW_HEAD)
          if(allow == null)
           allow = "HEAD";
          else allow = allow + ", HEAD";
        if(ALLOW_POST)
          if(allow == null)
          allow = "POST";
          else allow = allow + ", POST";
        if(ALLOW_PUT)
          if(allow == null)
          allow = "PUT";
          else allow = allow + ", PUT";
        if(ALLOW_DELETE)
          if(allow == null)
        allow = "DELETE";
        else allow = allow + ", DELETE";
      if(ALLOW_TRACE)
        if(allow == null)
        allow = "TRACE";
        else allow = allow + ", TRACE";
      if(ALLOW_OPTIONS)
        if(allow == null)
        allow = "OPTIONS";
        else allow = allow + ", OPTIONS";
      resp.setHeader("Allow", allow);
      }
    protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException
    {
      String CRLF = "/r/n";
     String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol();
      for(Enumeration reqHeaderEnum = req.getHeaderNames();
          reqHeaderEnum.hasMoreElements();)
    {
          String headerName = (String)reqHeaderEnum.nextElement();
     responseString = responseString + CRLF + headerName + ": " + req.getHeader(headerName);
   }
responseString = responseString + CRLF; int responseLength = responseString.length();
 resp.setContentType("message/http");
resp.setContentLength(responseLength);
 ServletOutputStream out = resp.getOutputStream();
out.print(responseString);
out.close();
}

  如果我们改写了上面的代码,将可以写出一些针对性更强的特殊领域中的应用。限于篇幅,这里将不在举例。另外,在HttpServlet类(或子类)中,可以对一些系统底层支持的功能进行一些操作,比如Session、Cookie等。其中HttpSession接口在Sun公司提供的包中没有找到它的类,应该是由Server引擎来实现、管理它的相关功能。

jsp_servlet【基础】相关推荐

  1. 第一章:Jsp_Servlet基础--尚学堂

    2019独角兽企业重金招聘Python工程师标准>>> Servlet Servlet是服务器小应用程序(http/ftp等) ,用来完成B/S架构下客户端请求的响应处理 .平台独立 ...

  2. java入门 慕路径,Java入门基础知识总结学习教程大全【必看经典】

    类型的表达式,是循环条件,表达式3是党执行了一遍循环之后,修改控制循环的变量值. ??? for语句的执行过程是这样的:首先计算表达式1,完成必要的初始化工作:然后判断表达式2的值,如果表达式的值为t ...

  3. 提交表单自动刷新_Web自动化测试:元素的基础操作和浏览器基础操作

    上一节,我们了解了如何定位元素,其实也有涉及对于元素的操作,这一节我们就详细的介绍一下对于元素的操作和对于浏览器的一些操作 一.对于元素的基础操作: clear():清除输入框内的文本 send_ke ...

  4. java mybatis基础

    java mybatis基础 1.1 什么是mybatis? mybatis是一个优秀的持久层框架. 避免几乎所有的JDBC代码和手动设置参数以及获取结果集的过程. 可以使用简单的xml或者注解来配置 ...

  5. 【J2SE】学习基础

    Java基础 语法基础 OO Exception Array 基础类 I/O Stream Collection/Generic Thread TCP/UDP GUI Meta Data Regula ...

  6. 【Linux系统】基础总结

    我不太清楚运维部门具体是做什么的,就接触过一点点运维部门! 也就是是知道他们负责管理服务器,管理网络,管理项目部署 偶尔自己需要部署,不得不接触一些linux命令.简单总结一些基础 linux系统发展 ...

  7. 【Java 2 Platform Enterprise Edition】基础

    问题1:为什么java是无关平台? 你之前用C或者C++写的源代码,编译好后,换一种操作系统,可能就执行不了了.因为新的操作系统不识别,你需要修改你的源码,并在新的操作系统上重新编译才能运行,比如Wi ...

  8. SpringCloud Alibaba微服务实战(一) - 基础环境搭建

    说在前面 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案.此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来 ...

  9. Redis概述和基础

    Redis 1.NoSQL NoSQL = Not Only SQL(不仅仅是SQL) 泛指非关系型数据库的,随着web2.0互联网的诞生!传统的关系型数据库很难对付web2.0时代!尤其是超大规模的 ...

最新文章

  1. web service 和 remoting 有什么区别
  2. mysql事务在提交后才发送给数据库执行_从一个线上问题分析binlog与内部XA事务提交过程...
  3. python运维之轻松模拟开发FTP软件05
  4. 绝地求生手游7月服务器维护,绝地求生维护公告7月22 | 手游网游页游攻略大全...
  5. 记一次 Python Web 接口优化
  6. 世界上没有技术驱动型公司
  7. 剑指Offer(java版):字符串的排列
  8. python -屏保
  9. 烟台大学举办首届ACM程序设计大赛
  10. 网易云参数解析(多图)
  11. 视频教程-2021软考网络工程师-上午真题解析培训视频课程-软考
  12. 4星|《激荡十年,水大鱼大》:过去十年间国内商业简史
  13. C#利用HttpClient获取微信Web扫描登录二维码
  14. 南京信息工程大学 第二届程序设计大赛团队赛 试题
  15. android scrollview 设置高度,Android创建显示区高度可以调整的ScrollView
  16. RFID建筑工地人员考勤管理解决方案——铨顺宏FUWIT
  17. jquery动态增加多行文本框并计算值
  18. c语言编码数字的范围,C语言数据类型的表示范围
  19. 什么是多重签名?多重签名的概念
  20. Linux MTD架构下的nand flash驱动详解

热门文章

  1. camera调试基础经验分享
  2. 苏州技师学院计算机专业怎么样,苏州技师学院是怎样的一个学校
  3. MATLAB SCI论文绘图及绘图窗口大小设置
  4. ps如何制作宇宙星空梦幻人像照片效果
  5. sja1000 CAN驱动学习、调试记录(基于PeliCan Mode)
  6. (7)web安全|渗透测试|网络安全 如何判断是否有CDN存在,并绕过CDN找到真正的ip的方法
  7. YOYO 软件下载及8个使用技巧
  8. WZOI-416反反复复
  9. 【学习笔记】网关 路由
  10. Java101班1组作业完成情况