@cxm-2016
2016-12-26T18:06:19.000000Z
字数 7903
阅读 2664
Web
版本:2
作者:陈小默
声明:禁止商业,禁止转载
JSP全名为Java Server Pages,其根本是一个简化的Servlet设计。也就是说,看起来像是一个HTML网页的JSP在Tomcat中是以Servlet对象的形式存在的。JSP与Servlet一样,是在服务器端执行的。通常JSP页面很少进行数据处理,只是用来实现网页的静态化页面,只是用来提取数据,不会进行业务处理。
一个JSP会在第一次被访问时翻译成一个Servlet对象,此后所有的响应都由这个对象输出。
每个JSP页面在第一次被访问时,WEB容器都会把请求交给JSP引擎去处理。JSP引擎先将JSP翻译成Servlet
,然后以Servlet的调用方式调用。以后再访问时不再翻译而是直接使用当前Servlet对象。
JSP引擎在调用JSP对应的_jspServlet
时,会传递或创建9个与web开发相关的对象供其使用。
用于向客户端发送文本数据。
out对象通过调用pageContext对象的getOut
方法返回,其作用和用法与ServletResponse.getWriter
对象相似。
out对象的类型为JSPWriter
,是一个实现了缓存功能的PrintWriter
对象。可以通过设置page指令的buffer属性设置缓冲区的大小,也可以关闭缓冲区。
当满足以下任意一个条件后,out对象会去调用ServletResponse
的getWriter
方法,并将当前out缓冲区的内容写到Servlet的缓冲区中。
当前页面的上下文对象。
该对象代表了JSP页面的运行环境。其中封装了其他八个隐式对象的引用,并且其自身还是一个域对象。并且,这个对象还封装了web开发中经常使用的一些操作,例如跳转等。
我们可以通过pageContext对象获取其他对象的引用。
<%
Object page1 = pageContext.getPage();
ServletRequest request1 = pageContext.getRequest();
ServletResponse response1 = pageContext.getResponse();
HttpSession session1 = pageContext.getSession();
ServletConfig config1 = pageContext.getServletConfig();
JspWriter out1 = pageContext.getOut();
ServletContext application1 = pageContext.getServletContext();
Exception exception = pageContext.getException();
%>
<%
//保存到PageContext域
pageContext.setAttribute("key", 1);
//保存到Application域
pageContext.setAttribute("key", 2, PageContext.APPLICATION_SCOPE);
//保存到Session域
pageContext.setAttribute("key", 3, PageContext.SESSION_SCOPE);
//保存到Request域
pageContext.setAttribute("key", 4, PageContext.REQUEST_SCOPE);
%>
JSP页面中的HTML内容都可以被称之为模板元素。
接下来我们在webapp目录下创建一个JSP index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
Welcome to Smart JSP !!!
</body>
</html>
由于webapp的可访问性,其中所有的文件,除WEB-INF目录外,都可以被浏览器通过地址直接访问。而文件名为index
的文件又具有默认访问的特性。所以我们既可以通过
http://127.0.0.1:8080/smart/index.jsp
形式访问,也可以省略index.jsp,直接通过
http://127.0.0.1:8080/smart
访问。
<%=System.currentTimeMillis() %>
JSP引擎在翻译表达式时会使用out.print
输出表达式中的内容。
JSP脚本也叫作JSP脚本片段
<%
for (int i = 0; i < 10; i++) {
out.print(i);
out.print("<br>");
}
%>
JSP脚本允许不完整的脚本片段,但是多个片段组合后的脚本片段必须是完整的,比如上面的示例还可以改成这个样子:
<%
for (int i = 0; i < 10; i++) {
out.print(i);
%>
<br>
<%
}
%>
JSP脚本片段会被原封不动的放在生成的Servlet代码中。
JSP页面中编写的代码会被翻译到Servlet的service
中,而JSP声明中的java代码会被翻译到_jspService
方法的外面。
通常JSP声明被用于
<%!
private int base = 10;
%>
<%
for (int i = 0; i < 10; i++) {
out.println(base++);
}
%>
<%!
{
System.out.println("init");
}
%>
<%!
private String getCurrent() {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
return format.format(new Date());
}
%>
<%=getCurrent() %>
<%!
private class DateUtil {
String getCurrent() {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
return format.format(new Date());
}
}
%>
<%
DateUtil util = new DateUtil();
out.print(util.getCurrent());
%>
在JSP中注释有三种方式,第一种为JSP注释,该注释不会被保存到Servlet中。
<%-- JSP注释 --%>
第二种是Java注释,这种注释只能在JSP脚本中使用,并且会被写入到Servlet中。
<%
// 单行注释
/*
多行注释
*/
/**
* 文档注释
*/
%>
第三种是HTML注释,该注释会被当做模板元素输出。
<!-- HTML -->
对于HTML注释,有一点需要注意:
<% int i = 0; %>
<!--<% i+=10; %> -->
<%=i %>
上述网页会输出数字10
。
这是因为在JSP翻译为Servlet时,对于模板元素采取的是直接输出:
int i = 0;
out.print("<!--");
i+=10;
out.print("-->");
out.print(i)
JSP指令用于指挥JSP引擎如何处理JSP页面。其中包含三个主要部分
page
、include
、taglib
用于定义JSP页面中各种属性,无论指令在何处,都作用域整个JSP页面。
常用属性有:
java.lang.*
包和javax.servlet.*
)text/html;charset=utf-8
language
<%@ page
language="java"
%>
目前仅支持Java语言。
import
<%@ page
language="java"
import="java.util.Date,java.util.ArrayList"
%>
session
<%@ page
language="java"
import="java.util.Date,java.util.ArrayList"
session="false"
%>
当我们将session设置为false之后,我们就无法在JSP脚本中使用session隐式对象了。
我们可以通过errorPage标签指定当前页面发生后跳转到的页面。
首先创建一个JSP页面用来显示错误:
<%@ page
contentType="text/html;charset=UTF-8"
language="java"
isErrorPage="true"
%>
<html>
<head>
<title>错误页面</title>
</head>
<body>
发生了一个错误,错误原因是:<%=exception.getMessage()%>
</body>
</html>
然后在需要的JSP页面中指定错误页面。
<%@ page
language="java"
errorPage="ErrorPage.jsp"
%>
<html>
<head>
<title>Hello</title>
</head>
<body>
<%
throw new RuntimeException("用户未登录");
%>
</body>
</html>
最后也是最重要的就是在web.xml文件中指定错误类型与访问路径的关系。
我们可以使用相应代码:
<error-page>
<error-code>500</error-code>
<location>/ErrorPage.jsp</location>
</error-page>
或者使用错误类型:
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/ErrorPage.jsp</location>
</error-page>
通知JSP将两个JSP文件翻译成一个Servlet
比如:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
---------a----------
<%@include file="index.jsp" %>
---------b----------
</body>
</html>
我们可以从浏览器看到翻译过后的Servlet的输出内容是:
<html>
<head>
<title>Hello</title>
</head>
<body>
---------a----------
<html>
<head>
<title>index</title>
</head>
<body>
Welcome to Smart JSP !!!
</body>
</html>
---------b----------
</body>
</html>
include指令属于静态引入,也就是源文件级别的合并,并最终生成一个Servlet。
需要注意的是:
.jspf
作为静态引入文件的扩展名。用于在JSP页面中导入标签库
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
我们将
<servlet>
<servlet-name>helloJsp</servlet-name>
<jsp-file>/WEB-INF/view/HelloJsp.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>helloJsp</servlet-name>
<url-pattern>/view/hello</url-pattern>
</servlet-mapping>
JSP最终是以Servlet的方式运行的。那么一个JSP最终转换成的Servlet结构是什么样子的?
首先我们创建一个最简单的JSP页面:
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<%!
private String getDate() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.format(new Date());
}
%>
<%-- 注释1 --%>
<%=getDate()%>
<%
//注释2
for (int i = 0; i < 10; i++) {
out.print(i);
%>
<br>
<!--<%
}
%>-->
</body>
</html>
那么生成的Servlet页面源码如下(已精简)
package org.apache.jsp;
...
import java.text.SimpleDateFormat;
import java.util.Date;
public final class HelloJsp_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
/**
* 使用JSP声明定义的方法
*/
private String getDate() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.format(new Date());
}
...
/**
* JSP生命周期的初始化方法,在第一次被访问时调用
*/
public void _jspInit() {
}
/**
* JSP生命周期的销毁,在JSP被移除出容器时调用
*/
public void _jspDestroy() {
}
/**
* 模板元素在这里被输出,JSP脚本在这里被运行
*/
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
...
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("\n");
out.write("\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <title>Hello</title>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write('\n');
out.write('\n');
out.print(getDate());
out.write('\n');
//注释2
for (int i = 0; i < 10; i++) {
out.print(i);
out.write("\n");
out.write("<br>\n");
out.write("<!--");
}
out.write("-->\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
...
} finally {
...
}
}
}