JavaJsp(二)

来源:互联网 发布:法治网络知识大赛登录 编辑:程序博客网 时间:2024/06/07 07:44
第一、JSP是什么?
JSP全称是Java Server Pages,它和Servlet一样,都是用来开发动态web资源的技术,说白了就是做动态网页的。


可以这么认为:JSP就是Servlet。从本质来讲,它们两个没有任何区别。因为所有的jsp文件都会被jsp引擎翻译成对应的.java
文件,当然也会编译成对应的.class文件,可以在对应的服务器目录查看,如:Tomcat服务器,
D:\JAVA\apache-tomcat-7.0.32-windows-x86\apache-tomcat-7.0.32\work\Catalina\localhost
大家到对应目录查看就知道,不过jsp,需要客户端访问过jsp才会看见对应的servlet。
------------------------------------------------


第二、既然Servlet已经可以用来做动态网页,为什么还需要JSP技术呢?
主要的原因是Servlet做界面设计太困难了。
Servlet向网页输出内容,需要使用write()或print()方法,假如现在要把一大串的HTML代码写到网页上,并且还要排版,这时候依靠write()或print()方法输出HTML代码实在太麻烦。
如果这个时候该HTML还配合CSS和javascript还使用,那这些代码全部都要通过write()或print()方法来输出,那有多累人啊……
因此,JSP的推出很大程度是为了解决这个问题,我们使用JSP技术来做html页面非常的美观和方便,甚至就算有CSS和javascript代码在html页面里面都没问题,JSP能够处理得很完美。


------------------------------------------------




第三、JSP入门示例
写一个显示当前时间的JSP页面:
在Web工程的WebRoot文件夹右键 --> 新建JSP页面
既然Servlet可以写java代码,那么JSP也可以写java代码,使用<% %>
  当前时间为:
  <%
  java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  out.write(format.format(new java.util.Date()));
  %>


------------------------------------------------


第四、JSP的运行原理
当IE浏览器访问JSP页面的时候,Web服务器是如何调用并执行一个JSP页面的呢?


找到tomcat目录下的work文件夹,打开jsp转换成servlet代码的*.java文件:
public final class _1_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {}


我们的jsp页面继承了HttpJspBase类,而HttpJspBase类是什么呢?
打开tomcat的源代码,我们发现HttpJspBase继承了HttpServlet,原来“JSP就是Servlet”!


通过JSP的源码,快速了解JSP的内置对象
    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;




运行原理:
当服务器Tomcat把带有JSP的网站部署完毕之后,并不会马上把JSP翻译成Servlet。
而是当某个用户的IE浏览器第一次访问JSP页面的时候,服务器Tomcat才把该JSP页面翻译成Servlet代码,并编译成*.class文件加载到内存当中同时生成实例给用户访问。
接着下来如果别的用户的IE浏览器要访问此JSP页面的时候,直接访问服务器内存里的JSP对应的Servlet实例就行了。
所以有时候我们感觉第一次访问JSP页面的时候会慢,而第二次之后访问JSP页面会变快就是这个原因了。
当然,这里虽然说第二次之后速度快,这是建立在JSP文件没有被修改的基础之上,如果JSP引擎发现JSP的文件修改过,那么JSP引擎会把这JSP文件重新翻译成Servlet之后再生成*.class文件。


------------------------------------------------


第五、JSP最佳实践
既然JSP做界面设计比servlet好,那是不是意味着以后干脆不要用servlet,而全部都使用jsp来代替呢?
不管是JSP还是Servlet,虽然都可以用于开发动态web资源。但由于这2门技术各自的特点,在长期的软件实践中,
人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
其原因为,程序的数据通常要美化后再输出:
让jsp既用java代码产生动态数据,又做美化会导致页面难以维护。让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护。


因此最好的办法就是根据这两门技术的特点,让它们各自负责各的,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做。


总结一句话:JSP以后专门负责显示页面数据,而Servlet专门做请求数据处理。
为什么要这样子?因为如果把处理数据的工作也放在JSP里面,那么JSP既要处理数据,又保设计美观的界面,到时JSP页面不但有java代码,而且还有html、javascript、css的代码,页面会变得很乱,很难维护。


Servlet: 专门负责处理用户的请求
JSP: 专门显示数据组用户看
MVC模式: 
M:model   --> javabean
V:view    --> JSP
C:control --> Servlet


------------------------------------------------
JSP语法的学习


要学习JSP,就必须要学习它的语法,JSP的语法分为以下几部份:
1. JSP模版元素
2. JSP脚本表达式
3. JSP脚本片断
4. JSP声明
5. JSP注释
6. JSP指令


------------------------------------------------


第一、JSP模版元素
JSP页面中的HTML内容称之为JSP模版元素。
JSP模版元素定义了网页的基本架构,即定义了页面的结构和外观。




------------------------------------------------


第二、JSP脚本表达式
JSP表达式(expression)用于将程序数据输出客户端。
语法:<%= 变量或表达式 %>
举例:当前时间:<%= new java.util.Date() %>
<%="ABC" %> 相当于 <%out.write("ABC");%>
------------------------------------------------


第三、JSP脚本片断 
JSP脚本片断(scriptlet)用于在JSP页面中编写多行java代码。
语法:
<% 多行java代码 %>
例如:
<%
  java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  out.write(format.format(new java.util.Date()));
%>
JSP脚本片断中只能出现java代码,不能出现其它模版元素,JSP引擎在翻译JSP页面中,会将JSP脚本片断中的java代码原封不动的放到Servlet的_jspService方法中。
JSP脚本片断中的java代码必须严格遵守java语法。


在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。
例如:
<%

int x = 10;

out.println(x);


%><p>这是JSP页面文本</p>


<%

int y = 20;

out.println(y);

%>
多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况。如:out.println(x);


单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句。
例如:
<%

for (int i=1; i<5; i++) 

{


%>



<H1>www.itcast.cn</H1>




<%

}


%> 
演示之后看jsp源码。
------------------------------------------------


第四、JSP声明
刚才我们学习了“JSP脚本表达式”和“JSP脚本片断”,它们都是放在Servlet的_jspService方法中的。
思考一下,我们能不能使用“JSP脚本表达式”来声明一个方法?
如:
<%
public void method() {
System.out.println("method()");
}
%>
很显然是不行的,但有时候我们需要通过JSP来声明一些属于自已的方法怎么办?这时候我们可以使用“JSP声明”。


JSP声明的语法格式是:<%! java代码 %>
JSP声明的代码最终会翻译到_jspService方法的外面,也就是作为Servlet类的成员(变量和方法都可以)。
所以,JSP声明可用于定义JSP页面转换成Servlet程序的静态代码块、成员变量或成员方法。
演示:
<%!
public void method() {
System.out.println("method()");
}
%>
<%!
static {
System.out.println("staic ");
}
%>

<%!
int a = 9;
%>
<%!
static int b = 99;
%>
多个静态代码块、变量和方法可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
JSP隐式对象的作用范围仅限于Servlet的_jspService方法中,所以在JSP声明中不能使用这些隐式对象。


------------------------------------------------


第五、JSP注释
我们可以为JSP添加注释,格式如下:
<%-- JSP注释 --%>
JSP注释的区域不会在翻译后的Servlet代码里显示,JSP注释专门用来注释java代码的。


思考:jsp和html注释有什么区别?
<%-- JSP注释--%>
<!-- html注释 -->
答:html注释是用户可见的,比如你现在点击右键,查看源代码,源文件什么的,是可以看得到html注释的。
而jsp注释是不可见的,也就是说你查看源代码是没法查看这个jsp注释的。
总得来说,html注释,是(可能是,因为很少人蛋疼地去查看源文件以获得帮助)服务于用户的。而jsp注释是服务于程序员的。


------------------------------------------------


第六、JSP指令
JSP引擎是什么?我们写的JSP代码最终会被翻译成Servlet代码,而这个翻译的过程必定是由某个程序来执行的,这个程序就称为“JSP引擎”。
简单把“JSP引擎”想像成是Tomcat就行了。


JSP指令(directive)是为“JSP引擎”而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
在JSP 2.0规范中共定义了三个指令:


1. page指令


2. Include指令(不讲)


3. taglib指令(不讲)






1. page指令
<%@ 指令 属性名="值" %>
举例:<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。例如:<%@ page contentType="text/html;charset=gb2312"%><%@ page import="java.util.Date"%>也可以写作:<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
JSP2.0规范中定义的page指令的完整语法:
<% page
[ language="java" ]
[ import="{package.class | package.*}"]
JSP引擎自动导入下面的包:
java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*

使用import指令可以在一条page指令中引入多个类或包,其中的每个包或类之间使用逗号分隔。
如:<%@ page import="java.util.Date, java.sql.:*, java.io.*" %>
上面语句也可以使用多条page指令来写:
<%@ page import="java.util.Date" %>
<%@ page import="java.sql.*" %>
<%@ page import="java.io.*" %>


[ session="true | false" ]
控制JSP页面里的java脚本是否允许直接使用session。
假设设置为true,我们在翻译后的JSP代码可以看到:
    HttpSession session = null;
        session = pageContext.getSession();
假设设置为false,那就没有session被创建。
因为在IE6.0后每个用户对应一个session,如果用户多的话session会相应的增多,服务器的压力就会加大,所以JSP提供了session可开可关的设置。
这里要注意一点,如果没有任何配置的情况下,session在关闭浏览器30分钟后才会消失。


[ isThreadSafe="true | false" ]
实现SingleThreadModel接口,这个不推荐配置。


[ errorPage="relative_url" ]
errorPage属性用来指定当前JSP页面抛出异常后的跳转的JSP页面位置。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" errorPage="/error.jsp" %>
<%
int a = 10 / 0; // 此代码报错后将自动跳转到error.jsp页面
%>
errorPage="/..." 这里的/表示Web工程的根目录。建议养成习惯,写errorPage的时候先写/


可以在web.xml文件中使用<error-page>元素为整个web应用程序设置错误处理页面,其中的<exception-type>子元素指定异常类的完全限定名,<location>元素指定以“/”开头的错误处理页面路径。
如果1.jsp 2.jsp 3.jsp...页面里都有异常,那为每个JSP页面都配置errorPage是很麻烦的,现在提供一种方式,在web.xml文件里面配置“全局异常”,这样就不需要在每个JSP页面里都配置了。
web.xml
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>


[ isErrorPage="true | false" ]
设置此jsp网页是否为错误处理页面。默认值为”false”。当设置为”true”时,jsp页面将可存取隐含的exception对象,并通过该对象取得从发生错误之网页所传出的错误信息。取得错误信息的语法如下:<% =exception.getMessage()%>


[ contentType ]
设置jsp网页输出时数据时,所使用的字符压缩方式,以及所使用的字符集,当编写中文网页时,设置如下:
<%@page contentType=”text/html;charset=Gb2312”%>
此属性的默认值为”text/html;charset=ISO-8859-1”。
[ buffer ]
设置jsp网页的缓冲区大小,默认为”8k”,如果设置为”none”,则表示不使用缓冲,所有的响应输出都将被PrintWriter直接写到ServletResponse中。




下面讲一个重点内容:使用page指令解决JSP中文乱码问题
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" contentType="text/html;charset=utf-8"%>
pageEncoding与contentType属性的设置问题




------------------------------------------------
JSP隐式对象讲解:


JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。
JSP技术的设计者为方便开发人员在编写JSP页面时获得这些web对象的引用,特意定义9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。


JSP的9大隐式对象:
1. request        --> HttpServletRequest
2. response       --> HttpServletResponse
3. session        --> HttpSession
4. application    --> ServletContext
5. config         --> ServletConifg
6. out            --> JspWriter --> PrintWriter
7. page           --> this
8. exception      --> 别的页面报错后导航到此页面的异常信息
9. pageContext    --> 当前页面


------------------------------------------------------------------


page对象就是指当前JSP页面本身,有点像this指针,它是java.lang.Object类的实例。
在JSP页面中,很少使用page对象。


------------------------------------------------------------------


out隐式对象讲解:
out隐式对象用于向客户端发送文本数据。 


out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。 


JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,
设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。 只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,
并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:(1) 设置page指令的buffer属性关闭了
(2) out对象的缓存功能
out对象的缓冲区已满
(3) 
整个JSP页面结束


看以下JSP程序:
  <%
  out.write("aaa");
  response.getWriter().write("bbb");
%>
思考一下,先打印aaa,还是先打印bbb ?
结果是先打印bbb,再打印aaa。 这是为什么呢?
[画图解释运行原理]
因为out是JspWriter类的,而out.write("aaa")会先把aaa放在JspWriter的缓冲区,接着response.getWriter().write("bbb")会把bbb放在response的缓冲区。
然后在JSP页面结束后,JspWriter会把自已缓冲区的内容刷到response缓冲区里面,因此aaa此时在bbb后面。


再思考下面的程序,看看先打印什么:
<html>
  <head>
  </head>
  aaa
  <body>
  <%
  response.getWriter().write("bbb");
%>
  </body>
</html>
答案是还是跟刚才一样:先打印bbb,再打印aaa
因为当JSP翻译成Servlet的时候,会把aaa放在out.write里面输出。


------------------------------------------------------------------


pageContext对象讲解
pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境。
pageContext对象有以下三个特点:
1. pageContext封装了对其它8大隐式对象的引用(除去pageContext本身剩下8个呵呵)。
2. pageContext自身还是一个域对象,可以用来保存数据。
3. pageContext还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。


pageContext这个域对象是四大域对象当中范围最小的一个,只在某个JSP页面中有效,出了JSP页面就失效了。




pageContext的域问题:
pageContext本身可以通过setAttribute()和getAttribute()方法来设置或获取数据。
pageContext还可以通过以下方法来获取别的域对象里的数据:
getAttribute(String name, int scope)
通过这个方法可以取得request、session、application域对象里的数据。
例如:
  <%
  application.setAttribute("name", "xxxyyy");
  String name = (String)pageContext.getAttribute("name", pageContext.APPLICATION_SCOPE);
  out.write(name);
%>
代表各个域的常量


PageContext.APPLICATION_SCOPEPageContext.SESSION_SCOPE


PageContext.REQUEST_SCOPEPageContext.PAGE_SCOPE 


pageContext还有一个非常重要的方法:findAttribute(String name)
findAttribute()方法可以从四个域中查到数据,这里重点要知道:
findAttribute()查找四个域的顺序是:
第一、先找pageContext
第二、接着找request
第三、再找session
第四、最后找application


pageContext还可以引入和跳转到其它资源
  pageContext.forward("/index.jsp");