Jsp/Servlet基础-JSP脚本中的8个内置对象详解

来源:互联网 发布:php bug管理系统 编辑:程序博客网 时间:2024/04/19 22:29

1.application对象

            介绍application对象之前,先说下Web服务器的运行机制,大致需要完成如下几个步骤:

                   1.启动单独的线程。

                   2.使用I/O流读取用户的请求数据。

                   3.从请求数据中解析参数。

                   4.处理用户请求。

                   5.生成响应数据。

                   6.使用I/O流向客户端发送请求数据。

在上面的6个步骤中,第1、2、6步是通用的,可以由Web服务器来完成,但第3、4、5步则存在差异:因为不同请求里包含的请求参数不同,处理用户请求的方式也不同,所生成的响应自然也不同。那么Web服务器到底如何执行地3、4、5步呢?

         实际上,Web服务器会调用Servlet的_jspService()方法来完成第3、4、5步,当我们编写JSP页面时,页面里的静态内容、JSP脚本都会转换成_jspService()方法的执行代码,这些执行代码负责完成解析参数、处理请求、生成响应等业务功能,而Web服务器则负责完成多线程、网络通信等底层功能。

         Web服务器在执行了第3步解析到用户的请求参数之后,将需要通过这些请求参数来创建HttpServletRequest、HttpServletResponse等对象,作为调用_jspService()方法的参数,实际上一个Web服务器必须为Servlet API中绝大部分接口提供实现类。

         从上面介绍可以看出,Web应用里的JSP页面、Servlet等程序都将由Web服务器来调用,JSP、Servlet之间通常不会相互调用,这就产生了一个问题:JSP、Servlet之间如何交换数据?

         为了解决这个问题,几乎所有Web服务器(包括java、ASP、PHP、Ruby等)都会提供4个类似Map的结构,分别是application、session、request、page,并允许JSP、Servlet将数据放入这4个类似Map的结构中,并允许从这4个Map结构中取出数据。这4个Map结构的区别是范围不同。

           》application:对于真个Web应用有效,一旦JSP、Servlet将数据放入application中,该数据将可以被该应用下其他所有的JSP、Servlet访问。

           》session:仅对一次会话有效,一旦JSP、Servlet将数据放入session中,该数据将可以被本次会话的其他所有的JSP、Servlet访问。

           》request:仅对本次请求有效,一旦JSP、Servlet将数据放入request中,该数据将可以被该次请求的其他JSP、Servlet访问。

           》page:仅对当前页面有效,一旦JSP、Servlet将数据放入page中,该数据只可以被当前页面的JSP脚本、声明部分访问。

          application对象代表Web应用本身,因此使用application来操作Web应用相关数据。application对象通常有如下两个作用:

          》在整个Web应用的多个JSP、Servlet之间共享数据。

          》访问Web应用的配置参数。

          eg:web.xml有如下片段:

            <!--配置第一个参数-->

            <context-param> 

                     <param-name>driver</param-name>

                     <param-value>com.mysql.jdbc.Driver</param-value>

            </context-param>

             。。。。。。

则application这样操作,application.getInitParameter("driver")。

web.xml文件中使用<context-parm.../>元素配置的参数对整个Web应用有效,所以也被称为Web应用的配置参数。与整个Web应用有关的数据,应该通过application对象来操作。

注意:通过这种方式,可以将一些配置信息放在web.xml文件中配置,避免使用硬编码方式写在代码中,从而更好地提高程序的移植性。

2.config对象

           config对象代表当前JSP配置信息,但JSP页面通常无须配置,因此也就不存在配置信息。该对象在JSP页面中比较少用,但在Servlet中则用处较大,因为Servlet需要在web.xml文件中进行配置,可以指定配置参数。下面只介绍下config的用法。

eg1:test.jsp页面中有如下内容:

<body>

<!--直接输出config的ServletName的值-->

<%=config.getServletName()%>

</body>

测试:在浏览器中直接输入地址http://localhost:8080/webTest/test.jsp,结果如下:

jsp。

所有JSP页面都有相同的名字:jsp,所以代码输出jsp。

实际上,我们也可以再web.xml文件中配置JSP(只是比较少用),这样就可以为JSP页面指定配置信息,并为JSP页面另外设置一个URL。

eg2:web.xml中有如下配置:

<servlet>

       <!--指定Servlet名字-->

       <serlet-name>config</serlet-name>

       <!--指定将哪个JSP页面配置成Servlet-->

       <jsp-file>/configTest.jsp</jsp-file>

       <!--配置名为name的参数,值为yeeku-->

       <init-param>

             <param-name>name</param-name>

             <param-value>yeeku</param-value>

       </init-param>

       <!--配置名为age的参数,值为23-->

      <init-param>

             <param-name>age</param-name>

             <param-value>23</param-value>

       </init-param>

</servlet>

<servlet-mapping>

       <!--指定将conig Servlet配置到/config路径-->

       <serlet-name>config</serlet-name>

       <url-pattern>/config</url-pattern>

</servlet-mapping>

configTest.jsp页面中有如下内容:

<body>

<!--输出该JSP名为name的配置参数-->

name配置参数的值:<%=config.getInitParameter("name")%><br/>

<!--输出该JSP名为age的配置参数-->

age配置参数的值:<%=config.getInitParameter("age")%>

</body>

测试1:在浏览器访问/config看到如下结果:

name配置参数的值:yeeku

age配置参数的值:23

测试2:在浏览器直接访问configTest.jsp,将看到如下结果:

name配置参数的值:null

age配置参数的值:null

从例子可以看出,如果希望JSP页面可以直接获取web.xml配置文件中的配置信息,则必须通过为该JSP配置的路径来访问该页面,因为只有这样访问JSP页面才会让配置参数起作用。

3.exception对象

exception对象是Throwable的实例,代表JSP脚本中产生的错误和异常,是JSP页面异常机制的一部分。在JSP脚本中无须处理异常,即使该异常是checked异常。事实上,JSP脚本包含的所有可能出现的异常都可以交给错误处理页面处理。看如下代码片段(异常处理结构):

try{

     //代码处理段

     ......

}

catch(Thorwable exception){

     //异常处理段

     ......

}

这是典型的异常捕获处理块。在JSP页面,普通的JSP脚本只执行代码处理段,而异常处理页面负责异常处理段。在异常处理段,可以看到有个异常对象,该对象就是内置对象exception。exception对象仅在异常处理页面中才有效。

打开普通JSP页面所生成的Servlet类,将可以发现如下代码片段:

public void _jspService(HttpServletRequest request,HttpServletResponse response) throws java.io.IOException,ServletExcetption{

          ...

          try{

               //所有JSP脚本、静态HTML部分都会转换成此部分代码

               response.setContentType("text/html;character=gb2312");

               ...

               out.write("</body>\r\n");

               out.write("</html>\r\n");

          }catch(Throwable t){

                ...

                //处理该异常

                if(_jspx_page_context != null)_jspx_page_context.handlePageException(t);

          }finally{

                //释放资源

                _jspxFactory.releasePageContext(_jspx_page_context);

          }

}

从上面代码可以看出,JSP脚本和静态HTMl部分都将转换成_jspService()方法里的执行性代码——这就是JSP脚本无须处理异常的原因:因为这些脚本已经处于try块中。一旦try块捕捉到JSP脚本的异常,并且_jspx_page_context不为null,就会由该对象来处理异常,如代码所示。

_jspx_page_context对异常的处理也非常简单:如果该页面的page指令指定了errorPage属性,则将请求forward到errorPage属性指定的页面,否则将使用系统页面来输出异常信息。

注意:1.由于只有JSP脚本、输出表达式才会对应于_jspService()方法里的代码,所以这两个部分的代码无须处理checked异常。但JSP页面的声明部分依然需要处理checked异常,JSP的异常处理机制对JSP声明不起作用。2.应将异常处理页面中的page指令的isErrorPage属性设置为true。一般只有当isErrorPage属性设置为true时才可以访问exception内置对象。

4.out对象

          out对象代表一个页面输出流,通常用于在页面上输出变量值及常量。一般在使用输出表达式的地方,都可以使用out对象来达到同样效果。

           所有使用out的地方,都可以使用输出表达式来代替,而且使用输出表达式更加简洁。<%=...%>表达式的本质就是out.write(...);通过out对象的介绍,可以很好的理解输出表达式的原理。

5.pageContext对象

          这个对象代表页面上下文,该对象主要用于访问JSP之间的共享数据。使用pageContext可以访问page、request、session、application范围的变量。pageContext是PageContext类的实例,它提供了如下两个方法来访问page、request、session、application范围的变量。

          》getAttribute(String name):取得page范围内的name属性。

          》getAttribute(String name,int scope):取得指定范围内的name属性,其中scope可以是如下4个值:

                   >PageContext.PAGE_SCOPE:对应于page范围。

                   >PageContext.REQUEST_SCOPE:对应于request范围。

                   >PageContext.SESSION_SCOPE:对应于session范围。

                   >PageContext.APPLICATION_SCOPE:对应于application范围。

与getAttribute()方法相对应,PageContext也提供了2个对应的setAttribute()方法,用于将指定变量放入page、request、session、application范围内。如下:

          》setAttribute(String name,String value):将value放入name属性内。

          》setAttribute(String name,String value,int scope):将value放入name属性内,并指定scope范围。

eg:某jsp页面有如下代码片段:

//使用session将属性设置在session范围中

session.setAttribute("session","hello");

//使用pageContext将属性放在session范围中

pageContext.setAttribute("session2","hello",pageContext.SESSION_SCOPE);

//获取各属性所在的范围

out.println("session变量所在范围:"+pageContext.getAttributeScope("session")+"<br/>");

out.println("session2变量所在范围:"+pageContext.getAttributeScope("session2")+"<br/>");

测试:页面输出为:

session变量所在范围:3

session2变量所在范围:3

这些整型变量分别对应如下4个生存范围。

          1:对应page生存范围。

          2:对应request生存范围。

          3:对应session生存范围。

          4:对应application生存范围。

不仅如此,pageContext还可以用于获取其他内置对象,pageContext对象包含如下方法。

     》ServletRequest getRequest():获取request对象。

     》ServletResponse getResponse():获取response对象。

     》ServletConfig getServletConfig():获取config对象。

     》HttpSession getSession():获取session对象。

因此一旦在JSP、Servlet编程中获取了pageContext对象,就可以通过它提供的上面方法来获取其他内置对象。

  6.request对象

request对象是JSP中重要的对象,每个request对象封装着一次用户请求,并且所有的请求参数都被封装在request对象中。request的作用有3个:

           1.获取请求头/请求参数

           2.操作request范围的属性

           3.执行forward或include

        下面详细介绍这3个作用。

         》获取请求头/请求参数

        Web应用是请求/响应架构的应用,浏览器发送请求时通常总会附带一些请求头,还可能包含一些请求参数发送给服务器,服务器端负责解析请求头/请求参数的就是JSP或Servlet,而JSP和Servlet取得请求参数的路径就是request。request是HttpServletRequest接口的实例,它提供了如下几个方法来获取请求参数。

          》String getParameter(String paramName):获取paramName请求参数的值。

          》Map getParameterMap():获取所有请求参数名和参数值所组成的Map对象。

          》Enumeration getParameterNames():获取所有请求参数名所组成的Enumeration对象。

          》String[] getParameterValues(String paramName):paramName请求参数的值,当该请求参数有多个值时,该方法返回多个值所组成的数组。

        HttpServletRequest提供了如下方法来访问请求头。

          》String getHeader(String name):根据指定请求头的值。

          》java.util.Enumeration<String> getHeaderNames():获取所有请求头的名称。

          》java.util.Enumeration<String> getHeaders(String name):获取指定请求头的多个值。

          》int getIntHeader(String name):获取指定请求头的值,并将该值转为整数值。

        对于开发人员来说,请求头和请求参数都是由用户发送到服务器的数据,区别在于请求头通常由浏览器自动添加,因此一次请求总是包含若干请求头;而请求参数则通常需要开发人员控制添加,让客户端发送请求参数通常分为两种情况。

        》GET方式的请求:直接在浏览器地址栏输入访问地址所发送的请求或提交表单发送请求时,该表单对应form元素没有设置method属性,或设置method属性为get,这几种请求都是GET方式的请求。GET方式的请求会将请求参数的名和值转换成字符串,并附加在原URL之后,因此可以在地址栏中看到请求参数名和值。且GET请求传送的数据量较小,一般不超过2kb。

        》POST方式的请求:这种方式通常使用提交表单(由form HTML元素表示)的方式来发送,且需要设置form元素的method属性为post。POST方式传送的数据量较大,通常认为POST请求参数的大小不受限制,但往往取决于服务器的限制,POST请求传输的数据量总比GET传输的数据量大。而且POST方式发送的请求参数以及对应的值放在HTML HEADER中传输,用户不能在地址栏里看到请求参数值,安全性相对较高。

         如果POST请求的请求参数里包含非西欧字符,则必须在获取请求参数之前先调用setCharacterEncoding()方法设置编码的字符集。如果发送请求的表单页采用gb2312字符集,该表单页发送的请求也将采用gb2312字符集,所以需要先执行如下方法:

         request.setCharacterEncoding("gb2312");//设置request编码所用的字符集

         如果GET请求的请求参数里包含非西欧字符,有如下两种解决办法:

         第一种办法如下:

         //1.获取请求里包含的查询字符串
       String rawQueryStr = request.getQueryString();
       out.println("原始查询字符串为:"+rawQueryStr+"<br/>");
       //2.使用URLDecoder解码字符串
       String queryStr = java.net.URLDecoder.decode(rawQueryStr,"gbk");
       out.println("解码后的查询字符串为:"+queryStr+"<hr/>");
       //以&符号分解查询字符串
       String[] paramPairs = queryStr.split("&");
       for(String paramPair:paramPairs){
         out.println("每个请求参数名、值对为:"+paramPair+"<br/>");
         //以=来分解请求参数名和值
         String[] nameValue = paramPair.split("=");
         out.println(nameValue[0]+"参数的值为:"+nameValue[1]+"<hr/>");
       }

       第二种办法如下:

        //1.获取原始的请求参数值
       String rawName = request.getParameter("name");
       //2.将请求参数值使用ISO-8859-1字符串分解成字节数组
       byte[] rawBytes = rawName.getBytes("ISO-8859-1");
       //3.将字节数组重新编码成字符串
       String name =
new String(rawBytes,"gb2312");

       》操作request范围的属性

        HttpServletRequest还包含如下两个方法,用于设置和获取request范围的属性。

                》setAttribute(String attName,ObjectattValue):将attValue设置成request范围的属性。

                》Object getAttribute(String attName):获取request范围的属性。

       》执行forward或include

       HttpServletRequest类提供了一个getRequestDispatcher(String path)方法,其中path就是希望forward或者INCLUDE的目标路径,该方法返回RequestDispatcher,该对象提供了如下两个方法。

        》forward(ServletRequest request,ServletResponse response):执行forward。

        》include(ServletRequest request,ServletResponse response):执行include。

如下代码行可以将a.jsp页面include到本页面中:

getRequestDispatcher("/a.jsp").include(request,response);

如下代码行可以将请求forward到a.jsp面中:

getRequestDispatcher("/a.jsp").forward(request,response);

注意:使用request的getRequestDispatcher(String path)方法时,该path字符串必须以斜线开头。

7.response对象

        response代表服务器对客户端的响应。大部分时候,程序无须使用response来响应客户端请求,因为有个更简单的响应对象——out,它代表页面输出流,直接使用out生成响应更简单。但out是JspWriter的实例,JspWriter是Writer的子类,Writer是字符流,无法输出非字符内容。假如需要在JSP页面中动态生成一副位图、或者输出一个PDF文档,使用out作为输出响应对象将无法完成,此时必须使用response作为输出响应。所以response对象的作用如下:

        》response响应生成非字符响应

        》重定向

        》增加Cookie

下面介绍下Cookie吧!

        Cookie通常用于网站记录客户的某些信息,比如客户的用户名及客户的喜好等。一旦用户下次登录,网站可以获取到客户的相关信息,根据这些客户信息,网站可以对客户提供更友好的服务。Cookie与session的不同之处在于:session会随浏览器的关闭而失效,但Cookie会一直存放在客户端机器上,除非超出Cookie的生命期限。由于安全性的原因,使用Cookie客户端浏览器必须支持Cookie才行。客户端浏览器完全可以设置禁用Cookie。

        增加Cookie也是使用response内置对象完成的,response对象提供了如下方法。

        》void addCookie(Cookie Cookie):增加Cookie。

        正如上面的方法所示,在增加Cookie之前,必须先创建Cookie对象。增加Cookie请按如下步骤进行。

        1.创建Cookie实例,Cookie的构造器为Cookie(String name,String value)。

        2.设置Cookie的生命期限,即该Cookie在多长时间内有效。

        3.向客户端写Cookie。

例如下面的代码片段为向客户端增加一个Cookie对象:

        //1.获取请求参数

        String name  =  request.getParameter("name");

        //2.以获取到的请求参数为值,创建一个Cookie对象

        Cookie c = new Cookie("username",name);//new Cookie("cnName",java.net.URLEncoder.encode("孙悟空","gbk"));

        //设置Cookie对象的生存期限

        c.setMaxAge(24*3600);

         //3.向客户端增加Cookie对象

         response.addCookie(c);

访问客户端Cookie使用request对象,request对象提供了getCookies()方法,该方法将返回客户端机器上所有Cookie组成的数组,遍历该数组的每个元素,找到希望访问的Cookie即可。下面代码片段是访问Cookie的JSP页面的代码:

        //获取本站在客户端上保留的所有Cookie

        Cookie[] cookies = request.getCookies();

        //遍历客户端上的每个Cookie

        for(Cookie c : cookies){

                 //如果Cookie的名为username,表明该Cookie是我们需要访问的Cookie

                 if(c.getName().equals("username")){

                         out.println(c.getValue());//out.println(java.net.URLDecoder.decode(c.getValue()));

                 }

        }

注意:使用Cookie对象必须设置其生存期限,否则Cookie将会随浏览器的关闭而自动消失。

8.session对象

        session对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开为止,这个过程就是一次会话。session通常用于跟踪用户的会话信息,如判断用户是否登录,或者在购物车应用中,用于跟踪用户购买的商品等。session范围内的属性可以在多个页面的跳转之间共享。一旦关闭浏览器,即session结束,session范围内的属性将全部丢失。

        session对象时HttpSession的实例,HttpSession有如下两个常用的方法。

        》setAttribute(String attName,Object attValue):设置session范围内attName属性的值为attValue。

        》getAttribute(String attName):返回session范围内attName属性的值。

        关于session有一定需要指出,session机制通常用于保存客户端的状态信息,这些状态信息需要保存到Web服务器的硬盘上,所以要求session里的属性值必须是可序列化的,否则将引发不可序列化的异常。

注意:1.考虑session本身的目的,通常只应该把用户会话状态相关的信息放入session范围内。不要仅仅为了两个页面之间交换信息,就将该信息放入session范围内。如果仅仅为了两个页面交换信息,可以将该信息放入request范围内,然后forward请求即可。2.session的属性值可以是任何可序列化的Java对象。

0 0