Web-第十一天 JSP学习

Web-第十一天 JSP学习

JSP 服务器端页面技术

今日内容介绍

  • 案例:显示商品信息

今日内容学习目标

  • 简单阐述JSP的执行原理
  • 会使用page执行处理JSP编码问题
  • 会使用page执行导入jsp需要使用的类
  • 列举JSP内置对象
  • 列举JSP四大作用域
  • 比较静态包含和动态包含

第1章 案例一:在JSP的页面中显示商品的信息.

1. 需求:

数据库中存放了很多商品信息,现在将商品的信息全部显示到页面.

2. 相关知识点:

1.2.1 JSP概述

1.2.1.1 什么是JSP

JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。为了与传统HTML有所区别,JSP文件的扩展名为.jsp。

JSP技术所开发的Web应用程序是基于Java的,它可以用一种简捷而快速的方法从Java程序生成Web页面,其使用上具有如下几点特征:

  • 跨平台:由于JSP是基于Java语言的,它可以使用Java API,所以它也是跨平台的,可以应用于不同的系统中,如Windows、Linux等。当从一个平台移植到另一个平台时,JSP和JavaBean的代码并不需要重新编译,这是因为Java的字节码是与平台无关的,这也应验了Java语言“一次编译,到处运行”的特点。
  • 业务代码相分离:在使用JSP技术开发Web应用时,可以将界面的开发与应用程序的开发分离开。开发人员使用HTML来设计界面,使用JSP标签和脚本来动态生成页面上的内容。在服务器端,JSP引擎(或容器,本书中指Tomcat)负责解析JSP标签和脚本程序,生成所请求的内容,并将执行结果以HTML页面的形式返回到浏览器。
  • 组件重用:JSP中可以使用JavaBean编写业务组件,也就是使用一个JavaBean类封装业务处理代码或者作为一个数据存储模型,在JSP页面中,甚至在整个项目中,都可以重复使用这个JavaBean,同时,JavaBean也可以应用到其他Java应用程序中。
  • 预编译:预编译就是在用户第一次通过浏览器访问JSP页面时,服务器将对JSP页面代码进行编译,并且仅执行一次编译。编译好的代码将被保存,在用户下一次访问时,会直接执行编译好的代码。这样不仅节约了服务器的CPU资源,还大大的提升了客户端的访问速度。

1.2.1.2 编写第一个JSP文件

在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的语法元素。

新大头儿子和小头爸爸3:俄罗斯奇遇记

主演:刘纯燕 / 董浩 / 鞠萍

猫眼电影演出 广告

购买

1.2.1.3 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

1.2.2 JSP基本语法

在JSP文件中可以嵌套很多内容,例如,JSP的脚本元素和注释等,这些内容的编写都需要遵循一定的语法规范,接下来,本节将针对这些语法进行详细的讲解。

1.2.2.1 JSP脚本元素

JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java程序代码。通过JSP脚本元素可以将Java代码嵌入HTML页面中,所有可执行的Java代码,都可以通过JSP脚本来执行。

JSP脚本元素主要包含如下三种类型:

  • JSP Scriptlets
  • 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表达式中的变量或表达式后面不能有分号(;)。

1.2.2.2 JSP注释

同其他各种编程语言一样,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注释

java注释

html注释

1.2.3 JSP指令

为了设置JSP页面中的一些信息,Sun公司提供了JSP指令。 JSP 2.0中共定义了page、include和taglib三种指令,每种指令都定义了各自的属性。接下来,本节将针对page和include指令进行详细的讲解。

1.2.3.1 page指令

在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页面的最前面。

1.2.3.2 include指令

在实际开发时,有时需要在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页面中的位置保持一致。

1.2.3.3 taglib指令

用于页面中引入标签库的,这个指令会在后面介绍JSTL的时候讲解.

1.2.4 JSP内置对象

1.2.4.1 内置对象的概述

在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对象进行详细的讲解。

1.2.4.2 out对象

在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引擎按照缓冲区中的数据存放顺序输出内容。

1.2.4.3 pageContext对象

在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个值,具体如下:

  • PageContext.PAGE_SCOPE:表示页面范围
  • PageContext.REQUEST_SCOPE:表示请求范围
  • PageContext.SESSION_SCOPE:表示会话范围
  • PageContext.APPLICATION_SCOPE:表示Web应用程序范围

需要注意的是,当使用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对象,并且还可以获取不同范围内的属性。

1.2.5 JSP的四个域范围:

PageContext常量名

描述

作用域名称

域对象类型

PageScope

当前页面中有效

pageContext

PageContext

RequestScope

一次请求范围

request

HttpServletRequest

SessionScope

一次会话范围

session

HttpSession

ApplicationScope

应用范围

application

ServletContext

  • page:表示当前页,通常没用。jsp标签底层使用。
  • request:表示一次请求。通常一次请求就一个页面,但如果使用请求转发,可以涉及多个页面。
  • session:表示一次会话。可以在多次请求之间共享数据。
  • application:表示 一个web应用(项目)。可以整个web项目共享,多次会话共享数据。

1.2.6 JSP动作元素(了解)

JSP动作元素用来控制JSP的行为,执行一些常用的JSP页面动作。通过动作元素可以实现使用多行Java代码能够实现的效果,如包含页面文件,实现请求转发等。

1.2.6.1 <jsp:include>动作元素

在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>标签都能够包含一个文件,但它们之间有很大的区别,具体如下:

  • <jsp:include>标签中要引入的资源和当前JSP页面是两个彼此独立的执行实体,即被动态引入的资源必须能够被Web容器独立执行。而include指令只能引入遵循JSP格式的文件,被引入文件与当前JSP文件需要共同合并才能翻译成一个Servlet源文件。
  • <jsp:include>标签中引入的资源是在运行时才包含的,而且只包含运行结果。而include指令引入的资源是在编译时期包含的,包含的是源代码。
  • 7<jsp:include>标签运行原理与RequestDispatcher.include()方法类似,即被包含的页面不能改变响应状态码或者设置响应头,而include指令没有这方面的限制。

1.2.6.2 动态包含和静态包含的区别:

3. 案例分析

综合案例需要点击“导航条/分类”进行列表信息的展示,本案为了巩固重定向,在首页编写重定向代码直接跳转到ProductFindAllServlet进行查询,在Servlet中调用ProductService获得所有的查询结果,在service中调用ProductDao使用DBUtils进行查询,当查询完数据,在JSP页面进行数据显示。

4. 代码实现:

  • 步骤1:创建项目,并导入jar包
  • 步骤2:初始化数据库

#创建数据库和表:

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

) ;

  • 步骤3:导入工具类和c3p0配置 文件,并修改数据库
  • 步骤4:编写JavaBean,并提供相应构造方法,以及toString()方法

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;

}

  • 步骤5:dao层实现

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);

}

}

}

  • 步骤6:service层实现

public class ProductService {

/**

* 查询所有商品

* @return

*/

public List<Product> findAll(){

ProductDao productDao = new ProductDao();

return productDao.findAll();

}

}

  • 步骤7:首页编写

<%-- 重定向到查询所有servlet --%>

<%

response.sendRedirect("/day11_findall/productFindAllServlet");

%>

  • 步骤8:servlet编写

<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);

}

}

  • 步骤9:拷贝jsp页面,显示具体信息

<%-- 列表 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 --%>

第2章 总结

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2018-07-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏pangguoming

Dropwizard框架入门

最近项目用到了Dropwizard框架,个人感觉还不错,那么这里就从他们官网入手,然后加上自己的实现步骤让大家初步了解这个框架。 官网对DW(Dropwizar...

7134
来自专栏技术墨客

Spring核心——资源数据管理 原

在Profile管理环境一文中介绍了环境的概念以及Spring Profile特性控制Bean的添加。本文将进一步介绍Spring管理和控制操作系统变量、JVM...

964
来自专栏你不就像风一样

史上超全面的Elasticsearch使用指南

elasticsearch简写es,es是一个高扩展、开源的全文检索和分析引擎,它可以准实时地快速存储、搜索、分析海量的数据。

3K2
来自专栏用户2442861的专栏

muduo 4 网络库学习之Exception类、Thread 类封装中的知识点(重点讲pthread_atfork())

class Exception : public std::exception

1511
来自专栏GreenLeaves

WebService 之 身份验证

  在项目开发,我们经常会使用WebService,但在使用WebService时我们经常会考虑到了WebService是安全问题,很容易想到通过一组用户名与密...

3827
来自专栏java达人

JSP中文乱码的产生原因及解决方案

JSP中文乱码的产生原因及解决方案在JSP的开发过程中,经常出现中文乱码的问题,可能一直困扰着大家,现在把JSP开发中遇到的中文乱码的问题及解决办法写出来供大家...

3666
来自专栏芋道源码1024

面试问烂的 Spring AOP 原理

来源:https://www.jianshu.com/p/e18fd44964eb

2274
来自专栏Java后端生活

JavaWeb(六)JSP-1

2143
来自专栏xdecode

使用Dagger2做静态注入, 对比Guice.

Dagger 依赖注入的诉求, 这边就不重复描述了, 在上文Spring以及Guice的IOC文档中都有提及, 既然有了Guice, Google为啥还要搞个D...

5147
来自专栏Java 技术分享

一篇 JPA 总结

下面是 JDBC 在 Java 应用和数据库之间的位置,充当着一个中间者,供 Java 应用程序访问所有类别的数据库,建立一个标准

1232

扫码关注云+社区

领取腾讯云代金券