[JSP]JSP基本元素以及和Servlet的对应关系

来源:互联网 发布:js .index 编辑:程序博客网 时间:2024/05/01 16:42

1. JSP页面是由JSP元素构成的:

    1) 和HTML页面有标签构成的概念类似,元素是JSP构成的基本单位;

    2) JSP的基本元素主要有6大类:指示元素、声明元素、Scriplet元素、表达式元素(也称为运算元素)、注释元素和隐式对象;


2. 指示元素:

    1) 指示元素是JSP转译为Servlet源代码时的指导信息,即告知容器应该如何将JSP网页转换为Servlet源代码;

    2) 语法格式:<%@指示类型 [属性="值"]* %>

    3) 最常用的三种指示类型为page、include、taglib:

         i. page:指示转译时的环境信息,比如应该用何种编码转译当前JSP页面为.java源代码;

         ii. include:将别的JSP页面包括进当前页面进行转译;

         iii. taglib:告知容器该如何转译当前JSP页面中的标签库,这在JSTL中会详细讲解;

     4) 同一个元素可以有多个属性,而同一个指示类型可以用多个指示元素来描述,比如:

<%@page import="java.util.Date" %><%@page contentType="text/html" pageEncoding="UTF-8" %>
!这两个元素都是用了同一个指示元素,在第二个指示元素中是用了多个属性,这个可以视具体情况而来,关键就是要让代码清晰易懂、见名知意;


3. <%@page%>的常用属性:

    1) 首先是import属性:

         i. import属性会被转译为Java的import语句,就是在.java源代码中导入包和类,有时会在JSP中出现Java的一些对象表达式,如果不想写这些对象的完整包路径名就必须加入相对应的import属性;

         ii. 多个导入可以写在同一个import属性中,中间用逗号隔开,比如:import="java.util.*, com.lirx.*"

         iii. 当然也可以分多个<%@page%>指示元素编写import属性,通常推荐第二种方法,因为一行一个import非常清晰,不会弄混,更易于代码的维护;

    2) contentType/pageEncoding:

         i. contentType属性告知转译时必须使用HttpServletRequest的setContentType方法设定MIME类型,比如contentType="text/html";

         ii. pageEncoding指示JSP源码使用的文字编码,如果文字中包含非ASCII字符就必须指定正确的文字编码,比如pageEncoding="UTF-8";

         iii. 这两者通常需要放在一个page指示元素中写,这样就会作为一个整体传入setContentType方法:setContentType("text/html;charset=UTF-8");

    3) 其余不是特别常用的属性:

         i. info:其信息可以通过getServletInfo()获取,用于设置JSP页面的基本信息,相当于一种软件说明;

         ii. autoFlush:是否自动冲刷缓冲,默认为true(即自动冲刷),如果为false,则必须手动调用flush方法将缓冲区中的内容送至客户端,如果满了还为冲刷则会产生异常,通常该项保持默认值;

         iii. buffer:输出缓冲区的大小,默认为"8kb",如果有需要可以改变,注意必须指定单位,例如buffer="16kb";

         iv. errorPage:设置如果当前JSP页面产生异常应该转发到哪一个页面来处理这个异常,这在之后会详细讲解;

         v. extends:指示JSP页面转译为Servlet程序后应该继承哪一个类,默认是HttpJspBase,通常这个属性不去动它;

         vi. isErrorPage:设置该JSP页面是否是一个异常处理页面,该属性要与errorPage属性进行配合;

         vii. language:设置JSP页面应该转译成何种语言,这里默认是Java语言,目前世界上还没有开发其它语言来转译JSP,但不过这个扩展性还是被保留了一个位置;

         viii. session:设置是否在转译后创建HttpSession对象来对会话进行跟踪,默认是true,很少有情况是不用到会话管理的,但有时候设置成false可以产生一些奇效;

         ix. isELIgnored:决定是否忽略EL表达式,EL表达式会用到一些Java语言,比如调用Java的某个方法返回一个对象等,如果为true则表示禁用EL表达式,这就意味着禁止在JSP中使用Java语言,如果开发的项目对MVC Model2模式有严格的要求则需要开启这项;

         x. isThreadSafe:设置当前JSP页面是否开启线程安全属性,默认为true,如果为false则转译后的Servlet类会实现SingleThreadModel接口(即单线程,而非多线程),如果程序涉及到多线程则应该开启该项;

    

4. <%@include%>指示元素:

    1) 其只有一个属性,就是file="路径名",该路径名是相对于环境根目录的,比如"/WEB/INF/jspf/header.jspf";

    2) 该元素仅仅就是将另一个JSP页面的完整文字代码包括到当前指示元素的位置,和C语言的#include宏纯文本替换如出一辙,仅仅就是一种纯静态的替换,包括进来后和主体JSP合成为同一个JSP;

    3) 这是一种转译期就已经决定好的;

    4) 如果想进行动态包含JSP代码(就是在执行网页流程过程中再决定“包括”那一段其它的JSP代码)就得使用<jsp:include>标签了,包含和被包含的两个网页各独自生成一个Servlet,其实这不是真正意义上的包括,精确地讲应该是请求调配(内部使用了forward等);


5. 在web.xml中配置统一的JSP行为属性:

    1) 配置的就是上面所有的JSP指示元素中的指示类型和属性,如果在JSP和web.xml中都配置了,则以JSP中的配置为准;

    2) 配置标签:标签层级为<web-app> -> <jsp-config> -> <jsp-property-group>下;

    3) 各项属性标签:

         i. <url-pattern>:JSP的URL模式,决定了那些URL请求会调用该JSP进行服务;

         ii. <page-encoding>:即@page pageEncoding属性;

         iii. <defualt-content-type>:即@page contentType属性;

         iv. <buffer>:即@page buffer属性;

         ...其它不一一列举;

         v. <include-prelude>:JSP页面中开头需要包括的页面,就相当于整个JSP页面的第一句话就是<%@include file="该标签中指示的JSP页面" %>

         vi. <include-coda>:JSP页面中结尾需要包括的页面,就相当于整个JSP页面的最后一句话就是<%@include file="该标签中指示的JSP页面" %>


6. 声明元素:

    1) 声明元素用来编写转以后Servlet所具有的数据成员和成员方法;

    2) 元素格式:<%!成员声明和方法声明%>

    3) 例如:

<%!String name="Peter";String getName() {return name;}%>
!经过转译后就会成为这样:

public final class xxx_jsp extends HttpJspBaseimplements JspSourceDependent {String name="Peter";String getName() {return name;}}
    4) 使用声明元素时一定要注意线程安全问题:

         i. 因为在J2EE标准下Web容器会使用同一个Servlet示例来服务多个用户的请求;

         ii. 而对于每个请求Web容器都会分配一个线程;

         iii. 因此也就是多个线程共享一个Servlet类对象,那么该一个对象中的数据就会同时被多个线程所访问,因此会涉及到线程安全的问题;

         iv. 有必要对<%! %>中所声明的数据进行线程安全处理;

    5) 声明元素中最常见的成员方法就是jspInit和jspDestroy,这两个方法来自HttpJspBase,在该基类中都是空的方法,都是留给用户来定义,因此可以在JSP中声明元素中定义这两个方法进行一些初始化和资源释放工作;


7. Scriptlet元素:

    1) 该元素就是专门用于在JSP中编写Java语句的;

    2) 元素格式:<% Java语句 %>

    3) 通常不建议在JSP中写Java语句,因为这不符合MVC规范,可以将web.xml中<jsp-property-group>标签下的<scripting-invalid>标签定义为true来禁用Scriptlet,这样JSP中的Scriptlet就不会被转译了,而是直接当做注释一样忽略掉了;

    4) Scriptlet示例:

<%for (int i = 0; i < 10; i++) {System.out.println("xxx");}%>
    5) 所有的Scriptlet元素经过转译后都将放到_service方法的try代码块中,各个Scriptlet按照定义顺序出现在try代码块中;

    6) 注意!和声明元素的区别,声明元素中定义的方法都是Servlet中独立的方法,而在Scriptlet中定义的语句都是_service中的语句;


8. 表达式元素:

    1) 也称为运算元素,可以将一个Java语句(或者表达式)的运算结果变成纯字符串返回到元素位置和前后的字符系列相连;

    2) 元素格式:<%=Java表达式%>

    3) 注意!表达式无需加分号,比如"result = <%= new Date()%>"将会被转译为"result = " + (new Date()),因此无需加分号,这仅仅表示一个返回结果而已;

    4) 表达式元素也是转译到_service的try体中的,Web容器会将表达式元素、Scriptlet元素按照JSP中编写的顺序统一放到_service方法的try体中;


9. 如果想在JSP中写<%或%>的纯字符:

    1) 在JSP中<%和%>会被当成特殊符号,即元素的开始和结束符号;

    2) 如果想在JSP中把这两个符号当做纯字符输出则必须进行转义;

    3) %符号不需要转义,但是<和>需要转义,转义符号和HTML一样,都是&lt;和&gt;,但是>也可以用\进行转义,即\>也表示>的纯字符;


10. 注释元素:

    1) 用来在JSP源码中进行注释;

    2) 元素格式<%--注释内容--%>

    3) 注释后的内容不会转译到.java源文件中;

    4) 还有两种注释容易和JSP注释元素混淆:

         i. Java注释:比如在Scriptlet的Java代码中进行注释,使用\\和/* */,但不过这些注释都会原木原样地写入转译后的.java源代码中;

         ii. HTML注释:即使用<!--注释内容-->的注释,这个会被转译为out.write("<!--注释内容-->");,这些注释仍然会作为返回的HTML页面的一部分传给用户,用户在查看网页源码的时候仍然可以看到这些HTML注释,只不过网页经过浏览器解释后不会出现注释内容而已;


11. 隐式对象简介以及out对象的效果:

    1) 就是先前讲到过的在_service中定义的各种局部对象,诸如out、request等;

    2) 之所以称之为“隐式”,是因为这些对象要么在作用时根本看不到其存在,比如out在作用时从来都不会出现out的引用(即JSP代码中不出现out这个字眼),还有一层含义是,在JSP源码中看不到这些对象的定义,但是可以直接使用(因为定义是在转译后的.java文件中定义的);

    3) 由于隐式对象是_service中定义的局部变量,因此也就只能在Scriptlet元素和表达式元素中使用,而不能在声明元素中使用!!

    4) 全部隐式对象:

JspWriter out; // 用于输出HttpServletRequest request; // 请求对象HttpServletResponse response; // 响应对象ServletConfig config; // Servlet配置信息ServletContext application; // 应用程序环境信息HttpSession session; // 会话管理PageContext pageContext; // JSP页面资源的封装Throwable exception; // 接受其它页面抛出的异常,只有在处理错误的JSP页面中会使用它HttpJspBase page = this; // 代表Servlet本身,主要是为了让不熟悉Java的用户可以较直觉地使用page进行存取

    5) 首先是无处不在的out对象及其效果:

         i. 在JSP源码中,除了元素定义之外的所有字符串都会被转译成out.write("内容");

         ii. 例如:

<html>  <head>
!就会被转译为out.write("<html>\n  <head>");

         iii. 对!连续多行文字之间的换行符\n也会被写入,因此像这样的JSP代码:

<%@page import="java.util.Date"%><%@page contentType="text/html"%>
!就会被转译成:

<pre name="code" class="html">import java.util.Dateout.write("\n");request.setContent("text/html");out.write("\nhello!");

         iv. 即,连续的多行文字,如果中间没有定义其它JSP元素,则全部用一个out.write输出,多行之间用\n进行连接,不放过任何一个字符;

         v. 在上例中,指示元素后面的两个\n也被输出了,那么这样在hello!之前就会有两个空行,通常不希望这样,因为这样影响页面的艺术设计,因此可以在web.xml中配置该功能:将<jsp-property-group>的<trim-directive-whitespaces>标签定义为true就能忽略指示元素后面的所有空白符(包括空格、制表和换行);

!!该标签默认情况下就是true!

12. out对象的大致实现:

    1) out是JspWriter的对象,并非PrintWriter的对象,而JspWriter直接继承于Writer类;

    2) JspWriter和PrintWriter不同,它具有双重功能,它里面包含了PrintWriter类对象和BufferedWriter类对象,因此即具有前者的输出功能,也具有后者的缓冲功能;

    3) JspWriter的缓冲功能可以自己决定开不开启,如果开启了缓冲功能,那么在使用JspWriter的print、println、write等进行输出时只有在flush缓冲区时才会创建其内部的PrintWriter对象,并把缓冲区中的内容flush到该对象中进行输出,如果没开启缓冲功能,则直接创建其内部的PrintWriter对象进行输出;

    4) 该缓冲区可以由page指示元素的buffer和autoFlush两个属性共同管理,buffer可以设置缓冲区大小,默认为8kb,autoFlush为true时表示缓冲区一满就冲刷,如果为false则表示需要手动调用flush进行冲刷,如果满了还未flush则会直接抛出异常;

13. pageContext隐式对象:

    1) 该对象封装了所有JSP页面的信息,几乎有关该JSP的所有信息都可以获取;

    2) 其实其它隐式对象都是用pageContext初始化的,这在_service转译后的源码中可以看到:

application = pageContext.getServletContext();config = pageContext.getConfig();out = pageContext.getOut();...
    3) 除了封装了所有JSP页面信息之外还可以往里面添加属性并获取自己添加的属性:

         i. 使用的方法还是setAttribute和getAttribute,以及使用removeAttribute删除属性;

         ii. 这三个方法的使用方式和HttpServletRequest、HttpSession、ServletContext的相应方法完全相同;

         iii. 此外,PageContext还对这三个方法提供了扩展,也就是分别还重载了一个版本,那就是多了一个参数int scope,即:

Object getAttribute(String name, int scope);void setAttribute(String name, Object value, int scope);void removeAttribute(String name, int scope);
!这个scope就是指这三个方法作用于那个范围,总共有4个范围,用以下4个常数来指定:

pageContext.PAGE_SCOPE:整个PageContext的范围

pageContext.REQUEST_SCOPE:request对象的范围内

pageContext.SESSION_SCOPE:session对象的范围内

pageContext.APPLICATION_SCOPE:ServletContext的那个application对象的范围内

!比如pageContext.setAttribute("name", "Peter", pageContext.REQUEST_SCOPE);就相当于request.setAttribute("name", "Peter");

    4) 其余的pageContext和设置属性相关的方法:

         i. Enumeration<String> getAttributeNamesInScope(int scope); // 返回指定对象范围的全部属性的名称

         ii. int getAttributeScope(String name); // 返回指定属性名的属性所属的范围,返回结果就是上述4个常数值

         iii. Object findAttribute(String name); // 在所有范围中寻找指定名称的属性,并返回其值

!!在ii.和iii.中,可能存在这样的情况,就是两个对象具有相同名称的属性,这两个方法都会在所有对象中寻找,只不过找的顺序是page、request、session、application,找到第一个就立即返回!!所以这里要注意,如果想找到全部的就最好分别到每个范围中去找,以免漏掉!!



0 0
原创粉丝点击