免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1724 | 回复: 0
打印 上一主题 下一主题

sevlet and applet [复制链接]

论坛徽章:
27
水瓶座
日期:2014-08-22 21:06:34程序设计版块每日发帖之星
日期:2015-11-25 06:20:0015-16赛季CBA联赛之新疆
日期:2015-12-19 19:05:48IT运维版块每日发帖之星
日期:2015-12-25 06:20:31IT运维版块每日发帖之星
日期:2015-12-25 06:20:31IT运维版块每日发帖之星
日期:2015-12-25 06:20:3315-16赛季CBA联赛之上海
日期:2016-04-15 19:51:31程序设计版块每日发帖之星
日期:2016-04-17 06:23:29程序设计版块每日发帖之星
日期:2016-04-23 06:20:00程序设计版块每日发帖之星
日期:2016-05-26 06:20:00每日论坛发贴之星
日期:2016-05-26 06:20:0015-16赛季CBA联赛之辽宁
日期:2017-02-16 23:59:47
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-04-03 17:11 |只看该作者 |倒序浏览
Java Servlet的概念
  Java Servlet是一个专门用于编写网络服务器应用程序的Java组件。所有基于Java的服务器端编程都是构建在Servlet之上的。

  在J2EE中Servlet已经是一个标准的组件。让我们来认识一下,Servlet在Java的软件包中是怎样的一个结构,这会有助于我们理解Servlet的概念。

 
 在J2EE中跟Servlet相关的一个包是javax.servlet,其中最基本的Servlet被声明为一个接口javax.servlet:
Interface
Servlet,这是Servlet最高层次的一个抽象,它是和网络协议无关的。同样在javax.servlet中,实现了一个类
javax.servlet: class
GenericServlet,这个类实现了Servlet接口,也是和协议无关的。而这个类是构建其他和协议相关的Servlet子类型的通用的父类
(至少HttpServlet是从它继承而来的,从它的名字也能看出这一点)。

  也就是
说Servlet所适用的网络协议可以是多种多样的,比如HTTP,FTP,SMTP,TELNET等,但是就目前而言,只有HTTP服务已经形成了标准
的Java组件。对应的软件包有两个javax.servlet.http和javax.servlet.jsp,分别对应我们要讲解的Servlet和
JSP编程。我们通常所说的Servlet编程主要就是指针对HTTP的Servlet编程,用到的就是javax.servlet.http包中的类
(典型的就是HttpServlet类),实际上Java
Servlet编程的概念要更广一些,在这里我们也就约定俗成的使用Servlet来指代HTTP
Servlet的编程,这点读者是需要了解的。由于JSP最终都是要经过JSP引擎转换成Servlet代码的,而且Servlet编程和一般的Java
编程是没有大的区别的,只需要了解一定的规范即可,所以我们在这里先讲解Servlet的编程,这样对以后理解JSP是很大的有好处的,尽管在使用的时候
可能JSP更为简单一些。

  目前,Servlet引擎一般是第三方的插件,它通过一定的
方法连接到Web服务器,Servlet引擎把它识别为Servlet请求的那些HTTP请求截获下来处理,而其他的HTTP请求由Web服务器按照通常
的方式来处理,Servlet引擎会装载合适的Servlet到内存中,如果Servlet还没有运行的话,会分配一个可以使用的线程来处理请求,再把
Servlet的输出返回到发出请求的Web客户机。

  Java Servlet和Java Applet正好是相对应的两种程序类型,Applet运行在客户端,在浏览器内执行,而Servlet在服务器内部运行,通过客户端提交的请求启动运行,读者在学习过程可以作简单的比较。
  
  使用过CGI的读者一定知道CGI程序的作用,Servlet要实现的功能和CGI是一样的,只是实现的时候更为方便,效率更高。如果读者对以上概念不是很清楚,也不必着急,通过学习以下的内容,有了感性的认识,再回来看看,一定会有更大的收获。



10.1.2 Servlet的优点和应用范围

 
 由于Servlet是用Java编写的,所以它与生俱来就有跨平台的特性,因此Servlet程序的设计完全和平台是无关的,同样的Servlet完全
可以在Apache,IIS等不同Web服务器上执行,不管底层的操作系统是Windows,Solaris,Mac,Linux还是其他的能支持
Java的操作系统。

  Servlet是跟普通的Java程序一样,是被编译成字节码后
由JVM执行的。相比传统的CGI,尽管CGI是用本地代码直接执行的,但是由于每次客户端发出请求,服务器必须启动一个新的程序来处理请求,这就把高负
载强加给了服务器资源,尤其如果CGI使用脚本语言编写时,如perl,服务器还必须启动语言解释程序,程序越多,占用的内存就越多,消耗CPU也越多,
严重影响系统性能。

  Servlet运行于Servlet引擎管理的Java虚拟机中,
被来自客户机的请求所唤醒,与CGI不同的是,在虚拟机中只要装载一个Servlet就能够处理新的请求,每个新请求使用内存中那个Servlet的相同
副本,所以效率比CGI来得高。如果采用服务器端脚本,如ASP,PHP,语言解释程序是内置程序,因此可以加快服务器的运行,但是效率还是比不上准编译
的Servlet。实际的使用也已经证明,Servlet是效率很高的服务器端程序,很适合用来开发Web服务器应用程序。

  Java Servlet有着十分广泛的应用。不光能简单的处理客户端的请求,借助Java的强大的功能,使用Servlet还可以实现大量的服务器端的管理维护功能,以及各种特殊的任务,比如,并发处理多个请求,转送请求,代理等。

  在实际的使用中,读者会有更多的机会去学习了解Servlet的最新应用,在这里我们只介绍基本的应用。

10.1.3 Servlet的运行环境
  为了运行Servlet,首先当然需要一个JVM来提供对Java的基本支持,一般需要安装JRE(Java Runtime Environment)或JDK(Java Develop Kit,JRE是其一个子集)。

  其次我们需要Servlet API的支持,一般的Servlet引擎都自带Servlet API,只要我们安装Servlet引擎,或直接支持Servlet的Web服务器之后便会自动安装上Servlet相关的程序包。

 
 典型的Servlet运行环境有JSWDK,Tomcat,Resin等,这几个都是免费的软件,适合用来学习Servlet和JSP。它们都自带一个
简单的HTTP
Server,只需简单配置即可投入使用,你也可以把它们绑定到常用的Web服务器上,如Apache,IIS等,提供小规模的Web服务。还有一些商业
的大中型的支持Servlet和JSP的Web服务器,如JRun,Web Sphere,Web
Logic等等,配置比较复杂,并不适合初学者。但是功能较为强大,有条件的读者可以一试。后面我们会讲解如何配置一简单的支持Servlet和JSP的
Web服务器。

10.1.4 Servlet与CGI环境变量

  在使用CGI时,最重要的内容是CGI接口的环境变量。CGI规范列出了19个环境变量。尽管其他的环境变量,如HTTP_COOKIE(用于查询站点信息的)不是该规范的组成部分,但也是经常使用。

 
 由于Java运行于JVM,不直接在服务器上运行,所以不能直接访问环境变量。由于CGI环境变量是Web服务器建立的,而且用户能够用其他的方法查询
变量值,所以Java不访问环境变量没有什么大问题。Java Servlet API定义几种查询在CGI环境变量中发现大多数信息的方法。

 
 有些信息是HTTP标题的组成部分,而且采用HttpServletRequest类中的getHeader()方法能够很容易的获取。采用特殊的方法
可以查询其他的信息。Java唯一不可用的CGI环境变量是GATEWAY_INTERFACE。当在CGI程序中使用时,该变量包含CGI版本。在
Java Servlet中这种变量信息是无关紧要的。

  以上的内容是针对有CGI编程经验的读者的,通过对比能帮助读者更快的理解Servlet。对CGI一无所知的读者浏览一下便可。
10.1.5 Servlet的安全性

 
 Java
Servlet能够使用包括SSL在内的安全协议。Servlet与Java内在的安全措施紧密相连,如不能直接访问内存等。采用安全管理器,用户能够限
定对其他资源的访问,如文件、目录和局域网。Java Servlet支持代码符号,从而能够更好的控制委托每个Servlet要执行的程序。

  Java的安全机制本身是比较复杂的,在这里我们只能作简单讲解,否则就喧宾夺主了。具体的分析参看有关Java安全性的章节。

10.1.6 Servlet的管理

 
 对于大多数用户来说,Servlet比CGI程序和服务器脚本更容易管理。Servlet是以Java类的形式编译的。Java采用能够保存在Java
Archive(.JAR)文件中的编制目录树内的组件,提供一种管理类的方法,如Sun公司的Java
Web服务器的Servlet管理平台。有些服务器和第三方产品为管理Servlet提供图形用户界面。

  具体的Servlet的管理是比较复杂的一件事情,尤其是对于一个大系统而言。对于初学者只要能掌握基本的配置一个Servlet,使其能正常运行的技能就可以了。更高级的技巧要在更多的实践中才能真正掌握。


10.1.7 Servlet的编译

  Servlet的编译和一般的Java程序是完全一样的,在使用javac编译的时候不需要任何特殊的参数。只要Servlet的编写是正确的,编译完后生成的Class文件就可以做为Servlet来运行了。

10.1.8 用Servlet Runner运行Servlet

 
 在真正开始编写Servlet之前,我们先介绍一个简单的Servlet引擎--Resin。目前支持Servlet的Web服务器不下数十种,
Resin是一个简单易用的Servlet运行器(Servlet
Runner),很适合初学者。由于各个厂家的Servlet引擎各不相同,配置方法也是千差万别,在这里不可能一概而论,但是Servlet的编写方法
却是一样的,所以读者不必太在意服务器的配置方法,只要知道如何让自己的Servlet正常运行就可以了,把更多的注意力放在Servlet的编写上。

  Resin自带一个Servlet Runner和HTTP Server,因此要构建一个简单的Web环境,光有Resin已经足够了,不需要额外的支持软件。Resin不需要安装,解压之后即可使用。

 
 Resin目录下有几个子目录,bin目录存放的是可执行文件,要启动HTTP Server和Servlet
Runner只需要分别点击其中的httpd.exe和srun.exe即可,启动后会出现四个窗口,分别对应HTTP
Server的标准输出,启/停控制和Servlet Runner的标准输出,启/停控制。conf目录下存放的是Resin Servlet
Runner的配置文件,这是配置整个Web环境的关键,包括Servlet的配置和后面要用到的JSP的配置。doc目录是默认的发布目录,即
Resin自带的HTTP Server是以这个目录为根目录的。

  下面我们以一个最简单的HelloWorld的例子,来讲解如何配置Resin,使其能运行Servlet程序,同时也做为Servlet编写的入门。程序如下:
   //HelloServlet.java
   import java.io.*;
   import java.util.*;
   import javax.servlet.http.*;
   import javax.servlet.*;
   //导入必要的包
   public class HelloServlet extends HttpServlet {
          //所有Servlet必须从HttpServlet派生
     public void doGet (HttpServletRequest req, HttpServletResponse res)
     throws ServletException, IOException
     //doGet()是这个Servlet的核心,真正处理请求的地方
   {
   res.setContentType("text/html");
     //设置相应的类型为text/html
   PrintWriter pw = res.getWriter();
     //从HttpServletResponse得到输出流

   pw.println("");
   pw.println("");
   pw.println("");
   pw.println("");
   pw.println("");
   pw.println("");
   pw.println("");
   pw.println("

Hello, world!
");
   pw.println("");
   //上面的语句都是向客户端打印HTML文本
   pw.close();
   //关闭HttpServletResponse,使Web服务器知道相应结束
  }
  public HelloServlet() {} //构造函数,可以不要
 }

 
 这是最简单的一个Servlet程序,整个类从HttpServlet派生,就跟Applet一样,这个派生关系是必须的。这个Servlet必须实现
doGet()方法(因为它是作为静态页面通过地址访问的,这种方式在HTTP中称为GET请求,在后面还会有更具体的讲解),这是这个Servlet真
正处理请求的地方,是整个Servlet的主体,就跟线程体的run()方法一样。doGet()有两个参数HttpServletRequest
req和 HttpServletResponse
res。HttpServletRequest包含了客户请求的各种信息,HttpServletResponse则包装了服务器响应,主要处理对客户机
的输出。这个程序是很简单的,如果对网络编程和HTML有一些概念的话,很容易就应该能理解。

 
 通过javac对以上程序进行编译,我们可以得到HelloServlet.class,下面我们就通过配置Resin来运行这个Servlet。前面
说过如果你没有修改过Resin的配置文件的话,doc是Resin默认的发布目录。发布目录下的WEB_INF/classes是Resin默认的
Classpath,读者只要把自己的Servlet拷贝到该目录下,Resin就能识别,当然只要拷贝的有效的系统的或用户的Classpath下,
Resin都是能够找到的。我们把HelloServlet.class拷贝到WEB_INF/classes目录下。接下来就需要修改conf目录下的
resin.conf文件,来配置我们的Servlet。读者可以使用任何一种自己所熟悉的文本编辑器来打开该配置文件。找到,在它和
之间任何地方添加以下的配置语句(可以参考已有的语句)
   
       servlet-class='HelloServlet' >
   

  这样当客户端产生/Hello请求的时候,Resin就能把这个请求定向到HelloServlet上,该Servlet就能正常运行了,我们也可以采用以下的配置语句
   

 
 这种情况下,没有对Servlet的名字进行映射,系统会默认的使用servlet-name作为servlet-class进行类的查找,所以
servlet-name必须填写正确的类名,而不能是随意的名字。关于Resin更多的配置信息,有兴趣的读者可以参考Resin的帮助文档,这里就不
再赘述了。

  下面我们启动Http Server和Servlet Runner(通过双击bin下的httpd.exe和srun.exe)。这样我们就可以通过浏览器访问这个Servlet了。打开浏览器,比如IE,在地址栏键入
http://localhost:8080/Hello
,我们可以打开如下的一个网页:

 通过查看源码,我们可以得到如下的结果
  
  
  
  
  
  
  
  
Hello, world!

  

  很显然这些文本正是我们在Servlet中向客户端所打印的信息,在Http头部content=text/html也是我们在程序中所设置的。

  通过这样一个简单的HelloWorld的程序,读者对Servlet的工作原理的基本配置方法应该有了一个大概的了解,如果读者对这个例子还有疑问,务必搞清楚后再继续学习。




10.2 Servlet的应用实例

  上面我们已经讲解了Servlet的基本概念,并介绍了一个运行环境及其配置方法,下面我们就开始讲解Servlet在编写Web应用方面的具体应用。

 10.2.1 Servlet与表单交互的方法

 
 表单是HTML中使用最广泛的传递信息的手段。搞清楚Servlet与表单的交互,就在客户端与服务器之间架起了一座桥梁。Servlet使用
HttpServlet类中的方法与表单进行交互。在HttpServlet类中有几个未完全实现的方法,你可以自己定义方法的内容,但是必须正确使用方
法名称以使HTTP Server把客户请求正确的映射到相应的函数上。

  doHeader 用于处理HEADER请求
  doGet 用于处理GET请求,也可以自动的支持HEADER请求
  doPost 用于处理POST请求
  doPut 用于处理PUT请求
  doDelete 用于处理DELETE请求
  HttpServlet的Service方法,当它接收到一个OPTIONS请求时,它会自动调用doOptions方法,当接收到一个TRACE请求时调用doTrace。DoOptions默认执行方式是自动决定什么样的HTTP被选择并返回哪个信息。

  在使用这些方法时必须带两个参数。第一个包含来自客户端的数据HttpServletRequest。第二个参数包含客户端的相应HttpServletResponse。在我们的第一个例子中使用的是doGet方法,因为通过地址访问的话,对应的方式是GET。

  一个HttpServletRequest对象提供请求HTTP头部数据,也允许获取客户端的数据。怎样获取这些数据取决于HTTP请求方法。

  不管何种HTTP方式,都可以用getParameterValues方法返回特定名称的参数值。

  对于HTTP GET请求的方式,getQueryString方法将会返回一个可以用来解剖分析的参数值。

 
 对于用HTTP
POST,PUT和DELETE请求的方式,HttpServletRequest有两种方法可以选择:如果是文本数据,你能通过getReader的方
法得到BufferedReader获取数据;如果是二进制数据,可以通过getInputStream方法得到ServletInputStream获
取数据。

  为了相应客户端,一个HttpServletResponse对象提供返回数
据给用户的两个方法:一种是用getWriter方法得到一个PrintWriter,用于返回文本数据;另一种方法是用getOutputStream
方法得到ServletOutputStream,用于返回二进制数据。在使用Writer或OutputStream之前应先设置头部
(HttpServletResponse中有相应的方法),然后用Writer或OutputStream将相应的主体部分发给用户。完成后要关闭
Writer或OutputStream以便让服务器知道相应已经结束。

  下面我们举一个使用HttpServletRequest和HttpServletResponse得到并打印客户端信息的例子:

  //RequestInfo.java
  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class RequestInfo extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ServletException
               //处理GET请求的方法
    { 
      response.setContentType("text/html");
      //先设置Header,在这里只设置ContentType一项
      PrintWriter out = response.getWriter();
      //得到文本输出Writer

      //下面打印相关的HTML
      out.println("");
      out.println("");
      out.println("");
      out.println("");
      out.println("");
      out.println("

Request Information Example
");

      out.println("Request URI: " + request.getRequestURI()+"
");
      //打印请求的路径
      out.println("Protocol: " + request.getProtocol()+"
");
      //打印协议名称
      out.println("PathInfo: " + request.getPathInfo()+"
");
      //打印额外的路径信息
      out.println("Remote Address: " + request.getRemoteAddr());
      //打印客户机的地址,如果没有打印IP地址
      out.println("");
      out.println("");
      out.close(); //关闭Writer
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
     //如果是POST请求类型,同样调用GET类型的响应函数
     doGet(request, response);
    }
  }

  用我们在前面介绍的方法在Resin中配置使其运行,我们得到的结果如下:



  这样的一个例子很好的说明了所谓的动态网页和静态网页的区别,就上面这个例子而言,每个客户看到的内容是不一样的,而静态网页则对每一个客户而言都是一成不变的。



10.2.2 Servlet与表单交互的例子

 
 上面我们介绍了Servlet如何与表单进行交互,并提供了一个从HTTP请求头部得到客户端信息的例子,下面我们给出一个Servlet与HTTP提
交的表单进行交互的例子,通过这个例子读者应该能对整个客户端和服务器端交互的过程有一个整体的了解。这个例子分成两个文件,一个是静态的HTML文件,
提供一个表单,并设置提交按钮,表单被提交后,服务器会把它定向到另一个文件,也就是我们的Servlet,由它读取表单并打印到客户端。

  1. 静态HTML文本:ourform.html

  2. FormDemo.java

 1. 静态HTML文本:ourform.html

  
  
  
  
  
  

Our Form

  

  
      
        姓名:
         
    

      
        性别:
                男        女      
    

  
  

  
  

  在IE下显示效果如图所示:


  不熟悉HTML的读者可以参考有关HTML的书籍,尤其要注意的form的两个属性method和action

 2. FormDemo.java

  //FormDemo.java
  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class FormDemo extends HttpServlet {
   public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException //处理GET请求的方法
   {
    response.setContentType("text/html");
    //先设置Header,在这里只设置ContentType一项
    PrintWriter out = response.getWriter();
    //得到文本输出Writer

    String name = request.getParameter("Name");
    //得到表单值Name
    String sex = request.getParameter("Sex");
    //得到表单值Sex
    name = new String(name.getBytes(),"ISO-8859-1");
    //转换到正确的编码

    //打印得到的表单值
    out.println("");
    out.println("");
    out.println("");
    out.println("");
    out.println("");
    out.println("");
    out.println("

Data You Posted
");
    out.println(" ");
    out.println("  ");
    out.println(new String(new String("  你的姓名: ").getBytes(),"ISO-8859-1"));
    out.println("  "+name+" ");
    out.println("
");
    out.println("  ");
    out.println(new String(new String("  你的性别: ").getBytes(),"ISO-8859-1"));
    out.print("  ");
    if(sex.equals("1")) out.println(new String(new String("男 ").getBytes(),"ISO-8859-1"));
    else out.println(new String(new String("女").getBytes(),"ISO-8859-1"));
    out.println("
");
    out.println(" ");
    out.println("");
    out.println("");
    out.close(); //关闭Writer
   }
  }

  这个Servlet也是比较简单的,首先从提交的表单中得到需要的两个值,然后用HTML向客户端打印这些信息。
  
 
 值得注意的是,在这个例子中,所有出现打印中文的地方,我们都使用了字符编码的转换来正确打印中文。前面的例子我们都没有涉及中文,在这里我们有必要提
一下Servlet的中文问题。我们知道在同一台机器上,所有的编码方式都是一样的,一般中文平台是gb2312,英文平台是ISO-8859-1,但是
网络上的两台机器并不能保证他们的编码方式都是一样的,这时候就有可能出现乱码的问题。在进行HTTP网络传输的时候,统一采用的编码方式是ISO-
8859-1,这时候如果还是按照本地编码来传输就会出现问题,这也是Servlet在实现网络传输的时候一个不完美的地方,它不会自动进行本地编码到
ISO-8859-1的转换,所以直接打印的话就会出现乱码。原理上讲任何出现打印字符串的地方,都是需要进行编码转换的,但是西文字符在不同字符集下对
应相同的编码,以在打印西文字符的时候就不需要转换了。在Servlet后继的规范中可能会改变这种麻烦的状况。不同的是,从网络提交的表单数据,
Servlet是自动把它转换成本地编码的,所以程序中得到的name字符串变量是gb2312编码的,同样需要进行转换后才能在客户端正确打印。

  字符编码转换常用的方法是
  String native_encoded = "中文字符串";
            //本地编码的字符串
  Byte[] byte_array = native_encoded.getBytes();
            //得到本地编码的字节数组
  String net_encoded = new String(native_encoded, "ISO-8859-1");
            //生成ISO-8859-1编码的字符串

  这样得到的net_encoded字符串就可以用来向客户端打印而不出错了。
  还有一点要注意的是,为了在客户端正常显示中文,必须在HTML头部设置charset=gb2312。

  当我们按下提交按钮后,我们得到的结果如下:


  如果我们把ourform.html中的method由GET改成POST,会有什么样的结果呢?由于我们没有重写doPost方法,所以在Resin下,我们得到如下的结果:


  有兴趣的读者可以修改FormDemo类来响应POST方法。

  通过以上的几个例子,读者对Servlet如何响应HTTP请求,并从提交的表单中获取数据应该有了一个大概的了解,但是要构建Web应用程序,光有这几点是不够的,下面我们要讲解的Servlet的会话和生命周期对于构建Web应用是及其重要的两个特性。

10.2.3 用Servlet控制会话

 
 会话状态的维持是开发Web应用所必须面对的问题,有多种方法可以来解决这个问题,如使用Cookies,hidden类型的表单域,或直接把状态信息
加到URL中等,还有Servlet本身提供了一个HttpSession接口来支持会话状态的维持,在这里我们主要介绍基于这个接口的会话状态的管理。

 
 Session的发明是为了填补HTTP协议的局限。请注意HTTP协议是如何工作的--用户发出请求,服务器作出响应,这种用户端和服务器端的联系就
是离散的,非连续的。HTTP协议不能提供允许服务器跟踪用户请求的功能。在服务器端完成响应用户的请求之后,服务器不能继续与该浏览器继续保持连接。从
服务器这端来看,每一个请求都是独立的,因此HTTP协议被认为是无状态协议,当用户在多个主页间切换时,服务器无法知道他的身份。Session的出现
就是为了弥补这个局限。利用Session,您就可以当一个用户在多个主页间切换的时候也能保存他的信息。这样很多以前根本无法去做的事情就变得简单多
了。

  在访问者从到达某个特定的主页到离开为止的那段时间,每个访问者都会单独获得一个Session。
  Java Servlet定义了一个HttpSession接口,实现的Session的功能,在Servlet中使用Session的过程如下:
  
  (1) 使用HttpServletRequest的getSession方法得到当前存在的session,如果当前没有定义session,则创建一个新的session,还可以使用方法getSession(true)

  (2) 写session变量。可以使用方法HttpSession.setAttribute(name,value)来向Session中存储一个信息。也可以使用HttpSession.putValue(name,value),但这个方法已经过时了。

 
 (3)
读Session变量。可以使用方法HttpSession.getAttribute(name)来读取Session中的一个变量值,如果name是
一个没有定义的变量,那么返回的是null。需要注意的是,从getAttribute读出的变量类型是Object,必须使用强制类型转换,比如:
     String uid = (String) session.getAttribute("uid");
  也可以使用HttpSession.getValue(name),但是这个方法也已经过时了。

  (4) 关闭session,当时用完session后,可以使用session.invalidate()方法关闭session。但是这并不是严格要求的。因为,Servlet引擎在一段时间之后,自动关闭seesion。

  下面举一个简单的例子说明session的使用
  // SessionExample.java
  import java.io.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  //导入必要的软件包
  public class SessionExample extends HttpServlet
  {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ServletException //实现doGet方法
    {
      response.setContentType("text/html"); //设置HTTP头
      PrintWriter out = response.getWriter(); //得到输出Writer
      HttpSession session = request.getSession(true);
                          //得到session对象

      //打印HTML标记
      out.println("");
      out.println("");
      out.println("");
      out.println("");
      out.println("");

      Date created = new Date(session.getCreationTime());
                  //得到session对象创建的时间
      Date accessed = new Date(session.getLastAccessedTime());
                  //得到最后访问该session对象的时间
      out.println("ID " + session.getId()+"
");
                  //得到该session的id,并打印
      out.println("Created: " + created+"
");
                  //打印session创建时间
      out.println("Last Accessed: " + accessed+"
");
                  //打印最后访问时间

      session.setAttribute("UID","12345678");
                  //在session中添加变量UID=12345678
      session.setAttribute("Name","Tom");
                  //在session中添加变量Name=Tom

      Enumeration e = session.getAttributeNames();
                  //得到session中变量名的枚举对象
      while (e.hasMoreElements()) { //遍历每一个变量
        String name = (String)e.nextElement(); //首先得到名字
        String value = session.getAttribute(name).toString();
                  //由名字从session中得到值
        out.println(name + " = " + value+"
"); //打印
      }
      out.println(""); //打印HTML标记
      out.println("");
      }
    }
  }

  该Servlet运行的结果是:


 
 有了Session对象,Web应用程序就可以在服务器端保存客户的状态,这对构建Web应用的重要性读者在以后的实践中会逐步有所体会。正像前面提到
的,Session只是一个概念,可以有多种实现方法,在这里我们就不过多的介绍了。因为Servlet本身就是实用性很强的内容,各种各样的技巧,实现
方案,不胜枚举。而且很多相关内容也不只是Servlet的专利,本讲在这里只能做简单的介绍,使读者对Servlet有一个概念上的认识。有兴趣的读者
可以参考相关书籍。

10.2.4 Servlet的生命周期

  跟客户端的Applet相似,Servlet(这里Servlet的概念又回到了最原始的含义)也遵循严格的生命周期。在每个Servlet实例的生命中有三种类型的事件,这三种事件分别对应于由Servlet引擎所唤醒的三个方法:

 
 1.init()。当Servlet第一次被装载时,Servlet引擎调用这个Servlet的init()方法,只调用一次。如果某个Sevlet
需要特殊的初始化需要。那么Servlet编写人员可以重写该方法来执行初始化任务。这是一个可选的方法。如果某个Servlet不需要初始化,那么默认
情况下将调用它父类的init方法。系统保证,在init方法成功完成以前,是不会调用Servlet去处理任何请求的。

  2.service()。这是Servlet最重要的方法,是真正处理请求的地方。对于每个请求,Servlet引擎将调用Servlet的service方法,并把Servlet请求对象和Servlet响应对象最为参数传递给它。

  3.destroy()。这是相对于init的可选方法,当Servlet即将被卸载时由Servlet引擎来调用,这个方法用来清除并释放在init方法中所分配的资源。
  
  Servlet的生命周期可以被归纳为以下几步:
  (1) 装载Servlet,这一项操作一般是动态执行的。然而,Servlet通常会提供一个管理的选项,用于在Servlet启动时强制装载和初始化特定的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调用Servlet的destroy

 
 至此关于Servlet的内容已经讲解完毕,读者通过对比Servlet与传统静态网页的区别,应该能大概理解Web应用程序的概念,Web应用的出
现,使得呆板的Web页面变得生动,具有交互能力。Java在Web应用方面算不上独树一帜,但是却是做的相当优秀的。通过Servlet与下面我们要讲
解的JSP的配合,可以方便的构建出功能强大的Web应用。

  学习Servlet,其实
最主要的已经不是Java本身,大家也已经看到Servlet和一般Java程序是没有什么区别的。要学好Servlet,除了掌握基本Servlet
API之外,最关键的还在于如何从整体上把握整个Web应用,如何合理的使用Servlet,使Servlet在构建Web网站的时候起到画龙点睛的作
用,而不是复杂冗余的重复性劳动。在真正编写Servlet的时候,一般是没有什么大的困难的。所以读者在学习之余,最好能找一些规模大一点的例子,通过
阅读代码,分析结构,更好的掌握Servlet的使用方法,知道什么时候该用Servlet实现,什么时候应该用其他的方法实现更为合适,而不必深究
Servlet的语法或其他的一些小技巧。对于那些对Web网站不熟悉的读者,在学习的时候可能有困难,那么我们的建议是,先去学习基本的Web网站的知
识。可以这么说Servlet只是一个工具,思想是需要读者在实践中慢慢体会的,当你有了成熟的思想之后再来学习Servlet,一定会有驾轻就熟的感觉
的。

10.3 JSP简介

 10.3.1 JSP的概念

 
 JSP(Java Server Pages?)是Sun
Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。它在HTML代码中,插入JSP标记(tag)及Java程序片段
(Scriptlet), 构成JSP页面,其扩展名为
.jsp。当客户端请求JSP文件时,Web服务器执行该JSP文件,然后以HTML的格式返回给客户。前面已经提到过JSP只是构建在Servlet之
上的高层次的动态网页标准,因此,从概念上将,相对Servlet而言,JSP并没有什么新的东西,如果读者对前面的Servlet已经十分的了解,那么
JSP的概念可说跟Servlet是完全一样的,只不过在实现方法上稍有不同。
  
  目前JSP,ASP是使用最为广泛的两种服务器端脚本语言,如果读者对ASP已经有所了解的话,那么对于JSP应该也是很容易理解的,从概念上讲,JSP和ASP是一样的,只不过使用的语言不同而已。
10.3.2 JSP的优点

  1. 一次编译,多次、多处运行,代码的执行效率高
 
 JSP的脚本语言是JAVA语言,因此它具有JAVA语言的一切特性。同时,JSP也支持现在大部分平台。
当JSP第一次被请求时,JSP页面转换成servlet,然后被编译成.calss文件,以后(除非页面有改动或Web服务器被重新启动)再有客户请求
该JSP页面时,JSP页面不被重新编译,而是直接执行已编译好的.class文件,因此执行效率特别高。

  2. 组件的重用性
 
 可重用的、跨平台的JavaBeans和EJB(Enterprise
JavaBeans)组件,为JSP程序的开发提供方便,我们可以将复杂的处理程序(如页面中需要显示的动态内容及对数据库的操作)放到组件中。可以多次
使用这些组件,极大的减少了在JSP页面中重写重复的代码。

  3. 将内容的生成和显示进行分离
 
 使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者脚本来生成页面上的动态内容。生成动态
内容的语句一般被封装在JavaBean组件、EJB组件或JSP脚本段中。这样,页面的设计人员和页面的编程人员可以同步进行。同时在客户端通过查看源
文件,看不到JSP标识的语句,更看不到JavaBean和EJB组件,也可以保护源程序的代码。






10.3.3 JSP的运行方式

 
 JSP一般的运行方式为:当服务器启动后,当Web浏览器端发送过来一个页面请求时,Web服务器先判断是否是JSP页面请求。如果该页面只是一般的
HTML/XML页面请求,则直接将HTML/XML页面代码传给Web浏览器端。如果请求的页面是JSP页面,则由JSP引擎检查该JSP页面,如果该
页面是第一次被请求、或不是第一次被请求但已被修改,则JSP引擎将此JSP页面代码转换成Servlet代码,然后JSP引擎调用服务器端的Java编
译器javac.exe对Servlet代码进行编译,把它变成字节码(.class)文件,然后再调用JAVA虚拟机执行该字节码文件,然后将执行结果
传给Web浏览器端。如果该JSP页面不是第一次被请求,且没有被修改过,则直接由JSP引擎调用JAVA虚拟机执行已编译过的字节码.class文件,
然后将结果传送Web浏览器端。下面是一张JSP运行的示意图:


  从这里我们
已经不难看出JSP和Servlet的关系,JSP引擎负责把JSP页面翻译成Servlet,因此JSP在底层完全就是Servlet(指原始概念上的
Servlet,而不是HttpServlet)。前面我们提到JSP编程对应javax.servlet.jsp,更确切的讲,这个包是供JSP引擎使
用的,它在做翻译的时候需要用到这个包,我们在编写JSP页面的时候是不需要涉及这个包的使用的。

 
 为什么有了Servlet还要在高层实现一个JSP呢?这个问题跟Servlet本身编写的烦杂程度有关,如果用Servlet来控制页面外观的话,将
是一件十分头疼的事情,使用JSP就把烦杂的打印任务交给了JSP引擎,程序员可以把精力集中到逻辑控制上面。在后面还会有进一步的比较。




10.3.4 JSP与ASP的比较

 
 JSP,ASP是使用最为广泛的两种服务器端脚本语言,总体说来这两者在技术上有很多的相似之处。两者都是为基于Web应用实现动态交互网页制作所提供
的技术环境。两者都能够为程序开发人员提供实现应用程序的编制与自带组件设计网页的从逻辑上分离的技术。而且两者都能够替代CGI,使网站建设与发展变得
较为简单与快捷。

  但是两者还是有很大的区别的,其中最本质的区别在于:两者是来于不同的技术规范组织,其实现的基础不同。JSP技术基于平台和服务器的互相独立,输入支持来自广泛的、专业化的各种工具包和数据库产品。相比之下,ASP技术主要依靠微软的技术支持。

  从学习的角度来讲,这两者是同多于不同的,有ASP经验的读者完全可以对比着学习。


10.3.5 JSP与传统CGI的比较
  跟Servlet一样,CGI的概念是十分简单的,但是真正编写CGI程序却不是这样的,它需要实实在在的技巧,必须具备调试程序的能力。编写CGI是一件令程序员头痛的事情,也正是应为这样,才会有象JSP,ASP这样的服务器端脚本语言出现。

  JSP隐藏了传统CGI编程中的大部分复杂性,使得服务器端编程大大简化。同时由于JSP最终是编译成Servlet执行的,通过前面Servlet与CGI的比较,我们很容易知道JSP的效率会比CGI来得高。


10.3.6 建立JSP运行环境

  一般说来支持JSP的服务器总是支持Servlet的,因为JSP本身需要Servlet的支持。前面我们介绍的Resin其实是一个JSP引擎,对Servlet的支持只是其功能的一部分。所以我们不必再寻找什么新的环境去试验我们的JSP。

  Resin中JSP的配置相对Servlet而言更为简单一些,因为它本身就是为JSP编写的,你只要启动httpd和srun,
在doc目录下的JSP文件就能够被识别。下面举一个最简单的例子:
  JSP文件:add.jsp
  2+2=
  
  把这个文件保存到doc目录下,在IE的地址栏键入
http://localhost:8080/add.jsp
,这时候如果出现以下的页面就说明你的JSP页面已经开始工作了:

  至于这个简单JSP的意义在后面有分析。


10.3.7 服务器参数设置

 
 我们刚才只是在默认发布目录下试验了一个JSP文件,这个在Resin的默认配置文件中是已经有相应的配置语句的。如果需要配置其他目录或虚拟目录,就
需要手工修改配置文件,由于各个JSP
Server的配置方法各不相同,在这里我们就不对Resin的配置进行过多的介绍了,有兴趣的读者可以参考已有的配置语句和Resin的帮助文档。


10.3.8 JSP指令(1)

  下面我们开始讲解JSP的语法。从本质上讲JSP还是Java程序,因为它最终还是会被翻译成Servlet进而编译成class文件执行。但是由于JSP是嵌入式的Java程序,有些特殊的符号还是需要学习的。下面我们一一列举,读者不必深究,多使用之后就会熟悉。

  1.HTML注释

  2.JSP注释

  3. 声明

  4. 表达式

  5. 脚本段

 1.HTML注释

  该注释在客户端可通过查看源文件的方法看到。
  JSP语法:

  例1
  
  在客户端页面源程序中显示为:
  

  例2
     -->
  在客户端页面源程序中显示为:
  

  描述
 
 可以在注释中使用任何有效的JSP表达式。表达式是动态的,当用户第一次调用该页面或该页面后来被重新调用时,该表达式将被赋值。JSP引擎对HTML
注释中的表达式执行完后,其执行的结果将直接插入到表达式显示的地方。然后该结果和HTML注释中的其它内容一起输出到客户端。在客户端可通过查看源文件
的方法看到该注释。

 2.JSP注释

  JSP注释作为JSP页面的文档资料,但是该注释在客户端通过查看源文件的方法是看不到的。即该注释不发送到客户端。

  JSP语法:

  例子
  
  
  
  
  

注释测试

  
  
  

  描述
  JSP引擎对JSP注释不作任何处理。JSP注释既不发送到客户端,也不在客户端的JSP页面中显示。在客户端查看源文件时也看不到。因此,如果你想在JSP页面源程序中写文档说明时,JSP注释是很有用的。
注意:在JSP注释中,不能使用--%>,但是如果你一定要使用的话,可以通过使用--%\>来避开。

 3. 声明

  在JSP页面脚本语言中声明变量或方法

  JSP语法:

  例子
  
  
  

  描述
  在JSP文件中,一次可以声明一个或多个变量和方法,它们之间用分号隔开。在声明时使用JAVA语言时,必须符合JAVA语言规范。

  注意:
  (i) 变量必须先声明,然后才能使用。
  (ii) 声明必须以分号结尾,但是在表达式中则不用。
  (iii) 通过page指令导入的包中已声明的变量或方法,可以在主JSP文件中直接使用它们。
 
 (iv)
一般情况下,一个声明的有效范围是本页面。但是,如果JSP源文件用指令或include指令包含一些静态文件,声明的有效范围将会扩大,也就是说:声明
在该静态文件中也有效。但是如果JSP源文件中用指令包含进来一个动态文件,主JSP文件中的声明在该动态文件中将不起作用。

 4. 表达式

  在JSP脚本语言中,可以使用任何有效的表达式。

  JSP语法:
 
  例子1:
  
  

  例子2:
  随机显示一个数字:
  
 
  描述
  表达式用于求值,然后其值转化为字符串,而且插入在JSP文件中显示该表达式的地方。而且可以在文本中使用表达式。表达式标签能包含符合JAVA语言规范的任何有效表达式,但是要注意:不能使用分号作为表达式的结尾,然而,在脚本段标签中,表达式要求以分号作为结尾。

 5. 脚本段

  在JSP页面脚本语言中,包含一段有效的代码片段。

  JSP语法:

  例1:
  
  
  

  描述
  在脚本段能声明多个变量和方法。能使用任何有效的表达式。能使用任何JSP隐含的对象或任何用标签声明的对象。能使用页面语言中任何有效的语句,如果使用Java语言,必须符合JAVA语言程序规范。

  说明:假如脚本段有输出语句,则输出内容被存储在out对象中,通过out对象输出到JSP页面中。

 
 以上介绍的是JSP的基本语法,有了以上的几条规则,我们就可以方便的书写一般的JSP文件了。比如我们前面测试Resin用的那个例子只有一句话,使
用的就是表达式的语法,2+2=,前面一部分对应的是需要直接打印的HTML文本,对中的是Java语句,加了个等号就表示要返回表达式的值,并打印到客
户端。翻译成对应的Servlet语句,大概就是:
        out.println("2+2="+(2+2));
  这样的一个语句如果改成
        System.out.println("2+2="+(2+2));
  并在console上运行,那么运行的结果就是2+2=4

10.3.8 JSP指令(2)

  下面是JSP中一些功能语句:

  1.Include指令

  2.Page 指令

  3.元素

  4.

  5.

  6.

  7.

  8.

 1.Include指令

  该指令用于包含一个文本或代码的文件。

  JSP语法:

  例子:
  include.jsp文件内容为:
  
  
  
  random.jsp中的随机显示的数为:
  
  
  
  random.jsp文件中内容为:
  

  在页面中显示为:
  random.jsp中的随机显示的数为: 2148.093521070482

  描述
 
 Include指令在JSP文件中插入一个包含文本和代码的文件。被包含的文件可以是JSP文件,HTML文件或文本文件。如果被包含的文件是JSP文
件,则JSP引擎编译完该JSP文件后,执行的结果将插入到主JSP文件中Include指令所在的位置。如果被包含的文件是HTML文件或文本文件,则
JSP引擎不对其进行编译,直接将其内容插入到主JSP文件中Include指令所在的位置。该包含是静态包含,即被包含的文件处理完,而且结果也插入到
主JSP文件完毕,主JSP文件将继续执行include指令下面的内容。

  注意:
  (1)被包含的文件中不能含有,,,或标签。因为被包含的文件的全部内容将被插入到JSP文件中include指令所在的地方,这些标签将会同JSP文件中已有的同样的标签发生冲突。
  (2)假如被包含的文件发声变化,主JSP页面将被重新编译。
  
  属性:
  file="relativeURL"
  file是被包含文件的路径名。 其值是一个URL的一部分,没有协议、端口号或域名. 如:
  "error.jsp"
  "/templates/onlinestore.html"
  "/beans/calendar.jsp"
 
 如果相对URL以"/"开始,这个路径是相对于JSP应用上下文而言的,JSP应用上下文是存储在application对象中的
javax.servlet.ServletContext对象。如果相对URL以目录或文件名开始,这个路径是相对于当前JSP文件所在的路径而言的。

 2. Page 指令

  定义整个JSP页面的全局属性。
  
  JSP语法:
  
  
  例:
  
  
  
  
  
  描述:
 
 Page指令的作用范围是整个JSP文件和该JSP文件用include指令或包含进来的任何静态文件,整个JSP文件和这些静态文件一起叫做一个"平
移单元".
注意:Page指令不适用于任何动态的包含文件。你可以在一个"平移单元"使用多个Page指令。但是每一个属性你只能使用一次,除了import(因为
import属性和JAVA程序语言的import语句很类似,你能够多次使用它,就象在JAVA语言中你能够多次使用import命令一样)。不论你将
Page指令放到JSP文件或被包含的文件的任何一个位置,它的作用范围都是整个"平移单元".然而,一个好的编成风格是常常将它放到文件的顶部.

  language="java"
  在JSP文件的脚本段、声明和表达式中使用的语言。现只允许用"JAVA"。

  extends="package.class"
  该属性用于指明JAVA类文件超类全名。使用该属性时要小心,因为,它会限制JSP引擎编译文件的能力。

  import= "{ package.class | package.* }, ..."
 
 JSP文件中导入的一个或多个用逗号隔开的包的列表。这些包(和它们的类)可以在JSP文件的脚本段、表达式、声明和标签中使用。你必须将import
属性放到调用被到入的类的标签前面。如果你想导入多个包,你可以在import后面用逗号将每个包隔开即可,或你可以在一个JSP文件中使用多个
import.

  session="true|false"
  该属性用于确定JSP页面是否使用HTTP session.假如这个值是true, 则sesssion引用的是当前或新的session. 假如这个值是false,则在JSP文件中,不能使用session对象。 默认值是true.

  buffer="none|8kb|sizekb"
  设置buffer缓冲区的大小,当out对象将被编译的JSP页面向客户Web浏览器端输出时使用。它的默认值是8kb.假如你指定了buffer缓冲区的大小,这个输出量将不低于你指定的大小。

  autoFlush="true|false"
  该属性指出:当缓冲区充满时,是否自动刷新。如果值为true(默认值为true),则自动刷新。如果值为false,则当缓冲区溢出时,将会产生错误。而且如果buffer属性的值设为none,autoFlush属性的值不能设为false.

  isThreadSafe="true|false"
  假设这个值设为true,多个线程能同时访问一个JSP页面。假如这个值为false,对一个JSP页面,JSP引擎一次只能响应一个用户的请求。默认值为true。

  info="text"
  关于作者、版本和著作权等信息,可以通过javax.sevlet.Servlet.getServletInfo()方法查到该信息的详细情况。

  errorPage="relativeURL"
  该属性用于设置处理例外事件的JSP文件的路径名。假如这个路径名以"/"开始,则这个路径名是JSP应用文档根目录而言的,而且由Web服务器决定。否则,这个路径是相对于当前JSP文件而言的。

  isErrorPage="true|false"
  JSP文件是否显示错误页面。 如果这个值为true,你可以使用例外exception对象。如果这个值为false(默认值也为false),在JSP文件中,不能使用exception对象。

  contentType="mimeType [ ;charset =characterSet ]" |
  "text/html;charset=ISO-8859-1"
 
 JSP文件中使用的MIME type和character
encoding(字符编码)是用于响应客户端的请求。你可以使用JSP引擎中有效的任何MIME type或character
set(字符集).默认的MIME type是text/html,而且默认的字符集合是ISO-8859-1

 3.元素

  将客户端的请求转交给一个HTML文件、JSP文件或脚本段处理。
  
  JSP语法:

  例子:
  
  
  描述:
  标签将请求对象从一个JSP文件转交给另一个文件处理。

  特别注意:JSP引擎对主JSP页面下面的代码不再执行。

 
 说明:如果JSP文件的输出被设置为缓冲输出(即使用默认的Page指令值或直接设置缓冲区的buffer大小),则在请求被转交之前,缓冲区被清空。
如果输出被设置为非缓冲输出(即用Page指令设置buffer=none),而且输出区中已经有内容,则使用元素,将会导致非法例外。

  属性

  page="{ relativeURL | }"
  该属性用于设置将要转交的文件的相关URL.
  该URL不能包含协议名、端口号或域名,相对于当前JSP文件来说的。如果它是绝对地址(以"/"开始),该路径由你的Web或应用服务器决定。

 4.

  取得Bean属性的值,以便在结果页面中显示。
 
  JSP语法:

  例:
  Bean的程序代码为:
  package AccessDatabase;
  public class Readdate
  {
  private String username="changcheng";
  public String void getUsername(){return username; }
  }

  JSP文件的内容为:
  
  
  从Bean中取得属性名为username的值为:
  
  

  执行后显示结果为:
  从Bean中取得属性名为user的值为:changcheng

  描述:
  在使用前,你必须使?lt;jsp:useBean>元素创建或调用一个Bean实例。标签是用于取得JavaBeans属性值,相当于调用Bean中的某个属性的getXXX()方法。

  属性:
  name="beanInstanceName"
  在标签中声明的Bean实例的名字。
  property="propertyName"
  Bean属性的名字。

  说明:使用元素时如上例中:,username必须是Bean(Readdate)中的属性,且该Bean中要有getUsername()方法,否则编译时会出错。

 5.

  在JSP文件中,包含一个静态或动态文件.
 
  JSP语法?lt;jsp:include page="{ relativeURL | }" flush="true" />

  例子:
  
  
  

  属性:
  标签允许你包含一个静态文件或动态文件。一个静态文件被执行后,它的内容插入在主JSP页面中。一个动态文件对请求作出响应,而且将执行结果插入到JSP页面中。
  标签能处理两种文件类型,当你不知道这个文件是静态或动态的文件时,使用该标签是非常方便的。
  当include动作执行完毕后,JSP引擎将接着执行JSP文件剩下的文件代码。

  page="{ relativeURL | }"
  该属性指出被包含文件相关URL;该URL不能包含协议名、端口号或域名。该URL是绝对或相对于当前JSP文件来说的。如果它是绝对地址(以"/"开始),该路径由你的Web或应用服务器决定

  flush="true"
  在JSP文件中,常设置flush="true",因为它不是一个默认值。

 6.

  下载一个plugin插件到客户端以便执行applet或Bean

  JSP语法:
    type="bean|applet"
  code="classFileName"
  codebase="classFileDirectoryName"
  [ name="instanceName"]
  [ archive="URIToArchive, ..." ]
  [ align="bottom|top|middle|left|right" ]
  [ height="displayPixels"]
  [ width="displayPixels"]
  [ hspace="leftRightPixels"]
  [ vspace="topBottomPixels"]
  [ jreversion="JREVersionNumber | 1.1"]
  [ nspluginurl="URLToPlugin"]
  [ iepluginurl="URLToPlugin"]>
  [
  [ ]+
   ]
  [ text message for user ]
  
  
  例子:
  
  
  
  
  
  

Unable to load applet

  
  
  

 
 元素在计算机启动时,给applet或Bean传递参数及其值。如果plugin没有启动,〈jsp:fallback>元素将给使用者提供一条
信息。如果plugin启动了但是applet或Bean没有启动,plugin常常弹出一个window窗口,该用户解释出错的原因。

  属性:
  type="bean|applet"
  plugin将执行的对象的类型。你必须指定Bean或applet,因为这个属性没有默认值。

  code="classFileName"
  plugin将执行的JAVA类文件的名字。在文件名后面必须跟上.class扩展名。文件名是相对于codebase属性中命名的目录。

  codebase="classFileDirectoryName"
  包含applet代码的目录名的相对或绝对地址。如果没有提供该值,调用的JSP文件的路径将被使用。

  name="instanceName"
  Bean或applet实例的名字,相同的JSP文件通过它可以相互通信。

  archive="URIToArchive, ..."
  一个用逗号隔开的路径列表,该路径列表指出用类装载器装载的类文件的位置。类装载器是位于codebase属性中命名的目录。

  align="bottom|top|middle|left|right"
  applet或Bean中显示的图象的位置是相对于JSP结果页面中的这样的行来说的,该行是JSP文件中包含的行。不同值的显示结果如下:
  bottom使图象的底部与下一文本行的基线对齐。
  Top使图象的顶部与下一文本行的顶部对齐。
  Middle使图象的垂直中心与下一文本行的基线对齐。
  Left使图象左对齐.
  Right使图象右对齐.

  height="displayPixels" width="displayPixels"
  applet或Bean以像素为单位显示的初始高度和宽度,不包括applet或Bean弹出的任何窗口和对话框.

  hspace="leftRightPixels" vspace="topBottomPixels"
  applet或Bean以像素为单位显示的图象的左右(或上下)之间间距的大小。一般是一个非常小的非零值。
  jreversion="JREVersionNumber|1.1"
  applet或Bean要求的JAVA运行时环境(JRE)的版本。默认的值是1.1

  nspluginurl="URLToPlugin"
  用户使用Netscape Navigator浏览器时需下载JRE插件的URL。它是完整的URL地址,有协议名、端口号和域名。

  iepluginurl="URLToPlugin"
  用户使用Internet Explorer浏览器时需下载JRE插件的URL.它是完整的URL地址,有协议名、端口号和域名。

  [ ]+
  传递给applet或Bean的参数和值。为了传递多个参数和值,你可以在〈jsp:params>元素中使用多个标签. Applets取得参数是通过java.applet.Applet.getParameter方法。

   text message for user
  如果plugin插件不能使用时,显示给用户的文本信息

 7.

  设置Bean的一个或多个属性值。

  JSP语法:
    {
  property= "*" | property="propertyName" [ param="parameterName"] | property="propertyName" value="{ string | }"
  }
  />

  例子:
  
  
  
  
  属性:
  标签用于设置JavaBean组件中的属性值。在你使用元素前,你必须使用标签  声明这个Bean.在中的name的值必须和在〈jsp:useBean>中的id的值一致.

  一般设置属性的值有三中方法:
  (i)使用方法 ,即可将用户请求中的所有值(这些值一般是客户  表单中的元素的值,且作为参数存储在request对象中)和Bean中的相匹配的属性赋值。此时,Bean中属性的名字必须和客户端表单中元素的名字一样。

  (ii)使用方法, 用请求对象中一个特定的值和Bean中相匹配的属性赋值或不相匹配的属性赋值。

  (iii)使用方法,用字符串的值或表达式的值直接设置为Bean的属性

  属性和用法: name="beanInstanceName"
  在标签中被创建或调用的Bean的实例名. Name的值必须和中的id的值一致。

  property="*"
  该属性用于一次性设置Bean属性的值。客户端表单中元素的值一次性赋予Bean中相匹配的属性赋值。另外,如果Bean有一个属性没有和它对应的表单元素,则这个属性将不被设置。

  property="propertyName" [ param="parameterName"]
  当用表单中一个元素的值给Bean中一个属性赋值,而且元素名和属性名不一样时,则必须用param指定一个参数。

 8.
  
  调用或创建一个指定名字和使用范围的Bean.

  JSP语法:
    id="beanInstanceName"
  scope="page|request|session|application"
  { class="package.class"| type="package.class"|
  class="package.class" type="package.class"|
  beanName="{ package.class | }" type="package.class"
  }
  { /> |
  > other tags
  }

  例子:
  
  
  
  
  

  属性:
  标签首先调用一个指定的名字和使用范围的Bean,如果这个Bean不存在,则创建该 Bean。
  
  属性和用法

  id="beanInstanceName"
  被调用或创建的Bean的名字.你可以在JSP文件的表达式、脚本段中使用该变量名。如果该Bean已经被另一个创建,id值必须同原来的标签中使用的id号相同.

  scope="page|request|session|application"
  定义Bean存在的范围。默认值是page。Bean的必须在其指定的范围内使用,否则使用它,将会出错。

  class="package.class"
  指定Bean的存放位置即存在哪个包中的哪个类。该类不能是抽象类,而且有一个公共的、无参数构造函数。包和类名是严格区分大小写的。

  class="package.class" type="package.class"
  类型type的值可以和类、该类的超类或该类实现的接口的类型一样。

  以上就是编写JSP要用到的一些语法,读者不必也不可能一下子掌握,在需要的时候进行查询即可,在使用中会自然而然的熟练起来。

 
 JSP的基本思想和Servlet是完全一样的,以上列举的语法只是一种工具来实现这些想法,而且其中很多语法跟JSP中的一些高级的技术是有关的,比
如bean,plugin等,读者在以后的实践中才能有所体会。在这里我们也举了一个从JSP翻译到Servlet的小例子,读者可以从中领会JSP和
Servlet的关系。


10.3.9 JSP中的隐藏对象(1)

 
 由于JSP是嵌入式的语言,不能显式的把一些必须的参数传递进来,比如Request对象,Response对象等,所以在JSP规范中提供了几个隐含
的对象来实现折椅功能。所谓隐含的对象,就是大家约定好使用一个名字来指代某个特定的对象,在编写JSP的时候不用显式的声明就能使用,由JSP引擎负责
在解释的时候把隐含对象加入到解释完的.java文件中。常用的隐含对象有application, session, request,
response, out, page, exception, pageContext

  1.session对象

  2.application对象

  3.request对象

  4.respose对象

  5.out对象

  6.page对象

  7.exception对象

  8.pageContext对象

 1.session对象

 
 前面在Servlet部分已经提到,过当客户第一次访问Web服务器发布目录(一个Web服务器有一个或多个"发布目录")下的网页文件时,Web服务
器会自动创建一个session对象,并为其分配唯一的ID号,客户可以将其需要的一些信息保存到该session对象,以便需要时使用。session
对象就是指通过getSession法办法得到的对象,在JSP中是隐含对象,关于session对象的使用读者可以参见Servlet API

 2.application对象

  当Web服务器启动时,Web服务器会自动创建application对象。Application对象一旦创建,它将一直存在,直到Web服务器关闭。因此,application对象可以实现多客户间的数据共享。

  一个Web服务器常常有多个发布目录,当Web服务器启动时,它自动为每个发布目录都创建一个application对象,这些application对象各自独立,而且和发布目录一一对应。

  application的生命周期:从Web服务器启动到Web服务器关闭。

 
 application在生命周期内的作用范围:在同一个发布目录A下的所有网页文件中,都可以对"和发布目录A对应"的application对象进
行操作,而且访问发布目录A的所有客户都共用一个application对象。因此,当在该application中存放数据信息时,所有访问该发布目录
A的客户都能够对其进行访问,实现了多客户之间的数据共享。

  application对象的基类是:javax.servlet.ServletContext类。可以用该类中的getServletContext()方法取得application。具体的使用方法参见Servlet API。

 3.request对象

  request对象主要用于取得客户在表单中提交的数据信息及多个网页之间数据信息传递等。同时通过它也可以取得Web服务器的参数。跟Servlet参数中的Request对象是相对应的。

  request对象的基类为:javax.servlet.ServletRequest

  如果传输协议是http,则是javax.servlet.HttpServletRequest
  
  具体的使用方法参见Servlet API。

 4. respose对象

  respose对象主要用于向客户端输出信息,响应客户端的请求。跟Servlet参数中的Response对象是相对应的。

  respose对象的基类是:javax.servlet.ServletResponse

  如果传输协议是http.则为javax.servlet.HttpServletResponse.

  具体的使用方法参见Servlet API。

 5.out对象

  out对象用于向客户端输出数据。

  out对象基类是:javax.servlet.JspWriter类,跟Servlet中由HttpServletResponse得到的PrintWriter略有不同,但是都是从
Writer继承而来,所以基本上还是一样的。

  具体的使用方法参见Servlet API。

 6.page对象

  page对象是当前JSP页面本身的一个实例。它的类型是:java.lang.Object。

  其方法就是Object类中的方法。如:Class getClass()返回一个对象在运行时所对应的类的表示,从而可以得到相应的信息。String toString()返回当前对象的字符串表示。page对象在当前页面中可以用this代替。

  具体的使用方法参见Java 2 API。

 7.exception对象

  当JSP页面在执行过程中发生例外或错误时,会自动产生exception对象。

  在当前页面用设置后,就可以使用该exception对象,来查找页面出错信息。
  exception对象的类型是:java.lang.Exception类.

  exception对象的常用方法为:

  String getMessage()
  返回页面的出错信息,如果没有则返回null

  void printStackTrace()
  以标准错误输出流的形式,打印并显示当前exception对象及其执行轨迹.

  具体的使用方法参见Java 2 API。

 8.pageContext对象

  pageContext对象相当于当前页面的容器,可以访问当前页面的所有对象。
  pageContext对象的基类是:javax.servlet.jsp.PageContext类。
  pageContext对象的常用方法:
  HttpSession getSession() 取得当前页面的session对象。
  ServletRequest getRequest() 取得当前页面的request对象。
  ServletResponse getResponse() 取得当前页面的response对象。
  ServletContext getServletContext() 取得当前页面的application对象。
  ServletConfig getServletConfig() 取得当前页面的config对象。
  Object getPage() 取得当前页面的page对象。
  JspWriter getOut() 取得当前页面的out对象。
  Exception getException() 取得当前页面的exception对象。
  void setAttribute(String variabelName, Object objectName)
  将对象objectName保存到pageContext中。
  Object getAttribute(String variableName)

  取得pageContext对象中保存的数据。如果参数variableName在当前session中不存在,则返回null.
  void removeAttribute(String variableName)

  删除pageContext中指定名字variableName的对象。如果该对象名不存在,则不执行任何操作。

  具体的使用方法参见Servlet API。


10.3.9 JSP中的隐藏对象(2)

 
 下面举一个简单例子来说明JSP的基本的编写方法,具体的应用技巧还需要读者到实践中去体会。这个例子就是用JSP来实现我们在讲解Servlet的时
候给出的从表单获取数据并打印到客户客户端的例子,原来的例子中用到的静态HTML文件,只需把form的action改成我们新的响应文件
JSPtest.jsp即可,读者主要查看JSP文件和原来的Java文件的区别。

  1.静态HTML文件ourform..html

  2.JSP文件:JSPtest.jsp

 1.静态HTML文件ourform.html

  
  
  
  
  
  

Our Form

  

  
      
        姓名:
         
    

      
        性别:
                男        女      
    

  
  

  
  

 2.JSP文件:JSPtest.jsp

  
  
  
  
  
  
  
  

Data You Posted

  
  
    
    你的姓名:
     
  

    
    你的性别:
     
  

  
  
  

  这个例子的执行结果和前面是一摸一样的。在以前Servlet分析的基础上,读者看懂这个例子应该没什么问题,这里就不对语法做过多分析了。下面我们来分析一下这个例子的几个特点。

 
 首先最明显的一点就是,使用JSP之后文件变得更短,格式更清晰了,这也是要使用JSP的一个最主要的原因,使用Servlet来打印大量的HTML语
句是很费事的,而JSP的主体是HTML,嵌入的Java语句只负责动态效果,所以使用比Servlet方便的多。在下面我们会分析如何使Servlet
和JSP互相配合,取长补短,获得更好的应用效果。

  另外一个就是JSP使用的时候不需
要单独配置每一个文件,只要是扩展名为jsp,JSP引擎会自动识别。而Servlet是必须进行配置后才能投入使用的,这也是处于安全性的考虑,直接访
问.class文件是不允许的,因为不能保证它是一个合法的Servlet。而JSP是没有经过编译的文本,即使是编译成了Servlet,也肯定是符合
Servlet规范的,尽管可能不符合HTML语法,所以它是安全的。

  还有就是中文问
题在这里的到了简化,本地的中文字符串不需要编码转换就能够正常在客户端显示。这里关键的一点是在头部设置页属性,其中charset=gb2312就是
告诉JSP引擎本地编码是gb2312,然后JSP引擎就会自动进行转换,不需要手工转了。但是,并不是说就这么一劳永逸了,中文问题在JSP页面之间传
参的时候还是存在的,读者只要掌握了编码的转换方式,应付任何中文问题就是转来转去的问题,因此读者应该从根本上理解中文问题,这才是一劳永逸的办法。

 
 这时候如果我们把静态页面的GET改成POST会是什么后果呢?我们会发现,不象HttpServlet,这个JSP还是能够正常工作的,这是因为
JSP的实现在最低层是Servlet,但跟HttpServlet又是有所区别的,所以它不存在客户端请求的分类问题,它只有一个
_jspService(HttpServletRequest request, HttpServletResponse
response)方法由JSP引擎实现,所以写JSP不必象Servlet那样关心那么多杂碎的事情。

  下面是Resin生成的临时Java文件,是上面的例子转换成Servlet之后的样子,有兴趣的读者可以读一下,如果真正读通懂了,一定会受益匪浅的。

  // Resin(tm) generated JSP
  package _jsp;
  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.jsp.*;
  import javax.servlet.jsp.tagext.*;
  import javax.servlet.http.*;

  public class _JSPtest__jsp extends com.caucho.jsp.JavaPage{
    
    public void
    _jspService(javax.servlet.http.HttpServletRequest request,
        javax.servlet.http.HttpServletResponse response)
     throws IOException, javax.servlet.ServletException
    {
 
    javax.servlet.jsp.PageContext pageContext =
com.caucho.jsp.QJspFactory.create().getPageContext(this, request,
response, null, true, 8192, true);
     javax.servlet.jsp.JspWriter out = (javax.servlet.jsp.JspWriter) pageContext.getOut();
     com.caucho.jsp.ByteWriteStream _jsp_raw_out;
     _jsp_raw_out = (com.caucho.jsp.ByteWriteStream) out;
     javax.servlet.ServletConfig config = getServletConfig();
     javax.servlet.Servlet page = this;
     javax.servlet.http.HttpSession session = pageContext.getSession();
     javax.servlet.ServletContext application = pageContext.getServletContext();
  try {
     _jsp_raw_out.write(_jsp_string0, 0, _jsp_string0.length);

     String name = request.getParameter("Name");
     String sex = request.getParameter("Sex");
     _jsp_raw_out.write(_jsp_string1, 0, _jsp_string1.length);
       out.print((name));
       _jsp_raw_out.write(_jsp_string2, 0, _jsp_string2.length);
        if(sex.equals("1")) out.print("男");
        else out.print("女");_jsp_raw_out.write(_jsp_string3, 0, _jsp_string3.length);
    } catch (Exception e) {
     pageContext.handlePageException(e);
    } finally {
      JspFactory.getDefaultFactory().releasePageContext(pageContext);
    }
  }

  private java.util.ArrayList _caucho_depends;
  private java.util.ArrayList _caucho_cache;
  private com.caucho.java.LineMap _caucho_line_map;

  public boolean _caucho_isModified()
  {
   if (com.caucho.util.CauchoSystem.getVersionId() != -1983231406)
    return true;
   for (int i = 0; i

  public long _caucho_lastModified()
  {
   return 0;
  }

  public com.caucho.java.LineMap _caucho_getLineMap()
  {
   return _caucho_line_map;
  }

  public void _caucho_init(HttpServletRequest req, HttpServletResponse res)
  {
   res.setContentType("text/html; charset=GB2312");
  }

  public void init(ServletConfig config,
      com.caucho.java.LineMap lineMap,
      com.caucho.vfs.Path pwd)
  throws ServletException
  {
   super.init(config);
   _caucho_line_map = new com.caucho.java.LineMap("_JSPtest__jsp.java", "/JSPtest.jsp");
   _caucho_line_map.add(1, 1);
   _caucho_line_map.add(1, 28);
   _caucho_line_map.add(9, 29);
   _caucho_line_map.add(16, 33);
   _caucho_line_map.add(20, 35);
   _caucho_depends = new java.util.ArrayList();
   _caucho_depends.add(new com.caucho.jsp.Depend(pwd.lookup("/D:/gzf@WeiHai/Resin/doc/JSPtest.jsp"),
   996991110000L));
  }

  private static byte []_jsp_string0;
  private static byte []_jsp_string1;
  private static byte []_jsp_string2;
  private static byte []_jsp_string3;
  static {
    try {
      _jsp_string0 = "\r\n\r\n\r\n \r\n\r\n\r\n\r\n

Data You Posted
\r\n".getBytes("GB2312");
      _jsp_string1 = "\r\n \r\n  \r\n  你的姓名: \r\n  ".getBytes("GB2312");
      _jsp_string2 = " \r\n
\r\n  \r\n  你的性别: \r\n  ".getBytes("GB2312");
      _jsp_string3 = " \r\n
\r\n \r\n\r\n\r\n".getBytes("GB2312");
    } catch (UnsupportedEncodingException e) {
     e.printStackTrace();
    }
  }
}

 
 到这里为止,JSP这部分已经讲解完毕,读者对JSP应该有了一个概念上的认识,应该有能力书写简单的JSP文件。如果对某些概念还不是很清楚,也不必
着急,多多练习就会有更深的体会。下面我们会对JSP和Servlet的关系做进一步的讨论,希望能帮助读者更好的理解Servlet和JSP。

10.4 JSP和Servlet的结合使用

 
 前面我们已经介绍了Servlet和JSP两种不同的Web开发工具,他们都源于Java,所以本质上是一样的,只是形式上有差别,但是对于开发程序而
言,形式上的差别往往也是很重要的,因为往往会对开发效率有极大的影响。所以正是因为形式上的差别,使他们的应用领域也大为不同。

 
 在使用JSP技术开发网站时,不强调使用Servlet。,这是为什么呢?Servlet的应用是没有问题的,它非常适合服务器端的处理和编程。但是如
果用Servlet处理大量的HTML文本,那么将是一件及其繁琐的事情。这种事情更适合机器去做,否则就是浪费程序员的体力。所以Servlet更适合
处理后端的事务,前端的效果用JSP来实现更为合适。

  早期的JSP标准给出了两种使用
JSP的方式。这些方式都可以归纳为JSP模式1和JSP模式2,主要的差别在于处理大量请求的位置不同。在模式1中,JSP页面独自响应请求并将处理结
果返回客户。这里仍然有视图和内容的分离,因为所有的数据都依靠bean来处理。尽管模式1可以很好的满足小型应用的需要,但却不能满足大型应用的需要。
大量使用模式1,常常会导致页面被嵌入大量的Script和Java代码。特别是当需要处理的商业逻辑很复杂时,情况会变得很严重。也许这对于Java程
序员来说,这不是大问题。但是如果开发者是前台界面设计人员,在大型项目中,这是很常见的,则代码的开发和维护将出现困难。在任何项目中,这样的模式多少
总是会导致定义不清的响应和项目管理的困难。下图是模式1的示意图:


  JSP
模式2是一种面向动态内容的实现,结合了Servlet和JSP技术。它利用两种技术原有的优点,采用JSP来表现页面,采用Servlet来完成大量的
处理,Servlet扮演一个控制者的角色,并负责响应客户请求。接着,Servlet创建JSP需要的Bean和对象,再根据用户的行为,决定将哪个
JSP页面发送给用户。特别要注意的是,JSP页面中没有任何商业处理逻辑,它只是简单的检索Servlet先前创建的Beans或者对象,再将动态内容
插入预定义的模板。

  从开发的观点来看,这一模式具有更清晰的页面表现,清楚的开发者角色划分,可以充分的利用开发小组中的界面设计人员。事实上,越是复杂的项目,使用模式2的好处就越突出。

  使用模式2,JSP和Servlet可以在功能最大幅度的分开。正确的使用模式2,导致一个中心化的控制Servlet,以及只完成显示的JSP页面。另一方面,模式2的实现很复杂,因此,在简单应用中,可以考虑使用模式1。下面是模式2的示意图:


 
 在Web的建设中到底使用哪一种模式是很重要的事前规划,只有积累了大量的经验才能作出正确而有效的选择。总之网站建设不光是技术的问题,总体的规划是
很重要的,读者在学习JSP和Servlet的同时更应该注意从中吸取思想的精华,技术是会过时的,而思想却是永远有价值的。


【本讲小结】

  本讲主要讲解了Servlet和JSP的基本概念,基本语法。本讲的目的并不在于从技术上很详细的讲解Servlet,JSP的每一个细节,而是希望能给读者一个概念上的了解。为读者以后学习基于Java的网站开发奠定一个基础。

  本讲首先介绍了Servlet了基本概念和如何编写简单的Servlet,以及如何配置Resin,构建一个简单的调试环境。着重从概念上分析了Servlet的类层次,理清了Servlet,HttpServlet,JSP等概念的异同。

 
 紧接着,承着Servlet的思路,我们介绍了JSP的编写。由于JSP在底层就是用Servlet实现的,所以在概念上和Servlet是没有什么区
别的,因此这部分主要侧重与JSP的语法以及JSP中的隐含变量。主要起到一个参考的作用,读者可以在使用的时候再来查询。最后通过一个例子比较了
Servlet和JSP的异同,这是很重要的一部分,读者应该好好理解。


  本讲的最后我们列举了两种JSP的工作模式,分析它们所适用的场合,读者可以稍做浏览,对以后的实践会有很大的帮助。

  本讲过程中顺带分析了一下Servlet和JSP的中文问题,以及解决方案。在开发中文网站的时候也是很有用的技术。

  Servlet和JSP是实用性很强的技术,而且有大量的内容在这里是没有办法完全涵盖,读者可以参考有关书籍,从实践中真正理解和掌握这两种技术的精髓。

               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15010/showart_516541.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP