Web-第十一天 JSP学习
今日内容介绍
今日内容学习目标
数据库中存放了很多商品信息,现在将商品的信息全部显示到页面.
JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。为了与传统HTML有所区别,JSP文件的扩展名为.jsp。
JSP技术所开发的Web应用程序是基于Java的,它可以用一种简捷而快速的方法从Java程序生成Web页面,其使用上具有如下几点特征:
在Eclipse中,创建一个名称为day17的Web项目,然后右击WebContent目录à【new】à【Other】,在弹出的窗口中找到JSP文件,如图1-1所示。
图1-1 创建JSP文件
在图1-1中,选择JSP File后,点击【Next】按钮,在新窗口的File name文本框中填写JSP文件名称HelloWorld,如图1-2所示。
图1-2 命名文件
填写完图1-2中JSP文件名称后,点击【Next】按钮,进入选择模板窗口,此处采用默认设置,如图1-3所示。
图1-3 选择模板窗口
点击图1-3中的【Finish】按钮后,第一个JSP文件就创建成功了。创建后的JSP文件代码如图1-4所示。
图1-4 HelloWorld.jsp
从图1-4中可以看出,新创建的JSP文件与传统的HTML文件几乎没有什么区别,唯一的区别是默认创建时,页面代码最上方多了一条page指令,并且该文件的后缀名是jsp,而不是html,关于page指令会在1.3节中详细讲解,此处了解即可。JSP文件必须发布到Web容器中的某个Web应用中才能查看出效果。在HelloWorld.jsp的<body>元素内添加上文字“My First JSP”并保存后,将day13项目发布到Tomcat中并启动项目,在浏览器地址栏中输入地址“http://localhost:8080/day13/HelloWorld.jsp”,此时浏览器的显示效果如图1-5所示。
图1-5 HelloWorld.jsp文件显示效果
从图1-5中可以看出,HelloWorld.jsp中添加的内容已被显示出来,这说明了HTML中的元素可以被JSP容器所解析。实际上,JSP只是在原有的HTML文件中加入了一些具有Java特点的代码,这些代码具有其独有的特点,称为JSP的语法元素。
主演:刘纯燕 / 董浩 / 鞠萍
猫眼电影演出 广告
购买
JSP的工作模式是请求/响应模式,客户端首先发出HTTP请求,JSP程序收到请求后进行处理并返回处理结果。在一个JSP文件第一次被请求时,JSP引擎(容器)把该JSP文件转换成为一个Servlet,而这个引擎本身也是一个Servlet。JSP的运行过程如图1-6所示。
图1-6 JSP的运行原理
JSP的运行过程具体如下:
(1)客户端发出请求,请求访问JSP文件。
(2)JSP容器先将JSP文件转换成一个Java源文件(Java Servlet源程序),在转换过程中,如果发现JSP文件中存在任何语法错误,则中断转换过程,并向服务端和客户端返回出错信息。
(3)如果转换成功,则JSP容器将生成的Java源文件编译成相应的字节码文件*.class。该class文件就是一个Servlet,Servlet容器会像处理其他Servlet一样来处理它。
为了使同学们更容易理解JSP的运行原理,接下来简单介绍分析一下JSP所生成的Servlet代码。
以HelloWorld.jsp为例,当用户第一次访问HelloWorld.jsp页面时,该页面会先被JSP容器转换为一个名称为HelloWorld_jsp.java的源文件,然后将源文件编译为一个名称为HelloWorld_jsp.class字节码文件。如果项目发布在Tomcat的webapps目录中,源文件和.class文件可以在“Tomcat安装目录/work/Catalina/localhost/项目名/org/apache/jsp”下找到,如图1-7所示。
图1-7 JSP文件编译后的文件
在图1-7中,地址栏中的路径多出了org\apache\jsp,这是由于JSP文件转换成类文件时会带有包名,该包名为org.apache.jsp。从图中还可以看出,HelloWorld.jsp已被转换为源文件和.class文件。打开HelloWorld_jsp.java文件,可查看转换后的源代码,其主要代码如下所示。(以下代码可以快速浏览,确定父类和方法名即可)
package org.apache.jsp;
...
public final class HelloWorld_jspextends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
...
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(
getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
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 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("\r\n");
out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" My First JSP\r\n");
out.write("</body>\r\n");
out.write("</html>");
} 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);
}
}
}
从上面的代码可以看出,HelloWorld.jsp文件转换后的源文件没有实现Servlet接口,但继承了org.apache.jasper.runtime.HttpJspBase类。在Tomcat源文件中查看HttpJspBase类的源代码,具体如下所示:(以下代码可以快速阅读,确定父类即可)
package org.apache.jasper.runtime;
...
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
private static final long serialVersionUID = 1L;
protected HttpJspBase() {
}
@Override
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
@Override
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
@Override
public final void destroy() {
jspDestroy();
_jspDestroy();
}
@Override
public final void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
@Override
public void jspInit() {
}
public void _jspInit() {
}
@Override
public void jspDestroy() {
}
protected void _jspDestroy() {
}
@Override
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
从HttpJspBase源代码中可以看出,HttpJspBase类是HttpServlet的一个子类,由此可见,HelloWorld_jsp类就是一个Servlet。 结论:JSP就是Servlet。
在JSP文件中可以嵌套很多内容,例如,JSP的脚本元素和注释等,这些内容的编写都需要遵循一定的语法规范,接下来,本节将针对这些语法进行详细的讲解。
JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java程序代码。通过JSP脚本元素可以将Java代码嵌入HTML页面中,所有可执行的Java代码,都可以通过JSP脚本来执行。
JSP脚本元素主要包含如下三种类型:
1. JSP Scriptlets
JSP Scriptlets 是一段代码段。当需要使用Java实现一些复杂操作或控制时,可以使用它。JSP Scriptlets的语法格式如下所示:
<% java 代码(变量、方法、语句等)%>
在JSP Scriptlets中声明的变量是JSP页面的局部变量,调用JSP Scriptlets时,会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。
2. JSP声明语句
JSP的声明语句用于声明变量和方法,它以“<%!”开始,以“%>”结束,其语法格式如下所示:
<%!
定义的变量或方法等
%>
在上述语法格式中,被声明的Java代码将被编译到Servlet的_jspService()方法之外,即在JSP声明语句中定义的都是成员方法、成员变量、静态方法、静态变量、静态代码块等。在JSP声明语句中声明的方法在整个JSP页面内有效。
在一个JSP页面中可以有多个JSP声明语句,单个声明中的Java语句可以是不完整的,但是多个声明组合后的结果必须是完整的Java语句。接下来,通过一个案例来演示JSP Scriptlets和声明语句的使用。
在day12项目的WebContent目录下创建一个名称为example01.jsp的文件,在该文件中编写声明语句,如文件1-1所示。
文件1-1 example01.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP声明语句</title>
</head>
<%!
int a = 1, b = 2; //定义两个变量a,b
%>
<%!
public String print() { //定义print方法
String str = "javahelp "; //方法内定义的变量str
return str;
}
%>
<body>
<%
out.println(a + b); //输出两个变量的和
%>
<br>
<%
out.println(print());//调用print()方法,输出其返回值
%>
</body>
</html>
在文件1-1中,首先使用<%!和%>定义了两个变量a、b,以及print()方法,然后使用了<%和%>输出了两个常量的和,以及print()方法中的返回信息。启动项目后,在浏览器地址栏中输入地址“http://localhost:8080/day17/example01.jsp”访问example01.jsp文件,显示效果如图1-8所示。
图1-8 example01.jsp的执行结果
从图1-8中可以看到,浏览器中已经显示出了相应的结果。
需要注意的是,<%!和%>里面定义的变量是成员变量,方法是全局的方法,此处只是声明,也就是定义,变量或方法都没有被调用。<%和%>里面定义的是局部变量,不能定义方法(Java方法中不能再嵌套定义方法),代码块操作可以将结果输出到浏览器。总之,<%!和%>是用来定义成员变量属性和方法的,<%和%>主要是用来输出内容的,因此如果涉及到了成员变量的操作,那么就应该使用<%!和%>,而如果是涉及到了输出内容的时候,就使用<%和%>。
3. JSP表达式
JSP表达式(expression)用于将程序数据输出到客户端,它将要输出的变量或者表达式直接封装在以“<%=” 开头和以“%>”结尾的标记中,其基本的语法格式如下所示:
<%= expression %>
在上述语法格式中,JSP表达式中的将“expression”表达式结果输出到浏览器。例如,对example01.jsp文件进行修改,将<body>内的脚本元素修改为表达式,具体如下。
<%=a+b %><br>
<%=print() %>
在浏览器中再次访问example01.jsp页面,同样可以正确输出如图1-8中的显示结果。需要注意的是:
同其他各种编程语言一样,JSP也有自己的注释方式,其基本语法格式如下:
<%-- 注释信息 --%>
需要注意的是,Tomcat在将JSP页面编译成Servlet程序时,会忽略JSP页面中被注释的内容,不会将注释信息发送到客户端。接下来,通过一个案例来演示JSP注释的使用。
在day12项目的WebContent目录下创建一个名称为example02的JSP页面,如文件1-2所示。
文件1-2 example02.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP注释</title>
</head>
<body>
<!-- 这个是HTML注释 -->
<%-- 这个是JSP注释 --%>
</body>
</html>
在上述页面代码中,包含HTML注释和JSP两种注释方式。启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/day17/example02.jsp”访问example02.jsp页面,此时,可以看到example02.jsp页面什么都不显示,接下来在打开的页面中点击鼠标右键,在弹出菜单中选择【查看源文件】选项,结果如图1-9所示。
图1-9 example02.jsp的源代码
从图1-9中可以看出,JSP的注释信息没有显示出来,而只显示出了HTML注释。这是因为在Tomcat编译JSP文件时,会将HTML注释当成普通文本发送到客户端,而JSP页面中格式为“<%-- 注释信息 --%>”的内容则会被忽略,不会发送到客户端。
<%-- jsp注释--%>
<% //java注释 %>
<!-- html注释-->
jsp源码 | java源码 | html源码 | |
---|---|---|---|
jsp注释 | 有 | 无 | 无 |
java注释 | 有 | 有 | 无 |
html注释 | 有 | 有 | 有 |
为了设置JSP页面中的一些信息,Sun公司提供了JSP指令。 JSP 2.0中共定义了page、include和taglib三种指令,每种指令都定义了各自的属性。接下来,本节将针对page和include指令进行详细的讲解。
在JSP页面中,经常需要对页面的某些特性进行描述,例如,页面的编码方式,JSP页面采用的语言等,这时,可以通过page指令来实现。page指令的具体语法格式如下所示:
<%@ page 属性名1= "属性值1" 属性名2= "属性值2" ...%>
在上面的语法格式中,page用于声明指令名称,属性用来指定JSP页面的某些特性。page指令提供了一系列与JSP页面相关的属性,如表1-1所示。
表1-1 page指令的常用属性
属性名称 | 取值or范围 | 描述 |
---|---|---|
pageEncoding | 当前页面 | 指定页面编码格式 |
contentType | 有效的文档类型 | 客户端浏览器根据该属性判断文档类型,例如:HTML格式为text/html纯文本格式为text/plainJPG图像为image/jpegGIF图像为image/gifWord文档为application/msword |
buffer | 8kb | jsp缓存大小 |
autoFlush | true / false | 是否自动刷新 |
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。需要注意的是,JSP 引擎自动导入以下4个包:java.lang.*javax.servlet.*javax.servlet.jsp.*javax.servlet.http.* |
表1-1中列举了page指令的常见属性,其中,除了import属性外,其他的属性都只能出现一次,否则会编译失败。需要注意的是,page指令的属性名称都是区分大小写的。
下面列举两个使用page指令的示例:
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ page import="java.awt.*" %>
<%@ page import="java.util.*","java.awt.*"%>
上面代码中使用了page指令的language、contentType、pageEncoding和import属性。
需要注意的是,page指令对整个页面都有效,而与其书写的位置无关,但是习惯上把page指令写在JSP页面的最前面。
在实际开发时,有时需要在JSP页面静态包含一个文件,例如HTML文件,文本文件等,这时,可以通过include指令来实现,include指令的具体语法格式如下所示:
<%@ include file="被包含的文件地址"%>
include指令只有一个file属性,该属性用来指定插入到JSP页面目标位置的文件资源。
为了使读者更好地理解include指令的使用,接下来,通过一个案例来学习include指令的具体用法。
在day12项目的WebContent目录下创建两个JSP页面文件date.jsp和include.jsp,在include.jsp文件中使用include指令将date.jsp文件包含其中,具体如文件1-3和文件1-4所示。
文件1-3 date.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head><title>Insert title here</title>
</head>
<body>
<% out.println(new java.util.Date().toLocaleString());%>
</body>
</html>
文件1-4 include.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>欢迎你</title>
</head>
<body>
欢迎你,现在的时间是:
<%@ include file="/date.jsp"%>
</body>
</html>
启动tomcat服务器,在浏览器中访问地址“http://localhost:8080/day17/include.jsp”,浏览器的显示结果如图1-10所示。
图1-10 运行结果
从图1-10中可以看出,date.jsp文件中用于输出当前日期的语句已显示出来,这说明include指令成功地将date.jsp文件中的代码合并到了include.jsp文件中。
关于include指令的具体应用,有很多问题需要注意,接下来,将这些问题进行列举,具体如下:
(1) 被引入的文件必须遵循JSP语法,其中的内容可以包含静态HTML、JSP脚本元素和JSP指令等普通JSP页面所具有的一切内容。
(2) 除了指令元素之外,被引入的文件中的其他元素都被转换成相应的Java源代码,然后插入进当前JSP页面所翻译成的Servlet源文件中,插入位置与include指令在当前JSP页面中的位置保持一致。
用于页面中引入标签库的,这个指令会在后面介绍JSTL的时候讲解.
在JSP页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化Web应用程序的开发,JSP2.0规范中提供了9个隐式(内置)对象,它们是JSP默认创建的,可以直接在JSP页面中使用。这9个隐式对象的名称、类型和描述如表1-2所示。
表1-2 JSP隐式对象
名称 | 类型 | 描述 |
---|---|---|
out | javax.servlet.jsp.JspWriter | 用于页面输出 |
request | javax.servlet.http.HttpServletRequest | 得到用户请求信息, |
response | javax.servlet.http.HttpServletResponse | 服务器向客户端的回应信息 |
config | javax.servlet.ServletConfig | 服务器配置,可以取得初始化参数 |
session | javax.servlet.http.HttpSession | 用来保存用户的信息 |
application | javax.servlet.ServletContext | 所有用户的共享信息 |
page | java.lang.Object | 指当前页面转换后的Servlet类的实例 |
pageContext | javax.servlet.jsp.PageContext | JSP的页面容器 |
exception | java.lang.Throwable | 表示JSP页面所发生的异常,在错误页中才起作用 |
在表1-2中,列举了JSP的9个隐式对象及它们各自对应的类型。其中,由于request、response、config、session和application所属的类及其用法在前面的章节都已经讲解过,而page对象在JSP页面中很少被用到。因此,在下面几个小节中,将针对out和pageContext对象进行详细的讲解。
在JSP页面中,经常需要向客户端发送文本内容,这时,可以使用out对象来实现。out对象是javax.servlet.jsp.JspWriter类的实例对象,它的作用与ServletResponse.getWriter()方法返回的PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out对象的类型为JspWriter,它相当于一种带缓存功能的PrintWriter。接下来,通过一张图来描述JSP页面的out对象与Servlet引擎提供的缓冲区之间的工作关系,具体如图1-11所示。
图1-11 out对象与Servlet引擎的关系
从图1-11可以看出,在JSP页面中,通过out隐式对象写入数据相当于将数据插入到JspWriter对象的缓冲区中,只有调用了ServletResponse.getWriter()方法,缓冲区中的数据才能真正写入到Servlet引擎所提供的缓冲区中。为了验证上述说法是否正确,接下来,通过一个具体的案例来演示out对象的使用。
在day12项目的WebContent目录下创建一个名称为out的JSP页面,如文件1-5所示。
文件1-5 out.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<%
out.println("first line<br>");
response.getWriter().println("second line<br>");
%>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中访问“http://localhost:8080/day12/out.jsp”,浏览器的显示结果如图1-12所示。
图1-12 运行结果
从图1-12中可以看出,尽管out.println语句位于response.getWriter().println语句之前,但它的输出内容却在后面。由此可以说明,out对象通过print语句写入数据后,直到整个JSP页面结束,out对象中输入缓冲区的数据(即:first line)才真正写入到Serlvet引擎提供的缓冲区中,而response.getWriter().println语句则是直接把内容(即:second line)写入Servlet引擎提供的缓冲区中,Servlet引擎按照缓冲区中的数据存放顺序输出内容。
在JSP页面中,使用pageContext对象可以获取JSP的其他8个隐式对象。pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它代表当前JSP页面的运行环境,并提供了一系列用于获取其他隐式对象的方法。pageContext对象获取隐式对象的方法如表1-3所示。
表1-3 pageContext获取隐式对象的方法
方法名 | 功能描述 |
---|---|
JspWriter getOut() | 用于获取out隐式对象 |
Object getPage() | 用于获取page隐式对象 |
ServletRequest getRequest() | 用于获取request隐式对象 |
ServletResponse getResponse() | 用于获取response隐式对象 |
HttpSession getSession() | 用于获取session隐式对象 |
Exception getException() | 用于获取exception隐式对象 |
ServletConfig getServletConfig() | 用于获取config隐式对象 |
ServletContext getServletContext() | 用于获取application隐式对象 |
表1-3中列举了pageContext获取其他隐式对象的方法,这样,当传递一个pageContext对象后,就可以通过这些方法轻松地获取到其他8个隐式对象了。
pageContext对象不仅提供了获取隐式对象的方法,还提供了存储数据的功能。pageContext对象存储数据是通过操作属性来实现的,表1-4列举了pageContext操作属性的一系列方法,具体如下:
表1-4 pageContext操作属性的相关方法
方法名称 | 功能描述 |
---|---|
void setAttribute(String name,Object value,int scope) | 用于设置pageContext对象的属性 |
Object getAttribute(String name,int scope) | 用于获取pageContext对象的属性 |
void removeAttribute(String name,int scope) | 删除指定范围内名称为name的属性 |
void removeAttribute(String name) | 删除所有范围内名称为name的属性 |
Object findAttribute(String name) | 从4个域对象中查找名称为name的属性 |
表1-4列举了pageContext对象操作属性的相关方法,其中,参数name指定的是属性名称,参数scope指定的是属性的作用范围。pageContext对象的作用范围有4个值,具体如下:
需要注意的是,当使用findAttribute()方法查找名称为name的属性时,会按照page、request、session和application的顺序依次进行查找,如果找到,则返回属性的名称,否则返回null。接下来,通过一个案例来演示pageContext对象的使用。
在day12项目的WebContent目录下创建一个名称为pageContext.jsp的页面,编辑后如文件1-7所示。
文件1-6 pageContext.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>pageContext</title>
</head>
<body>
<%
//获取request对象
HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
//设置page范围内属性
pageContext.setAttribute("str", "Java",pageContext.PAGE_SCOPE);
//设置request范围内属性
req.setAttribute("str", "Java Web");
//获得的page范围属性
String str1 = (String)pageContext.getAttribute("str",pageContext.PAGE_SCOPE);
//获得的request范围属性
String str2 = (String)pageContext.getAttribute("str",pageContext.REQUEST_SCOPE);
%>
<%="page范围:"+str1 %><br>
<%="request范围:"+str2 %><br>
</body>
</html>
在上述代码中,首先使用pageContext获取了request对象,并设置page范围内属性;然后使用获取的request对象设置了request范围内属性,接下来使用pageContext对象获得page和request范围内的相应属性,最后使用JSP表达式输出数据。
启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/day17/pageContext.jsp”访问pageContext.jsp页面,浏览器显示的结果如图1-13所示。
图1-13 运行结果
从图1-13的显示结果可以看出,通过pageContext对象可以获取到request对象,并且还可以获取不同范围内的属性。
PageContext常量名 | 描述 | 作用域名称 | 域对象类型 |
---|---|---|---|
PageScope | 当前页面中有效 | pageContext | PageContext |
RequestScope | 一次请求范围 | request | HttpServletRequest |
SessionScope | 一次会话范围 | session | HttpSession |
ApplicationScope | 应用范围 | application | ServletContext |
JSP动作元素用来控制JSP的行为,执行一些常用的JSP页面动作。通过动作元素可以实现使用多行Java代码能够实现的效果,如包含页面文件,实现请求转发等。
在JSP页面中,为了把其他资源的输出内容插入到当前JSP页面的输出内容中,JSP技术提供了<jsp:include>动作元素,<jsp:include>动作元素的具体语法格式如下所示:
<jsp:include page="relativeURL" flush="true|false" />
在上述语法格式中,page属性用于指定被引入资源的相对路径,flush属性用于指定是否将当前页面的输出内容刷新到客户端,默认情况下,flush属性的值为false。
<jsp:include>包含的原理是将被包含的页面编译处理后将结果包含在页面中。当浏览器第一次请求一个使用<jsp:include>包含其他页面的页面时,Web容器首先会编译被包含的页面,然后将编译处理后的返回结果包含在页面中,之后编译包含页面,最后将两个页面组合的结果回应给浏览器。为了使读者更好地理解<jsp:include>动作元素,接下来,通过一个案例来演示<jsp:include>动作元素的使用,具体如下:
(1)在day12项目的WebContent目录下编写两个JSP文件,分别是included.jsp和dynamicInclude.jsp。其中dynamicInclude.jsp页面用于引入included.jsp页面。included.jsp作为被引入的文件,让它暂停5秒钟后才输出内容,这样,可以方便测试<jsp:include>标签的flush属性。included.jsp的具体代码如文件1-10所示,dynamicInclude.jsp具体代码如文件1-11所示。
文件1-7 included.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>include</title>
</head>
<body>
<%Thread.sleep(5000);%>
included.jsp内的中文<br>
</body>
</html>
文件1-8 dynamicInclude.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>dynamicInclude page</title>
</head>
<body>
dynamicInclude.jsp内的中文
<br>
<jsp:include page="included.jsp" flush="true" />
</body>
</html>
(2)启动Tomcat服务器,访问地址“http://localhost:8080/day12/dynamicInclude.jsp”后,发现浏览器首先会显示dynamicInclude.jsp页面中的输出内容,等待5秒后,才会显示included.jsp页面的输出内容。说明被引用的资源included.jsp在当前JSP页面输出内容后才被调用。其最后显示结果如图1-14所示。
图1-14 dynamicInclude.jsp
(3)修改dynamicInclude.jsp文件,将<jsp:include>动作元素中的flush属性设置为false,刷新浏览器,再次访问地址“http://localhost:8080/day12/dynamicInclude.jsp”,这时,浏览器等待5秒后,将dynamicInclude.jsp和included.jsp页面的输出内容同时显示了出来。由此可见,Tomcat调用被引入的资源included.jsp时,并没有将当前JSP页面中已输出的内容刷新到客户端。
需要注意的是,虽然include指令和<jsp:include>标签都能够包含一个文件,但它们之间有很大的区别,具体如下:
综合案例需要点击“导航条/分类”进行列表信息的展示,本案为了巩固重定向,在首页编写重定向代码直接跳转到ProductFindAllServlet进行查询,在Servlet中调用ProductService获得所有的查询结果,在service中调用ProductDao使用DBUtils进行查询,当查询完数据,在JSP页面进行数据显示。
#创建数据库和表:
create database day17_db;
#使用
use day17_db;
#创建商品表
CREATE TABLE `product` (
`pid` varchar(32) primary key,
`pname` varchar(50) DEFAULT NULL, #商品名称
`market_price` double DEFAULT NULL, #商场价
`shop_price` double DEFAULT NULL, #商城价
`pimage` varchar(200) DEFAULT NULL, #商品图片路径
`pdate` date DEFAULT NULL, #上架时间
`is_hot` int(11) DEFAULT NULL, #是否热门:0=不热门,1=热门
`pdesc` varchar(255) DEFAULT NULL, #商品描述
`pflag` int(11) DEFAULT 0, #商品标记:0=未下架(默认值),1=已经下架
`cid` varchar(32) DEFAULT NULL #分类id
) ;
public class Product {
private String pid;
private String pname;
private Double market_price;
private Double shop_price;
private String pimage;
private Date pdate;
private Integer is_hot; // 0 不是热门 1:热门
private String pdesc;
private Integer pflag; // 0 未下架 1:已经下架
private String cid;
…
}
public class ProductDao {
/**
* 查询所有商品
* @return
*/
public List<Product> findAll(){
try {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from product";
Object[] params = {};
return queryRunner.query(sql, new BeanListHandler<Product>(Product.class), params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class ProductService {
/**
* 查询所有商品
* @return
*/
public List<Product> findAll(){
ProductDao productDao = new ProductDao();
return productDao.findAll();
}
}
<%-- 重定向到查询所有servlet --%>
<%
response.sendRedirect("/day11_findall/productFindAllServlet");
%>
<servlet>
<servlet-name>ProductFindAllServlet</servlet-name>
<servlet-class>cn.com.javahelp.web.servlet.ProductFindAllServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProductFindAllServlet</servlet-name>
<url-pattern>/productFindAllServlet</url-pattern>
</servlet-mapping>
代码实现
public class ProductFindAllServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 获得数据,并封装(本案例没有)
//2 调用service进行查询所有
ProductService productService = new ProductService();
List<Product> allProduct = productService.findAll();
//3.1 将查询结果存放在request作用域(查询数据当前有效)
request.setAttribute("allProduct", allProduct);
//3.2 请求转发到jsp(jsp可以使用request作用域的数据)
request.getRequestDispatcher("/product_list.jsp").forward(request, response);
}
…
}
<%-- 列表 start --%>
<%
List<Product> allProduct = (List<Product>)request.getAttribute("allProduct");
for(Product p : allProduct){
out.write("<div>");
out.write(" <a href='product_info.htm'>");
out.write(" <img src='"+p.getPimage()+"' width='170' height='170' style='display: inline-block;'>");
out.write(" </a>");
out.write(" <p><a href='product_info.html' style='color:green'>"+p.getPname()+"</a></p>");
out.write(" <p><font color='#FF0000'>商城价:¥"+p.getShop_price()+"</font></p>");
out.write("</div>");
}
%>
<%-- 列表 end --%>