JSP工作原理

一、 JSP 工作原理 JSP


在一个 JSP 文件第一次被请求时, JSP 引擎把该 JSP 文件转换成为一个 servlet 。而这个引擎本身也是一个 servlet ,在 JSWDK WEBLOGIC 中,它就是 JspServlet JSP 引擎先把该 JSP 文件转换成一个 Java 源文件,在转换时如果发现 jsp 文件有任何语法错误,转换过程将中断,并向服务端和客户端输出出错信息;如果转换成功, JSP 引擎用 javac 把该 Java 源文件编译成相应的 class 文件。然后创建一个该 SERVLET 的实例,该 SERVLET jspInit() 方法被执行, jspInit() 方法在 servlet 的生命周期中只被执行一次。然后 jspService() 方法被调用来处理客户端的请求。对每一个请求, JSP 引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求该 JSP 文件,则 JSP 引擎会创建多个线程。每个客户端请求对应一个线程。以多线程方式执行可大大降低对系统的资源需求 , 提高系统的并发量及响应时间 . 但应该注意多线程的编程限制,由于该 servlet 始终驻于内存,所以响应是非常快的。 如果 .jsp 文件被修改了,服务器将根据设置决定是否对该文件重新编译,如果需要重新编译,则将编译结果取代内存中的 servlet ,并继续上述处理过程。 虽然 JSP 效率很高,但在第一次调用时由于需要转换和编译而有一些轻微的延迟。 此外,如果在任何时候如果由于系统资源不足的原因, JSP 引擎将以某种不确定的方式将 servlet 从内存中移去。当这种情况发生时 jspDestroy() 方法首先被调用 , 然后 servlet 实例便被标记加入 " 垃圾收集 " 处理。 jspInit() jspDestory() 格式如下:可在 jspInit() 中进行一些初始化工作 , 如建立与数据库的连接,或建立网络连接,从配置文件中取一些参数等,在 jspDestory() 中释放相应的资源。  

<%!
public void jspInit()
{
      System.out.println("jspinit");  
}
 
%>
 
<%!
public void jspDestory()
{
      System.out.println("jspDestory");  
}
%>

二、服务端的输出缓冲区

缺省情况下 : 服务端要输出到客户端的内容 , 不直接写到客户端 , 而是先写到一个输出缓冲区中 . 只有在下面三中情况下,才会把该缓冲区的内容输出到客户端上:


JSP 网页已完成信息的输出  
输出缓冲区已满  
JSP
中调用了 out.flush() response.flushbuffer()  
输出缓冲区的大小可以用 : response.setBufferSize() 设置 , 如下:  
设置输出缓冲区的大小为 1KB 。或 response.setBufferSize(1);  
设置输出缓冲区的大小为 0 ,即不缓冲。或 response.setBufferSize(0);  
response.getBufferSize() out.getBufferSize() 可取的输出缓冲区的大小 , 单位为字节 . response.isCommitted() 可检查看服务端是否已将数据输出到客户端 . 如果返回值是 TRUE 则已将数据输出到客户端 , FALSE 则还没有 .  

三、服务端输出重定向

有以下 3 种方法可以做到输出重定向 :  

RESPONSE.SETREDERECT("URL")
该方法通过修改 HTTP 协议的 HEADER 部分 , 对浏览器下达重定向指令的 , 使浏览器显示重定向网页的内容 . response.sendRedirect(" http://localhost:7001/index.html");  
下面的方法也能改变 HTTP HEADER 属性,它的原理和 1 是一样的 .  
<%  
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);  
String newLocn="/index.html";  
response.setHeader("Location",newLocn);  
% >  
采用 <JSP:FORWORD> 该方法是利用服务器端先将数据输出到缓冲区的机制 , 在把缓冲区的内容发送到客户端之前 , 原来的不发送 , 改为发送该页面的内容 , 如果在 <JSP:FORWORD> 之前有很多输出 , 前面的输出已使缓冲区满 , 将自动输出到客户端 , 那么该语句将不起作用 , 这一点应该特别注意 . 如下面的例子中 (1) 会输出 index.html 的内容, 2 不会输出 index.html 的内容,而是输出 out.println("@@@@@@@@@@@@@@@@@"); 中的内容 , 并且在服务端会抛出 :java.lang.IllegalStateException: Response already committed 异常,但客户端没有任何错误输出。  
(1)
<%@page buffer="1kb"%>
 
<%
long i=0;
 
for(i=0;i<10;i++)
{
      out.println("@@@@@@@@@@@@@@@@@");
}
%>
 
<jsp:forward page="./index.html" />
 
 
(2)
<%@page buffer="1kb"%>
 
<%
long i=0;
 
for(i=0;i<600;i++)
{                  
      out.println("@@@@@@@@@@@@@@@@@");
}
%>
 

说明:
1.
方法 (1),(2) 可以使用变量表示重定向的地址 ; 方法 (3) 不能使用变量表示重定向的地址。
String add="./index.html";  
<jsp:forward page= add />  
无法重定向到 index.html 中去  

String add=http://localhost:7001/index.html  
response.sendRedirect(add);  
可以重定向到 http://localhost:7001/index.html 中去。  

2.
采用方法 (1),(2)request 中的变量 ( 通过 request.setAttribute() 保存到 request 中的值 ) 不能在新的页面中采用 , 采用方法 (3) . 综上 , 我们应该采用 (1),(2) 重定向比较好 .  


四、 JSP 中正确应用类 :  

应该把类当成 JAVA BEAN 来用,不要在 <% %> 中直接使用 . 如下的代码 (1) 经过 JSP 引擎转化后会变为代码 (2):
从中可看出如果把一个类在 JSP 当成 JAVA BEAN 使用 ,JSP 会根据它的作用范围把它保存到相应的内部对象中 .
如作用范围为 request, 则把它保存到 request 对象中 . 并且只在第一次调用 ( 对象的值为 null) 它时进行实例化 . 而如果在 <% %> 中直接创建该类的一个对象 , 则每次调用 JSP , 都要重新创建该对象 , 会影响性能 .  

代码 (1)
<jsp:useBean id="test" scope="request" class="demo.com.testdemo">
</jsp:useBean>
 
<%
test.print("this is use java bean");
 
testdemo td= new testdemo();
td.print("this is use new");
%>
 


代码 (2)
demo.com.testdemo test = (demo.com.testdemo)request.getAttribute("test");  
if (test == null)  
{  
      try  
      {  
                test = (demo.com.testdemo) java.beans.Beans.instantiate(getClass().getClassLoader(),"demo.com.testdemo");  
      }  
      catch (Exception _beanException)  
      {
              throw new weblogic.utils.NestedRuntimeException("cannot instantiate 'demo.com.testdemo'",_beanException);  
      }  
      request.setAttribute("test", test);  
      out.print("/r/n");
}  
out.print("/r/n/r/n/r/n");
test.print("this is use java bean");  
 
testdemo td= new testdemo();
td.print("this is use new");

 



五、 JSP 的调试  

JSP
的调试比较麻烦 , 特别是当 bean 是在一个 session 中存在时,更加困难。得从好几个页面开始往里面走才行。通常是用 out.println() System.out.print() 来打一大堆的信息来查问题。如果是用 jbuilder 做开发 , 它能直接调试 JSP. 不过更重要的是知道错误产生的原因及解决方法。下面对一些 JSP 编程常见错误进行分析。  

(1).java.lang.NullPointerException
异常
一般是对一个为 NULL 值的变量进行操作引起的 . 如下面的操作就会抛出
java.lang.NullPointerException
String a = null;  
a.substring(0,1);  
 
为避免这种异常最好在对变量操作之前检查看它是否为 NULL . :
<% String ss=Session.getAttribute("NAME")  
if isnull(ss)  
{  

}  
else  
{  

}  
%>  

(2).JSP
是用 JAVA 写的,所以它是大小写敏感的,用过其他编程语言的人最容易犯这个错误。另外在浏览器的地址栏中输入的访问 JSP 的地址也是区分大小写的 . http://localhost:7001/demo/t.jsp http://localhost:7001/Demo/t.jsp 是不一样的

(3).
jsp 中判断字符串要使用 compareTo 方法,不要用 == ,因为在 java String 变量不是一个简单的变量而是一个类实例,不同的方法会得到 不同的结果,如下所示:  

  

   String str1="ABCD";  
   String str2="ABCD"; ( String str2="AB"+"CD";  
   if (str1==str2)  
   out.print("yes");  
   else  
   out.print("no");  
  结果是 "yes"  
   

   String str1,str2,str3;  
   str1="ABCD";  
   str2="AB";  
   str3=str2+"CD";  
   if (str1==str3)  
   out.print("yes");  
   else  
   out.print("no");  
  结果是 "no"  


String str1=new String("ABCD");  
   String str2=new String("ABCD");  
   if (str1==str2)  
   out.print("yes");  
   else  
   out.print("no");  
  结果是 "no"  


String str1=new String("ABCD");  
   String str2=new String("ABCD");  
   if (str1.compareTo(str2)==0)  
   out.print("yes");  
   else  
   out.print("no");  
  结果是 "yes"  

(4)
防止 JSP SERVLET 中的输出被浏览器保存在缓冲区中 :
浏览器在默认情况下会把浏览过的网页保存在缓冲区中 , 在调试时 , 一般不希望这样 . 把下面的脚本加入程序中 , 就可防止 JSP SERVLET 中的输出被浏览器保存在缓冲区中  
<%  
response.setHeader("Cache-Control","no-store"); //HTTP 1.1  
response.setHeader("Pragma","no-cache"); //HTTP 1.0  
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server  
%>  
IE 中也可通过设置实现:把 / 工具 /INTERNET 选项 / 常规 / 设置 / 的检察所存页面的较新版本 , 设为每次访问该页时都检查 .


六、 COOKIE

HTTP COOKIE
实质是服务端与在客户端之间传送的普通 HTTP , 可保存也可不保存在客户的硬盘上 . 如果保存 , 每一个文件大小不超过 4K 的文本文件 . 多个 COOKIE 可保存到同一个文件中 . 如果从编程角度来看 , JSP COOKIE 就是 JAVA 提供的一个类 . 常用的方法如下所表示,因为客户端可能不接受 COOKIE ,所以建议不用它,改用 SESSION 等其他方式。  


public class cookie  
{  
public String getDomain() //
返回该 COOKIE 的有效域  
public int getMaxAge() //
返回该 COOKIE 的有效期 , 单位为秒  
public String getName() //
返回该 COOKIE 的名称  
public String getPath() //
返回该 COOKIE 的有效路径  
public boolean getSecure() //
返回该 COOKIE 的安全设置  
public String getvalue() //
返回该 COOKIE 的值  
public void setDomain(java.lang.String pattern) //
设置该 COOKIE 的有效域  
public void setMaxAge(int expiry) //
设置该 COOKIE 的有效期 , 单位为秒  
public void setPath(java.lang.String uri) //
设置该 COOKIE 的有效路径  
public void setSecure(boolean flag) //
设置该 COOKIE 的安全设置  
public void setvalue(java.lang.String newvalue) //
设置该 COOKIE 的值  
}  
一个 COOKIE 包含以下五部分 :  

NAME/value
, 设置该 COOKIE 的名字及它保存的值  
COOKIE
通常和服务器相关 , 如果将域设为 JAVA.SUN.COM, 那么该 COOKIE 就和这个域相关 , 只对该网址起作用 , 当浏览该网址时 , 浏览器将把该 COOKIE 的内容发送给服务端 ,COOKIE 是作为 HTTP HEADER 的一部分被发送的,如果没有设置域 , 那么 COOKIE 就只和创建该 COOKIE 的服务器相关 .  
路径用于指定服务器上可以使用该 COOKIE 的文件所在的路径 , 它只对该网址下的该路径下的应用起作用 ."/" 表示服务器上所有目录都可以使用该 COOKIE.  
COOKIE
都有一个有效期 , 有效期默认值为 -1, 这表示没有保存该 COOKIE, 当该浏览器退出时 , COOKIE 立即失效 .  
安全选项 true/false, 如果设置为 true, 那么在服务端与在客户端之间传送该 COOKIE 的内容时 , 采用 HTTPS 协议 .  
如何检查一个客户端是否支持 COOKIE 的方法 :  
用下面的方法写一个 COOKIE 到客户端 , 并确认成功  
try  
{  
Cookie c = new Cookie("mycookie","COOKIE TEST");  
response.addCookie(c);  
}  
catch(Exception e)  
{  
     System.out.println(e);  
}  


然后在一个新的 JSP 文件中 : 用下面的方法取客户端的 COOKIE cookies , 如果 cookies.length ==0, 说明该客户端的浏览器不支持 COOKIE  
try  
{  
Cookie[] cookies = request.getCookies();  
if(cookies.length ==0)  
{  
     System.out.println("not support cookie");  
}  
}  
catch(Exception e)  
{  
     System.out.println(e);  
}  



七、 JSP SERVLET 的区别 :

  SUN
首先发展出 SERVLET ,其功能比较强劲,体系设计也很先进,只是,它输出 HTML 语句还是采用了老的 CGI 方式,是一句一句输出,所以,编写和修改 HTML 非常不方便。 后来 SUN 推出了类似于 ASP JSP ,把 JAVA 代码嵌套到 HTML 语句中,这样,就大大简化和方便了网页的设计和修改。 ASP PHP JSP 都是嵌套型的 SCRIPT 语言。 一个分布式系统应分为三层:表示层 , 业务逻辑层 , 数据存取层 , J2EE 体系结构中 ,SERVLET 用来写业务逻辑层是很强大的,但是对于写表示层就很不方便。 JSP 则主要是为了方便写表示层而设计的。 ENTITY BEAN 实现数据存取层, SESSION BEAN 实现业务逻辑层。如果是简单的应用系统 , 可采用 JSP+BEANS 的结构进行设计 ,JSP 中应该仅仅存放与表示层有关的东西,也就是说,只放输出 HTML 网页的部份。而所有的数据计算,数据分析,数据库联结处理,统统是属于业务逻辑层,应该放在 JAVA BEANS 中。通过 JSP 调用 JAVA BEANS ,实现两层的整合。 实际上,微软的 DNA 技术,简单说,就是 ASP+COM/DCOM 技术。与 JSP+BEANS 完全类似,所有的表示层由 ASP 完成,所有的业务逻辑由 COM/DCOM 完成。 为什么要采用这些组件技术呢?因为单纯的 ASP/JSP 语言是非常低效率执行的,如果出现大量用户点击,纯 SCRIPT 语言很快就到达了他的功能上限,而组件技术就能大幅度提高功能上限,加快执行速度。另外一方面,纯 SCRIPT 语言将表示层和业务逻辑层混在一起,造成修改不方便,并且代码不能重复利用,采用组件技术就只改组件就可以了。 对于复杂的应用,应该采用 ENTITY BEAN 实现数据存取层, SESSION BEAN 实现业务逻辑层,用 JSP 来调用 SESSION BEAN ,由 SESSION BEAN 调用 ENTITY BEAN 。即采用 JSP+EJB 来构建一个复杂的分布式系统。它比 JSP+BEAN 具有更高的吞吐量,可靠性,安全性。综上所述,对简单应用,可采用 JSP+BAEN ,对复杂的应用系统,应采用 JSP+EJB SERVLET 变的无足轻重。用 JSP 完全可替代它。当然不要忘记 structs 阿:)



 
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值