JavaWeb(三):JSP
JSP是JavaServer Page的缩写,也就是服务端网页。
一、概述
1.1 为什么使用JSP
在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。JSP是简化Servlet编写的一种技术,它将Java代码和HTML语句混合在同一个文件中编写,只对网页中的要动态产生的内容采用Java代码来编写,而对固定不变的静态内容采用普通静态HTML页面的方式编写。
如果仅仅为了少量的动态内容而用Java代码来生成整个网页,会有什么不便的地方?
程序员真的很难:
如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程序代码产生,整个Servlet程序的代码将非常臃肿,编写和维护都将非常困难。 对大量静态内容的美工设计和相关HTML语句的编写,并不是程序员所要做的工作,程序员对此也不一定在行。网页美工设计和制作人员不懂Java编程,更是无法来完成这样的工作。
使用Java生成HTML代码,这些HTML代码将会包裹在双引号当中,即字符串的形式。代码编辑器无法检查HTML代码,而且会有冗长的行结束符\r\n,HTML里的引号还需要进行转义。
示例:
PrintWriter writer = Response.getWriter();
writer.append("<!DOCTYPE html>\r\n")
.append("<html>\r\n")
.append(" <body>\r\n")
.append(" \"Hello World!\"\r\n")
.append(" <\body>\r\n")
.append("</html>\r\n");
于是,可以想到一种混合解决方案,在页面中而不是后台结合Java代码和HTML标签。绝大部分的静态页面采用固定的HTML标签,在HTML标签中嵌入运行Java代码的功能,JSP技术应运而生。
1.2 运行原理
JSP本质上是Servlet
Web容器(Servlet引擎)接收到以.jsp为扩展名的URL的访问请求时,它将把该访问请求交给JSP引擎去处理。Tomcat默认每个JSP 页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序,接着再把这个Servlet源程序编译成Servlet的class类文件,然后再由Web容器(Servlet引擎)像调用普通Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的Servlet程序。
JSP规范也没有明确要求JSP中的脚本程序代码必须采用Java语言,JSP中的脚本程序代码可以采用Java语言之外的其他脚本语言来编写。但是,JSP页面最终必须转换成Java Servlet程序。
如果担心第一次访问时编译JSP影响性能,可以在Web应用程序正式发布之前,将所有JSP页面预先编译成Servlet程序。
JSP工作流程:
- 客户端发送请求给web容器
- web容器将jsp首先转译成servlet源代码
- web容器将servlet源代码编译成.class 文件
- web容器执行.class 文件
- web容器将结果响应给客户端
JSP的编译
JSP会被翻译成.java放Tomcat/work/Catalina/localhost/***/org/apache/jsp/page,然后编译成.class。一个JSP页面的生成的.java文件如下:
public class My$jsp extends HttpJspBase {
static {}
public date$jsp() {}
private static boolean _jspx_inited = false;
public final void _jspx_init() throws org.apache.jasper.runtime.JspException {};
public void _JSP pageservice(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String _value = null;
try { if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init(); _jspx_inited = true;
}
}
}
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response, "", true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
// HTML
// begin
[file="/date.jsp";
from=(0,0);to=(7,6)] out.write("\r\n\r\n\r\n" + "\r\n\r\n\r\n" + "The date is\r\n");
// end
// begin
[file="/date.jsp";from=(7,8);to=(7,57)] out.println((new java.util.Date()).toString());
// end
// HTML
// begin
[file="/date.jsp";from=(7,59);to=(10,7)] out.write("\r\n \r\n \r\n");
// end
} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0) {
out.clearBuffer();
} if (pageContext != null) {
pageContext.handlePageException(t);
}
} finally { if (_jspxFactory != null) { _jspxFactory.releasePageContext(pageContext); }
}
}
}
最重要的函数就是pageservice,web容器在编译好一个JSP类以后,就申请这个类的对象,并且直接调用pageservice来获得Response,最后返回给客户。
所有的JSP页面翻译出来的class,都从HttpJspBase继承,并且命名为PageName$jsp。在第一次调用pageservice函数的时候,该class会进行一次初始化,而这个初始化函数是_jspx_init,我们还可以自定义这个函数来实现JSP页面的初始化。
HTML代码直接被写到PrintWriter里面回馈给用户。
为什么JSP页面有那么多省写方式,比如说session , out , page , context之类。
这都是在pageservice里面定义的临时变量,每一次调用JSP页面,这些变量都会被重新初始化一次。当然我们也可以方便的声明自己的变量。
指令只是一个一个的对应为response.setContentType()的语句而已。
JSP页面转向这个语句被翻译为getServletContext().getRequestDispatcher("/List.jsp").forward(req, res);语句。
二、创建一个JSP
概览
模板元素:
JSP页面中的静态HTML内容称之为JSP模板元素,在静态的HTML内容中可以嵌套JSP的其他各种元素来产生动态内容和执行业务逻辑JSP模板元素定义了网页的基本骨架,即定义了页面的结构和外观。
所有JSP中已经隐含式地包含了一个标签库,那就是JSP标签库(前缀为jsp),使用它不用在JSP中添加taglib指令(不过需要为jsp标签添加XMLNS声明)。
几个JSP常用标签:
<jsp:include>标签
<jsp:forward>标签
<jsp:param>标签
<jsp:useBean>标签
<jsp:setProperty>标签
<jsp:getProperty>标签
后面会介绍Java标准标签库
标签语法:
<prefix:tagname[ attribute=value[ attribute=value [...] ] ] /> <prefix:tagname[ attribute=value[ attribute=value [...] ] ] >
content
</prefix:tagname>
prefix表示JSP标签库前缀,也被称为命名空间(XML术语),tagname是TLD中定义的标签名称。特性值将使用单引号或者双引号括起来,特性之间需要空白。
几种结构:
<%@ 这是一个指令 %>
<%! 这是一个声明 %>
<% 这是一个脚本 %>
<%= 这是一个表达式 %>
指令用于指示JSP解释器执行某个操作(例如设置内容类型)或者对文件作出假设(例如使用的是哪种脚本语言)、导入类、在转换时包含其他JSP或者包含JSP标签库。
声明用于在JSP Servlet类的范围内声明一些东西,例如可以定义实例变量、方法或声明标签中的类。要记住:这些声明都将出现在自动生成的JSP Servlet类中,所以声明中定义的类实际上是JSP Servlet类的内部类。声明中的代码将在转换时被复制到JSP Servlet类的主体中,并且它们可用于声明某些字段、类型或方法。
脚本中也包含Java代码,但不同于声明,脚本有不同的作用域,脚本被复制到_jspService方法(Tomcat 8.0)中,而非Servlet类的主体中(即和_jsService方法地位相同)。_jspService方法中的所有局部变量都可以在脚本中使用,任何在该方法体中合法的代码在脚本中也是合法的。所以,脚本中定义的是局部字段而非实例字段。还以在脚本中使用条件语句、操作对象和执行数学计算,这些在声明中都无法完成。我们甚至可以在脚本中定义类,这些类是_jspService方法中有效。声明中定义的类、方法或变量都可以在脚本中使用,但脚本中定义的类或变量不能在声明中使用。
表达式包含了一些简单的Java代码,可用于向客户端输出一些内容,它将把代码的返回值变量输出到客户端。任何赋值表达式的右侧都可以用在表达式中,表达式的作用域与脚本相同,如同脚本一样,表达式也将被复制到_jspServlet方法中。
映射JSP:
JSP就是一个Servlet,因此我们在web.xml文件中也可以使用<servlet>标签和<servlet-mapping>标签来映射JSP,使JSP能有一个虚拟目录(对外访问路径)。
<servlet>
<servlet-name>myjsp</servlet-name>
<jsp-file>/MyJsp.jsp</jsp-file>
</servlet> <servlet-mapping>
<servlet-name>myjsp</servlet-name>
<url-pattern>/myhtml.html</url-pattern>
</servlet-mapping>
注释
在JSP中可以使用4种注释:
- XML注释: <!-- 这是注释 -->
- 传统的Java注释: // 这是注释
- 传统的Java块注释: /* 这是注释 */
- JSP注释: <%-- 这是JSP注释 --%>
2.1 声明
JSP声明将Java代码封装在<%!和 %>之中,它里面的代码将被插入进Servlet的_jspService方法的外面,所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法。
多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。
<%!
void test(){}
%>
几乎不用
2.2 脚本——在JSP中使用Java代码(不推荐)
JSP脚本片断(scriptlet)是指嵌套在<% 和 %>之中的一条或多条Java程序代码。
在JSP脚本片断中,可以定义变量、执行基本的程序运算、调用其他Java类、访问数据库、访问文件系统等普通Java程序所能实现的功能。
JSP脚本片断中的Java代码将被原封不动地搬移进由JSP页面所翻译成的Servlet的_jspService方法中,所以,JSP脚本片断之中只能是符合Java语法要求的程序代码,除此之外的任何文本、HTML标记、其他JSP元素都必须在脚本片断之外编写。
JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每条命令执行语句后面必须用分号(;)结束。
在一个JSP页面中可以有多个脚本片断(每个脚本片断代码嵌套在各自独立的一对<% 和 %>之间),在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。
<%
int x = 3;
%>
<p>这是一个HTML段落</p>
<%
out.println(x);
%>
for
<%for (int i=1; i<5; i++) {%>
<H<%=i%>>www.it315.org</H<%=i%>>
<%}%>
if...else...
<%if(java条件表达式){%>
其他元素
<%}else{%>
其他元素
<%}%>
隐含变量
隐含变量是不用定义或声明就能使用的变量,可以在脚本和表达式中使用request、response、pageContext、session、application、config、out、page这8个隐含对象,实际上还可以使用一个叫exception的隐含对象。
JSP规范要求JSP的转换器和编译器提供这些变量,并且名字也要完全相同。这些隐含变量实际定义在JSP执行的Servlet方法(Tomcat 8.0中是_jspServlet方法)的开头。因为隐式的变量定义在_jspServlet中,所以定义在类中的声明不能使用它们。表达式也在_jspServlet中,可以使用。
下面我们新建了一个空白的JSP文件,访问该文件,在Tomcat中生成了java文件和编译的.class文件
在tomcat_home\work\Catalina\localhost\project_name\org\apache找到java文件:
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException { final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
} 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("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta 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("\r\n");
out.write(" "); Person person = new Person();
System.out.println(person.getPersonInfo()); out.write("\r\n");
out.write(" \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);
}
}
request:HttpServletRequest的一个对象
response:HttpServletRespons的一个对象,在JSP页面中几乎不用
pageContext:页面的上下文,是PageContext的一个对象,可以从该对象中获取到其他8个隐含对象,也可以从中获取到当前页面的其他信息,后面自定义标签时使用
HttpServletRequest req = pageContext.getRequest();
System.out.println(req == request);
结果为true
session:代表浏览器和服务器的一次会话,是HttpSession的一个对象。
获得会话的ID
System.out.println(session.getId());
application:代表当前Web应用,是ServletContext对象
config:是当前JSP对应的Servlet的ServletConfig对象,几乎不用
out:JspWriter对象,调用out.println()可以直接把字符串打印到浏览器上
out.println("hello");
out.println("<br>"); 换行
out.println("world");
page:指向当前JSP对应的Servlet对象的引用,但为Objetc类型,只能调用Object类的方法,几乎不用
exception有下面的声明才能用
<%@ page isErrorPage="true" %>
pageContext、request、 session、 application 对属性的作用域的范围从小到大
在application、session、request、pageContext对象中都可以调用setAttribute方法和getAttribute方法来设置和检索各自域范围内的属性。这四个对象也称为域对象。
存储在application对象中的属性可以被同一个Web应用程序中的所有Servlet和JSP页面访问。
存储在session对象中的属性可以被属于同一个会话的所有Servlet和JSP页面访问,浏览器打开直到关闭是一次会话(会话未失效的前提下)。
存储在request对象中的属性可以被属于同一个请求的所有Servlet和JSP页面访问,例如使用PageContext.forward和PageContext.include方法连接起来的多个Servlet和JSP页面。
存储在pageContext对象中的属性仅可以被当前JSP页面的当前响应过程中调用的各个组件访问,例如,正在响应当前请求的JSP页面和它调用的各个自定义标签类。
PageContext类中还提供了对各个域范围的属性进行统一管理的方法,以简化对各个域范围内的属性的访问。
setAttribute方法 设置属性
public void setAttribute(java.lang.String name,java.lang.Object value)
public void setAttribute(java.lang.String name,java.lang.Object value,int scope)
常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
getAttribute方法 获取指定的属性
public java.lang.Object getAttribute(java.lang.String name)
public java.lang.Object getAttribute(java.lang.String name,int scope)
removeAttribute方法
public void removeAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name,int scope)
getAttributeNamesInScope方法
findAttribute方法 (*)
设置
<%
pageContext.setAttribute("pageContextAttr", "pageContextValueAttr");
request.setAttribute("requesAttr", "requesAttr");
session.setAttribute("sessionAttr", "sessionAttr");
application.setAttribute("applicationAttr", "applicationAttr");
%>
获取
pageContextAttr:<%= pageContext.getAttribute("pageContextValueAttr"); %>
requestAttr:<%= request.getAttribute("requesAttr"); %>
sessionAttr:<%= session.getAttribute("sessionAttr"); %>
applicationAttr:<%= application.getAttribute("applicationAttr"); %>
2.3 使用指令
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
JSP指令的基本语法格式:
<%@ 指令 属性名="值" %>
举例:
<%@ page contentType="text/html;charset=gb2312"%>
注意:属性名部分是大小写敏感的
在JSP 2.0中,定义了page、include和taglib这三种指令,每种指令中又都定义了一些各自的属性。
如果要在一个JSP页面中设置同一条指令的多个属性,可以使用多条指令语句单独设置每个属性,也可以使用同一条指令语句设置该指令的多个属性。
第一种方式:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>
第二种方式:
<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
2.3.1 page指令
page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
JSP 2.0规范中定义的page指令的完整语法:
<%@ page
[ language="java" ]
[ extends="package.class" ]
[ import="{package.class | package.*}, ..." ]
[ session="true | false" ]
[ buffer="none | 8kb | sizekb" ]
[ autoFlush="true | false" ]
[ isThreadSafe="true | false" ]
[ info="text" ]
[ errorPage="relative_url" ]
[ isErrorPage="true | false" ]
[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ] 指定当前JSP页面的响应类型(前面word文档方式的例子),实际调用的是respons.setContentType()方法,对于JSP而言一般取text/html;charset=UTF-8 ,即html类型文件,字符编码为utf-8 [ pageEncoding="characterSet | ISO-8859-1" ] 指定当前JSP页面的字符编码,通常与contentType中charset一致。 [ isELIgnored="true | false" ] 指当前JSP页面是否可以使用EL表达式,通常取值为true
%>
导入类
无论何时在JSP包中包含直接使用类的Java代码,该JSP要么使用完全限定类名,要么在JSP文件中添加一条导入命令。
对于不产生输出的JSP标记、指令、声明和脚本,它们将会在客户端输出一行空白。所以,如果在变量声明和脚本之前有许多导入类的page指令,那么将会在输出中显示出数行空白。为了解决这个问题,通常会将一个标记的尾部与另一个标记的头部连接在一起:
<%@ page import="java.util.Map"
%><%@ page import="java.util.List"
%><%@ page import="java.util.IOException" %>
错误页
<%@page errorPage="/error.jsp" %>
当前页面如果出错,会自动把error.jsp当作出错页面
在erro.jsp这个错误页面里可以添加如下,以显示错误信息,用到了转发,因为错误信息实际上是在跳转到error.jsp之前的那个页面的
Error Message:<%= exception.getMessage() %>
但是,要想使用上面的exception这个隐含对象,必须在网页里添加
<%@page isErrorPage="true" %>
errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),否则,表示相对于当前页面。
可以在web.xml文件中使用<error-page>元素为整个WEB应用程序设置错误处理页面,其中的<exception-type>子元素指定异常类的完全限定名,<location>元素指定以“/”开头的错误处理页面的路径。
<error-page>
<!--指定出错的代码:404没有指定的资源 500内部错误-->
<error-code>404<error-code>
<!--指定响应页面的位置-->
<location>/WEB-INF/erro.jsp</location>
</error-page> <error-page>
<!--指定异常的类型-->
<excepttion-type>java.lang.ArithmeticException<error-code>
<location>/WEB-INF/erro.jsp</location>
</error-page>
如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。
在响应error.jsp时,JSP引擎使用的是请求转发的方式,
如何时客户不直接访问某一个页面?一般情况下,对于Tomcat服务器而言,WEB-INF下的文件是不能通过在浏览器中直接输入来访问的,但通过请求的转发是可以的。
contentType
JSP引擎会根据page指令的contentType属性生成相应的调用ServletResponse.setContentType方法的语句。
page指令的contentType属性还具有说明JSP源文件的字符编码的作用。
2.3.2 包含其他JSP
include指令用于通知JSP引擎在翻译当前JSP页面时将其他文件中的内容合并进当前JSP页面转换成的Servlet源文件中,这种在源文件级别进行引入的方式称之为静态引入,当前JSP页面与静态引入的页面紧密结合为一个Servlet。
语法:
<%@ include file="relativeURL"%>
其中的file属性用于指定被引入文件的相对路径。
b.jsp
<body>
<h4>BBB PAGE</h4>
</body>
a.jsp
<body>
<h4>AAA PAGE</h4>
<!--在a.jsp中包含b.jsp-->
<%@ include file="b.jsp" %>
</body>
访问a.jsp,结果如下:
被引入的文件必须遵循JSP语法,其中的内容可以包含静态HTML、JSP脚本元素、JSP指令和JSP行为元素等普通JSP页面所具有的一切内容。
被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
在将JSP文件翻译成Servlet源文件时,JSP引擎将合并被引入的文件与当前JSP页面中的指令元素(设置pageEncoding属性的page指令除外)。所以,除了import和pageEncoding属性之外,page指令的其他属性不能在这两个页面中有不同的设置值。
除了指令元素之外,被引入的文件中的其他元素都被转换成相应的Java源代码,然后插入进当前JSP页面所翻译成的Servlet源文件中,插入位置与include指令在当前JSP页面中的位置保持一致。
引入文件与被引入文件是在被JSP引擎翻译成Servlet的过程中进行合并,而不是先合并源文件后再对合并的结果进行翻译。当前JSP页面的源文件与被引入文件的源文件可以采用不同的字符集编码,即使在一个页面中使用page指令的pageEncoding或contentType属性指定了其源文件的字符集编码,在另外一个页面中还需要用page指令的pageEncoding或contentType属性指定其源文件所使用的字符集 。
Tomcat 5.x在访问JSP页面时,可以检测它所引入的其他文件是否发生了修改,如果发生了修改,则重新编译当前JSP页面
file属性的设置值如果使用相对路径,表示相对于当前文件所在目录开始定位包含文件。如果以“/”开头,使用绝对路径,表示从Web应用程序的根目录开始定位该文件。
举例:
下面都是相对路径,因此都是a.jsp同级目录下找b.jsp
假设myweb应用程序的根目录下有一个a.jsp文件,其一般的访问路径形式为:http://localhost:8080/myweb/a.jsp
在a.jsp页面中使用了如下语句引入b.jsp文件:
<%@ include file=“b.jsp”%>
这时候JSP引擎调用的b.jsp文件的完整URL路径为什么?
http://localhost:8080/myweb/b.jsp
如果将a.jsp页面映射为如下地址:http://localhost:8080/myweb/dir1/a.html
这时候JSP引擎调用的b.jspf文件的完整URL路径为:
http://localhost:8080/myweb/dir1/b.jsp
2.3.3 包含标签库
如果希望JSP中使用标签库中定义的标签,使用taglib指令引用该标签库即可。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
2.4 使用<jsp>标签
JSP还提供了一种称之为Action的元素,在JSP页面中使用Action元素可以完成各种通用的JSP页面功能,也可以实现一些处理复杂业务逻辑的专用功能。 Action元素采用XML元素的语法格式,即每个Action元素在JSP页面中都以XML标签的形式出现。JSP规范中定义了一些标准的Action元素,这些元素的标签名都以jsp作为前缀,并且全部采用小写,例如,<jsp:include>、<jsp:forward>等等。
<jsp:include>标签
<jsp:forward>标签
<jsp:param>标签
<jsp:include>标签与include指令
<jsp:include>标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:
<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。
<!--在a.jsp中包含b.jsp-->
<jsp:inclucde page="b.jsp"></jsp:include>
动态引入:并不像include指令生成一个Servlet源文件,而是生成两个Servlet源文件,然后通过一个方法把目标页面包含进来。
<jsp:include>标签是在当前JSP页面的执行期间插入被引入资源的输出内容,当前JSP页面与被动态引入的资源是两个彼此独立的执行实体,被动态引入的资源必须是一个能独立被WEB容器调用和执行的资源。include指令只能引入遵循JSP格式的文件,被引入文件与当前JSP文件共同合被翻译成一个Servlet的源文件。
使用<jsp:include>标签和include指令都可以把一个页面的内容分成多个组件来生成,开发者不必再把页眉和页脚部分的相同HTML代码复制到每个JSP文件中,从而可以更轻松地完成维护工作,但是都应注意最终的输出结果内容应遵循HTML语法结构,例如,如果当前页面产生了<html>、</html>、<body>、</body>等标记,那么在被引入文件中就不能再输出<html>、</html>、<body>、</body>等标记。
<jsp:include>标签对JSP引擎翻译JSP页面的过程不起作用,它是在JSP页面的执行期间才被调用,因此不会影响两个页面的编译。由于include指令是在JSP引擎翻译JSP页面的过程中被解释处理的,所以它对JSP引擎翻译JSP页面的过程起作用,如果多个JSP页面中都要用到一些相同的声明,那么就可以把这些声明语句放在一个单独的文件中编写,然后在每个JSP页面中使用include指令将那个文件包含进来。
<jsp:include>标签使用page属性指定被引入资源的相对路径,而include指令使用file属性指定被引入资源的相对路径。
<jsp:forward>标签
用于把请求转发给另外一个资源。
语法:
<jsp:forward page="relativeURL | <%=expression%>" />
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
<jsp:forward page="/include/b.jsp"></jsp:forward>
相当于
<%
request.getRequestDispatcher("/include/b.jsp").forward(request, response);
%>
RequestDispatcher.forward方法、PageContext.forward方法、<jsp:forward>标签的区别
调用RequestDispatcher.forward方法的JSP脚本代码的前后不能有JSP模版内容。
调用PageContext.forward方法的JSP脚本代码的后面不能有JSP模版内容。
<Jsp:forward>标签的前后都能有JSP模版内容。
<jsp:param>标签
当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给的资源是一个能动态执行的程序时,例如Servlet和JSP页面,那么,还可以使用<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:forward>
<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。
a.jsp
<jsp:forward page="/include/b.jsp">
<jsp:param name="username" value="abcd" />
</jsp:forward>
b.jsp
<%= request.getParameter("username") %>
b.jsp可以获取a.jsp的username参数
三、结合使用Servlet和JSP
3.1 转发和重定向
本质区别:请求的转发只发出了一次请求,而重定向则发出了两次请求。
请求的转发地址栏是初次发出请求的地址,重定向地址栏不再是初次发出的请求地址,地址栏为最后响应的那个地址。
请求转发:在最终的Servlet中,request对象和中转的那个request是同一个对象,而请求的重定向不是同一个对象。
Servlet实例
转发Servlet
public class ForwardServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
System.out.println("ForwardServlet's doGet.");
// 请求的转发:
// 1.调用HttpServletRequest的getRequestDispatcher()方法获取RequestDispatcher对象
// 调用getRequestDispatcher()需要转入要转发的地址
// 2.调用HttpServletRequest的forward(request, response)进行请求的转发
String path = "testServlet";
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/"+path);
requestDispatcher.forward(request, response);
}
}
重定向Servlet
public class RedirectServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
System.out.println("RedirectServlet's doGet");
//执行重定向,直接调用response.sendRedirect(path)方法
//path为重定向的地址
String path = "testServlet";
response.sendRedirect(path);
}
}
定义一个用于测试的Servlet
public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("TestServlet's doGet 方法. ");
} }
配置web.xml
<servlet>
<servlet-name>forwardServlet</servlet-name>
<servlet-class>com.atguigu.javaweb.ForwardServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>forwardServlet</servlet-name>
<url-pattern>/forwardServlet</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>redirectServlet</servlet-name>
<servlet-class>com.atguigu.javaweb.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>redirectServlet</servlet-name>
<url-pattern>/redirectServlet</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.atguigu.javaweb.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
HTML
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <a href="loginServlet">Test</a>
<br><br> <a href="forwardServlet">Forward</a>
<a href="redirectServlet">Redirect</a>
</body>
</html>
test.html浏览器页面如下
点击Forward,地址栏是该按钮指向的地址
控制台打印:
ForwardServlet's doGet.
TestServlet's doGet方法
说明执行了TestServlet
点击Redirect,地址栏不是该按钮指向的地址
控制台打印:
ForwardServlet's doGet.
TestServlet's doGet方法
说明执行了TestServlet
都执行了TestServlet
但是定向没有跳转到TestServlet对应的网址
而重定向跳转到了TestServlet对应的网址
RequestDispatcher实例对象
RequestDispatcher实例对象是由Servlet引擎创建的,它用于包装一个要被其他资源调用的资源(例如,Servlet、HTML文件、JSP文件等),并可以通过其中的方法将客户端的请求转发给所包装的资源。
RequestDispatcher接口中定义了两个方法:forward方法和include方法。
forward和include方法接收的两个参数必须是传递给当前Servlet的service方法的那两个ServletRequest和ServletResponse对象,或者是对它们进行了包装的ServletRequestWrapper 或ServletResponseWrapper对象。
获取RequestDispatcher对象的方法:
ServletContext.getRequestDispatcher (参数只能是以“/”开头的路径)
ServletContext.getNamedDispatcher
ServletRequest.getRequestDispatcher (参数可以是不以“/”开头的路径)
用sendRedirect方法实现请求重定向
sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给sendRedirect 方法的相对URL以“/”开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录。
请求重定向与请求转发的比较
RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。
调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。
RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。
3.2 JSP属性和JSP属性组
3.2 将Servlet请求转发给JSP
由Servlet接收请求,实现业务逻辑处理以及必需的数据存储或读取,创建可以由JSP轻松处理的数据模型,最终将请求转发给JSP。
JavaWeb(三):JSP的更多相关文章
- javaweb 与jsp页面的交互流程 (初次接触时写)
javaweb 与jsp页面的交互流程 javaweb项目目录 1. javaweb项目的一般目录: 2. jsp 页面一般情况下放在 top(前台页面) back(后台页面) 3. 后台代码 放在s ...
- 三 JSP 技术
一 JSP 概述 1. 本质:在 HTML 语言中混合 Java 程序代码,由服务器端 Java 语言引擎解释执行.其中,HTML 负责描述信息显示格式,JSP 负责描述处理逻辑. 2. JSP 代码 ...
- Intellij idea创建javaWeb:实现JSP/Servlet(转)
转自:https://www.jianshu.com/p/9684e90cf7b5 Intellij idea创建javaWeb:实现JSP/Servlet by_love唯念 关注 2016.12. ...
- JavaWeb后端jsp之增删改查
今日主题:JavaWeb后端jsp之增删改查 实体类: Student.java: package cn.itcast.model.entity; public class Student { pri ...
- JavaWeb总结(三)—JSP
一.JSP简介 1.基本认识 (1)JSP页面是由HTML语句和嵌套在其中的Java代码组成的一个普通文本文件,JSP 页面的文件扩展名必须为.jsp. (2)在JSP页面中编写的Java代码需要嵌套 ...
- MyEclipse配置Tomcat开发JavaWeb程序JSP以及Servlet
1.安装准备 1).下载安装MyEclipse2014,这已经是最新版本. 2).下载Tomcat 官网:http://tomcat.apache.org/ 我们选择8.0: http://tomca ...
- JavaWeb学习----JSP内置对象详解
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- JavaWeb学习----JSP脚本元素、指令元素、动作元素
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- JavaWeb学习----JSP简介及入门(含Eclipse for Java EE及Tomcat的配置)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
随机推荐
- 20180705-Java基础语法
Java基础语法 一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条 ...
- xpath定位不到原因浅析
在爬虫中,我们经常使用xpath来对元素进行定位,xpath定位分为两种,一种是绝对定位,/html/body/div[2]/div[1]/div/div[3]/a[7],另外一种是相对定位,比如r' ...
- ORA-00020: maximum number of processes (800) exceeded
[oracle@db04-1 ~]$ sqlplus -prelim / as sysdba SQL*Plus: Release 11.2.0.3.0 Production on 星期四 8月 31 ...
- ES6中set的用法回顾
ES6中的set类似一个数组,但是其中的值都是唯一的,Set本身是一个构造函数,用来生成 Set 数据结构. set函数可以接受一个数组作为参数,用来初始化: const set = new Set( ...
- spss如何选择需要的变量?
spss如何选择需要的变量? 今天一位网友问我,spss如何在许多字段(变量)中选择我需要的字段,而不显示其他的字段呢? 这个问题问的很好,在实际的数据分析或者挖掘的过程中,都需要用这个来找出对商业问 ...
- MySQL 1130错误,无法远程连接
错误:ERROR 1130: Host '192.168.1.3' is not allowed to connect to thisMySQL serve 错误1130:主机192.168.1.3” ...
- linux + eclipse + cdt 报错undefined reference......好麻烦的,这位大牛给出的方法可行,特此MARK!!!!
http://bbs.csdn.net/topics/390239632 kerosun kerosun 等级: 结帖率:96.92% 楼主 发表于: 2012-10-11 12:00:51 比如 ...
- spring事务——try{...}catch{...}中事务不回滚的几种处理方式(转载)
转载自 spring事务——try{...}catch{...}中事务不回滚的几种处理方式 当希望在某个方法中添加事务时,我们常常在方法头上添加@Transactional注解 @Respon ...
- 去JQUERY化
时间 2016-05-17 12:43:59 OurJS 原文 http://ourjs.com/detail/573a9cec88feaf2d031d24fc 主题 jQuery 这是一篇使用原 ...
- HttpUrlConnection工具类
package com.ligotop.core.utils; import com.ligotop.core.exceptions.BusinessException; import java.io ...