JSP在进行编译的时候动态的创建了很多的内置对象,那么如果开发者知道,可以直接在JSP页面中使用这些对象。我们将这些内置的对象称之为JSP内置九大对象。
如果需要将以下的九大内置对象直接获取出来,那么可以这样做:
编写一个错误处理页面,那么请求查看翻译好的jsp文件。
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { PageContext pageContext = null; HttpSession session = null; Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); if (exception != null) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; ...... }
因为在JSP中编写JSP脚本以及JSP输出表达式都会默认翻译在_jspService()那么以上该方法中定义的九大对象开发者可以任意使用。
JSP九大对象 |
Servlet类型 |
request |
HttpServletRequest |
response |
HttpServletResponse |
session |
HttpSession |
config |
ServletConfig |
application |
ServletContext |
out |
JspWriter |
page |
Object |
pageContext |
PageContext |
exception |
Throwable |
1 out对象
同时使用out和response的输出字符流给页面输出数据。
<% out.write("jack<br/>"); response.getWriter().write("lucy<br/>"); %>
输出结果是lucy jack。因为以上两个都是字符流且带有自己的缓冲区,因此JSPWriiter的缓冲区数据在JSP执行完毕之后才将数据刷新给Response字符流的缓冲区,因此out对象输出的数据在后面。如果需要提前输出,那么需要进行缓冲区数据的强行刷新。
<% out.write("jack<br/>"); out.flush(); response.getWriter().write("lucy<br/>"); %>
2 使用JspWriiter和response的字节流同时输出数据。
<% out.write("jack<br/>"); out.flush(); response.getOutputStream().write("lucy<br/>".getBytes()); %>
以上代码运行结果是jack然后抛出异常getWriter() has already been called for this response。在JSP中不能同时使用字节流和字符流。
3. 如何使用JSP实现图片的下载。
<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%><% // 获取图片资源 InputStream in = application.getResourceAsStream("/imgs/0004.jpg"); // 指定处理方式 response.setHeader("content-disposition", "attachment;filename=0004.jpg"); // 获取字节输出流 byte [] b = new byte[1024]; int len = 0; // 边读边写 OutputStream output = response.getOutputStream(); while((len = in.read(b)) != -1){ output.write(b,0,len); } // 释放资源 in.close();%>
为了避免页面JSP中使用out对象,那么需要将JSP的所有的模板元素全部删除掉包括页面中的回车和换行。
4. 使用out隐含对象的write方法和println方法。
<% String str1 = "data"; String str2 = null; int a = 65; out.write(str1); // data out.write(str2); // 不显示 out.write(a); // A out.write("<hr/>"); out.println(str1); // data out.println(str2); // null out.println(a); // 65 %>
二 pageContext对象
PageContext类主要的描述的是的JSP页面的上下文环境,可以获取servlet的信息、也可以将当前JSP的上下文环境传递给指定的类实现对JSP页面的操作。
1. 获取JSP中所有的数据
<% out.write( (pageContext.getRequest() == request ) + "<br/>"); out.write( (pageContext.getResponse() == response ) + "<br/>"); out.write( (pageContext.getSession() == session ) + "<br/>"); out.write( (pageContext.getServletConfig() == config ) + "<br/>"); out.write( (pageContext.getServletContext() == application ) + "<br/>"); out.write( (pageContext.getPage() == page ) + "<br/>"); out.write( (pageContext.getException() == exception ) + "<br/>"); out.write( (pageContext.getOut() == out ) + "<br/>"); %>
思考:为什么SUN需要将其他八大对象通过pageContext也要进行获取?
因为以后如果需要一个普通的java类来处理JSP页面数据那么直接将PageContext类传递过去即可。如:自定义标签。
2. 常见的域
我们将可以使用setAttribvute()/getAttribute()方法存储和获取数据的对象称之为域对象。
域对象 |
生命周期 |
page |
在当前页面中有效 |
request |
请求转发 |
session |
默认半小时 |
application |
服务器关闭的时候 |
3. 设置和获取不同域属性
<%-- 给不同的域对象设置属性 --%> <% pageContext.setAttribute("page","this is current page"); pageContext.setAttribute("name","lucy",PageContext.REQUEST_SCOPE); pageContext.setAttribute("age","38",PageContext.SESSION_SCOPE); String likes[] = {"football","sleep","basketball"}; pageContext.setAttribute("likes",likes,PageContext.APPLICATION_SCOPE); %> <%-- 获取域属性 --%> <%= pageContext.getAttribute("page") %><br/> <%= pageContext.getAttribute("name",PageContext.REQUEST_SCOPE) %><br/> <%= pageContext.getAttribute("age",PageContext.SESSION_SCOPE) %><br/> <%= Arrays.toString( (String[])pageContext.getAttribute("likes",PageContext.APPLICATION_SCOPE) ) %><br/>
总结:
使用pageContext设置和获取域属性的时候可以显示的指定域,如果没有指定域,那么默认该域是page域。
问题:
在实际的开发中设置属性和获取属性是分别由不同的程序员开发的程序,那么如果在获取的时候开发者不明确这样的属性名到底存储在哪一个域中,那么应该怎么办?
解决方案:可以使用以下语句
<%= pageContext.findAttribute("test") %>
该语句默认从pageàrequestàsessionàapplication逐个查找需要的属性,如果找到直接返回。
因此该语句就是EL表达式的底层实现原理。