1、JSP概述
1.1为什么要使用JSP
由于在Servlet中嵌入html代码非常麻烦,这常常使得Servlet很庞大,不便于页面的修改,难以维护,这样也就无法用网页设计工具来进行编辑了,页面的设计变得很麻烦,所以sun公司推出了JSP。JSP可以在html中嵌入java代码,可以在jsp页面中像在html页面一样写html代码,这样就不像在servlet中写html代码那样痛苦了,代码的可读性也变高了。
1.2 什么是JSP
JSP(Java Server Pages)是以Java语言为基础的动态网页开发技术,JSP与Java Servlet一样,是在服务器端执行的,不同的是先由服务器编译部署成Servlet执行。更多信息请查看JSP维基百科。
2、JSP运行原理
JSP的运行原理图如下:
JSP的执行过程:
- 客户端发送请求
- JSP Container 将JSP 翻译成Servlet 的源代码;
- 将产生的Servlet 的源代码经过编译后,加载到内存执行;
- 把结果Response (响应)发送至客户端。
JSP和Servlet的执行效率相差不大,只是第一次执行JSP页面时需要进行编译。一般人都会以为JSP 的执行性能会和Servlet 相差很多,其实执行性能上的差别只在第一次的执行。因为JSP 在执行第一次后,会被编译成Servlet 的类文件,即为XXX.class,当再重复调用执行时,就直接执行第一次所产生的Servlet,而不用再重新把JSP编译成Servlet。因此,除了第一次的编译会花较久的时间之外,之后JSP 和Servlet 的执行速度就几乎相同了。在执行JSP 网页时,通常可分为两个时期:转译时期(Translation Time)和请求时期(Request Time) 。
tomcat为什么能处理jsp文件,因为在${tomcat}/conf/web.xml(这个文件存放这web应用的默认配置)文件中存在这样的配置:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
上面的配置用来处理jsp的,可以试验下,假如在自己的web.xml文件中配置一个servlet,该servlet处理所有的*.jsp请求,当你在访问相应的jsp时,始终都会走这个servlet。
我们先来写一个简单的jsp,里面写的东西不要求理解:
<%@page import="java.util.Date"%>
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>JSP小例子</title>
</head>
<body>
<%
Date date = new Date();
%>
今天是<%=date%>
</body>
</html>
这个页面只是简单的输出了下当前的时间,产生的servlet存放在%tomcat%\work\引擎\主机\项目名\org\apache\jsp,生成的java源代码如下:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;
public final class demo_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\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(" <title>JSP小例子</title>\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" ");
Date date = new Date();
out.write("\r\n");
out.write(" 今天是");
out.print(date);
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);
else log(t.getMessage(), t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
从上面的代码不难开出与jsp生命周期相关的方法为:
public void _jspInit() {…}
public void _jspDestroy() {…}
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException {…}
demo_jsp的继承关系如下图
:
从上图不难看出jsp通过tomcat的jsp引擎处理后,实际上还是一个servlet,只不过我们访问jsp文件时,jsp引擎已经帮我们做好处理了。好,我们已经对jsp有所了解了,那么jsp页面是由什么组成的呢?
- JSP原始代码中包含:JSP元素、Template(模板)dataJSP元素指将由JSP引擎直接处理的部分,这一部分必须符合JSP语法,否则会导致编译错误Template Data指的是JSP引擎不处理的部分。即标记在<%...%>以外的部分,例如:代码中的HTML内容等,这些数据会直接传送到客户端的浏览器
- JSP组成
* 动态的Java代码(必须包含在特定的标签中)
3、jsp基本语法
3.1、jsp指令元素
jsp指令元素的功能:
- 用于指示JSP执行某些步骤,用于指示JSP表现特定行为 。
- 用来设定JSP网页的整体配置信息。
总的来说指令就是在页面提供一些配置信息的。语法的基本格式:<%@ directive [attribute="value"]*%> ,jsp指令元素主要分为page指令,include指令,taglib指令。jsp指令不会向客户端产生任何输出,所有的指令元素在整个jsp文件都有效,为编译阶段提供全局的信息,理论上指令可以得到页面的任何位置 。
3.1.1 page指令
page指令的基本格式为<%@ page [attribute="value"] *%> ,用来定义jsp文件的全局属性,无论page指令出现在jsp文件的什么地方,它的作用都是整个jsp页面,为了保持持续的可读性和遵循良好的编程习惯,page指令最好存放在jsp文件的开头。这些属性可以单独使用也可以几个或多个同时使用,在jsp页面中只有import属性可以出现多次,其他属性只能出现一次(当然这些属性多次出现,而且都是相同的值都是可以的)。
属性配置:
language:确定当前jsp所使用的语言,默认是java,为以后扩展用。
pageEncoding:配置当前页面所保存的页面信息的编码
contentType:定义jsp响应的MIME类型,例如:text/html; charset=UTF-8
与pageEncoding的比较:
仅有pageEncoding: 配置当前页面的编码,配置jsp响应的MIME类型
仅有contentType: 配置当前页面的编码,配置jsp响应的MIME类型
两者都有:pageEncoding仅设置当前页面的编码,contentType设置jsp响应的MIME类型
一般只需要配置pageEncoding就行了。
import:导入当前jsp页面需要使用的包或类的列表,可以重复引用,多个之间用逗号分隔,导包的最后一 条可以输入多个分号,例如import="java.util.*"
info:确定当前页面的输出信息
session:确定当前页面是否可以使用session,默认为true
extends: 确实jsp页面生成servlet,继承的父类,例如extends="java.util.List"
errorPage: 确实当前页面出现异常时,跳转的页面
isErrorPage: 是否为错误页面。如果设置成true,则可以使用exception内置对象(后面会介绍)
isThreadSafe:默认为true,如果设置成false则会实现SingleThreadModel接口(这个接口以及废弃)
isELIgnored:是否忽略el表达式,默认为false
buffer: 当前servlet的缓冲区的大小,默认为8kb
autoFlush: 是否自动刷新,当buffer缓存区被填写满后,会自动的刷新内容到浏览器
3.1.2 include指令
include指令的基本格式为<%@ include file="filename"%> ,include指令的作用是在jsp文件静态包含一个文件,同时由jsp解析包含的文件内容。静态包含的含义:用于通知JSP引擎在翻译当前JSP页面时将其他文件中的内容合并进当前JSP页面转换成的Servlet源文件中。当前JSP页面与静态引入的页面紧密结合为一个Servlet。
include指令注意事项:
- file不能为一变量
<% String url="index.html" ; %>
<%@ include file = "<%= url %>" %>
- 不可以在file 所指定的文件后接任何参数
<%@ include file = "jw.jsp?nm=browser" %>
- 被引入的文件必须遵循JSP语法,JSP引擎会按照处理JSP页面的方式处理里面的内容
- 被引入的文件可以使用任意的扩展名,为了见名知意,JSP规范建议使用*.jspf(JSP fragments)作为静态引入文件的扩展名
- 在将JSP文件翻译成servlet源文件时,JSP引擎将合并被引入的文件与当前JSP页面中的指令元素。除了import和pageEncoding属性之外,page指令的其他属性不能在这两个页面中有不同的设置值
使用include可以便于网站的维护,例如网站的头和尾的相关信息一般都是不变的,网站的实际内容是变得的,这样就可以使用include指令将头和尾的信息包含进来,专业当要修改头和尾时,只需要在对应的文件中进行修改,而不必修改其他的文件。例如<%@ include file="top.jsp"%> 实际的内容 <%@ include file="foot.jsp"%>
3.1.3 taglib指令
taglib指令用于在jsp文件中导入标签库,常用的属性有uri: 标签文件的uri地址,prefix:标签组的命名空间前缀,关于标签库的详细内容将会在后续介绍。
4 jsp脚本元素
4.1 声明标签(Declaration)
声明的格式: <%! 声明1;[声明2];……%>,用于成员变量和方法的声明。声明的变量是全局变量,声明的方法将转换成servlet的方法,声明的作用范围是整个JSP页面,同时它只在一个JSP页面有效。例如:
<%! private String msg = "msg"; private void sayHi(String name){ System.out.println("Hi," + name); } %>
4.2 代码块(Scriptlets)
语法格式:<% java code %>,在“<%”和”%>”之间插入java程序片段,一个JSP页面可以有许多程序片段,这些代码块将被JSP服务器按照顺序执行,在一个代码块中声明的变量是JSP页面的局部变量,只在当前页面有效,代码块中不能定义方法,代码块在JSP编译后,将成为对应的Servlet的_jspService()方法体的一部分。例如:
<% Date date = new Date(); System.out.println("当前时间:" + date); %>
4.3 表达式(Expression)
语法格式:<%= 变量或表达式 %>,表达式的计算结果转换成字符串,使用隐含对象out进行输出,结果显示在页面中标签所在的位置例如:<%=“abc” %> 等价于 out.print(“abc”);,JSP脚本表达式中的变量或表达式后面不能有分号(;)。
练习一:输入h1-h6
<%@page import="java.util.Date"%> <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>输出h1-h6</title> </head> <body> <% for(int i = 1; i <=6; i++){ %> <h<%=i%>>Hello World!</h<%=i%>> <% } %> </body> </html>
从上面的练习可以看出代码块是可以分散使用的,只要保证<%和%>成对出现就行。
练习二:输出当前的日期,格式为(xxxx年xx月xx日 星期x)
<%@page import="java.text.SimpleDateFormat"%> <%@page import="java.text.DateFormat"%> <%@page import="java.util.Date"%> <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>当前日期</title> </head> <body> <% Date curDate = new Date(); DateFormat df = new SimpleDateFormat("yyyy年MM月dd日 E"); %> <p><%=df.format(curDate)%></p> </body> </html>
练习三:输出九九乘法表(仅能使用jsp脚本)
5、 jsp页面注释
- jsp注释:<%-- 注释内容--%>,转换阶段消失,只能被开发人员看到,属于源码级别的注释
- html注释: <!--注释内容-->,在转换阶段不会消失,在页面中也能看到
- java注释://、/*注释内容*/、/**注释内容*/,转换阶段不会消失,在编译时消失
例如:
<%--jsp注释--%> <!-- html注释 --> <% //java行级注释 /* java块级注释 */ /** * javaDoc */ %>
6、jsp内置对象
jsp的9大内置对象如下:
jsp内置对象的分类:
为什么在jsp中能直接的使用这些对象(exception对象需要设置isErrorPage="true",才能使用)?因为在jsp转换成servlet是在_jspService()方法中定义了这些变量,所以能使用。
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { PageContext pageContext = null; HttpSession session = null; Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); if (exception != null) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null;
由上可以很清楚的看出内置对象的类型:
- request HttpServletRequest
- response HttpServletResponse
- session HttpSession
- application ServletContext
- config ServletConfig
- page this
- pageContext PageContext
- exception Throwable
- out JspWriter
page对象:
page对象代表了正在运行的由jsp产生的类对象。这个对象其实并没有太大的用处,一般不建议使用该对象。page对象指的是当前jsp程序本身的对象,有点像类中的this,page对象其实是java.lang.Object类的实例对象。
out对象:
向客户端输出数据,管理服务器输出缓冲区内部使用PrintWriter对象来输出文本级数据,通过page指令的buffer属性来调整缓冲区的大小,默认的缓冲区是8kb。
注意:在jsp页面不能在调用response.getOutputStream(),否则会抛出异常。
out对象的工作原理如下:
config对象:
用来取得jsp的初始化参数信息,需要在WEB-INF/web.xml中进行配置,jsp文件也可以作为servlet配置,例如在web.xml中的进行如下的配置:
<servlet> <servlet-name>demo</servlet-name> <jsp-file>/demo.jsp</jsp-file> <init-param> <param-name>name</param-name> <param-value>Riccio Zhang</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>demo</servlet-name> <url-pattern>/jsp/demo/</url-pattern> </servlet-mapping>
那么就可以再demo.jsp文件中取得配置的参数:
注意:只有通过web.xml文件中配置的路径访问在能获取到参数信息,否则是获取不到参数的。使用jsp文件访问使用的是tomcat的servlet引擎,并不知道配置的相关参数信息,只有通过自定义的路径才能获取到参数。<% String name = config.getInitParameter("name"); System.out.println(name); %>
response对象:服务器对浏览器的响应
request对象:浏览器向服务器发出的请求,作用范围是一次请求(可能涉及多个jsp或servlet)
exception对象:exception对象是java.lang.Trowable类的实例,exception对象用来处理JSP文件在执行时所有发生的错误和异常。exception对象可以和page指令一起使 用,通过指定某一个页面为错误处理页面,对错误进行处理<%@ page isErrorPage=”true “%>的页面内使用。
application对象:作用范围:整个web项目
session对象:作用范围:一个会话
pageContext对象:pageContext对象可以直译为“页面上下文”对象,代表的是当前页面运行的一些属性。它是javax.servlet.jsp.PageContext类的实例对象,可以使用PageContext类的方法,PageContext对象继承自javax.servlet.jsp.JspContext。pageContext对象提供了对JSP页面所有的对象及命名空间的访问。提供了page范围的存取数据的方法:Object getAttribute(String name),void removeAttribute(String name),void setAttribute(String name, Object value)
jsp的四种数据范围:<% pageContext.setAttribute("name", "Riccio Zhang"); String name = (String)pageContext.getAttribute("name"); System.out.println(name); pageContext.removeAttribute("name"); //等价于pageContext.setAttribute("name", null),为了增强可读性还是使用removeAttribute方法 System.out.println(name);;;;; %>
pageContext对象封装着对其他8个内置对象的引用,可以通过相应的get方法来获取引用,为什么要封装这8个对象呢?通过封装这8个内置的对象,可以方便编程,你只需要把pageContext给我传进来,其它对象就都可以用了,而不需要把一个个零散的对象都给传进来,这也为后面将会将到的EL表达式提供了方便,这里再次体现了封装的思想。
- page:当前jsp页面
- request:一次请求
- session:一个会话
- application:整个web项目
pageContext除了能在page域存取数据外,还能提供了在其它域存取数据的方法:
- 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.setAttribute("name", "name_page", PageContext.PAGE_SCOPE); //与pageContext.setAttribute("name", "name_page");等价 pageContext.setAttribute("name", "name_request", PageContext.REQUEST_SCOPE); pageContext.setAttribute("name", "name_session", PageContext.SESSION_SCOPE); pageContext.setAttribute("name", "name_application", PageContext.APPLICATION_SCOPE); //在各个域中取出数据,并打印到控制台上 String name_page = (String)pageContext.getAttribute("name", PageContext.PAGE_SCOPE);//与pageContext.getAttribute("name");等价 System.out.println("PAGE_SCOPE name = " + name_page); String name_request = (String)pageContext.getAttribute("name", PageContext.REQUEST_SCOPE); System.out.println("REQUEST_SCOPE name = " + name_request); String name_session = (String)pageContext.getAttribute("name", PageContext.SESSION_SCOPE); System.out.println("SESSION_SCOPE name = " + name_session); String name_application = (String)pageContext.getAttribute("name", PageContext.APPLICATION_SCOPE); System.out.println("APPLICATION_SCOPE name = " + name_application); %>
最后比较重要的一个方法就是 findAttribute方法,先来看看这个方法实现的源代码:
public Object findAttribute(final String name) { if (SecurityUtil.isPackageProtectionEnabled()) { return AccessController.doPrivileged(new PrivilegedAction() { //HTTPS使用 public Object run() { if (name == null) { throw new NullPointerException(Localizer .getMessage("jsp.error.attribute.null_name")); } return doFindAttribute(name); } }); } else { //一般的HTTP使用 if (name == null) { throw new NullPointerException(Localizer .getMessage("jsp.error.attribute.null_name")); } return doFindAttribute(name); } } private Object doFindAttribute(String name) { Object o = attributes.get(name); if (o != null) return o; o = request.getAttribute(name); if (o != null) return o; if (session != null) { try { o = session.getAttribute(name); } catch(IllegalStateException ise) { // Session has been invalidated. // Ignore and fall through to application scope. } if (o != null) return o; } return context.getAttribute(name); }
这个方法会从各个域中去取数据,如果取到了就直接返回,如果没有取到,则继续往下走,查找的顺序为:page --> request -->session --> application。这个方法再后续中也是很重要的一个方法。
可以注释掉相应的域的存值语句去验证上面的顺序。<% //pageContext.setAttribute("user", "zq_page", PageContext.PAGE_SCOPE); pageContext.setAttribute("user", "zq_request", PageContext.REQUEST_SCOPE); pageContext.setAttribute("user", "zq_session", PageContext.SESSION_SCOPE); pageContext.setAttribute("user", "zq_application", PageContext.APPLICATION_SCOPE); String findedUser = (String)pageContext.findAttribute("user"); System.out.println(findedUser); %>
练习:完成猜数游戏
<%@page import="java.util.Random"%> <%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>猜数游戏</title> </head> <body> <% //从session中获取那个随机的数字 Integer randNum = (Integer)session.getAttribute("randNum"); //产生一个随机的数字 if(randNum == null){ Random rand = new Random(); randNum = rand.nextInt(100) + 1; session.setAttribute("randNum", randNum); } %> <p> <% String num = request.getParameter("num"); if(num != null && !num.equals("")){ int n = Integer.valueOf(num); if( n == randNum ){ session.removeAttribute("randNum"); out.print("恭喜您,猜对了!"); }else if(n > randNum){ out.print("对不起,您猜错大了!"); }else{ out.print("对不起,您猜错小了!"); } } %> </p> <form action="" method="post"> 请输入一个1~100之间的整数:<input type="text" name="num"><br/> <input type="submit" value="猜"/> </form> </body> </html>
7、JSP标签
JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。
jsp常用标签:<jsp:useBean> 在指定范围内获取需要的javabean对象,如果不存在则创建
- id,指定范围内,当前bean的实例化对象的变量名
- scope,当前bean的使用,范围取值:"page | request | session | application",默认为page
- class ,获得指定bean的实例对象,如果没有则创建取值:指定bean的完整路径名
- type ,获得指定bean的实例对象,如果没有则抛异常,取值:指定bean的完整路径名
- beanName,使用java.beans.Beans实例化bean对象,取值:指定bean的完整路径名
package cn.zq.domain; public class User { private String name; private int age; private String address; public User() {} public User(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } 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; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", address=" + address + "]"; } }
<% User u = new User("Riccio Zhang", 21, "广州市"); pageContext.setAttribute("user", u); %> <%-- 这里可以从指定域中获取到User对象 --%> <jsp:useBean id="user" class="cn.zq.domain.User" scope="page"/> <%=user%> <%-- 此处会自动的创建一个变量名为user2的javabean,并存放到指定域中 --%> <jsp:useBean id="user2" class="cn.zq.domain.User"/> <%=user2%> <%-- 此处会抛出异常,用type指定的javabean的完整名称时,未获取到会抛出异常 <jsp:useBean id="user3" type="cn.zq.domain.User"/> --%> <%-- 未获取到指定javabean,则会调用 java.beans.Beans.instantiate会实例化指定的bean, 使用beanName属性时,不能使用class属性,只能使用type属性 --%> <jsp:useBean id="user4" beanName="cn.zq.domain.User" type="cn.zq.domain.User" /> <%=user4 %>
<jsp:setProperty >使用Bean的setter方法给bean的属性设置值。在使用之前必须使用<jsp:useBean>声明一个bean
- name,使用已有的bean,取值必须与<jsp:useBean>的id匹配,如果不存在抛异常
- property,bean的属性值
- value ,需要设置的值
- param ,请求参数的值,取值必须与URL参数的值相同,如果没有此参数则不赋值
注意:value与param不能同时使用
<jsp:useBean id="user" class="cn.zq.domain.User"/> <jsp:setProperty name="user" property="name" value="Riccio Zhang"/> <jsp:setProperty name="user" property="age" value="1"/> <jsp:setProperty name="user" property="address" value="gz"/> <%=user%> <%-- 如果指定的参数为空或空字符串,则不会设置相应的值 --%> <jsp:setProperty name="user" property="name" param="name"/> <%-- 未指定value属性,则会获取参数的值来填充,如果为空,则同上 --%> <jsp:setProperty name="user" property="name"/> <%-- 通配符* 表示用所有的参数来填充该bean,如果为空,则同上 --%> <jsp:setProperty name="user" property="*"/> <%=user%>
<jsp:getProperty>使用bean的getter方法获得属性的值,在使用之前必须使用<jsp:useBean>声明一个bean
- name,需要获得bean的实例对象变量值,取值必须与<jsp:useBean>的id匹配
- property,需要获得bean的属性值
<jsp:useBean id="user" class="cn.zq.domain.User"/> <jsp:setProperty name="user" property="name" value="Riccio Zhang"/> <jsp:setProperty name="user" property="age" value="1"/> <jsp:setProperty name="user" property="address" value="gz"/> <jsp:getProperty property="name" name="user"/>-- <jsp:getProperty property="age" name="user"/>-- <jsp:getProperty property="address" name="user"/>
<jsp:include>
- 语法
<jsp:include page={"relativeURL" | "<%= expression %>"} />
或
<jsp:include page={"relativeURL" | "<%= expression %>"} >
<jsp:param name="PN" value="{PV | <%= expression %>}" /> *
</jsp:include>另一个属性flush:表示在动态包含另一个文件时,是否先刷新
- 用于把另一个资源的输出内容插入进当前JSP页面的输出内容中,这种在JSP页面执行时的引入方式称之为动态引入
org.apache.jasper.runtime.JspRuntimeLibrary
public static void include(ServletRequest request, ServletResponse response, String relativePath, JspWriter out, boolean flush) throws IOException, ServletException { if (flush && !(out instanceof BodyContent)) out.flush(); String resourcePath = getContextRelativePath(request, relativePath); RequestDispatcher rd = request.getRequestDispatcher(resourcePath); rd.include(request, new ServletResponseWrapperInclude(response, out)); }
<jsp:include>和include指令的比较:
- 使用<jsp:include>标签和include指令都可以把一个页面的内容分成多个组件来生成,开发者不必再把页眉和页脚部分的相同的HTML代码复制到每个JSP文件中,从而可以更轻松的完成维护工作,但是合并过程需要遵循HTML语法结构。例如:<html><head><body>个数等
- <jsp:include>标签是在当前JSP页面的执行期间引入被引入资源的输出内容。当前JSP页面与被动态引入的资源是两个彼此独立的执行实体,被动态引入的资源必须是一个能够独立被web容器调用和执行的资源。include指令只能引入遵循JSP格式的文件,被引入文件与当前JSP文件共同被编译成一个servlet的源文件
- <jsp:include>标签对JSP引擎编译JSP页面的过程不起作用,它是在JSP页面的执行期间才被调用,因此不会影响两个页面的编译。由于include指令是在JSP引擎编译JSP页面的过程中被编译处理的,所以它对JSP引擎编译JSP页面的过程起作用。如果多个JSP页面中都要用到一些相同的声明,那么就可以把这些声明语句放在一个单独的文件中编写,然后在每个JSP页面中使用include指令将那个文件包含进来
通过上面的比较不难得出在开发时,尽量的用include指令来代替<jsp:include>,<jsp:include>会增加服务器的负担。
demo.jsp
<jsp:include page="include.jsp"> <jsp:param name="country" value="中国"/> </jsp:include>
include.jsp
发现在include.jsp中获取的是乱码,为什么是乱码呢?仔细查看如下的源代码:<%@ page language="java" pageEncoding="UTF-8"%> <p> 获取带的参数为:<%=request.getParameter("country")%> </p>
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "include.jsp" + (("include.jsp").indexOf('?')>0? '&': '?') + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("country", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("中国", request.getCharacterEncoding()), out, false);
这个参数传递参数时先通过编码,编码是通过request.getCharacterEncoding()获取的,而我们并没有设置相应的值,只需要在包含语句之前加上这行java代码乱码就解决了
request.setCharacterEncoding("UTF-8");
<jsp:forward>将请求传递给另一个JSP页面。
- <jsp:forward page={"relativeURL" | "<%= expression %>"} />
或
<jsp:forward page={"relativeURL" | "<%= expression %>"} >
<jsp:param name="PN" value="{PV | <%= expression %>"}/> *
</jsp:forward>
注意:被forward转发的资源必须与发送请求的页面处于相同的上下文环境中,每当遇到此标签时,容器就会停止执行当前的JSP,转而执行被转发的资源
<jsp:forward page="forward.jsp" > <jsp:param name="country" value="中国"/> </jsp:forward>
练习:实现简单的计算器http://blog.csdn.net/ricciozhang/article/details/43233819