文章目录
JSP服务器端页面技术
1 JSP概述
1.1 什么是JSP
JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中, HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。
1.2 JSP的运行过程
JSP的工作模式是请求/响应模式,客户端首先发出HTTP请求,JSP程序收到请求后进行处理并返回处理结果。**在一个JSP文件第一次被请求时,JSP引擎(容器)把该JSP文件转换成为一个 Servlet,而这个引擎本身也是一个Servlet。**如下图所示:
JSP的具体运行过程如下:
①客户端发出请求,请求访问JSP文件。
② JSP容器先将JSP文件转换成一个Java源文件(Java Servlet源程序),在转换过程中,如果发现JSP文件中存在任何语法错误,则中断转换过程,并向服务端和客户端返回出错信息。
③如果转换成功,则JSP容器将生成的Java源文件编译成相应的字节码文件* class。该class文件就是一个Servlet,Servlet容器会像处理其他Servlet—样来处理它。
以HelloWorld.jsp为例,当用户第一次访问HelloWorld.jsp页面时,该页面会先被JSP容器转换为一个名称为HelloWorld_Jsp.java的源文件,然后将源文件编译为一个名称为HelloWorld_Jsp.class字节码文件。如果项目发布在Tomcat的webapps目录中,源文件和.class文件可以在Tomcat安装目录/work/Catalina/localhost/项目名/org/apache/jsp 下找到。HelloWorld.jsp文件转换后的java源文件没有实现Servlet接口,但继承了 org.apache.jasper runtime.HttpJspBase 类。而HttpJspBase类是HttpServlet的一个子类,由此可见, HelloWorld_jsp 类就是一个 Servlet。
结论:JSP 就是 Servlet。
问题:我们访问服务器的jsp文件时,服务器时如何处理的呢?
下面是Tomcat的Web.xml的全局配置文件的部分代码。我们可以看到,当我们访问服务器的后缀名为jsp或jspx文件时,会创建org.apache.jasper.servlet.JspServlet处理请求的页面,将动态页面转换为静态页面输入到客户端。
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
2 JSP基本语法
2.1 JSP脚本元素
JSP脚本元素主要包含如下三种类型:JSP Scriptlets、JSP声明语句、JSP表达式
- JSP Scriptlets:
<% java代码(变虽、方法、语句等)%>
在JSP Scriptlets中声明的变量是JSP页面的局部变量,在调用的时候会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。
- JSP声明语句:
<%! 定义的变里或方法等 %>
JSP的声明语句用于声明成员变量和方法,被声明的Java代码将被编译到Servlet的JspService()方法之外,即在JSP声明语句中定义的都是成员方法、成员变量、静态方法、静态变量、静态代码块等。
在一个JSP页面中可以有多个JSP声明语句,单个声明中的Java语句可以是不完整的,但是多个声明组合后的结果必须是完整的Java语句。
接下来,通过一个案例来演示JSPScriptlets和声明语句的使用。
JSP代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好JSP!!</title>
</head>
<body>
<h1>HelloWorld!!!</h1>
<h1>Hello JSP!!!</h1>
<%--此处写的代码都会放在转换后的java文件中的service()方法中 --%>
<%
//在此处写方法会报错
int a = 1;
int b = 1;
//调用run方法
out.print(run());
%>
<%--此处写的代码都会放在转换后的java文件中的service()方法外,即成员位置 --%>
<%!
//定义成员变量和静态变量
int a = 3;
static int c = 3;
//定义成员方法
public int run(){
return a + c;
}
%>
</body>
</html>
上面jsp代码转换后的部分Servlet代码
public final class HelloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
//定义成员变量和静态变量
int a = 3;
static int c = 3;
//定义成员方法
public int run(){
return a + c;
}
......省略一些代码......
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
......省略一些代码......
//在此处写方法会报错
int a = 1;
int b = 1;
//调用run方法
out.print(run());
......省略一些代码......
}
}
- JSP表达式
<%=java变量或表达式>
会被翻译成service方法内部out.print()
例如:
<%="休斯顿火箭的莫雷真的是猪队友" %>
转换为
out.print("休斯顿火箭的莫雷真的是猪队友" );
2.2 JSP注释
<%-- jsp的注释格式 --%>
JSP注释、java的注释和html的注释对比:
注释名称 | 注释格式 | jsp源码 | 翻译后的Servlet源码 | 页面显示HTML源码 |
html注释 | < !--注释内容--> | 可见 | 可见 | 可见 |
java注释 | //单行注释 /**/ 多行注释 | 可见 | 可见 | 不可见 |
jsp注释 | <%--注释内容--%> | 可见 | 不可见 | 不可见 |
3 JSP指令
为了设置JSP页面中的一些信息,Sun公司提供了 JSP指令。JSP 2.0中共定义了 page、include 和taglib三种指令,每种指令都定义了各自的属性。接下来,本节将针对page和mclude指令进行详细的讲解。
3.1 page指令
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
page指令一些常用的属性:
属性名称 | 取值/范围 | 描述 |
---|---|---|
contentType | 有效的文档类型 | 客户端浏览器根据该属性判断文档类型 |
pageEncoding | 当前页面 | 指定页面的编码格式。(内部包含contentType可以只设置此属性) |
buffer | 8kb | jsp缓存大小,即out的缓存大小 |
errorPage | 某个JSP页面的相对路径 | 指定一个错误页面,如果该JSP程序抛出一个未捕捉的异常,则转到errorPage指定的页面。errorPage指 定页面的isErrorPage属性力true,一旦内置的exception 对象为未捕捉的异常 |
isErrorPage | true/false | 指定该页面是否为错误处理页面,如果为true,则该 JSP内置有一个Exception对象的exception,可直接使用。默认情况下,isErrorPage的值为false |
import | 任何包名、类名 | 指定在JSP页面翻译成的Servlet源文件中导入的包或类。import是唯一可以声明多次的page指令属性。 一个import属性可以引用多个类,中间用英文逗号隔开。 |
language | java | 指明解释该JSP文件时采用的语言,默认是Java |
session | true/false | 指明该JSP内是否内置Session对象,如果为true,则说明内置Session对象,可以直接使用,否则没有内置Session对象。默认情况下,session属性的值为 true。 |
注意:表中列举了page指令的常见属性,其中,除了 import属性外,其他的属性都只能出现一次, 否则会编译失败。需要注意的是,page指令的属性名称都是区分大小写的。
3.2 include指令
静态包含
<%@ include file="被包含的文件地址" %>
3.3 taglib指令
在jsp页面中引入标签库(jstl标签库、struts2标签库)
<%@ taglib uri="标签库地址" prefix="前缀"%>
4 JSP内置/隐式对象
4.1 内置对象概述
在JSP页面中,有一些对象需要频繁使用,如果每次都獻新创建这些对象则会非常麻烦。为了 简化Web应用程序的开发,JSP2.0规范中提供了 9个隐式(内置)对象,它们是JSP默认创建的, 可以直接在JSP页面中使用。
名称 | 类型 | 描述 |
---|---|---|
request | HttpServletRequest | 得到用户请求信息 |
response | HttpServletResponse | 服务器向客户的响应信息 |
out | JspWriter | 用于页面输出 |
application | ServletContext | 所有用户的共享信息 |
config | ServletConfig | 服务器配置,可以获得初始化参数 |
page | Object | 当前页面转换后得Servlet类的实例 |
pageContext | PageContext | JSP页面容器 |
session | Session | 保存用户的信息 |
exception | Throwable | 表示JSP页面所发生的异常,在错误页面才起作用 |
4.2 out对象
在JSP页面中,经常需要向客户端发送文本内容,这时,可以使用out对象来实现。out对象是 javax.servlet jsp.JspWriter 类的实例对象,它的作用与 ServletResponse.getWriter()方法返回的 PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out对象的类型 为JspWriter,它相当于一种带缓存功能的PrintWriter。
使用out对象写数据到客户端的时候,会先将数据写到out缓冲区(默认8kb)。再把out缓冲区中的数据写到response缓冲区,再输出给客户端。
小案例:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
aaaa
<%
out.write("bbbb");
response.getWriter().write("cccc");
%>
<%="dddd" %>
</body>
</html>
页面输出效果:
cccc aaaa bbbb dddd
上面的效果表明,尽管a和b在c之前输出,但是a、b、d都是先写到out缓冲区,再写到response缓冲区的。而c是直接写在response缓冲区的。
我们也可以在指令中将out的缓冲区设置为0kb,代表关闭out缓冲区,内容直接写到response缓冲区。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" buffer="0kb"%>
页面输出效果:
aaaa bbbb cccc dddd
4.3 pageContext对象
在JSP页面中,使用pageContext对象可以获取JSP的其他8个隐式对象。pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它代表当前JSP页面的运行环境,并提供了一系列用于 获取其他隐式对象的方法。
获取其他对象的方式都是get方法,例如:
JspWriter getOut()
ServletRequest getRequest()
......
pageContext除了能获取其他8大隐式对象,还是一个域对象,可以存储数据。
方法名称 | 功能描述 |
---|---|
void setAttribute(String name,Object value) | 给page域中存数据 |
Object getAttribute(String name) | 获取page域的数据 |
void removeAttribute(String name) | 删除page域的数据 |
void setAttribute(String name,Object value,int scope) | 给指定的域对象设置属性 |
Object getAttribute(String name,int scope) | 获得指定域对象的属性值 |
void removeAttribute(String name,int scope) | 移除指定域对象的属性 |
Object findAttribute(String name) | 从4个域对象中查找名称name属性 |
pageContext对象的作用范围有四个值:
- PageContext.PAGE_SCOPE:表示页面范围
- PageContext.REQUEST_SCOPE:表示请求范围
- PageContext.SESSION_SCOPE:表示会话范围
- PageContext.APPLICATION_SCOPE:表示 Web 应用程序范围
注意:需要注意的是,当使用findAttribute()方法查找名称为name的属性时,会按照pageContext、request、 session和application的顺序依次进行査找,如果找到,则返回属性的名称,否则返回null。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
pageContext.setAttribute("name", "wangba", PageContext.PAGE_SCOPE);
pageContext.setAttribute("name", "zhangsan", PageContext.REQUEST_SCOPE);
pageContext.setAttribute("name", "lisi", PageContext.SESSION_SCOPE);
pageContext.setAttribute("name", "zhaoliu", PageContext.APPLICATION_SCOPE);
%>
<%
String name1 = (String)pageContext.getAttribute("name", PageContext.PAGE_SCOPE);
String name2 = (String)pageContext.getAttribute("name", PageContext.REQUEST_SCOPE);
String name3 = (String)pageContext.getAttribute("name", PageContext.SESSION_SCOPE);
String name4 = (String)pageContext.getAttribute("name", PageContext.APPLICATION_SCOPE);
%>
<%=name1 %> <%--wangba--%>
<%=name2 %> <%--zhangsan--%>
<%=name3 %> <%--lisi--%>
<%=name4 %> <%--zhaoliu--%>
</body>
</html>
4.4 JSP的四个域的范围
PageContext 常量名 | 描述 | 作用域名称 | 域对象类型 |
---|---|---|---|
PAGE_SCOPE | 当前页面中有效 | pageContext | PageContext |
REQUEST_SCOPE | 一次请求范围 | request | HttpServletRequest |
SESSION_SCOPE | 一次会话范围 | session | HttpSession |
APPLICATION_SCOPE | 应用范围 | application | ServletContext |
5 JSP动作元素/标签
JSP动作元素用来控制JSP的行为,执行一些常用的JSP页面动作。通过动作元素可以实现使用多行Java代码能够实现的效果,如包含页面文件,实现请求转发等。
5.1 页面包含
动态包含格式:
<jsp:include page="要包含的文件的路径" />
5.2 请求转发
<jsp:forword page="要转发的文件的路径"/>
5.3 动态包含和静态包含的区别
- 动态包含要引入的资源和当前JSP页面是两个彼此独立的执行实体。而静态包含只能引入遵循JSP格式的文件,被引入文件与当前JSP文件需要共同合并才能被翻译成一个Servlet文件。
- 动态包含中引入的资源是在运行时才包含的,而且只包含运行结果。而静态包含引入的资源是在编译时期包含的,包含的是源代码。
- 动态包含产生两个独立的Servlet。静态包含产生一个Servlet。
- 静态包含在两个文件中不能有相同的变量,而动态包含允许,因为静态包含相当于将包含文件内容直接赋值到主体文件中,如果出现相同的变量,就会出现覆盖等问题,导致文件出错。而动态包含相当于调用不同的jsp,变量所在的空间不同。