《初识JSP》

JSP的基本知识

一. JSP是什么

  1. 英文名:Java Server Page(Java服务器页面)

  2. 特点:在HTML页面中嵌入Java代码片段,或使用各种JSP标签,其中包括用户自定义的标签,从而可以动态地提供页面内容。

  3. 其实原来的SP不仅充当着表现层的角色,还承担着业务逻辑的实现以及持久层组件的责任,但是,随着时间的推移,加上Java EE的标准的出现,又加上MVC的设计思想,让JSP充当多面手是不切实际的。渐渐地,JSP自己独立了出来,发展成只充当表现层的角色,而且很好地实现了动态网页技术(但目前流行的动态网页技术还有Asp.net,Php等)。

  4. 它是Java EE规范的成员之一,另一个成员是Servlet。虽然说其名字和Servlet风马牛不相及,但是它本质上也是一个Servlet。你可以把它想象成只是生成Servlet所需的draft(“草稿‘)文件,它最终也必须被编译成一个特殊的Java类–Servlet才能运行,但这项工作是Web容器自动帮我们做的,我们不必操心。

  5. 总之,JSP的本质是Servlet,当用户向指定的一个Servlet(由JSP转换而来)发送Request时,Servlet利用输出流(out)对象动态生成HTML页面,其中包括每一个静态的HTML标签和所有在HTML页面中出现的内容。



二. JSP的组成

JSP由两大部分组成:

1. 静态部分

标准的HTML标签、静态的页面内容。


2. 动态部分

由Java脚本动态生成,受Java程序的控制。经常用以与数据库的交互或其他需要动态生成的页面。



三. JSP的语法之注释

1. 显示注释[客户端可见]:

容器会将它直接发送给客户,在客户端,浏览器会将其解释为注释,客户可以通过点击查看网页源代码查看到。

格式:

<!-- HTML注释 -->


2. 隐式注释[客户端不可见,你只能看到空白行]

a. 标准的JSP注释

格式:

<%-- JSP注释 --%>



b. 标准的Java注释

格式:

<%

//单行注释

/*
  多行注释
*/

%>



c. 上面两种注释是为页面开发人员提供的,转换JSP页面时会将上面两种注释去掉。如果你键入一个JSP,想放些注释来说明你要做什么,就要像Java源文件中加注释一样地使用JSP注释。​



四. JSP语法之Scriptlet

所谓Scriptlet,是包含在<% %>之间的Java代码,表示脚本小程序,所有嵌入HTML中的java代码都必须使用Scriptlet标记出来。

1. 定义局部变量

格式:

<% 声明部分 %>

a. 它会将你在里面声明的内容转换成对应的Servlet中的_jspService()方法中的可执行代码。


b. 你在里面声明的变量会成为_jspService()方法中的局部变量。


c. 不能使用private、public等访问控制修饰符修饰,也不能使用static修饰。


d. 不能声明方法, 根据Java语法可知不允许在方法(_jspService())里定义方法.


2. 定义全局变量,方法,类

格式:

<%!声明部分 %>

a. 它会将你在里面定义的变量和方法转换成对应的Servlet中的成员变量或成员方法。


b. JSP声明部分定义的变量和方法可以使用private、public等访问控制修饰符,也可使用static修饰符将其变成类属性和类方法。


c. 不能使用abstract修饰声明部分的方法,因为抽象方法会导致JSP对应的Servlet类变成抽象类,从而导致无法实例化,当然,客户提交的请求也就没法处理了。


3. 定义表达式,输出一个变量或者具体的一个内容

格式:

<%=表达式 %>

a. 输出表达式后面不能带分号。


b. 容器拿到你在<%=和 %>之间键入的所有内容,并把它作为参数传递给打印语句,打印到隐式相应对象PrintWriter out ,并调用out.print()方法。

(这里要注意不是out.write()方法,out.write()一般的参数为JSP页面中HTML的各种标签的字符串形式)

eg:

容器看到:

<%!= Counter.getCount() %>

会将它转换为:

out.print(Counter.getCount());



c. 在表达式中的方法如果没有返回任何结果,会报错。容器很聪明,它知道,如果方法的返回类型为void,则打印不出任何东西。


d. 如果表达式是一个类的实例对象,则会打印该对象的toString()方法的结果。



五. JSP所生成的Servlet的API

当客户的一个请求过来时,web容器就根据你的JSP生成一个类,这个类实现了HttpJspPage接口。

继承树:
111


1. jspInit()

这个方法由Servlet的init()方法调用,可以覆盖该方法。


2. jspDestroy()

这个方法由Servlet的destroy()方法调用,可以覆盖该方法。


3._jspService()

a. 这个方法由Servlet的service()方法调用。这说明,对于客户的每个请求,它会在一个单独的线程中运行,容器会将封装好的Request和Response对象传递给这个方法。


b. 不能覆盖该方法。对于这个方法,我们什么也做不了,不过你在JSP中编写的代码会放在其中。


Notice:

_jspService()前面还有个下划线,你可以这样认为,前面的下划线的是在表示“Don’t touch me!”,哈哈,就记住了该方法不能被覆盖。如果方法前面没有下划线,就可以覆盖它了~~。


Summary:

当jsp文件第一次被处理时,他会被转化成一个servlet。jsp引擎首先把jsp文件转化成一个java源文件,如果在转化过程中发生错误的话,会立刻中止,同时向服务器端和客户端发送错误信息报告;如果转化成功了,就会产生一个class类。然后再创建一个 Servlet对象,首先执行jspInit()方法进行初始化操作,由于整个执行过程jspInit()方法只执行一次,所以可以在这个方法中进行一些必要的操作比如连接数据库,初始化部分参数等等,接着执行_jspService()方法,对客户端的请求进行处理,对每一个请求会创建一个线程,如果同时有多个请求需要处理的话就会创建多个线程,由于servlet长期贮存于内存中,所以执行速度快,但是由于初始化需要编译,所以第一次执行还是比较慢的,如果由于某种原因导致jsp网页关闭或者销毁的话会执行jspDestroy()方法。



六. 用白话一探JSP的LifeCycle(生命周期)

本人喜欢看哆啦A梦,第三方就用大雄替代~~

Step 1

大雄写了一个.jsp文件,并部署为Web应用的一部分。容器就读取这个应用的web.xml(DD), 但是对.jsp文件不做任何处理(直到得到第一个请求)。此时,大雄的.jsp就一直待在服务器上,等待客户发出请求,好苦逼。。。


Step 2

终于!客户来了!客户在网页点击了一个链接,请求了大雄编写的这个.jsp。容器尝试将.jsp转换为一个servlet类的.java源代码。在这个阶段就可以发现大雄的.jsp文件有没有语法错误,毕竟大雄很粗心的,大雄马上祈祷了起来。。。


Step 3

大雄很开心,.jsp文件没有语法错误!但是,还高兴得太早! 容器还会尝试将这个servlet .java源文件编译成一个.class文件,一切的java语法错误在这里都展露无遗,大雄只能继续祈祷。。。


Step 4

没有java语法错误!大雄喜出望外!此时容器加载新生成的servlet~~


Step 5

容器实例化servlet,并导致servlet的jspInit() 方法被调用,现在终于成为了一个真正的servlet对象,一切准备就绪,可以接受客户请求了!


Step 6

容器创建一个新线程来处理客户的这个请求,导致servlet的_jspService()方法被调用并运行。此后发生的所有事情都只是普通的servlet请求处理~~


Step 7

最终servlet向客户发回一个响应(或者将请求转发到另一个Web应用组件),大功告成~~


Notice:

  1. 从上面可以看到,在整个JSP生命周期中,整个转换和编译步骤只发生了一次。JSP一旦经过转换和编译,就像其他servlet一样了。

  2. 从上面可以知道,只有第一个请求JSP的客户才会等得长一些,但是,肯定有法子将服务器配置成完成预转换和编译吧?
    Sure,如今大多数容器开发商确实提供了一种方法,可以让整个转换和编译过程提前进行,这样甚至第一个请求也能像所有其他servlet请求一样很快地得到处理。但是,要注意,这取决于具体地开发商,而且不能得到保证。JSP规范中确实提到了一种推荐的JSP预编译协议,感兴趣的朋友可以自行上网了解一下~~



七. JSP的三个编译指令

编译指令在将 JSP被编译成 Servlet时生效,是一种通知 Servlet引擎的处理信息。

基本格式:

           <%@ 编译指令名称 属性名=“属性值”,...%>


1. page

定义页面特定的属性,为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令,但page指令至多可以使用13个不同的属性。

属性:

  • language:声明JSP脚本的语言,默认为“java”。
  • extends:指定servlet从哪一个类继承。
  • import:导入我们需要的java包。
  • session:设定该页面是否需要HTTP Session。
  • buffer:指定out对象使用缓冲区的大小。
  • autoFlush: 当输出缓冲区即将溢出,设置缓冲区是否要强制输出其中的内容。
  • info:设置JSP的相关信息或说明。
  • errorPage:指定错误处理页面。
  • isErrorPage: 设置该页面是否为错误处理页面。
  • contentType:指定生成网页时使用的文件格式(MIME类型)和编码字符集。默认分别为text/html,ISO-8859-1。
  • pageEncoding:指定生成网页的编码字符集。
  • isThreadSafe:指定对JSP页面的访问是否为线程安全。
  • isELIgnored:指定是否执行EL表达式。
  • isScriptingEnabled:确定脚本元素能否被使用。


2. include

定义在转换时增加到当前页面的文本或代码,可想而知,这样从而允许你建立许多可重用的块,比如页面标题或导航栏,节省时间和人力。这些可重用的块可以增加到各个页面中,而不必在每个JSP都重复写所有这些代码。

所以,当你想要将一个外部文件(不管是JSP文件、HTML文件或文本文件)嵌入你的JSP文件中时,就要使用该指令。被包含的文件就好像是该JSP文件的一部分,会被同时编译和执行。同时该指令是一个静态的include指令,会将目标页面的其他编译指令包含进来,下面要介绍的动态的include指令则不会。


3. taglib

该指令允许用户自定义标签,一个自定义标签库就是自定义标签的集合。该指令用于引入一个自定义标签集合的定义,包括库路径、自定义标签。


Notice:

  1. include指令是唯一一个对位置敏感的指令,所包含的内容会插入到页面中的include指令所在的位置。

  2. include指令实际上只是复制了被包含文件中的所有内容,然后将它黏贴到有include指令的页面中。最后,容器将所有被包含的文件的内容整合起来,只编译一个文件来生成servlet。所以在运行时,有include指令的页面将成为一个“大”页面,就像是你把所有源代码键入到一个文件中一样。



八. JSP的七个动作元素

与JSP指令元素不同的是,JSP动作元素在请求处理阶段生效。JSP动作元素是用 XML语法写成的。

基本格式:

           <jsp: 动作元素名称 属性名=“属性值”,.../>
1.jsp:forword

执行页面跳转。在页面被请求的时候引入一个文件,并将客户请求转发到该文件。


2. jsp:param

传递请求参数。使用名值对的形式,不可单独使用。


3.jsp:include

动态引入一个JSP页面。

这就是上面提到的动态的include指令。动态引入实质上只是使用一个include方法来插入目标页面的body中的内容(不包括目标页面的其他编译指令),而不是将目标页面完全融入到当前页面中。除此之外,该动态include指令还允许指定额外的请求参数。


4. jsp:plugin

下载JavaBean或Applet到客户端执行。目前很少用了,毕竟有HTML的存在。


5. jsp:useBean

新建一个JavaBean的实例对象。


6. jsp:setProperty

设置JavaBean实例对象的属性值。


7. jsp:getProperty

获取/输出JavaBean实例对象的属性值。


Notice:

  1. 静态的include指令使用的是”file”属性,而动态的include指令使用的是“page”属性。
  2. 对被包含的资源有一些限制:它不能改变响应状态码或设置首部。



九. JSP的九大内置/隐式对象

JSP隐式对象也被称为预定义变量,是JSP容器为每个页面提供的Java对象。JSP脚本中包含了9个内置对象,都是Servlet API接口的实例,只是JSP规范对它们都进行了默认的预先初始化,具体是由JSP页面对应的Servlet中的_jspService()方法来创建这些内置实例对象。它们已经是对象了,所以我们可以直接在我们的JSP脚本中直接引用其对象名。

1.application

a. ServletContext类的实例,该实例代表JSP所属的Web应用本身。

b. 该对象在JSP页面的整个生命周期中都代表着这个JSP页面,在JSP页面初始化时被创建,随着jspDestroy()方法的调用而被移除。

c. 常用方法:getAttribute、setAttribute、getInitParameter


2.config

a. ServletConfig类的实例,该实例代表JSP的配置信息。

b. 常用方法:getInitParameter、getInitParameternames


3.exception

a. Exception类的实例,该实例代表其他页面中的异常和错误对象。

b. 该对象包装了从先前页面中抛出的异常信息,它通常被用来产生对出错条件的适当响应。

c.常用方法:getMessage、printStackTrace


4.out

a. JspWriter类的实例,该实例代表JSP页面中的输出流。

b. JspWriter类包含了大部分java.io.PrintWriter类中的方法。不过,JspWriter新增了一些专为处理缓存而设计的方法。还有就是,JspWriter类会抛出IOExceptions异常,而PrintWriter不会。

c.常用方法: print、println、flush


5.page

代表页面本身,类似于Java类中的this关键字。


6.pageContext

a.PageContext类的实例,该实例代表该JSP页面的上下文,使用该对象可以访问页面中的共享数据。

b. 该对象存储了request对象和response对象的引用。application对象,config对象,session对象,out对象都可以通过这个对象得到。

c.常用方法:getServletContext、getServletConfig


7.request:

a. HttpServletRequest 接口的实例,该实例封装了客户的一次请求,客户端的请求参数都被封装在其中。

b. request对象提供了一系列方法来获取HTTP头信息,cookies,HTTP方法等等。

c.常用方法:getParameter、getParameterValues、setAttribute、getAttribute、setCharacterEncoding


8.response:

a.HttpServletResponse 接口的实例, 该实例代表服务器对于客户端的响应。

b. response对象也定义了处理HTTP头模块的接口。通过这个对象,我们可以添加新的cookies,时间戳,HTTP状态码等等。

c.常用方法:getOutputStream、sendRedirect


9.session:

a.HttpSession类的实例 ,该实例代表服务端和客户端的一次会话。

b.常用方法:getAttribute、setAttribute


猜你喜欢

转载自blog.csdn.net/wuchangi/article/details/80208990