重温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>
运行结果如下:
补充:还有一种方式引入页面: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对象常用的方法如下:
- void clear():清除缓冲区的内容
- void clearBuffer():清除缓冲区的当前内容
- void flush():将缓冲内容flush到客户端浏览器
- int getBufferSize():返回缓冲大小,单位KB
- int getRemaining():返回缓冲剩余大小,单位KB
- isAutoFlush():返回缓冲区满时,是自动清空还是抛出异常
- void close():关闭输出流
②、request对象
request表示客户端的请求。它包含了客户端的信息以及请求的信息,如请求那个文件,附带的地址参数等。每次客户端的请求都会产生一个request实例。request对象的常用方法如下:
- object getAttribute(String name):返回指定属性的属性值
- Enumeration getAttributeNames():返回所有可用属性名的枚举
- String getCharacterEncoding():返回字符编码方式
- int getContentLength():返回请求体的长度(以字节数)
- String getContentType():得到请求体的MIME类型
- ServletInputStream getInputStream():得到请求体中一行的二进制流
- String getParameter(String name):返回name指定参数的参数值
- Enumeration getParameterNames():返回可用参数名的枚举
- String[] getparameterValues(String name):返回包含参数name的所有值的数组
- String getProtocol():返回请求用的协议类型及版本号
- String getScheme():返回请求用的计划名,如:http https及ftp等
- int getServerPort():返回服务器接受此请求所用的端口号
- String getServerName():返回接受请求的服务器主机名
- BufferedReader getReader():返回解码过了的请求体
- String getRemoteAddr():返回发送此请求的客户端IP地址
- String getRemoteHost():返回发送此请求的客户端主机名
- void setAttribute(String key Object obj):设置属性的属性值
- String getRealPath(String path):返回一虚拟路径的真实路径
- void setCharacterEncoding(“gb2312”):设置接受参数的字符集
③、response对象
response对象代表客户端的响应。服务器端的任何输出都通过response对象发送到客户端浏览器。每次服务器端都会响应一个response实例。response对象的常用方法如下:
- String getCharacterEncoding():返回响应用的是何种字符编码
- ServletOutputStream getOutputStream():返回响应的一个二进制输出流
- PrintWriter getWriter():返回可以向客户端输出字符的一个对象
- void setContentLength(int len):设置响应头长度
- void setContentType(String type):设置响应的MIME类型
- sendRedirect(java.lang.String location):重新定向客户端的请求
- void setCharacterEncoding(“gb2312”):设置响应头的字符集
④、session对象
session与cookie是记录客户访问信息的两种机制,session是用于服务器端保存用户信息,cookie用于在客户端保存用户信息。Servlet中通过request.getSession()来获取session对象,而JSP中可以直接使用。如果JSP中配置了<%@page session=”false”%>,则隐藏对象session不可用。每个用户对应一个session对象。session对象的常用方法如下:
- long getCreationTime():返回Session创建时间
- public String getId():返回Session创建时JSP引擎为它设的唯一ID号
- long getLastAccessedTime():返回此Session里客户端最近一次请求时间
- int getMaxInactiveInterval():返回两次请求间隔多长时间此Session被取消(ms)
- String[] getValueNames():返回一个包含此Session中所有可用属性的数组
- void invalidate():取消Session,使Session不可用
- boolean isNew():返回服务器创建的一个Session,客户端是否已经加入
- void removeValue(String name):删除Session中指定的属性
- void setAttribute(String key,Object obj):设置Session的属性
- Object getAttribute(String name):返回session中属性名为name的对象
⑤、application对象
application封装JSP所在Web应用程序的信息,例如web.xml中国配置的全局的初始化信息。Servlet中application对象需要通过ServletConfig.getServletContext()来获取。整个Web应用程序对应一个application对象。application对象常用的方法如下:
- Object getAttribute(String name):返回application中属性为name的对象
- Enumeration getAttributeNames():返回application中的所有属性名
- void setAttribute(String name,Object value):设置application属性
- void removeAttribute(String name):移除application属性
- String getInitParameter(String name):返回全局初始话函数
- Enumeration getInitParameterNames():返回所有的全局初始话参数
- String getMimeType(String filename):返回文件的文档类型,例如getMimeType(“abc.html”)将返回“text.html”
- 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对象的常用方法如表:
- String getInitParameter(String name):返回配置在web.xml中初始化参数
- Enumeration getInitParameterNames():返回所有的初始化参数名称
- ServletContext getServletContext():返回ServletContext对象
- String getServletName:返回Servlet对象
⑧、page对象
page对象表示当前JSP页面,是当前JSP编译后的Servlet类的对象,想当于Java类中的关键字this。page对象在开发中几乎不用,了解一下即可。
⑨、pageContext对象
隐藏对象pageContext为javax.servlet.jsp.PageContext类的实例。pageContext对象代表当前JSP页面编译后的内容。通过pageContext能够获取到JSP中的资源,一般用它来获取其它八个内置对象。pageContext常用方法如下:
- JspWriter getOut():返回out对象
- HttpSession getSession():返回Session对象(session)
- Object getPage():返回page对象
- ServletRequest getRequest():返回request对象
- ServletResponse getResponse():返回response对象
- void setAttribute(String name,Object attribute):设置属性及属性值 ,在page范围内有效
- void setAttribute(String name,Object obj,int scope):在指定范围内设置属性及属性值 ,int1=page,2=request,3=session,4=application
- public Object getAttribute(String name):取属性的值
- Object getAttribute(String name,int scope):在指定范围内取属性的值
- public Object findAttribute(String name):寻找一属性,返回起属性值或NULL
- void removeAttribute(String name):删除某属性
- void removeAttribute(String name,int scope):在指定范围删除某属性
- int getAttributeScope(String name):返回某属性的作用范围
- Enumeration getAttributeNamesInScope(int scope):返回指定范围内可用的属性名枚举
- void release():释放pageContext所占用的资源
- void forward(String relativeUrlPath):使当前页面重导到另一页面
- 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目录下)
然后打开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中直接声明相应的成员变量。