第3章JSP内置对象 在Web程序设计中,用户交互是必不可少的。比如用户注册、用户登录时需要提交用户信息,程序是怎么处理这些请求的呢?本章介绍非常重要的用于处理浏览器请求的对象,通过使用内置对象,实现系统的访问控制、统计页面或网站的访问量等功能。通过本章的学习,达到如下的目标。 【技能目标】掌握用户页面控制、在线计数器、用户访问信息跟踪等的编程处理。 【知识目标】常见内置对象及其应用。 【关键词】请求(request)响应(response) cookie(含有key/value的小型文本文件)重定向(redirect) 会话(session)应用程序(application) 属性(attribute)时间间隔(interval) 3.1JSP内置对象概述 JSP内置对象是指在JSP中内置的不需要定义就可以在网页中直接使用的对象。它是Web服务器创建的一组对象。JSP内置对象的名称是JSP的保留字。 因为内置对象有些能够存储参数,有些能够提供输出,还有些能提供其他的功能,因此使用这些内置对象的频率比较高。内置对象有以下特点。 (1) 内置对象是自动载入的,因此它不需要直接实例化。 (2) 内置对象是通过Web容器来实现和管理的。 (3) 在所有的JSP页面中,直接调用内置对象都是合法的。 JSP标准中定义了9个内置对象。 (1) out对象: 负责管理对客户端的输出。 (2) request对象: 负责得到客户端的请求信息。 (3) response对象: 负责向客户端发出响应。 (4) session对象: 负责保存同一客户端一次会话过程中的一些信息。 (5) application对象: 表示整个应用的环境的信息。 (6) exception对象: 表示页面上发生的异常,可以通过它获得页面异常信息。 (7) page对象: 表示当前JSP页面本身,就像Java类定义中的 this一样。 (8) pageContext对象: 表示此JSP的上下文。 (9) config对象: 表示此JSP的ServletConfig。 3.2out对象 JSP通过out对象向客户端输出各种数据类型的内容,对应用服务器上的输出缓冲区进行管理。 3.2.1向客户端输出数据 out对象是一个输出流,用于向客户端输出数据,out对象基类是javax.servlet.jsp.JspWriter类。 out对象跟Servlet中由HttpServletResponse类得到的PrintWriter对象略有不同,但是JspWriter类和PrintWriter类都是从java.io.Writer类继承而来的,所以基本上还是一样的。out对象的常用方法如表31所示。 表31out对象的常用方法 方法名描述 void print()输出数据,不换行 void println()输出数据,换行 void newLine()输出一个换行符 void flush()输出缓冲区里的内容 void close()关闭输出流,从而可以强制终止当前页面的剩余部分向浏览器输出 void clear()清除缓冲区里的数据,但不把数据写入客户端 void clearBuffer()清除缓冲区里的数据,并且把数据写入客户端 int getBufferSize()获得缓冲区的大小 int getRemaining()获取缓冲区中没有被占用的空间的大小 1. print()方法 print()方法向客户端浏览器输出信息,通过该方法输出与使用JSP表达式输出相同。例如,下面两种方式其效果是一样的。 <% out.print("新闻动态"); %> <%="新闻动态"%> 2. println()方法 println()方法向客户端浏览器输出信息,并在输出内容后输出一个换行符。 说明: out内置对象的print()和println()方法与Java API中的PrintStream(System.out获取)提供的print()和println()方法作用相似。 例如,通过println()方法向页面中输出字符串“明日科技”及“编程词典”的代码如下。 <% out.println("明日科技"); out.println("编程词典"); %> 虽然println()方法输出了换行"\n",但在HTML语言中输出换行需要使用<br>标签,并且不会解析"\n"换行符。所以虽然println()方法输出了内容,但是并未换行,如果换行要使用<pre>标签。 <pre> <% out.println("明日科技"); out.println("编程词典"); %> </pre> 3.2.2管理缓冲区 out对象不仅可以向JSP页面输出内容,而且可以管理页面中的缓冲区,如清理缓冲区、刷新缓冲区以及获取缓冲区大小等。 crear():用于关闭输出流,清除缓冲区中的内容,一旦输出流被关闭了,就不能再使用out对象进行任何操作。 crearBuffer(): 清除当前缓冲区中的内容。 flush(): 刷新流。 isAutoFlush(): 检测当前缓冲区已满时是自动清空还是抛出异常。 getBufferSize(): 获取缓冲区的大小。 一般来说,不要在JSP页面中直接调用out对象的close()方法,否则将会抛出异常。 【例31】关闭输出流。 TestOut01.jsp的代码如下。 <%@ page contentType="text/html; charset=gb2312"%> <html> <body> <% out.println("清华大学<br>"); out.println("北京大学<br>"); out.close(); //关闭输出流 %> </body> </html> 3.2.3任务: 输出用户信息 1. 需求分析 使用out对象按表格格式输出显示用户信息。 2. 任务实施 (1) 使用MyEclips创建一个新项目task3_1。 (2) 新建一个JSP页面userList.jsp,编写如下代码。 <%@ page language="java" import="java.util.*" pageEncoding="GBK"%> <html> <head> <title>用户信息</title> </head> <body> <%! class User { private String code,String name; public User(String code,String name) { this.code=code; this.name=name; } public void setcode(String code) { this.code=code; } public String getcode() { return this.code; } public String toString() { return "code:"+this.code+" name:"+name; } } %> <% User[] s=new User[3]; s[0]=new student("910001","张上方"); s[1]=new student("910002","历史"); s[2]=new student("910003","王五"); out.println("<table border="1">") out.println("<tr><th>学号</th><th>姓名</th></tr>") int i; for (i=0;i<3;i++) { out.println("<tr> <td>"+s[i].code+"<\td>"); out.println("<td>"+s[i].name+"<\td><\tr>"); } out.println("</table>"); %> </body> </html> (3) 启动服务器,部署项目并在浏览器上显示。 3.3request对象 request对象是 HttpServletRequestWrapper 类的实例,代表着客户端的请求。request包含客户端的信息以及请求的信息,如请求哪个文件、附带的地址栏参数等。 它的继承层次结构图如图31所示。ServletRequest接口的唯一子接口是HttpServletRequest,HttpServletRequest接口的唯一实现类是HttpServletRequestWrapper。 图31request对象继承层次结构图 request内置对象是由Tomcat创建的,一旦HTTP请求报文发送到 Tomcat中,Tomcat对数据进行解析,就会立即创建request对象,并对参数赋值,然后将其传递给对应的JSP/Servlet。一旦请求结束,request对象就会立即被销毁。 request对象用来封装HTTP请求的参数信息、进行属性值的传递以及完成服务端跳转,其主要的方法如表32所示。 表32Request对象的主要方法 方法描述 void setAttribute(String name,Object value)在request中保存一个对象。本页面内或者forward之后的页面中可以通过getAttribute(String name)方法获取该对象 Object getAttribute(String name)从request中获取name对应的对象 String getParameter(String key)返回提交的参数 String getMethod()返回提交方式,一般为GET或者POST String[] getParameterValues(String key)返回提交的多个同名参数值。以数组形式返回 Enumeration getParameterNames()返回所有提交的参数名称 Cookie[] getCookies()返回所有的Cookie String getContextPath()返回应用程序路径,例如/jstweb String getRequestURL()"/jsp/method.jsp"返回请求的URI路径,例如/jsp/method.jsp void setCharacterEncoding(String encoding)设置request的编码方式 String getHeader(String name)获取request头信息 Enumeration getHeaderNames()返回所有的request头名称 Dispatcher getRequestDispatcher()返回Dispatcher对象。Dispatcher对象可以执行forward HttpSession getSession()返回HttpSession对象 3.3.1获取客户端请求参数 request对象封装了用户提交的信息,通过调用该对象相应的方法可以获取封装的信息,即使用该对象 可以获取用户提交信息。request对象可以用于获取客户端请求,如图32所示。 图32request对象处理客户请求 request对象的内存模型可以简单地划分为参数区和属性区。参数区存放的是Tomcat解析HTTP请求报文后提取出来的参数名和参数值。参数内的变量指向对象外部的相应的字符串对象,如果是多值参数,对应的就是字符串数组对象。 常见的客户端传递参数方式有以下几种。 (1) 浏览器地址栏直接输入: 一定是GET请求。 (2) 超链接: 一定是GET请求。 (3) 表单: 可以是GET请求,也可以是POST请求,这取决于<form>的method属性值。 GET请求和POST请求有以下区别。 (1) GET请求。 ① 请求参数会在浏览器的地址栏中显示,所以不安全。 ② 请求参数长度限制长度在1KB之内。 ③ GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码。 (2) POST请求。 请求参数不会显示在浏览器的地址栏中,相对安全。 请求参数长度没有限制。 下面介绍request的几种常见应用场合。 1. 单值参数的获取 对于单值参数,使用String getParameter(String name)方法得到对应的字符串对象的地址引用,如果客户端请求没有输入value值,得到的字符串对象就是null。 【例32】 通过超链接传递参数。 <a href="login.jsp?name=张三&sex=man&id=" >传递参数</a> login.jsp的代码如下。 <%= "name:"+request.getParameter("name") %><br> <%= "sex:"+request.getParameter("sex") %><br> <%= "id:"+request.getParameter("id") %><br> 如果指定的参数不存在,将返回null; 如果指定了参数名,但未指定参数值,将返回空的字符串。 【例33】 获取表单输入的文本信息。 <%@ page contentType="text/Html;charset=GB2312" %> <html> <body > <form action="tree.jsp" method="post" name="myform"> <input type="text" name="boy"> <input type="submit" value="提交" name="submit"> </form > </body > </html> tree.jsp的代码如下。 <%@ page contentType="text/html;charset=GBK" %> <html> <body> 获取文本框提交的信息: <%String textContent=request.getParameter("boy"); %> <%=textContent%> </body> </html> 注意: 使用request对象获取信息要格外小心,要避免使用空对象,否则会出现NullPointerException异常。 【例34】获取单选按钮的信息。 radio.jsp的代码如下。 <html> <%@ page contentType="text/html;charset=GBK" %> <body> <P>诗人李白是中国历史上哪个朝代的人: <form action="answer.jsp" method="post" name="form"> <input type="radio" name="dynasty" value="a">宋朝 <input type="radio" name="dynasty" value="b">唐朝 <input type="radio" name="dynasty" value="c">明朝 <input type="radio" name="dynasty" value="d" checked="ok">元朝 </form > </body> </html> answer.jsp的代码如下。 <html> <%@ page contentType="text/html;charset=GB2312" %> <body > <% String dynasty=request.getParameter("dynasty"); if(s1==null) s1=""; if(s1.equals("b")) { %> 你回答正确 <% } %> </body> </html> 【例35】获取列表框的信息。 select.jsp的代码如下。 <html> <%@ page contentType="text/html;charset=GB2312" %> <body > 请选择部门 <form action="dep.jsp" method="post" name="form"> <p>选择部门</p> <select name="dep"> <option Selected value="1">销售部 <option value="2">开发部 <option value="3">测试部 </Select> <input type="submit" value="提交你的选择" name="submit"> </form> </body > </html> dep.jsp的代码如下。 <html> <%@ page contentType="text/html;charset=GBK" %> <body > <% String s1=request.getParameter("dep"); %> 你选择的是:<%=dep%> </body > </html> 2. 多值参数的获取 对于多值参数,通过String[] getParameterValues(String name)方法可以得到这个多值参数的数组对象的地址引用。如果客户请求没有输入值,那么request获取的是一个null的数组对象。 【例36】获取复选框Check的信息。 <html> <%@ page contentType="text/html;charset=GB2312" %> <body > <form action="inte.jsp" method="post" name="form"> <p>选择爱好 <input type="checkBox" name="inte" value="1" />书法 <input type="checkBox" value="2" name="inte"/>体育 <input type="checkBox" value="3" name="inte"/>唱歌 <input type="submit" value="提交你的选择" name="submit"> </p> </form> </body > </html> inte.jsp的代码如下。 <%@ page language="java" import="java.util.*" pageEncoding="GBK"%> <html> <head> <title>复选框的应用</title> </head> <body> <% request.setCharacterEncoding("GBK"); String[] inter=request.getParameterValues("inte"); 爱好: <% for (int i=0;i<inter.length;i++) { %> <%=inter[i] %> <%}%> </body> </html> 3. 获取参数名称 通过Enumeration getParameterNames()方法获取所有参数的名称。 【例37】获取表单中所有参数名称。 test.jsp的代码如下。 <form action="param.jsp" method="post"> 参数1:<input type="text" name="p1"/><br/> 参数2:<input type="text" name="p2"/><br/> <input type="submit" value="提交"/> </form> param.jsp的代码如下。 <% Enumeration names = request.getParameterNames(); while(names.hasMoreElements()) { out.println(names.nextElement()); } %> 4. 获取参数名和参数值 还可以通过Map getParameterMap()方法得到所有参数名和参数值组成的 Map 对象,其中key为参数名,value为参数值,因为一个参数名称可能有多个值,所以参数值是String[],而不是String。 【例38】 获取参数名和参数值。 test.jsp的代码如下。 <a href="param.jsp?p1=v1&p1=vv1&p2=v2&p2=vv2">超链接</a> param.jsp的代码如下。 <% Map<String,String[]> paramMap = request.getParameterMap(); for(String name : paramMap.keySet()) { String[] values = paramMap.get(name); System.out.println(name + ": " + Arrays.toString(values)); } %> 5. 处理汉字信息 如果request对象获取客户提交的汉字字符时出现了乱码问题,就必须进行特殊处理。首先,将获取的字符串用ISO88591进行编码,并将编码存放到一个字节数组中,然后将这个数组转化为字符串对象。例如: String textContent=request.getParameter("boy"); byte b[]=textContent.getBytes("ISO-8859-1"); textContent=new String(b); 【例39】 处理乱码。 test.jsp的代码如下。 <%@ page contentType="text/html;charset=GB2312" %> <html> <body> 获取文本框提交的信息: <%String textContent=request.getParameter("boy"); byte b[]=textContent.getBytes("ISO-8859-1"); textContent=new String(b); %> </body> </html> 也可以用下面的方法处理乱码问题。 <% ----以POST方式提交数据时---- //设置读取请求信息的字符编码为GBK或者GB2312 request.setCharacterEncoding("GBK"); //读取用户名和密码 String name = request.getParameter("name"); String pwd = request.getParameter("pwd"); %>