TODO 想将Jsp的重点一次指明。
JSP的运行机制
1、首先,客户端发送URL请求。Tomcat服务器获取URL请求,如果获取的后缀名是.jsp,则Tomcat把请求交给JSPServlet处理
2、如果JSP第一次被调用,将把JSP编译成Servlet,如果JSP不被修改将不会再被编译,否则将会再次编译。通常,在JSP文件没有被修改的前提下,JSP只会被编译一次,所以在第一次访问的时候访问的速度会比较慢
3、编译的过程如下:Tomcat调用service方法编译JSP文件,创建一个*_jsp.java文件保存到服务器的\work\Catalina\目录下的相对应的项目文件夹里面,该java文件继承自父类HttpJspBase类
4、创建HttpServletRequest和HttpServletResponse
5、调用*_jsp.java继承自父类HttpJspBase的方法service(request,response)
6、在service方法里面会调用_jspService(request,response)方法渲染输出html返回给客户端
本文链接: http://www.itzhai.com/jsp-mechanism-and-principle-of-operation.html
jsp多线程
对每一个请求,web容器创建一个新的线程来处理该请求。如果有多个客户端同时请求该JSP文件,则JSP引擎会创建多个线程。每个客户端请求,对应一个线程。但servlet实例只有一个。
以多线程方式执行可大大降低对系统的资源需求,提高系统的并发量及响应时间.
但应该注意多线程的编程限制,由于该servlet始终驻于内存,所以响应是非常快的。如果.jsp文件被修改了,服务器将根据设置决定是否对该文件重新编译,如果需要重新编译,则将编译结果取代内存中的servlet(内存中的servlet需要Destroy()吗??),并继续上述处理过程(某些web应用服务器是这样的。但,Tomcat中如果.jsp文件被修改了,必须重启Tomcat才能有效。是这样吧??)。
如果在任何时候如果由于系统资源不足的原因,web容器将以某种不确定的方式将servlet从内存中移去。当这种情况发生时jspDestroy()方法首先被调用, 然后servlet实例便被标记加入"垃圾收集"处理。
如果JSP第一次被调用,将把JSP编译成Servlet(也可以事先编译好。是这样吧??),且一般只编译这一次,初始化放入内存中。
jsp_servlet的Destroy()方法,一般只有服务器停止时执行(是这样吧??)。
jsp本质就是servlet(单实例,多线程),采用的请求/响应模式。
浏览器输入URL可以访问jsp,同理,也可以访问servlet(*.java的*.class的位置)
jsp的指令元素
<%@page %>定义JSP文件的全局属性
<%@include %>在JSP被转为Serlet(*.java)文件时,静态包含一个文件的内容。在JSP转译前起作用。
jsp脚本元素
1、表达式
<%=expression%> 等价于<% out.print(String.valueof(expression)); %>,位于JSP被转为Serlet(*.java)文件的void _jspService()方法中,局部变量。
2、声明
<%! 声明;>,位于JSP被转为Serlet(*.java)文件的类成员声明(定义)中。根据servlet(单实例,多线程)的特点,可知,这是被所有客户端共享的。
jsp动作元素
<jsp:param>为其他标签提供附加信息,完成在页面间传递参数。必须配合<jsp:include>、<jsp:forward>、<jsp:plugin>使用。
<jsp:include>在当前的JSP页面中,包含静态或动态资源。在处理用户请求时起作用。
<jsp:forward>把当前的JSP页面从定向到另一个页面(HTML、JSP或servlet),但是地址不变(浏览器的URL),内容则是另一个页面的内容。
转发工作,是在服务器端进行的,不会引起用户端的二次请求,因此效率比重定向高。
<jsp:setProperty>设置已经实例化的Bean对象属性。只有在新建Bean实例时才会执行,如果是使用现有实例(已经设置过属性的实例?)则不执行。
<jsp:getProperty>用来提取一个Bean属性值。访问的属性值将它转化成一个String发送到输出流中。
<jsp:useBean>用来装载一个将在JSP页面中使用的javaBean。----实现view页面与业务逻辑分离的核心。scope参数:page/request/session/application。
javaBean也是一个java类,成员变量都设置了set()和get()方法----对应<jsp:setProperty>、<jsp:getProperty>。
<jsp:plugin>元素用于在浏览器中播放或显示一个对象(典型的就是applet和Bean),而这种显示需要在浏览器的java插件。
注意,<object>用于HTML 4.0 ,<embed>用于HTML 3.2。
jsp 内置对象
Request(Javax.servlet.ServletRequest)它包含了有关浏览器请求的信息.通过该对象可以获得请求中的头信息、Cookie和请求参数。
对应一次请求,作用域是当前页面。从当前页面利用它获取需要的客户端请求信息。
<form action="abc.jsp">:form向abc.jsp提取请求req,则只能从abc.jsp页面获取请求req,而不是<form>所在的页面(它是提交请求,请求不属于他,而应属于接收者)。
Response(Javax.servlet.ServletResponse)作为JSP页面处理结果返回给用户的响应存储在该对象中。并提供了设置响应内容、响应头以及重定向的方法(如cookies,头信息等)
对应一次请求的响应,作用域是当前页面。
Out(Javax.servlet.jsp.JspWriter)用于将内容写入JSP页面实例的输出流中,提供了几个方法使你能用于向浏览器回送输出结果。
对应一次请求的响应,作用域是当前页面。
pageContext(Javax.servlet.jsp.PageContext)描述了当前JSP页面的运行环境。可以返回JSP页面的其他隐式对象及其属性的访问,另外,它还实现将控制权从当前页面传输至其他页面的方法(控制权??)。
对应当前JSP页面。
Session(javax.servlet.http.HttpSession)会话对象存储有关此会话的信息,也可以将属性赋给一个会话,每个属性都有名称和值。会话对象主要用于存储和检索属性值。
对应一次会话,可用于多个页面。
一般情况下,用户首次登录系统时,容器会给此用户分配一个唯一的标记的SessionID。这个ID用于区别于其他用户。当用户退出登录系统时,这个session就会自动消失。session->HttpSession.
每个用户独有一个SessionID, session对象信息保存在容器里,但session对象的ID保存在客户端的Cookie中。
Application(javax.servle.ServletContext)存储了运行JSP页面的servlet以及在同一应用程序中的任何Web组件的上下文信息。
服务器启动后,就产生了这1个application对象,用户所访问的网站的各个页面之间浏览时,这个application对象都是同一个,直到服务器关闭。该对象能够被所有用户在不同的页面中共享(单实例,多线程??)。
注意区分:servlet,本质是某个页面,单实例,多线程。
Page(Java.lang.Object)表示当前JSP页面的servlet实例
对应当前JSP页面。
Config(javax.servlet.ServletConfig)该对象用于存取servlet实例的初始化参数。
对应当前页面(servlet、jsp)。
http://hi.baidu.com/may_62/item/02bbebc01d9da82747d5c02a
http://www.cnblogs.com/kelin1314/archive/2011/03/03/1969578.html
jsp转成的servlet中,使用out.wrte()向
浏览器中输出。out的内容会被先缓存在response中,最后再一次性给浏览器。对于print和write。除了字符集以外。这两个是没有多大区别的,因为JspWriter继承了Writer类,而这个类就实现了这两个方法。所以这两个方法你不用管它。print默认使用本身字符集。
jsp的pageContext对象
pageContext对象能够存取其他隐含对象。
例如
1、类成员:private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
2、_jspService()方法中
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();//其它页面调用该方法产生的application对象是同一个。
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
Jsp的session对象
session对象一般存储那些非request的信息,用于多个页面传递,如登录的用户名、密码。当然,你也可以将request的信息放于session对象,但是,一般不需要(对吧??)。
为什么session对象的作用域是一次会话(多个页面)?
因为客户端第一次访问某网站(web服务器)时,服务器给该客户端一个session对象和唯一的session ID,并将session对象放于服务器内,比如某个散列表中。以后该客户端访问这个服务器的同时,就会传回session ID(方法包括URL重写,发送cookie和表单隐藏字段(很少用))。服务器根据该session ID取出散列表中的session对象给被访问的位置(jsp页面、servlet)。
客户端是如何知道发送哪个session ID的呢?
客户端访问某个服务器需要发送session ID,会检查所有存储的session ID,如果某个session ID所声明的作用范围大于等于将要请求的资源所在的位置,则把该session ID发送给服务器。
http://java.chinaitlab.com/server/361839.html(session和cookie机制)
使用举例:
登录校验:
方案1
可以定义一个页面A,在页面里面判断Session["user"]是不是空,如果是跳转到登录页面
其他页面(除了登录页面外)都继承A页面。
在登录页面登录成功后把当前用户名存入Session["user"]
方案2
在web.config里面设置登录页面,及不允许匿名访问,则未登录用户会自动跳转到登录页面
---页面的跳转,session也跟着传递。