Hey, Nice to meet You. 

必有过人之节.人情有所不能忍者,匹夫见辱,拔剑而起,挺身而斗,此不足为勇也,天下有大勇者,猝然临之而不惊,无故加之而不怒.此其所挟持者甚大,而其志甚远也.          ☆☆☆所谓豪杰之士,

重温JSP技术的使用

1、前言

大家应该都很清楚,JSP也是一种古老的技术了,在实际的项目中现在基本不用了,或许在很老的项目中可以看到。而现在 在前后端分离的时代,后端只需要返回JSON给前端就可以了,页面完全不需要后端管。那我们还需要学习JSP吗?要呀!尤其对于新手来说,JSP肯定要学习的,但是可以不用深入的学习JSP的各种内容,但至少再看到JSP的时候,你能知道什么是JSP,能看懂JSP的代码。而且对于新手来说,刚刚开始学习JavaWeb的时候,前端页面更多使用的是JSP。所以不要求JSP很精通,但起码看到要会使用吧。虽然现在市面上有许多代替JSP的产品了,如常见的模板引擎如:Freemarker、Thymeleaf、Velocity等。它的用法跟JSP差不太多,但JSP出现的最早,它是大哥,所以我们还是跟着大哥一步一步的走吧。

2、JSP技术的简介

JSP是Java Server Pages的简称,即Java服务器页面。它是由Sun公司倡导的一种用于开发动态网页的技术标准。其特点就是在传统的网页HTML文件(*.htm、*.html)中插入Java程序段(Scriptlet)和JSP标记(Tag)。从而形成JSP文件(*.jsp)。其中HTML提供静态的数据,而JSP技术允许在页面中嵌套Java代码,所以它提供动态数据,不过一般不会在JSP页面中编写Java代码,只是在JSP页面中动态获取数据。

其实JSP本身就是一种Servlet。因为JSP在被访问后会被编译为一个Java类,该类继承了HttpJspBase,而HttpJspBase类又继承了HttpServlet。所以我们访问JSP时,其实不是在访问JSP,而是在访问JSP编译过后的那个Servlet。因为Servlet输出HTML非常困难,所以JSP就是替代Servlet输出HTML的。

JSP技术的特点:JSP技术所开发的web应用程序是基于Java的,它拥有Java跨平台的特性,以及业务代码分离,组建重用,基础Java Servlet功能和预编译功能。

  • 跨平台:由于JSP是基于Java语言的,因而它可以使用Java的API,所以也是跨平台的,可以应用在Windows、Linux、Mac和Solaris。
  • 业务代码分离:采用JSP开发的项目,通常使用HTML语言来设计和格式化静态页面内容,而使用JSP标签来实现动态部分,业务代码通常使用Servlet、Struts、Springmvc等业务控制层来处理,从而实现业务层和视图层分离,这样,JSP只负责显示数据即可,这样,修改业务代码不会影响JSP页面代码。
  • 组件重用:JSP中,可以使用JavaBean编写业务组件,也就是使用一个JavaBean封装业务处理代码或者作为一个数据处理模型,这个JavaBean可以重复使用,也可以应用到其他应用程序中。
  • 继承Java Servlet功能:JSP的本质是Servlet,因此说JSP拥有Servlet的所有功能。
  • 预编译:用户首次通过浏览器访问JSP页面时,服务器对JSP页面代码进行编译,并且仅执行一次编译,编译后被保存,下次访问时直接执行编译过的代码,节约了服务器资源,提升了客户端访问速度。

3、JSP的基础语法

3.1、JSP的注释

在jsp中常用的注释有两种:显示注释和隐式注释。

注释类型 描述
显示注释 HTML注释:<!- - 注释内容- ->
隐式注释 Java注释://单行注释 、/*…多行注释…*/
隐式注释 JSP专有注释:<%- - 注释内容- -%>

其中HTML注释在浏览器中查看源文件的时候是可以看得到的。而 Java 注释和 jsp 注释在浏览器中查看源文件时是看不到注释的内容的。

3.2、JSP的指令元素

JSP指令(Directives)主要用来提供整个JSP网页的信息,并用来设定JSP网页的相关属性,例如:设置网页的编码格式,语法,信息等。JSP指令的基本语法格式为:<%@ 指令 属性名="值" %> 。如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写,如下所示:

<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>
<!-- 也可以合并来设置,如下所示:-->
<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>

在 JSP 2.0规范中共定义了三个指令:

  • page指令
  • include指令
  • taglib指令

每个指令都有自己的属性,下面来介绍这三种指令。


①、page指令

我们通过page指令来设置JSP页面的属性,它作用整个JSP页面,所以为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。page指令一共有13个属性,下面介绍一下:

属性 参数 描述
language java 主要用来指定用何种语言来解释JSP网页,目前只能有Java来解释
import {package.class | package.*}, ... 指定此JSP网页引入哪些Java API
extends package.class 指定此JSP网页产生的Servlet所继承的类
pageEncoding characterSet | ISO-8859-1 指定此JSP网页的编码属性
session true | false 指定此JSP网页是否使用session(默认true)
buffer none | 8kb | sizekb 指定此JSP输出流是否有缓冲区(默认有,大小8KB的缓冲区)
autoFlush true | false 指定此JSP输出流的缓冲区是否自动清除(默认true)
isThreadSafe true | false 已经不使用了(默认true)
info text 表示此JSP的网页信息
erroPage relative_url 如果网页发生异常错误,则会重定向到指定的URL地址,前提是isErrorPage为true
isErrorPage true | false 指定此JSP能否在发生错误是转向另一个URL(默认true)
contentType mimeType;charset=characterSet | text/html;charset=ISO-8859-1 指定此JSP网页的编码方式
isElIgnored true | false 表示此JSP在执行时是否忽略EL表示(默认true)

简单举例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.*" pageEncoding="utf-8" %>

注意:这些指令必须包含在<%@page key=value …… %>中,而且只有import实现可以重复设置,其余属性只能设置一次或者不设置。

还有一点就是page指令中的errorPage属性。我们是可以在web.xml文件中使用<error-page>元素为整个Web应用程序设置错误处理页面。 <error-page>元素有3个子元素,<error-code><exception-type><location>

  • <error-code>子元素指定错误的状态码,例如:<error-code>404</error-code>
  • <exception-type>子元素指定异常类的完全限定名,例如:<exception-type>java.lang.ArithmeticException</exception-type>
  • <location>子元素指定以“/”开头的错误处理页面的路径,例如:<location>/404Error.jsp</location>
<!--处理404错误-->
<error-page>
    <error-code>404</error-code>
    <location>/404Error.jsp</location>
</error-page>
<!--处理500错误-->
<error-page>
    <error-code>500</error-code>
    <location>/500Error.jsp</location>
</error-page>

而如果你在某个JSP的页面设置了errorPage属性如:<%@ page errorPage="/error.jsp" %>,那么在web.xml文件中设置的错误处理将不对该页面起作用。


②、include指令

这个指令听名字是包含的意思。没错,include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。

语法:<%@ include file="relativeURL"%>,其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。被引入的文件可以使用任意的扩展名,即使其扩展名是html。

include指令使用举例:创建main.jsp、head.jsp和foot.jsp页面,分别作为jsp页面主体、头部和尾部,存放于Web根目录下,代码如下:

<%-- main.jsp:--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主网页</title>
</head>
<body>
    <%@ include file="head.jsp"%>
    <hr>
    <%@ include file="foot.jsp"%>
</body>
</html>
<%-- head.jsp: --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>这是网页head</title>
</head>
<body>
    这是网页head
</body>
</html>
<%-- foot.jsp: --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>网页foot</title>
</head>
<body>
    这是网页foot
</body>
</html>

运行结果如下:

image

补充:还有一种方式引入页面:jsp:include指令,功能与@include类似,后面会介绍。@include指令和jsp:include指令的在于:

  • @include只是把别的页面内容包含进来,属于静态包含。
  • jsp:include为动态包含,如果被包含的页面是JSP,则先处理之后再将结果包含,而如果包含的是非*.jsp文件,则只是把文件内容静态包含进来。

③、taglib指令

在JSP中,可以直接使用JSP提供的元素来完成特定的功能,而通过使用taglib指令,我们就可以在页面中使用自定义的标签,将标签库描述符文件导入到JSP页面即可。taglib指令的使用格式如下:

<%@ taglib uri="tigLibURL" 或 tagDir="tagDir" prefix="tagPrefix" %>

参数说明:

  • uri属性:定位标签库描述符的位置。唯一标识和前缀相关的标签库描述符,可以使用绝对或相对URL。
  • tagDir属性:指示前缀将被用于标识在WEV-INF/tags目录下的标签文件。
  • prefix属性:标签的前缀,区分多个自定义标签。不可以使用保留前缀和空前缀,遵循XML命名空间的命名约定。

例如后面需要使用JSTL的代码:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="name" value="hellojsp" />

上面就是通过<c:set />标签将"hellojsp”值赋给变量name。

3.3、JSP的表达式

JSP表达式、小脚本、声明这三者统称为JSP脚本表达式(expression),它用于将程序数据输出到客户端。下面对JSP表达式先进行讲解。

JSP表达式的语法:<%= Java表达式 %>。例如输出当前系统时间:

<%= new java.util.Date() %>

JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。JSP脚本表达式中的变量或表达式后面不能有分号(😉。

3.4、JSP的小脚本

JSP脚本元素(基本不用)用来插入Java代码,这些Java代码将会出现在由当前JSP页面生成的Servlet中。

JSP小脚本的语法:<% 多行Java代码 %>。我们可以在里面定义变量、编写语句,调用方法,但是不能定义方法。

<%
  //声明变量
  int sum=0;
 
  /*编写语句*/
  for (int i=1;i<=100;i++){
    sum+=i;
  }
  out.println("<h1>sum="+sum+"</h1>");
%>

多个脚本片断中的代码可以相互访问。单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,例如:

<%
  //声明变量
  int sum=0;
  /*编写语句*/
  for (int i=1;i<=100;i++){
%>
<%
    sum+=i;
  }
  out.println("<h1>sum="+sum+"</h1>");
%>

### 3.5、JSP的声明

JSP的声明用来在JSP页面中声明变量和定义方法。JSP的声明语法:<%! Java代码 %>,简单举例:

<%! String color[]={"red","yellow","blue"};
    String getColor(int i){
        return color[i];
    }
%>

### 3.6、JSP的动作标签

JSP动作标签的格式为:

<jsp:标签名 属性名="属性值" 属性名="属性值"></jsp:标签名>

在JSP中的动作标签包括有这几个:<jsp:param>、<jsp:include>、<jsp:forward>、<jsp:UseBean>、<jsp:getProperty>、<jsp:setProperty>、<jsp:plugin>。下面只介绍<jsp:include><jsp:forward>这两个,因为其它的几乎不会用到。

  • <jsp:include>:在前面提到过,它可以包含一个静态或动态的文件。格式:<jsp:include page=”URL”>
<jsp:include page="/include.jsp"></jsp:include>
  • <jsp:forward>:表示重定向到一个静态的HTML/JSP文件。格式:<jsp:forward page=”URL”>
<jsp:forward page="/index.jsp"></jsp:forward>

4、JSP的9大内置对象

JSP页面中一共内置了9个对象,分别为:out、session、response、request、config、page、application、pageContext、exception。在所有的JSP页面均可使用,但是必须在脚本元素的表达式或代码段中才可使用(<%=使用内置对象%>或<%使用内置对象%>内使用)。

而这9大内置对象又分为四类类型:

  • 输入输出对象:out、response、request。
  • 通信控制对象:pageContext、session、application。
  • Servlet对象:page、config。
  • 错误处理对象:exception。

下面依次介绍这9个内置对象的使用:

对象名 类型 描述
out javax.servlet.jsp.JspWriter 向客客户端、浏览器输出数据。
request javax.servlet.ServletRequest 封装了来自客户端、浏览器的各种信息。
response javax.servlet.SrvletResponse 封装了服务器的响应信息。
session javax.servlet.http.HttpSession 用来保存每个用户的信息,以便跟踪每个用户的操作状态。
application javax.servlet.ServletContext 代表了当前应用程序的上下文。可以在不同的用户之间共享信息。
exception javax.lang.Throwable 封装了JSP程序执行过程中发生的异常和错误信息。
config javax.servlet.ServletConfig 封装了应用程序的配置信息。
page javax.lang.Object JSP实现类的实例,它是当前JSP程序本身,通过这个可以对它进行访问。
pageContext javax.servlet.jsp.PageContext 为JSP页面包装页面的上下文。管理对属于JSP中特殊可见部分中己经命名对象的该问。

①、out对象

out对象是输出流,能把结果输出到网页上。获取方法: PrintWriter out = response.getWriter(); 常用的方法有两个:print(Object obj)和println(Object obj)。两者的区别就是out.println(Object obj)会在输出后的末尾加上换行符,而print则不会。

out对象常用的方法如下:

  1. void clear():清除缓冲区的内容
  2. void clearBuffer():清除缓冲区的当前内容
  3. void flush():将缓冲内容flush到客户端浏览器
  4. int getBufferSize():返回缓冲大小,单位KB
  5. int getRemaining():返回缓冲剩余大小,单位KB
  6. isAutoFlush():返回缓冲区满时,是自动清空还是抛出异常
  7. void close():关闭输出流

②、request对象

request表示客户端的请求。它包含了客户端的信息以及请求的信息,如请求那个文件,附带的地址参数等。每次客户端的请求都会产生一个request实例。request对象的常用方法如下:

  1. object getAttribute(String name):返回指定属性的属性值
  2. Enumeration getAttributeNames():返回所有可用属性名的枚举
  3. String getCharacterEncoding():返回字符编码方式
  4. int getContentLength():返回请求体的长度(以字节数)
  5. String getContentType():得到请求体的MIME类型
  6. ServletInputStream getInputStream():得到请求体中一行的二进制流
  7. String getParameter(String name):返回name指定参数的参数值
  8. Enumeration getParameterNames():返回可用参数名的枚举
  9. String[] getparameterValues(String name):返回包含参数name的所有值的数组
  10. String getProtocol():返回请求用的协议类型及版本号
  11. String getScheme():返回请求用的计划名,如:http https及ftp等
  12. int getServerPort():返回服务器接受此请求所用的端口号
  13. String getServerName():返回接受请求的服务器主机名
  14. BufferedReader getReader():返回解码过了的请求体
  15. String getRemoteAddr():返回发送此请求的客户端IP地址
  16. String getRemoteHost():返回发送此请求的客户端主机名
  17. void setAttribute(String key Object obj):设置属性的属性值
  18. String getRealPath(String path):返回一虚拟路径的真实路径
  19. void setCharacterEncoding(“gb2312”):设置接受参数的字符集

③、response对象

response对象代表客户端的响应。服务器端的任何输出都通过response对象发送到客户端浏览器。每次服务器端都会响应一个response实例。response对象的常用方法如下:

  1. String getCharacterEncoding():返回响应用的是何种字符编码
  2. ServletOutputStream getOutputStream():返回响应的一个二进制输出流
  3. PrintWriter getWriter():返回可以向客户端输出字符的一个对象
  4. void setContentLength(int len):设置响应头长度
  5. void setContentType(String type):设置响应的MIME类型
  6. sendRedirect(java.lang.String location):重新定向客户端的请求
  7. void setCharacterEncoding(“gb2312”):设置响应头的字符集

④、session对象

session与cookie是记录客户访问信息的两种机制,session是用于服务器端保存用户信息,cookie用于在客户端保存用户信息。Servlet中通过request.getSession()来获取session对象,而JSP中可以直接使用。如果JSP中配置了<%@page session=”false”%>,则隐藏对象session不可用。每个用户对应一个session对象。session对象的常用方法如下:

  1. long getCreationTime():返回Session创建时间
  2. public String getId():返回Session创建时JSP引擎为它设的唯一ID号
  3. long getLastAccessedTime():返回此Session里客户端最近一次请求时间
  4. int getMaxInactiveInterval():返回两次请求间隔多长时间此Session被取消(ms)
  5. String[] getValueNames():返回一个包含此Session中所有可用属性的数组
  6. void invalidate():取消Session,使Session不可用
  7. boolean isNew():返回服务器创建的一个Session,客户端是否已经加入
  8. void removeValue(String name):删除Session中指定的属性
  9. void setAttribute(String key,Object obj):设置Session的属性
  10. Object getAttribute(String name):返回session中属性名为name的对象

⑤、application对象

application封装JSP所在Web应用程序的信息,例如web.xml中国配置的全局的初始化信息。Servlet中application对象需要通过ServletConfig.getServletContext()来获取。整个Web应用程序对应一个application对象。application对象常用的方法如下:

  1. Object getAttribute(String name):返回application中属性为name的对象
  2. Enumeration getAttributeNames():返回application中的所有属性名
  3. void setAttribute(String name,Object value):设置application属性
  4. void removeAttribute(String name):移除application属性
  5. String getInitParameter(String name):返回全局初始话函数
  6. Enumeration getInitParameterNames():返回所有的全局初始话参数
  7. String getMimeType(String filename):返回文件的文档类型,例如getMimeType(“abc.html”)将返回“text.html”
  8. String getRealPath(String relativePath):返回Web应用程序内相对网址对应的绝对路径

⑥、exception对象

exception封装了JSP中抛出的异常信息。要使用exception隐藏对象,需要设置<%@page isErrorPage”true”%>。隐藏对象exception通常被用来处理错误页面。

⑦、config对象

隐藏对象config是javax.servlet.ServletConfig类的实例,ServletConfig封装了配置在web.xml中初始化JSP的参数。JSP中通过config获取这些参数。每个JSP文件中共有一个config对象。config对象的常用方法如表:

  1. String getInitParameter(String name):返回配置在web.xml中初始化参数
  2. Enumeration getInitParameterNames():返回所有的初始化参数名称
  3. ServletContext getServletContext():返回ServletContext对象
  4. String getServletName:返回Servlet对象

⑧、page对象

page对象表示当前JSP页面,是当前JSP编译后的Servlet类的对象,想当于Java类中的关键字this。page对象在开发中几乎不用,了解一下即可。

⑨、pageContext对象

隐藏对象pageContext为javax.servlet.jsp.PageContext类的实例。pageContext对象代表当前JSP页面编译后的内容。通过pageContext能够获取到JSP中的资源,一般用它来获取其它八个内置对象。pageContext常用方法如下:

  1. JspWriter getOut():返回out对象
  2. HttpSession getSession():返回Session对象(session)
  3. Object getPage():返回page对象
  4. ServletRequest getRequest():返回request对象
  5. ServletResponse getResponse():返回response对象
  6. void setAttribute(String name,Object attribute):设置属性及属性值 ,在page范围内有效
  7. void setAttribute(String name,Object obj,int scope):在指定范围内设置属性及属性值 ,int1=page,2=request,3=session,4=application
  8. public Object getAttribute(String name):取属性的值
  9. Object getAttribute(String name,int scope):在指定范围内取属性的值
  10. public Object findAttribute(String name):寻找一属性,返回起属性值或NULL
  11. void removeAttribute(String name):删除某属性
  12. void removeAttribute(String name,int scope):在指定范围删除某属性
  13. int getAttributeScope(String name):返回某属性的作用范围
  14. Enumeration getAttributeNamesInScope(int scope):返回指定范围内可用的属性名枚举
  15. void release():释放pageContext所占用的资源
  16. void forward(String relativeUrlPath):使当前页面重导到另一页面
  17. void include(String relativeUrlPath):在当前位置包含另一文件

5、JSP的4种作用域

JSP的4种作用域分别为:page域、request域、session域、application域。所谓的作用域就是通过setAttribute()设置一个属性之后,可以经过多少个其它页面后仍然可以通过getAttribute()获取到值的保存范围。所以我们在实际使用中,一定要区分内置对象的作用域。

域对象中操作共享数据的方法:

  • void setAttribute(String attributeName, Object attributeValue):在域对象中共享数据
  • Object getAttribute(String attributeName):获取域对象中共享的数据
  • void removeAttribute(String attributeName):删除域对象中共享的数据
域对象
作用域范围 使用场景
page域 只在当前页面有效 jstl中大部分的标签都会默认将数据共享在pageContext中
request域 只在当前请求中有效。(也就是一次请求中有效,第二次请求就不能再获取到了) 如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像错误信息提示,查询所有数据展示在页面中,新闻数据,属于用户看完就没用的。
session域 在当前会话中有效,仅供单个用户使用。(也就是在此次打开的浏览器中有效,如果关闭浏览器再打开就失效了) 如果客户向服务器发请求,产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中,像购物数据,用户需要看到自己购物信息,并且等一会儿,还要用这个购物数据结帐;还有记录用户的登录状态。
application域 在整个服务器中保存数据,全部用户共享。(重启服务器后失效) 如果客户向服务器发请求,产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在application(servletContext)域中,像聊天数据。

4种作用域小结:

  • 转发可以访问请求域中的数据,重定向不可以访问请求域中的数据(因为转发是一次请求,而重定向是两次请求)
  • session域对象中的数据区分浏览器
  • session域对象中的数据跟服务器是否关闭没有关系,只跟浏览器是否关闭有关
  • application域对象中的数据跟浏览器是否关闭没有关系,只跟服务器是否关闭有关

6、JSP的原理

我们知道,jsp的本质就是一个servlet,你访问的每一个jsp页面最后其实都是访问了一个Servlet,我们随便找一个JSP页面(注意:如果Tomcat没有配置全局变量的话,Tomcat编译jsp产生的java和class文件默认存储在C盘tomcat的work目录下)

image

然后打开index_jsp.java文件查看:

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
      return;
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\n");
      out.write("<html>\n");
      out.write("  <head>\n");
      out.write("    <title>Hello</title>\n");
      out.write("  </head>\n");
      out.write("\n");
      out.write("  <body>\n");
      out.write("    Hell Word!\n");
      out.write("    Hello Servlet!\n");
      out.write("    Hello JSP!\n");
      out.write("  </body>\n");
      out.write("</html>\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

从上面可以看出,index.jsp在运行被访问后解析成了一个Java类index_jsp.java,所生成的servlet的名字默认为jsp文件名加_jsp.java,例如:index.jsp变为index_jsp.java;test.jsp变为test_jsp.java。jsp所翻译成的servlet继承与于org.apache.jasper.runtime.HttpJspBase基类,而HttpJspBase又继承了HttpServlet类,所以说JSP本身就是一种Servlet。

经过观察,HttpJspBase中对HttpServlet继承的service(HttpServletRequest,HttpServletResponse)进行了重写,在重写的方法中调用了_jspService(HttpServletRequest,HttpServletResponse),因此在jsp所翻译成的servlet中真正处理请求和响应的就是_jspService(HttpServletRequest,HttpServletResponse)

在jsp所翻译成的servlet的_jspService()中,将HTML代码通过out.write()响应到浏览器,将jsp脚本片段中的代码直接在_jspService()执行,jsp表达式中的内容会通过out.print()响应到浏览器,jsp声明会在jsp所翻译成的servlet中直接声明相应的成员变量。

posted @ 2020-04-26 21:13  唐浩荣  阅读(774)  评论(0编辑  收藏  举报