JSP基本用法
JSP原理
JSP全称是Java Server Pages,和Servlet技术一样都用于开发动态Web资源的技术。
浏览器向服务器发送请求,其实都是在访问Servlet,服务器在执行JSP时,会把JSP翻译成Servlet。 假设我们有如下代码:
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>First Jsp</title>
</head>
<body>
<%
out.print("Hello Jsp");
%>
</body>
</html>
当我们通过浏览器访问index.jsp时,服务器首先将index.jsp翻译成一个index_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp
目录下可以看到index_jsp.class的源代码文件index_jsp.java:
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.AnnotationProcessor _jsp_annotationprocessor;
public Object getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
}
public void _jspDestroy() {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
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');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>First Jsp</title>\r\n");
out.write("\t\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" ");
out.print("Hello Jsp");
out.write("\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
index_jsp这个类是继承 org.apache.jasper.runtime.HttpJspBase这个类的,通过查看Tomcat服务器的源代码,可以知道在apache-tomcat-6.0.20-src\java\
org\apache\jasper\runtime目录下存HttpJspBase这个类的源代码文件,如下图所示:
我们可以看看HttpJsBase这个类的源代码,如下所示:
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
protected HttpJspBase() {
}
public final void init(ServletConfig config) throws ServletException {
super.init(config);
jspInit();
_jspInit();
}
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
_jspService(request, response);
}
public void jspInit() {
}
public void _jspInit() {
}
public void jspDestroy() {
}
protected void _jspDestroy() {
}
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承自HttpJspBase类的,所以index_jsp类也是一个Servlet。
1、JSP中的HTML排版标签是如何发送给服务端的?
浏览器接收到的下面这些数据
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="http://localhost:8080/JavaWebDemo/">
<title>First Jsp</title>
</head>
<body>
Hello Jsp
</body>
</html>
都是在_jspService方法中使用如下的代码输出给浏览器的:
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>First Jsp</title>\r\n");
out.write("\t\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" ");
out.print("Hello Jsp");
out.write("\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
在jsp中编写的java和html代码都会被翻译到_jspService方法中去,而HTML代码则会翻译成out.write("<html标签>\r\n");的形式输出到浏览器。
2、Web服务器在调用JSP时,会给JSP提供什么java对象?
查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象
PageContext pageContext;
HttpSession session;
ServletContext application;
ServletConfig config;
JspWriter out;
Object page = this;
HttpServletRequest request,
HttpServletResponse response
其中page对象,request和response已经完成了实例化,而其它5个没有实例化的对象通过下面的方式实例化
pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
这8个java对象在Jsp页面中是可以直接使用的,如下所示:
<%
session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
out.print(session.getAttribute("name")+"<br/>");//获取session对象的属性
pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
out.print(pageContext.getAttribute("name")+"<br/>");//获取pageContext对象的属性
application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
out.print(application.getAttribute("name")+"<br/>");//获取application对象的属性
out.print("Hello Jsp"+"<br/>");//使用out对象
out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");//使用page对象
out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");//使用config对象
out.print(response.getContentType()+"<br/>");//使用response对象
out.print(request.getContextPath()+"<br/>");//使用request对象
%>
软件开发中,习惯把servlet作为web应用中的控制器组件,而把JSP技术作为数据显示模板。
JSP基础语法
JSP虽然是在JAVA上的一种应用,但是也有自身的扩充语法,而且在JSP中是可以运行所有JAVA语句的。
JSP页面中的HTML内容称之为JSP模板元素,JSP模板元素定义了网页的基本骨架,既定义了页面的结构和外观。
JSP表达式
JSP脚本表达式(expression)用于将程序数据输出到客户端:
<%= 变量或表达式 %>
JSP脚本表达式后面不允许有分号,JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。
JSP脚本片段
JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。语法:
<%
多行java代码
%>
在<% %>中可以定义变量、编写语句,不能定义方法。
范例:在Scriptlet中定义变量、编写语句:
<%
int sum=0;//声明变量
/*编写语句*/
for (int i=1; i<=100; i++){
sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
注意事项:
JSP脚本片断中只能出现java代码,不能出现其它模板元素。
JSP脚本片断中的Java代码必须严格遵循Java语法。
在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。
多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况。如:out.println(x);单个脚本片断中的Java语句可以是不完整的,但是,
多个脚本片断组合后的结果必须是完整的Java语句,例如:
<%
for (int i=1; i<5; i++) {
%>
<H1>http://localhost:8080/JavaWebDemo/</H1>
<%
}
%>
JSP声明
多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。JSP隐式对象的作用范围仅限于Servlet的_jspService方法,
所以在JSP声明中不能使用这些隐式对象。
<%!
static {
System.out.println("loading Servlet!");
}
private int globalVar = 0;
public void jspInit(){
System.out.println("initializing jsp!");
}
%>
<%!
public void jspDestroy(){
System.out.println("destroying jsp!");
}
%>
JSP注释
在JSP中,注释有两大类:
显式注释:直接使用HTML风格的注释:<!- - 注释内容- ->
隐式注释:直接使用JAVA的注释://、/……/
JSP自己的注释:<%- - 注释内容- -%>
三种注释的区别分别是:
<%
//JAVA中的单行注释
/*
JAVA中的多行注释
*/
%>
<%--JSP自己的注释--%>
HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的,这就是这三种注释的区别。
JSP指令
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
在JSP2.0规范中定义三个指令:
指令 | 描述 |
---|---|
<%@ page ... %> | 定义网页依赖属性,比如脚本语言、error页面、缓存需求等等。 |
<%@ include ... %> | 包含其他文件 |
<%@ taglib ... %> | 引入标签库的定义 |
JSP指令的基本语法格式:
语法:<%@ 指令 属性名="值" %>
例子:<%@ page contentType="text/html;charset=gb2312"%>
如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>
也可以写作:
<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
Page指令
page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可
读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。例如:
JSP 2.0规范中定义的page指令的完整语法:
属性 | 描述 |
---|---|
buffer | 指定out对象使用缓冲区的大小 |
autoFlush | 控制out对象的 缓存区 |
contentType | 指定当前JSP页面的MIME类型和字符编码 |
errorPage | 指定当JSP页面发生异常时需要转向的错误处理页面 |
isErrorPage | 指定当前页面是否可以作为另一个JSP页面的错误处理页面 |
extends | 指定servlet从哪一个类继承 |
import | 导入要使用的Java类 |
info | 定义JSP页面的描述信息 |
isThreadSafe | 指定对JSP页面的访问是否为线程安全 |
language | 定义JSP页面所用的脚本语言,默认是Java |
session | 指定JSP页面是否使用session |
isELIgnored | 指定是否执行EL表达式 |
isScriptingEnabled | 确定脚本元素能否被使用 |
page指令的import属性
在Jsp页面中,Jsp引擎会自动导入下面的包
java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*
可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号(,)分隔
<%@ page import="java.util.*,java.io.*,java.sql.*"%>
上面的语句也可以改写为使用多条page指令的import属性来分别引入各个包或类
<%@ page import="java.util.Date"%>
<%@ page import="java.io." %>
<%@ page import="java.sql." %>
page指令的errorPage属性
errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),
否则,表示相对于当前页面,也可以在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>/ErrorPage/404Error.jsp</location>
如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。
(1)使用errorPage属性指明出错后要跳转的页面
比如Test.jsp页面有如下的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<html>
<head>
<title>测试page指令的errorPage属性</title>
</head>
<body>
<%
// 运行出错代码
int x = 1 / 0;
%>
</body>
</html>
代码运行出错后会跳转到error.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>错误友好提示界面</title>
</head>
<body>
对不起,出问题啦,赶快联系程序员修改代码!
</body>
</html>
(2)在web.xml中使用<error-page>标签配置全局错误处理
web.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 针对404错误的处理页面 -->
<error-page>
<error-code>404</error-code>
<location>/ErrorPage/404Error.jsp</location>
</error-page>
</web-app>
404Error.jsp代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>404错误友好提示页面</title>
<!-- 3秒钟后自动跳转回首页 -->
<meta http-equiv="refresh" content="3;url=${pageContext.request.contextPath}/index.jsp">
</head>
<body>
<img alt="对不起,你要访问的页面没有找到,请联系管理员处理!"
src="${pageContext.request.contextPath}/img/404Error.png"/><br/>
3秒钟后自动跳转回首页,如果没有跳转,请点击<a href="${pageContext.request.contextPath}/index.jsp">这里</a>
</body>
</html>
当访问一个不存在的web资源时,就会跳转到在web.xml中配置的404错误处理页面404Error.jsp。
如果错误页面比较小的话,ie可能显示自己的错误页面,而火狐和google浏览器是不存在该问题。解决办法有两种:
a) 修改IE浏览器的设置(不推荐)
操作步骤:在IE【工具】->【Internet选项】->【高级】中勾掉【显示友好http错误提示】
b) 定制错误页面的大小
修改500Error.jsp,多添加一些内容,让页面的字节数大一些,修改后的500Error.jsp的代码如下:
示例代码如下所示:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>500(服务器错误)错误友好提示页面</title>
<!-- 3秒钟后自动跳转回首页 -->
<meta http-equiv="refresh" content="3;url=${pageContext.request.contextPath}/index.jsp">
</head>
<body>
<img alt="对不起,服务器出错了,请联系管理员解决!"
src="${pageContext.request.contextPath}/img/500Error.png"/><br/>
3秒钟后自动跳转回首页,如果没有跳转,请点击<a href="${pageContext.request.contextPath}/index.jsp">这里</a>
</body>
</html>
经过测试,当定制的错误页面的size=617bytes时,在IE8下已经可以跳转到定制的错误页面。
(3)使用page指令的isErrorPage属性显示声明页面为错误页面
将error.jsp页面显示声明为错误处理页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="true"%>
<html>
<head>
<title>错误信息友好提示页面</title>
</head>
<body>
对不起,出错了,请联系管理员解决!
</body>
</html>
Jsp有9大内置对象,而一般情况下exception对象在Jsp页面中是获取不到的,只有设置page指令的isErrorPage属性为"true"来显式声明Jsp页面
是一个错误处理页面之后才能够在Jsp页面中使用exception对象。
include指令
在JSP中对于包含有两种语句形式:
@include指令
<jsp:include>指令
-
@include指令
@include可以包含任意的文件,当然,只是把文件的内容包含进来。它用于引入其他JSP页面,而JSP引擎会将两个JSP翻译成Servlet,
所以这种方式称之为静态引入。
<%@ include file="relativeURL"%>,
其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。
include指令细节注意事项:
被引入的文件必须遵循JSP语法。
被引入的文件可以使用任意的扩展名,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
由于使用include指令将会涉及到2个JSP页面,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
范例:
新建head.jspf页面和foot.jspf页面,分别作为jsp页面的头部和尾部,存放于WebRoot下的jspfragments文件夹中,代码如下:
head.jspf和foot.jspf内容如下:
head.jspf:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1 style="color: red;">网页头部</h1>
foot.jspf:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1 style="color: blue">网页尾部</h1>
在WebRoot文件夹下创建一个IncludeTagTest.jsp页面,在IncludeTagTest.jsp页面中使用@include指令引入head.jspf页面和foot.jspf页面,代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp的include指令测试</title>
</head>
<body>
<%--使用include标签引入其他JSP页面--%>
<%@include file="/jspfragment/head.jspf"%>
<h1>网页主体部分</h1>
<%@include file="/jspfragment/foot.jspf"%>
</body>
</html>
最后总结一下使用方法:
使用@include可以包含任意的后缀名的文件内容,属于静态包含。
jsp:include页面是JSP,则先处理再将结果包含,称为动态包含,而如果是非*.jsp文件,则是把文件静态包含。
JSP九大内置对象
JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写
JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。
内置对象 | 类型 |
---|---|
pageContext | javax.servlet.jsp.PageContext |
request | javax.servlet.http.HttpServletRequest |
response | javax.servlet.http.HttpServletResponse |
session | javax.servlet.http.HttpSession |
application | javax.servlet.ServletContext |
config | javax.servlet.ServletConfig |
out | javax.servlet.jsp.JspWriter |
page | java.lang.Object |
exception | java.lang.Throwable |
内置对象使用
page对象
page对象表示当前JSP页面,可以理解为对象本身,了解即可。
out对象
out对象用于向客户发送文本数据,它通过调用pageContext.getOut()方法返回,其作用和用法和ServletReponse.getWriter()方法非常类似。
JSP页面中的out对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它
的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的Print
Writer对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
设置page指令的buffer属性关闭了out对象的缓存功能
out对象的缓冲区已满
整个JSP页面结束
out对象的工作原理图:
pageContext对象
pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个
域对象(容器),可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。
我们可以通过pageContext中的如下方法来获得其他隐式对象:
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
除此之外,pageContext还可以作为容器来使用,可以将一些数据存储在pageContext对象中。
public void setAttribute(java.lang.String name,java.lang.Object value)
public java.lang.Object getAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name)
public java.lang.Object findAttribute(java.lang.String name)
当要查找某个属性时,findAttribute方法按照查找顺序"page→request→session→application"在这四个对象中去查找,只要找到了就返回属性值,如果四
个对象都没有找到要查找的属性,则返回一个null。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page import="java.util.*"%>
<head>
<title>pageContext的findAttribute方法查找属性值</title>
</head>
<%
pageContext.setAttribute("name1", "legend");
pageContext.setAttribute("name2", "vincent");
pageContext.setAttribute("name3", "uding");
application.setAttribute("name4", "kevin");
%>
<%
// 使用pageContext的findAttribute方法查找属性
String refName1 = (String) pageContext.findAttribute("name1");
String refName2 = (String) pageContext.findAttribute("name2");
String refName3 = (String) pageContext.findAttribute("name3");
String refName4 = (String) pageContext.findAttribute("name4");
// 查找一个不存在的属性
String refName5 = (String) pageContext.findAttribute("name5");
%>
<h1>pageContext的findAttribute方法找到的属性值如下:</h1>
<h1>name1:<%=refName1%></h1>
<h1>name2:<%=refName2%></h1>
<h1>name3:<%=refName3%></h1>
<h1>name4:<%=refName4%></h1>
<h1>name5:<%=refName5%></h1>
<hr/>
<h1>使用EL表达式进行输出:</h1>
<h3>pageContext对象的name1属性:${name1}</h3>
<h3>request对象的name2属性:${name2}</h3>
<h3>session对象的name3属性:${name3}</h3>
<h3>application对象的name4属性:${name4}</h3>
<h3>不存在的name5属性:${name5}</h3>
EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、 session、application四个域中查找相应的
对象,找到则返回相应对象,找不到则返回""(注意,不是null,而是空字符串)。
pageContext对象中封装了访问其它域的方法:
public java.lang.Object getAttribute(java.lang.String name,int scope)
public void setAttribute(java.lang.String name, java.lang.Object value,int scope)
public void removeAttribute(java.lang.String name,int scope)
代表各个域的常量:
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
使用pageContext访问其他域:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>pageContext访问其他域</title>
<%
// session中存放name属性
pageContext.setAttribute("name", "legend", PageContext.SESSION_SCOPE);
%>
<%
// 取得session对象属性,使用pageContext对象获得
String name = (String) pageContext.getAttribute("name", PageContext.SESSION_SCOPE);
// 直接获取属性
String name1 = (String) session.getAttribute("name");
%>
<h1>取出存在session对象中的属性值</h1>
<p>第一种方式:使用pageContext取出session对象中的值</p>
<h3>姓名:<%=name%></h3>
<p>第二种方式:使用session直接获取对象中的值</p>
<h3>姓名:<%=name1%></h3>
</html>
PageContext引入和跳转到其他资源
PageContext类中定义了一个forward方法(用来跳转页面)和两个include方法(用来引入页面)来分别简化和替代RequestDispatcher.forward方法和include
方法。方法接收的资源如果以“/”开头, “/”代表当前web应用。
a) 使用PageContext的forward()跳转其他页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>使用PageContext的forward方法跳转页面</title>
</head>
<%
//方式一: 使用pageContext的forward()跳转到其他jsp页面
pageContext.forward("/index.jsp");
//方式二: 使用RequstDispatch的forward()方法实现跳转
pageContext.getRequest().getRequestDispatcher("/index.jsp").forward(request,response);
%>
</html>
在开发中,一般会使用<jsp:forward>标签来实现跳转,<jsp:forward>标签用于把请求转发给另外一个资源。
b) 使用pageContext的include方法引入资源
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<h1>使用pageContext的include()方法引入资源</h1>
<%
pageContext.include("/jspfragment/head.jsp");
pageContext.include("jspfragment/foot.jsp");
%>
<hr/>
<h1>使用jsp的include方式引入资源</h1>
<jsp:include page="/jspfragment/head.jsp"/>
<jsp:include page="/jspfragment/foot.jsp"/>
</head>
</html>
在实际开发中,使用pageContext的include方法引入页面这种做法也很少用,一般都使用jsp:include标签引入资源,因此这种做法了解一下即可。
JSP属性范围
JSP的属性范围就是当一个属性设置后,可以经过多少个其他页面后仍然可以访问的范围。它有四种属性范围,分别如下:
当前页:属性只能当前页面中取得,跳转到其他页面后无法使用。
服务请求:一个页面中设置的属性,只要经过服务器跳转,跳转之后的页面可以继续使用。
会话:一个用户设置的内容,只要是与与此用户相关的页面都可以访问。
上下文:在整个服务器上设置的属性,所有人都可以访问。
其中四种属性范围中都将包含如下的属性操作方法:
方法 | 描述 |
---|---|
public void setAttribute(String name,Object value) | 设置属性 |
public object getAttribute(String name) | 取得属性 |
public void removeAttribute(String name) | 删除属性 |
四种属性范围
-
Page属性范围(PageContext)
Page属性范围在一个页面设置的属性,跳转到其他页面则无法访问,它可以表示一个页面中的所有内容。
范例:演示在本页中存储属性和获取属性:
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// pageContext设置的属性只能在当前页取得
pageContext.setAttribute("name", "legend");
pageContext.setAttribute("date", new Date());
%>
<%
// 取得设置的属性
String refName = (String) pageContext.getAttribute("name");
Date refDate = (Date) pageContext.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
注意:pageContext存储的属性只能在当前页面中获取。
-
request属性范围
request属性范围表示在一次服务器跳转中有效,只要是服务器跳转,则设置request属性可以一直传递下去。
范例:演示request在一次跳转中获取属性:
pageContextSet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
request.setAttribute("name", "legend");
request.setAttribute("date", new Date());
%>
<jsp:forward page="/PageContextGet.jsp" />
pageContextGet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String refName = (String) request.getAttribute("name");
Date refDate = (Date) request.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
运行结果:
姓名:legend
日期:Fri Jun 30 10:06:38 CST 2017
从运行结果来看,程序跳转了后,request对象还可以获取属性,如果现在有第三个页面,它也可以继续向后进行传递。
注意:request对象在多次跳转后依然可以获取属性值,如果使用超链接的形式跳转的话,则无法再获取属性。
session属性范围
session设置的属性不管如何跳转,都可以取得,但是只能针对一个用户来说。
范例:演示session的属性范围
sessionSet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 此时设置的属性只能在本页相关的任意页面中获得
session.setAttribute("name", "legend");
session.setAttribute("date", new Date());
%>
<jsp:forward page="sessionGet.jsp"/>
sessionGet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String refName = (String) session.getAttribute("name");
Date refDate = (Date) session.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
<%--使用超链接的方式跳转--%>
<h1><a href="${pageContext.request.contextPath}/sessionGet1.jsp">继续跳转</a></h1>
sessionGet1.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String refName = (String) session.getAttribute("name");
Date refDate = (Date) session.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
输出结果:
sessionGet1.jsp中获得:
姓名:legend
日期:Fri Jun 30 10:23:06 CST 2017
注意:session存储的属性不管如何跳转,只要跟当前页面有关的页面都能获取到,但是只针对某一个用户而言。
-
application属性范围
application属性范围是在服务器上设置的一个属性,所以一旦设置之后任何用户都可以浏览到此属性。
范例:演示观察application属性范围。
applicationSet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 设置的属性任何用户都可以获取
application.setAttribute("name", "legend");
application.setAttribute("date", new Date());
%>
<h1><a href="${pageContext.request.contextPath}/applicationGet.jsp">跳转</a></h1>
applicationGet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String refName = (String) application.getAttribute("name");
Date refDate = (Date) application.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
注意:application的属性可以供所有用户访问,除非关闭服务器。过多使用会影响服务器性能。
PageContext的Scope
上面所讲解的四种属性范围都是通过PageContext属性范围设置上的,PageContext类继承了JspContext类,在JspContext类中定义了setAttribute()方法,如下所示:
public abstract void setAttribute(String name,Object value,int scope)
范例:PageContext以REQUEST_SCOPE模式存储存储,然后用request对象获取属性。
PageContextSet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
pageContext.setAttribute("name", "legend", PageContext.REQUEST_SCOPE);
pageContext.setAttribute("date", new Date(), PageContext.REQUEST_SCOPE);
%>
<jsp:forward page="RequestGet.jsp"/>
RequestGet.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String refName = (String) request.getAttribute("name");
Date refDate = (Date) request.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
运行结果:
姓名:legend
日期:Fri Jun 30 13:28:16 CST 2017
四种属性的使用场景
request:如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的。
session:如果客户向服务器发请求产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中。
application(servletContext):如果客户向服务器发请求产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在application(servletContext)域中。
JSP动作标签
JSP标签也成为Jsp Action元素,它用于JSP页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码而造成难以维护。
常用动作标签
JSP有如下标签,其中常用的是include、forward、param标签:
标签 | 描述 |
---|---|
<jsp:include /> | 在页面被请求的时候引入一个文件。 |
<jsp:useBean /> | 寻找或者实例化一个JavaBean。 |
<jsp:setProperty /> | 设置JavaBean的属性。 |
<jsp:getProperty /> | 输出某个JavaBean的属性。 |
<jsp:forward /> | 把请求转到一个新的页面。 |
<jsp:plugin /> | 根据浏览器类型为Java插件生成OBJECT或EMBED标记。 |
<jsp:element /> | 定义动态XML元素 |
<jsp:attribute /> | 设置动态定义的XML元素属性。 |
<jsp:body /> | 设置动态定义的XML元素内容。 |
<jsp:text /> | 在JSP页面和文档中使用写入文本的模板 |
所有的动作要素都有两个属性:id属性和scope属性。
id属性:id属性是动作元素的唯一标识,可以在JSP页面中引用。动作元素创建的id值可以通过PageContext来调用。
scope属性:该属性用于识别动作元素的生命周期。 id属性和scope属性有直接关系,scope属性定义了相关联id对象的寿命。
<jsp:include>标签
<jsp:include>标签是把另外一个资源的内容插入到当前的JSP输出的页面之中,这种方式称之为动态引入。
jsp<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
其中page属性指定被引入资源的相对路径。flush属性指定在插入其他输出内容时,是否将当前已输出内容刷新到客户端。
范例:演示<jsp:include>标签引入资源
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>jsp的jsp:include标签测试</title>
</head>
<body>
<%--引入其它JSP页面--%>
<jsp:include page="/jspfragments/head.jsp"/>
<h1>网页主体内容</h1>
<jsp:include page="/jspfragments/foot.jsp"/>
</body>
</html>
<jsp:include>和include指令区别
<jsp:include>标签是动态引入, <jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。
include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。
通过下面的例子来说明<jsp:include>标签与include指令的区别
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%!
int i=1000;
%>
<h1>demo.jsp中i的值为:<%=i%></h1>
分别使用include指令和<jsp:include>标签两种包含语句,包含以上的demo.jsp
a) 使用@include静态包含
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%!
int i=10;
%>
<h1>i的值为:<%=i%></h1>
<h1><%@include file="/jspfragments/demo.jsp"%></h1>
此时在编译jsp时就已经提示出错了,如下所示
因为静态包含是将全部内容包含进来之后,再进行处理,属于先包含后处理。
b) 使用动态包含
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>JspIncludeTagDemo02.jsp</h1>
<%!
int i=10;
%>
<h1>i的值为:<%=i%></h1>
<h1><jsp:include page="/jspfragments/demo.jsp" /></h1>
发现结果已经可以正确地显示,而且不会互相影响,这是因为使用jsp:include属于动态包含,动态包含就是指先将各个页面分别处理,处理完之后再将处理后的
结果包含进来。
*.jspf在jsp:include、@include和c:import中的区别
JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。正常情况下只有@include指令才行正常解析jspf文件,而使用jsp:include和JSTL的
c:import都无法解析jspf文件,会把其当成纯文本文件处理。
解决方式有两种,他们分别如下:
a) 第一种方式:修改web.xml文件,添加对扩展名为*.jspf文件的映射
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<!-- 让jspf扩展名同样成为JSP Servlet处理的文件。-->
<url-pattern>*.jspf</url-pattern>
</servlet-mapping>
b)第二种方式:修改Tomcat服务器的web.xml文件,添加对*.jspf的映射
<!-- 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>
添加如上两种配置信息后,此时tomcat服务器就可以正常解析执行*.jspf文件了。
<jsp:forward>标签
<jsp:forward>标签用于把请求转发给另外一个资源。
<jsp:forward page="relativeURL | <%=expression%>" />
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
范例:演示使用<jsp:forwar>标签跳转页面
forwardDemo01.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--使用<jsp:forward>标签跳转到forwarddemo02.jsp--%>
<jsp:forward page="/forwardDemo02.jsp"/>
forwardDemo02.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>跳转之后的页面!!</h1>
<jsp:include>跳转后页面改变,而地址栏不会改变,因此它的跳转属于服务器端的跳转。
<jsp:param>标签
当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。
语法1:
<jsp:include page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
语法2:
<jsp:forward page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。
范例:使用<jsp:param>标签向被包含的页面传递参数。
JspIncludeDemo.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>JspIncludeTagDemo.jsp</h1>
<hr/>
<jsp:include page="/jspfragments/Inc.jsp">
<jsp:param name="parm1" value="legend" />
<jsp:param name="parm2" value="vincent" />
</jsp:include>
Inc.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>接收从JspIncludeDemo.jsp页面中传递过来的参数:</h1>
<h2><%=request.getParameter("parm1")%></h2>
<h2><%=request.getParameter("parm2")%></h2>
范例:使用<jsp:param>标签向跳转的页面传递参数。
forwardDemo01.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<jsp:forward page="/forwarddemo01.jsp">
<jsp:param name="ref1" value="legend" />
<jsp:param name="ref2" value="vincent" />
</jsp:forward>
forwardDemo02.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>跳转之后的页面!!</h1>
<h1>接收从forwarddemo03.jsp传递过来的参数:</h1>
<h1>ref1:<%=request.getParameter("ref1")%></h1>
<h1>ref2:<%=request.getParameter("ref2")%></h1>
JavaBean
JavaBean是一个遵循特定写法的Java类,它通常具备如下特点:
这个Java类必须具有一个无参的构造函数
属性必须私有化。
私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。
JavaBean的格式如下:
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵守命名规范的方法,
从而获知JavaBean的属性,进而调用其属性保存数据。
JSP中使用JavaBean
JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:
<jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
<jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
<jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。
<jsp:useBean>标签
<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它
以指定的名称存储到指定的域范围中。
<jsp:useBean id="beanName" class="package.className" scope="page|request|session|application"/>
"id"属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
"class"属性用于指定JavaBean的完整类名(即必须带有包名)。
"scope"属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application的一个,默认值是page。
范例:演示JavaBean的使用。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--在jsp中使用jsp:useBean标签来实例化java对象--%>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--给User对象进行赋值--%>
<%
user.setName("legend");
user.setAge(18);
%>
<html>
<head>
<title>标签使用范例</title>
</head>
<body>
<h2>姓名:<%=person.getName()%></h2>
<h2>年龄:<%=person.getAge()%></h2>
</body>
</html>
运行结果:
姓名:legend
年龄:18
带标签体的<jsp:useBean>标签
语法如下所示:
<jsp:useBean ...>
Body
</jsp:useBean>
Body部分的内容只在<jsp:useBean>标签创建JavaBean的实例对象时才执行。这种做法用得不多,了解一下即可。
<jsp:setProperty>标签
<jsp:setProperty>标签用于设置和访问JavaBean对象的属性。
语法格式一:
<jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>
语法格式二:
<jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />
语法格式三:
<jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>
语法格式四:
<jsp:setProperty name="beanName" property= "*" />
其中解释如下:
name属性用于指定JavaBean对象的名称。
property属性用于指定JavaBean实例对象的属性名。
value属性用于指定JavaBean对象的某个属性的值。
param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值。
范例一:演示使用jsp:setProperty标签设置User对象的属性值
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<jsp:setProperty name="user" property="name" value="legend"/>
<jsp:setProperty name="user" property="age" value="18"/>
<%--birthday属性是Date类型,属于复合数据类型,无法转换成字符串--%>
<jsp:setProperty name="user" property="birthday" value="<%=new Date()%>"/>
<html>
<head>
<title>jsp:setProperty标签使用</title>
</head>
<body>
<h2>姓名:<%=user.getName()%></h2>
<h2>年龄:<%=user.getAge()%></h2>
<h2>生日:<%=user.getBirthday()%></h2>
</body>
</html>
运行结果:
姓名:legend
年龄:18
生日:Sat Jul 01 19:45:19 CST 2017
范例二:使用请求参数为bean属性赋值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="usr" class="com.legend.jsp.User" scope="page"/>
<jsp:setProperty name="usr" property="name" param="param_name"/>
<html>
<head>
<title>jsp:setProperty标签使用</title>
</head>
<body>
<h2>姓名:<%=usr.getName()%></h2>
</body>
</html>
在浏览器中需要拼接param_name参数,输出结果如下:
http://localhost:8080/javaBean03.jsp?param_name=legend
姓名:legend
范例三:用所有的请求参数为bean属性赋值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--*代表bean的所有属性--%>
<jsp:setProperty name="user" property="*"/>
<html>
<head>
<title>jsp:setProperty标签使用</title>
</head>
<body>
<h2>姓名:<%=user.getName()%></h2>
<h2>年龄:<%=user.getAge()%></h2>
</body>
</html>
输出结果:
http://localhost:8080/javaBean04.jsp?name=legend&age=18
姓名:legend
年龄:18
<jsp:getProperty>标签
<jsp:getProperty>标签用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。
<jsp:getProperty name="beanInstanceName" property="PropertyName" />
name属性用于指定JavaBean实例对象的名称,其值应与<jsp:useBean>标签的id属性值相同。
property属性用于指定JavaBean实例对象的属性名。
如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串。
范例:演示jsp:getProperty获取bean对象的属性值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--设置属性值--%>
<jsp:setProperty name="user" property="name" value="legend"/>
<jsp:setProperty name="user" property="age" value="18"/>
<html>
<head>
<title>jsp:getProperty标签使用范例</title>
</head>
<body>
<%--获取属性值--%>
<h2><jsp:getProperty name="user" property="name"/></h2>
<h2><jsp:getProperty name="user" property="age"/></h2>
</body>
</html>
输出结果:
legend
18