知识点: 一个jsp页面的本质其实就是一个servlet。重写了Service方法。
tomcat服务器将jsp自动生成servlet的代码存放位置就在tomcat安装目录下的work中。
我的是在:C:\Program Files\Apache Software Foundation\Tomcat 9.0\work\Catalina\localhost\myPro\org\apache\jsp
创建一个 test.jsp页面
服务器自动生成的servlet代码:
jsp由Java代码和HTML代码组成,在生成的servlet中HTML代码是由
javax.servlet.jsp.JspWriter的对象out.write("<html>...</html>")写的。这个对象JspWriter正好是jsp的九大内置对象之一的out。
九大内置对象:
内置对象: jsp也就是servlet自动创建了九个对象。
page、config、request、response、session、application、out、exception、pageContext
exception对象默认不会创建,request和response对象作为参数传入。所以将test.jsp 生成的servlet打开可以看到剩下的6个内置对象的定义。
1.page对象
根据定义我们可以发现page对象的创建:final java.lang.Object page = this;
也就是page的本身就是servlet类本身(this)。
我们可以在jsp打印this和page的地址会发现是指向同一个地址,但是一些方法却被隐藏起来了。
page变量属于pageContext域, 也就是作用范围是当前jsp页面。这很容易理解了。当前page就是当前这个servlet的this指针。当然不能到其他页面。当然刷新页面相当于重新访问servlet,所以page也就重新刷新。之前储存的内容当然也就清空了。
2.config对象
web容器在初始化时使用一个ServletConfig(即config)对象向JSP页面传递信息,此配置信息包括初始化参数(在当前Web应用的应用部署描述文件web.xml中定义)以及表示Servlet或JSP页面所属Web应用的ServletContext对象。
也就是说config对象可以将web.xml配置信息传递到jsp页面。但是jsp初始化配置信息情况比较少,但是对于servlet的使用的情况较多。用法:
web.xml配置:
servlet写法:
我们可以在web.xml配置数据库的账号密码。然后再servlet中得到这个账号密码。当然还能得到一些其他的配置信息。
所以conf对象当然属于pageContext域,作用范围也固然是当前页面。
3. request对象
根据servlet中会发现,request对象并没有在servlet中定义,request对象是作为参数传递过来的。其实request对象是在客户端(浏览器)发送一次请求,服务器(tomcat)自动帮我们将请求的消息封装进request中,生成request对象传给servlet。所以request对象包含了客户端发起请求的所有信息。
request对象的作用是与客户端交互,收集客户端的Form、Cookies、超链接,或者收集服务器端的环境变量。
request对象的常用方法:
- String getParameter(String name),获取客户端的参数值,常用于表单
- String[] getParameterValues(String name),获取单个参数的所有值,常用语表单中的多选
- Enumeration getPameterName(),获取所有的参数的名称
- void setCharacterEncoding(String encoding),设置字符编码方式
- Cookie[ ] getCookies(),得到所有的Cookies
当然request还可以得到和设置请求头所有信息。
request还有一个很重要的作用:请求转发。
- request.getRequestDispatcher("url").forward(request, response);
- request.getRequestDispatcher("url").include(request, response);
因为可以转发,request对象可以存放数据,
用法:request.setAttribute(str, Object);
在转发的jsp页面中取数据:Object = request.getAttribute(str);
forward 和 include 的实质:
我们在servlet中分别用forward和include请求转发跳转页面。用out输出一些内容到网页中,并打印request对象和response对象的地址。然后在跳转的页面输出request对象和response对象的地址。
不论是forward还是include会发现地址不同,也就是jsp页面中的request,forward和servlet中的不是同一个request。但是却可以得到信息,所以应当是拷贝了一份request过去。
forward转发会发现,不论是转发前的“hhhh”还是转发后的“h1111hhh”,都不会在test.jsp的页面中输出。而include却会输出。
我们查看两者的jsp页面的源码便可发现,其实include其实是将servlet所代表的jsp页面和转发的jsp页面合并。所以如果前一个只是单纯的servlet页面,并无jsp。那么include就可以输出一些东西到转发的jsp页面中,但是include并不常用。
也就是response并不会传递,只是两个页面合并后才能用转发前页面的response对象的getWriter。
因此:请求转发只能转发到同一web项目的资源。客户浏览器只做了一次请求,服务器完成请求处理并转发请求,页面跳转。所以url地址不会变化,仍然是客户端(浏览器)的第一次请求的URL。
请求转发,不改变url地址,会跳转界面,还会将request对象的信息传递过去,直到请求结束,才会销毁request对象。
所以request对象属于request域,在请求结束后才会真正销毁。虽然每个页面都会新建一个request对象,但是对于请求转发来说,request会完全复制过去,也就相当于request对象并未消失。所以属于request域。刷新页面相当于重新发送请求,所以request对象会重新创建,之前的信息丢失。
4. response对象
Response对象用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应。Response对象只提供了一个数据集合cookie,它用于在客户端写入cookie值。若指定的cookie不存在,则创建它。若存在,则将自动进行更新。结果返回给客户端浏览器。
response最重要的就是响应页面。所以response最重要的也就是得到和设置响应头的信息
常用方法:
- String setCharacterEncoding()//设置响应字符编码格式
- String getCharacterEncoding()//获取响应字符编码格式
- void setContentType(String type)//设置响应MIME类型
- sendRedirect(java.lang.String location)//请求重定向
- PrintWriter getWriter()//获取打印输出对象
response可以响应界面并给浏览器添加cookie
用法:response.addCookie(cookie);
response还有一个很重要的功能,重定向:
用法:response.sendRedirect(location);
重定向也可以跳转界面,但是与请求转发不同的是重定向并不能传递request,地址栏上的url也会发生变化,而且能够访问其他web项目的资源。
本质:客户端(浏览器)发送了两次请求。客户端(浏览器)发送第一次请求,服务器接受处理,response返回一个状态码302 (3xx状态码重定向到其他地方: 需要客户端再次发送请求),客户端(浏览器)接收,发现是302,于是又发送了一条请求,请求的url便是重定向的参数location,服务器接收请求处理并跳转页面。
因为是客户端(浏览器)发送的请求,所以自然可以访问其他web项目。地址栏也自然会发生变化。
因此,response其实是pageContext域的属性,在访问jsp或者servlet时服务器自动创建,但是在有关请求转发或者重定向时,都没有拷贝过去,所以response是自然是属于pageContext域。
5. session对象
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
session实现的两种机制:
1. cookie, 服务器没生成一个session对象存储信息,每个session对象都有一个sessionid, 响应客户端(浏览器)生成一个cookie,存放sessionid,服务器会读取cookie中的sessionid来检索到以前的session对象。
2.重写url,上述方法在浏览器禁用cookie的话无法实现,所以我们在每个访问的url后加上sessionid也同样能做到。
得到session的一种方式:
HttpSession session = request.getSession();
为session设值:
session.setAttribute("usrid", userid);
取值:
userid = session.getAttribute("usrid");
session的生存周期,session会在客户端关闭,或者超过设定时间时自动销毁,默认为30分钟。
设值时间的一种方式,也可以在xml配置文件,或者tomcat中配置。
session.setMaxInactiveInterval(900); //在60*15 = 900, 15分钟后销毁
故,session属于session域。生存周期为时间到,或者浏览器关闭,自动销毁。
6.application对象
application对象的使用方法和session很类似,但是不同的是application的生存周期是在web项目删除或者服务器关闭才会销毁。
原理: 在服务器端创建的对象,储存在服务器端的内容中。所以客户端的一切行为都不会影响到application对象。
所以application属于application域,作用范围在整个web项目。
7. out对象
作用向页面输出内容, out对象被封装为javax.servlet.jsp.jspWriter接口,通过调用pageContext.getOut()方法可以获取out对象。
out对象是字符流对象,其作用和用法与ServletResponse.getWriter()方法返回的PrintWriter对象十分类似。都可以向页面输出信息,但是有所不同,那就是PrintWriter输出的内容一般都会在out对象输出内容的前面,给个例子:
访问该页面,得到结果:
但是也可以按照我们希望的顺序输出,那就是在out输出完后加一个方法 out.flush();顺序就是我们的代码顺序了。
原理:
PrintWriter 有一个缓冲区, 当我们用printwriter对象输出页面的内容会全部到缓冲区中,然后输出到页面。而JSPWriter也有这么一个缓冲区,当缓冲区满了就会输出到PrintWriter的缓冲区。然后再一起输出到页面。
刚刚的代码也就是。
- printwriter.write("<h1>PrintWriter1</h1>"); "PrintWriter1"进入PrintWriter的缓冲区。
- out.write("<h1>JSPWriter</h1>"); "JSPWriter"进入JSPWriter的缓冲区。
- printwriter.write("<h1>PrintWriter2</h1>"); "PrintWriter2"进入PrintWriter的缓冲区。
- 结束,JSPWriter缓冲区的内容写到PrintWriter的缓冲区中。
- 所以PrintWriter的缓冲区变成"PrintWriter1" "PrintWriter2" "JSPWriter";
可以用out.getBufferSize()查看缓冲区的大小,我的默认是8192。
out.flush 函数就是讲out缓冲区的内容直接输出到PrintWriter缓冲区中。
一些函数:
1.public abstract void clear()
清除缓冲区中的内容,不将数据发送至客户端。
2.public abstract void clearBuffer()
将数据发送至客户端后,清除缓冲区中的内容。
3.public abstarct void close()
关闭输出流。
4.public abstract void flush()
输出缓冲区中的数据。
5.public int getBufferSize()
获取缓冲区的大小。缓冲区的大小可用<%@ page buffer="size" %>设置。
6.public abstract int getRemainning()
获取缓冲区剩余空间的大小
7.public boolean isAutoFlush()
获取用<%@ page is AutoFlush="true/false"%>设置的AutoFlush值。
8.public abstract void newLine()
输出一个换行字符,换一行。
9.public abstract void print()
显示各种数据类型的内容。
10.public abstract void println()
分行显示各种数据类型的内容。
所以out对象为pageContext域。
8. exception对象
使用它,必须结合page指令中的isErrorPage属性和errorPage属性。都是在头部定义。如果定义了errorPage="error.jsp"那么就会抛出异常跳转到error.jsp页面,而不会直接弹出500错误。如果定义了isErrorPage="true",就说明这个页面就是能够接受异常的错误界面。
_jspx_page_context对异常的处理也非常简单:如果该页面的page指令指定了errorPage属性,则将请求forward到errorPage属性指定的页面,否则使用系统页面来输出异常信息。但是该页没有内置exception对象。
errorPage页面则定义了exception对象,定义如下:
java.lang.Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
也就是forward中的request请求带来了exception的信息。所以exception对象只存在error.jsp页面中,不会到其他页面。所以exception作用域:pageContext
举个栗子:
运行结果:
9. pageContext对象
JSP页面的管理者(上下文),它能获得其他八个内置对象。得到四个作用域常量。
1、获得其它八大内置对象 getXxx()c
- pageContext.getOut(); //获得out对象
- pageContext.getApplication(); //获得application对象
- pageContext.getRequest(); //获得request对象。
- ...... //获得其他内置对象
2、 提供作用域常量 scope, 其实就是int类型,分别为1、2、3、4。封装起来代表四种类型。
- PageContext.PAGE_SCOPE page
- PageContext.REQUEST_SCOPE request
- PageContext.SESSION_SCOPE response
- PageContext.APPLICATION_SCOPE application
3、为各个域存值和取值
- pageContext.getAttribute(name [, scope]); //获得scope作用域数据
- pageContext.setAttribute(name,value [, scope]); //给scope作用域设置内容
- pageContext.removeAttribute(name [, scope]); //给scope作用域移除内容
scope就是上面的四种作用域常量 。
一次获得指定名称内容
4、findAttribute(name); //依次从page、request、session、application 获得内容。
所以pageContext对象也是pageContext域。它只在本身页面范围有效。
四大作用域:
pageContext < request < session < application
pageContext 域: 范围页面本身。
request 域: 范围一次请求。
session域: 范围在设定时间内整个浏览器,只要浏览器不关闭,都有效。
application域: 范围整个服务器运行。只要项目没被移除,或者服务器没重启或关闭,那么application都存在。
参考链接,致谢:
https://www.cnblogs.com/whgk/p/6427759.html
http://blog.youkuaiyun.com/meiyalei/article/details/2129120
https://www.cnblogs.com/fjdingsd/p/4918748.html
http://blog.youkuaiyun.com/qq_34342083/article/details/53944941