JavaWeb学习笔记(七)—— JSP
一、什么是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的运行环境即jre),说跨平台其实也就是jre是跨平台的,java站在jre上,自然java也是跨平台的了. 举个栗子: jre就相当于一个多功能套街头,你java只要符合jre的规范,就能套上这个 多功能接头了.自然也就能跨平台了.
- 业务代码相分离: 在使用JSP技术开发Web应用时,可以将界面的开发与应用程序的开发分离开,使用HTML 来设计界面,使用JSP标签和脚本来动态生成页面上的内容. 在服务器端,JSP容器(tomcat,jboss,weblogic等的服务器)负责解析JSP标签和脚本程序,生成所请求的内容,并将这执行结果以HTML页面的形式返回到浏览器.(这是jsp的初衷, 但是在前辈们的使用中发现jsp中会出现大量的业务代码,导致业务逻辑等不清楚,开发完成后维护起来也不容易,后来就尽量将业务逻辑写在后台了,使用 MVC模式 这样逻辑更加清晰)
- 组件重用: JSP中可以使用JavaBean编写业务组件,也就是使用一个JavaBean类封装业务处理代码或者作为一个数据存储模型, 在JSP页面中, 甚至在整个项目中, 都可以重复使用这个JavaBean, 同时,JavaBean也可以应用到其他Java应用程序中.
- 预编译: 预编译也就是在用户第一次通过浏览器访问JSP页面时,服务器将对JSP页面代码进行编译,并且仅执行一次编译.编译好的代码将被保存,在用户下一次访问时,会直接执行编译好的代码.这样不仅节约了服务器的CPU资源, 还大大的提升了客户端的访问速度。
二、JSP的基本语法
2.1 JSP脚本元素
JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java程序代码。通过JSP脚本元素可以将Java代码嵌入HTML页面中,所有可执行的Java代码,都可以通过JSP脚本来执行。(不建议在jsp页面中嵌入java代码)
JSP脚本元素主要包含如下三种类型:
- JSP Scriptlets:<%...%>在这个里面书写内容等同于在方法中书写代码
Java语句;方法中能放什么,它就能放什么。如果在这个元素里面定义了一个变量,那么此时他就是一个局部变量!
- JSP声明语句:<%!...%> 在这个里面书写内容等同于在类中书写代码
Java定义类成员;没人会用它!有人会考它!定义类的成员!类能包含什么,它就可以包含什么。声明中没有9大内置对象!
- JSP表达式:<%=…%> 里面的代码会被输出!
Java表达式;等同与resopnse.getWriter().print()。写到这里的东西,都是用来输出的!
【JSP Scriptlets】
JSP Scriptlets是一段代码段。当需要使用Java实现一些复杂操作或控制时,可以使用它。JSP Scriptlets的语法格式如下所示:
<% java代码(变量、方法、语句等)%>
在JSP Scriptlets中声明的变量是JSP页面的局部变量,调用JSP Scriptlets时,会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。
【JSP声明语句】
JSP的声明语句用于声明变量和方法,它以“<%!”开始,以“%>”结束,其语法格式如下所示:
<%! 定义的变量或方法等 %>
在上述语法格式中,被声明的Java代码将被编译到Servlet的_jspService()方法之外,即在JSP声明语句中定义的都是成员方法、成员变量、静态方法、静态变量、静态代码块等。在JSP声明语句中声明的方法在整个JSP页面内有效。
在一个JSP页面中可以有多个JSP声明语句,单个声明中的Java语句可以是不完整的,但是多个声明组合后的结果必须是完整的Java语句。
【JSP表达式】
JSP表达式(expression)用于将程序数据输出到客户端,它将要输出的变量或者表达式直接封装在以“<%=” 开头和以“%>”结尾的标记中,其基本的语法格式如下所示:
<%=expression %>
在上述语法格式中,JSP表达式中的将“expression”表达式结果输出到浏览器。需要注意的是:
- <%=”和“%>”标记之间插入的是表达式,不能插入语句。
- “<%=”是一个完整的符号,“<%”和“=”之间不能有空格。
- JSP表达式中的变量或表达式后面不能有分号
2.2 JSP注释
同其它各种编程语言一样,JSP也有自己的注释方式,其基本语法格式如下:
<%-- 注释内容 --%>
需要注意的是,Tomcat将JSP页面编译成Servlet程序时,会忽略JSP页面中被注释的内容,不会将注释信息发送到客户端。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>JSP注释</title> </head> <body> <%--这是个JSP注释--%> <!--这是个HTML注释--> </body> </html>
上述代码中,包含HTML注释和JSP两种注释方式。启动tomcat服务器,访问该页面,可以看到该页面什么都不显示,接下来右键【查看页面源代码】:
从图中可以看出,JSP的注释信息没有显示出来,而只显示出了HTML注释。这是因为Tomcat编译JSP文件时,会将HTML注释当成普通文本发送到客户端,而JSP页面中格式为"<%-- 注释信息 --%>"的内容则会被忽略,不会发送到客户端。
JSP注释、Java注释、HTML注释对比:
<%--JSP注释--%> <% //java注释 %> <!--HTML注释-->
2.3 JSP运行原理
【Web服务器是如何调用并执行一个jsp页面的?】
浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet。
JSP的运行过程具体如下:
(1)客户端发出请求,请求访问JSP文件
(2)JSP容器先将JSP文件转换成一个Java源文件(Java Servlet源程序),在转换过程中,如果发现JSP文件中存在任何语法错误,则中断转换过程,并向服务器和客户端返回出错信息
(3)如果转换成功,则JSP容器将生成的Java源文件编译成响应的字节码文件*.class。该class文件就是一个Servlet,Servl容器会像处理其它Servlet一样处理它。
以HelloWorld.jsp为例:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello World</title> </head> <body> <% out.print("Hello World"); %> </body> </html>
当用户第一次访问HelloWorld.jsp页面时,该页面会先被JSP容器转换为一个名称为HelloWorld_jsp.java的源文件,然后将源文件编译为一个名称为HelloWorld_jsp.class字节码文件。如果项目发布在Tomcat的webapps目录中,源文件和.class文件可以在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下找到。而使用IDEA开发工具时,idea的web项目不是直接将webapp放在tomcat容器中。而是将生成的webapp与tomcat按照idea的“技术”形成连接,这样减少了很大的配置tomcat的时间,一次配置,一劳永逸。jsp编译后的class和java文件在C:/Users/登录名/.IntelliJIdea2017.2/system/tomcat/Tomcat-pure_工程名/work/Catalina/localhost/appcontext名称/org/apache/jsp目录下:
从图中可以看出,HelloWorld.jsp已被转换为源文件和.class文件。打开HelloWorld_jsp.java文件,可查看转换后的源代码:
public final class HelloWorld_jsp extends 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("<html>\r\n"); out.write("<head>\r\n"); out.write(" <title>Hello World</title>\r\n"); out.write("</head>\r\n"); out.write("<body>\r\n"); out.write(" "); out.print("Hello World"); out.write("\r\n"); out.write("</body>\r\n"); out.write("</html>\r\n"); } catch (java.lang.Throwable t) { if (!(t instanceof javax.servlet.jsp.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); else throw new ServletException(t); } } finally { _jspxFactory.releasePageContext(_jspx_page_context); } } }
可以看出HelloWorld.jsp文件转换后的源文件m没有实现Servlet接口,但继承了org.apache.jasper.runtime.HttpJspBase类。在Tomcat源文件中查看HttpJspBase类的源代码
从HeepJspBase的源码中可以看出,HttpJspBase类是HttpServlet的一个子类,由此可见,HelloWorld_jsp类就是一个Servlet。结论:JSP就是一个Servlet。
当浏览器访问服务器上的HelloWorld.jsp页面时,其实就是在访问HelloWorld_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。
【jsp页面中的html排版标签是如何被发送到客户端的?】
浏览器接收到的这些数据:
都是在_jspService方法中使用如下的代码输出给浏览器的:
在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello World");%>直接翻译成out.print("Hello World");,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。
【jsp页面中的java代码服务器是如何执行的?】
在jsp中编写的java代码会被翻译到_jspService方法中去,当执行_jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。
【Web服务器在调用jsp时,会给jsp提供一些什么java对象?】
查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象
其中page对象,request和response已经完成了实例化,而其它5个没有实例化的对象通过下面的方式实例化
这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对象 %>
运行结果如下:
三、JSP三大指令
3.1 page指令
在JSP页面中,经常需要对页面的某些特征进行描述,例如,页面的编码方式,JSP页面采用的语言等。这时,可以通过page指令来实现。page指令的具体语法格式如下所示:
<%@ page 属性名1=“属性值1” 属性名2=“属性名2”...%>
在上面的语法格式中,page用于声明指令的名称,属性用来指定JSP页面的某些特征。page指令提供了一系列与JSP页面相关的属性:
【pageEncoding和contentType】
pageEncoding指定当前JSP页面的编码!这个编码是给服务器看的,服务器需要知道当前JSP使用的编码,不然服务器无法正确把JSP编译成java文件。所以这个编码只需要与真实的页面编码一致即可!
contentType属性与response.setContentType()方法的作用相同!它会完成两项工作,一是设置响应字符流的编码,二是设置content-type响应头。例如:<%@ contentType=”text/html;charset=utf-8”%>,它会使“真身”中出现response.setContentType(“text/html;charset=utf-8”)。
无论是page指令的pageEncoding还是contentType,它们的默认值都是ISO-8859-1,我们知道ISO-8859-1是无法显示中文的,所以JSP页面中存在中文的话,一定要设置这两个属性。
【import属性】
指定在JSP页面翻译成的Servlet源文件中导入的包或类。一个import属性可以引入多个类,中间用英文逗号隔开:
<%@page import=”java.net.*,java.util.*,java.sql.*”%>
import是唯一可以声明多次的page指令属性:
<%@page import=”java.util.*” import=”java.net.*” import=”java.sql.*”%>
但是,我们一般会使用多个page指令来导入多个包:
<%@ page import=”java.util.*”%> <%@ page import=”java.net.*”%> <%@ page import=”java.text.*”%>
【errorPage和isErrorPage】
我们知道,在一个JSP页面出错后,Tomcat会响应给用户错误信息(500页面)!如果你不希望Tomcat给用户输出错误信息,那么可以使用page指令的errorPage来指定错误页!也就是自定义错误页面,例如:<%@page errorPage=”xxx.jsp”%>。这时,在当前JSP页面出现错误时,会请求转发到xxx.jsp页面。
a.jsp
<%@ page import="java.util.*" pageEncoding="UTF-8"%> <%@ page errorPage="b.jsp" %> <% if(true) throw new Exception("哈哈~"); %>
b.jsp
<%@ page pageEncoding="UTF-8"%> <html> <body> <h1>出错啦!</h1> </body> </html>
在上面代码中,a.jsp抛出异常后,会请求转发到b.jsp。在浏览器的地址栏中还是a.jsp,因为是请求转发!
而且客户端浏览器收到的响应码为200,表示请求成功!如果希望客户端得到500,那么需要指定b.jsp为错误页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page isErrorPage="true" %> <html> <body> <h1>出错啦!</h1> <%=exception.getMessage() %> </body> </html>
注意,当isErrorPage为true时,说明当前JSP为错误页面,即专门处理错误的页面。那么这个页面中就可以使用一个内置对象exception了。其他页面是不能使用这个内置对象的!而且,一旦转发到错误页,那么Tomcat会把状态码设置为500,而不再是200了。
【autFlush和buffer】
buffer表示当前JSP的输出流(out隐藏对象)的缓冲区大小,默认为8kb。
authFlush表示在out对象的缓冲区满时如果处理!当authFlush为true时,表示缓冲区满时把缓冲区数据输出到客户端;当authFlush为false时,表示缓冲区满时,抛出异常。authFlush的默认值为true。
这两个属性一般我们也不会去特意设置,都是保留默认值!
【isELIgnored】
isElIgnored属性表示当前JSP页面是否忽略EL表达式,默认值为false,表示不忽略(即支持)。
【language】:只能是Java
【session】:默认为true,表示当前JSP页面可以使用session对象,如果为false表示当前JSP页面不能使用session对象;
需要注意的是:page指令对整个页面都有效,而与其书写的位置无关,但是习惯上把page指令写在JSP页面的最前面。
3.2 include指令
include指令表示静态包含!即目的是把多个JSP合并成一个JSP文件!
include指令只有一个属性:file,指定要包含的页面,例如:<%@include file=”b.jsp”%>。
静态包含:当hel.jsp页面包含了lo.jsp页面后,在编译hel.jsp页面时,需要把hel.jsp和lo.jsp页面合并成一个文件,然后再编译成Servlet(Java文件)。
很明显,在lo.jsp中使用username变量,而这个变量在hel.jsp中定义的,所以只有这两个JSP文件合并后才能使用。通过include指定完成对它们的合并!
3.2 taglib指令
在JSP页面中使用第三方的标签库时,需要使用taglib指令来“导包”。例如:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
其中prefix表示标签的前缀,这个名称可以随便起。uri是由第三方标签库定义的,所以你需要知道第三方定义的uri。
四、JSP九大内置对象
在JSP页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化Web应用程序的开发,JSP2.0规范中提供了9个隐式(内置)对象,它们是JSP默认创建的,可以直接在JSP页面中使用 。
名称 |
类型 |
描述 |
pageContext |
javax.servlet.jsp.PageContext |
JSP的页面容器 |
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 |
指当前页面转换后的Servlet类的实例 |
exception |
java.lang.Throwable |
表示JSP页面所发送的异常,在错误页中才起作用 |
request,response,session,application,config这些对象在前面都已经作了详细的介绍,而page对象在JSP页面中很少被用到。所以这里重点介绍一下剩下的pageContext对象,out对象。
4.1 pageContext对象
在JavaWeb中一共四个域对象,其中Servlet中可以使用的是request、session、application三个对象,而在JSP中可以使用pageContext、request、session、application四个域对象。JSP这四个域的范围为:
PageContext常量名 |
描述 |
作用域名称 |
域对象类型 |
PageScope |
当前页面中有效 |
pageContext |
PageContext |
RequestScope |
一次请求范围 |
request |
HttpServletRequest |
SessionScope |
一次会话范围 |
session |
HttpSession |
ApplicationScope |
应用范围 |
application |
ServletContext |
- page:表示当前页,通常没用。jsp标签底层使用。
- request:表示一次请求。通常一次请求就一个页面,但如果使用请求转发,可以涉及多个页面。
- session:表示一次会话。可以在多次请求之间共享数据。
- application:表示一个web应用(项目)。可以整个web项目共享,多次会话共享数据。
在JSP页面中,使用pageContext对象可以获取JSP的其他8个隐式对象。pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它代表当前JSP页面的运行环境,并提供了一系列用于获取其他隐式对象的方法:
方法名 |
功能描述 |
JspWriter getOut() |
获取out内置对象 |
ServletConfig getServletConfig() |
获取config内置对象 |
Object getPage() |
获取page内置对象 |
ServletRequest getRequest() |
获取request内置对象 |
ServletResponse getResponse() |
获取response内置对象 |
HttpSession getSession() |
获取session内置对象 |
ServletContext getServletContext() |
获取application内置对象 |
Exception getException() |
获取exception内置对象 |
上表中列举了pageContext获取其他隐式对象的方法,这样,当传递一个pageContext对象后,就可以通过这些方法轻松地获取到其他8个隐式对象了。
pageContext对象不仅提供了获取隐式对象的方法,还提供了存储数据的功能。pageContext对象存储数据是通过操作属性来实现的:
方法名称 |
功能描述 |
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对象操作属性的相关方法,其中,参数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对象的使用:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <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%> </body> </html>
浏览器的显示结果如下:
从显示结果可以看出,通过pageContext对象可以获取到request对象,并且还可以获取不同范围内的属性。
4.2 out对象
out对象用于向客户端发送文本数据。
out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out对象的类型为JspWriter,它相当于一种带缓存功能的PrintWriter。设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
- 设置page指令的buffer属性关闭了out对象的缓存功能
- out对象的缓冲区已满
- 整个JSP页面结束
接下来,通过一张图来描述JSP页面的out对象与Servlet引擎提供的缓冲区之间的工作关系:
从图中可以看出,在JSP页面中,通过out隐式对象写入数据相当于将数据插入到JspWriter对象的缓冲区中,只有调用ServletResponse.getWriter()方法,缓冲区中的数据才能真正写入到Servlet引擎所提供的缓冲区中。为了验证上述说法是否正确,接下来通过一个具体的案例来演示out对象的使用。
创建out.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>out</title> </head> <body> <% out.println("first line<br>"); response.getWriter().println("second line<br>"); %> </body> </html>
启动服务器,访问该页面,显示如下:
从图中可以看出,尽管out.println语句位于response.getWriter().println语句之前,但它的输出内容却在后面。由此可以说明,out对象通过print语句写入数据后,直到整个JSP页面结束,out对象中输入缓冲区的数据(即:first line)才真正写入到Servlet引擎提供的缓冲区中,而 response.getWriter().println语句则是直接把内容(即:second line)写入Servlet引擎提供的缓冲区中,Servlet引擎按照缓冲区中的数据存放顺序输出内容。
五、JSP动作标签
JSP动作标签是用来控制JSP的行为,执行一些常用的JSP页面动作。通过动作标签可以实现使用多行Java代码能够实现的效果,如包含页面文件,实现请求转发等。
5.1 jsp:include
<jsp:include>标签的作用是用来包含其它JSP页面的!你可能会说,前面已经学习了include指令了,它们是否相同呢?虽然它们都是用来包含其它JSP页面的,但它们的实现的级别是不同的!
include指令是在编译级别完成的包含,即把当前JSP和被包含的JSP合并成一个JSP,然后再编译成一个Servlet。
include动作标签是在运行级别完成的包含,即当前JSP和被包含的JSP都会各自生成Servlet,然后在执行当前JSP的Servlet时完成包含另一个JSP的Servlet。它与RequestDispatcher的include()方法是相同的!
hel.jsp
<body> <h1>hel.jsp</h1> <jsp:include page="lo.jsp" /> </body>
lo.jsp
<% out.println("<h1>lo.jsp</h1>"); %>
5.2 jsp:forward
forward标签的作用是请求转发!forward标签的作用与RequestDispatcher#forward()方法相同。
hel.jsp
<body> <h1>hel.jsp</h1> <jsp:forward page="lo.jsp"/> </body>
lo.jsp
<% out.println("<h1>lo.jsp</h1>"); %>
注意,最后客户端只能看到lo.jsp的输出,而看不到hel.jsp的内容。也就是说在hel.jsp中的<h1>hel.jsp</h1>是不会发送到客户端的。<jsp:forward>的作用是“别在显示我,去显示它吧!”。
5.3 jsp:param
还可以在<jsp:include>和<jsp:forward>标签中使用<jsp:param>子标签,它是用来传递参数的。下面用<jsp:include>来举例说明<jsp:param>的使用。
a.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>a.jsp</title> </head> <body> <h1>a.jsp</h1> <hr/> <jsp:include page="b.jsp"> <%--给被包含的页面b.jsp传递参数。--%> <jsp:param name="username" value="zhangsan"/> </jsp:include> </body> </html>
b.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>b.jsp</title> </head> <body> <h1>b.jsp</h1> <hr/> <% // 获取参数 String username = request.getParameter("username"); out.print("你好:" + username); %> </body> </html>
参考:https://www.cnblogs.com/xdp-gacl/p/3764991.html