JavaWeb JSP
1. JSP指令元素
1.1. page指令
page指令是JSP页面中最常用的指令,用来声明JSP页面的属性等信息。一个page指令允许定义多个属性;也可以一个page指令定义一个属性,定义多个page指令。
<!-- 一个page指令,设置多个属性 --> <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- 一个page指令,设置一个属性.配置多个page指令 --> <%@ page import="java.util.*"%> <%@ page pageEncoding="UTF-8"%>
但是需要注意的是:
- page指令设置的属性只能出现一次,除import属性以外。
- 属性名称区分大小写。
page指令允许的属性如下:
属性名称 |
取值范围 |
描述 |
language |
java |
指明该JSP文件采用的语言。 |
extends |
任何类的全名 |
指明该JSP文件继承于哪个类。JSP为Servlet,因此当指明继承普通类时需要实现Servlet的init()、destroy()等方法。 |
import |
任何包名、类名 |
引入该JSP中用到的类、包等。import是唯一可以声明多次的page指令属性。一个import属性可以引用多个类,中间用英文逗号隔开。 JSP中下面四个包里的类可以直接使用:java.lang.*,javax.servlet.*,javax.servlet.jsp.*,javax.servlet.http.*。 |
session |
true,false |
指明该JSP内是否内置Session对象。如果为true,则内置Session对象,可直接使用。否则不内置Session对象。默认为true |
autoFlush |
true,false |
是否运行缓存。如果为true,则使用out.println()等方法输出的字符串并不是立刻到达服务器端的,而是暂时存在缓存里,缓存满或者程序执行完毕或者执行out.flush()操作时才到客户端。默认为true |
buffer |
none、数字+KB |
指定缓存大小,当autoFlush设为true时有效,默认值为8KB。 |
isThreadSafe |
true,false |
指定是否线程安全。如果为true,则运行多个线程同时运行该JSP程序,否则只运行一个线程运行,其余线程等待。默认为false |
isErrorPage |
true,false |
指定该页面是否为错误处理页面。如果为true,则该JSP内置Exception对象,可直接使用,否则没有。默认为false |
errorPage |
某个JSP页面的相对路径 |
指明一个错误显示页面,如果该JSP程序抛出一个未捕捉的异常,则转到errorPage指定的页面。errorPage指定的页面通常isErrorPage属性为true,且内置Exception对象为未捕捉的异常。 |
contentType |
有效的文档类型 |
客户端浏览器根据该属性判断文档类型。 |
info |
任意字符串 |
指明该JSP的信息,该信息可以通过Servlet.getServletInfo()方法获取。 |
trimDirective |
true,false |
是否去掉指令前后的空白字符。默认为false |
isELIgnored |
true,false |
指明当前页面是否忽略EL表达式。默认为false,表示不忽略。 |
- pageEncoding和contentType属性
- pageEncoding属性:指明当前JSP页面使用的编码格式。pageEncoding属性的值要与JSP页面的真实编码保持一致,否则会出现乱码。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
-
- contentType属性:在JSP页面编译成Servlet文件时,对应response.setContentType()方法。
pageEncoding属性与contentType属性只设置其中一个属性时,另一个属性的默认与设置的相同。如果两个属性都不设置的话,两个属性的默认值都为“ISO-8859-1”。一般情况下,至少设置其中一个。
- errorPage和isErrorPage属性
- 创建一个JSP页面,编写代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'page.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> This is my JSP page. <br> <% if(true){ throw new RuntimeException(); } %> </body> </html>
-
- 发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。
页面访问报错,提示JSP页面的throw new RuntimeException();这句报错。当页面报错时,是不希望用户看到这样的错误页面,而是友好的错误信息。
-
- 创建一个JSP页面,用于页面报错的友好提示信息。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'error.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> this is error page.<br> </body> </html>
-
- 在第一个JSP页面中增加如下代码,设置如果当前页面出现错误,利用error.jsp页面进行错误信息的提示。
<%@ page language="java" pageEncoding="UTF-8" errorPage="error.jsp"%>
-
- 重新发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。
这时再次访问当前的JSP页面,会发现显示的是error.jsp页面的内容。这样的处理使得报错更好友,但是还存在一个问题,就是通过HttpWatch工具抓取会发现响应状态码为200,并不是错误的状态码。这就说明了虽然页面报错并进行了相关提示,但实际上JSP页面将错误隐藏起来,这样不利于之后的处理。
-
- 在error.jsp页面中增加如下代码,设置如果当前JSP页面错误,响应对应的状态码,以便之后处理。
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="true"%>
-
- 重新发布Web工程,并访问http://localhost:8080/jsp/01_directive/page.jsp。
-
- 在error.jsp页面中,可以使用JSP内置对象exception获取异常信息等功能,该对象只能在错误页面中。
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="true"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'error.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> this is error page.<br> <%=exception.getMessage() %> </body> </html>
-
- 在JSP页面中指定错误页面虽然可以,但是操作繁琐(实际开发要为每一个JSP页面指定)。还可以使用web.xml文件配置错误页面信息。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" 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_2_5.xsd"> <!-- 配置对应状态码为404的错误页面 --> <error-page> <!-- 设置对应的状态码 --> <error-code>404</error-code> <!-- 配置错误页面路径 --> <location>/directive/error.jsp</location> </error-page> <!-- 配置对应异常的错误页面 --> <error-page> <!-- 设置对应的异常 --> <exception-type>java.lang.RuntimeException</exception-type> <!-- 配置错误页面路径 --> <location>/directive/error.jsp</location> </error-page> </web-app>
1.2. include指令
include指令用于在JSP页面中静态包含另一个文件,该文件可以是JSP页面、HTML页面、文本文件或一段Java代码。include语法格式如下:
<%@ include file="包含文件的路径" %>
设置包含文件的路径只能是常量,不能是变量。
include.jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'include.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> 欢迎你,现在的时间是: <%@ include file="date.jsp" %> </body> </html>
date.jsp页面
<% out.println(new java.util.Date().toString()); %>
1.3. taglib指令
JSP页面支持标签,使用标签功能可以实现视图代码重用,很少量的代码可以实现很复杂的显示效果。要使用标签功能必须先声明标签库以及标签前缀。taglib指令用于指明JSP页面使用的JSP标签库。taglib指令的语法格式如下:
<%@ taglib prefix="标签前缀" uri="标签库的完整路径" %>
目前使用最多的是如下标签库:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2. JSP动作标签
2.1. <jsp:include>标签
这个动作标签用于在当前页面中包含静态和动态的资源,一旦被包含的页面执行完毕,请求处理将在调用页面中继续进行。这个动作标签与javax.servlet.RequestDispatcher类的include方法一致。
<jsp:include flush="boolean值" page="被包含页面的路径"></jsp:include>
- flush属性:该属性是可选的。默认值为false,表示当前页面输出使用了缓冲区,在包含之前不刷新缓冲区。true表示刷新缓冲区。
- page属性:指定被包含资源的相对路径,该路径是相对于当前JSP页面的URL。
include标签与include指令的区别:
语法 |
相对路径 |
发生时间 |
包含的对象 |
描述 |
<%@ include file=”url”%> |
相对于当前文件 |
转换期间 |
静态 |
包含的内容被JSP容器分析 |
<jsp:include page=”url”> |
相对于当前页面 |
请求处理期间 |
静态和动态 |
包含的内容不进行分析 |
2.2. <jsp:forward>标签
这个动作标签运行在运行时将当前的请求转发给一个静态的资源、JSP页面或者Servlet,请求被转向到的资源必须位于同JSP发送请求相同的上下文环境中。这个动作标签与javax.servlet.RequestDispatcher类的forward()方法的作用相同。
这个动作标签的语法格式如下:
<jsp:forward page="请求转发到页面的路径"></jsp:forward>
具体用法如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'forward.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <h1>forward.jsp</h1> <% System.out.println("forward jsp start..."); %> <jsp:forward page="include.jsp?flag=true"></jsp:forward> <% System.out.println("forward jsp end..."); %> </body> </html>
转换成Servlet后的代码
out.write(" \t<h1>forward.jsp</h1>\r\n"); out.write(" \t"); System.out.println("forward jsp start..."); out.write("\r\n"); out.write(" "); if (true) { _jspx_page_context.forward("include.jsp?flag=true"); return; } out.write("\r\n"); out.write(" "); System.out.println("forward jsp end...");
2.3. <jsp:param>标签
这个动作标签与<jsp:include>标签、<jsp:forward>标签配合使用,以键值对形式为其他标签提供参数内容。这个动作标签的语法格式如下:
<jsp:param value="参数值" name="参数名称"/>
具体用法参考如下代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'forward.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <jsp:forward page="include.jsp"> <jsp:param value="true" name="flag"/> </jsp:forward> </body> </html>
3. JSP内置对象
3.1. out输出流对象
内置对象out是javax.servlet.jsp.JspWriter类的实例,与response.getWriter()方法的作用相同,都是服务器端向客户端输出的字符串内容。该对象的常用方法如下:
Method Summary |
|
abstract void |
clear() |
abstract void |
flush() |
int |
getBufferSize() |
abstract int |
getRemaining() |
boolean |
isAutoFlush() |
abstract void |
|
abstract void |
println(String x) |
3.2. pageContext上下文对象
内置对象pageContext是javax.servlet.jsp.PageContext类的实例,该对象是JSP的四大作用域对象之一,pageContext对象代表当前JSP页面编译后的内容,多用于JSP页面之间共享数据内容。
- pageContext对象的常用方法
Method Summary |
|
abstract Object |
getAttribute(String name) |
abstract void |
removeAttribute(String name) |
abstract void |
setAttribute(String name, Object value) |
- pageContext对象获取其他八个内置对象
Method Summary |
|
abstract JspWriter |
getOut() |
abstract Exception |
getException() |
abstract Object |
getPage() |
abstract ServletRequest |
getRequest() |
abstract ServletResponse |
getResponse() |
abstract ServletConfig |
getServletConfig() |
abstract ServletContext |
getServletContext() |
abstract HttpSession |
getSession() |
- pageContext对象操作其他三个域
Method Summary |
|
abstract Object |
findAttribute(String name) |
abstract Object |
getAttribute(String name, int scope) |
abstract void |
removeAttribute(String name, int scope) |
abstract void |
setAttribute(String name, Object value, int scope) |
上述方法中的scope参数表示其他三个域常量:
Field Summary |
|
static int |
APPLICATION_SCOPE |
static int |
REQUEST_SCOPE |
static int |
SESSION_SCOPE |
3.3. request请求对象
内置对象request是javax.servlet.ServletRequest类的实例,代表着客户端的请求。具体用法请参考Request对象内容。
3.4. response响应对象
内置对象response是javax.servlet.ServletResponse类的实例,代表着服务器端的响应。具体用法请参考Response对象内容。
3.5. config配置对象
内置对象config是javax.servlet.ServletConfig类的实例,ServletConfig对象封装了配置在web.xml文件中初始化JSP的参数,JSP通过config对象获取这些参数值。具体用法请参考ServletConfig对象内容。
3.6. session会话对象
内置对象session是javax.servlet.http.HttpSession类的实例,session与cookie是解决Http协议的无状态问题的两种解决方案。如果在JSP页面中使用<%@ page session=”false”%>指令的话,则在当前JSP页面中不能使用session内置对象。但一般情况下,不会禁止使用session对象,具体用法请参考HttpSession对象内容。
3.7. application应用对象
内置对象application是javax.servlet.ServletContext类的实例,ServletContext封装了JSP所在的Web应用程序的信息,整个Web应用程序对应一个ServletContext对象。具体用法请参考ServletContext对象内容。
3.8. page页面对象
内置对象page是javax.servlet.jsp.HttpJspPage类的实例,page对象代表当前JSP页面,是当前JSP编译后的Servlet类的对象。page相当于普通Java类中的关键字this。
3.9. exception异常对象
内置对象exception是java.lang.Exception类的实例,该对象封装了JSP中抛出的异常信息。exception对象只能在使用<%@ page isErrorPage=”true”%>指令的JSP页面中。
4. JSP与JavaBean
4.1. JavaBean概述
JavaBean本质上就是一个Java类,只不过这个类需要遵循一些编码的规范。在JSP页面中,既可以使用普通类一样实例化JavaBean类的对象,调用方法,也可以利用JSP提供的动作标签访问JavaBean。
一个标准的JavaBean具有以下几个特性:
- 是一个公开(public)的类。
- 有一个默认的无参构造方法。
- 提供Setter和Getter方法用于设置和获取JavaBean的属性。
换句话讲,只要是符合上述条件的类,都可以看作是JavaBean。下面就是一个JavaBean实例:
public class User { public String name; public Boolean married; public String getName() { return name; } public void setName(String name) { this.name = name; } public Boolean isMarried() { return married; } public void setMarried(Boolean married) { this.married = married; } }
4.2. 内省
SUN公司开发了一套API,方便更好地操作JavaBean的属性,这套API被称之为内省(Introspector)。内省的出现有利于对JavaBean的属性操作,减少了代码量,内省依赖于Java的反射。
通过内省来操作JavaBean的属性,具体步骤如下:
- 通过Class类对象获取BeanInfo实例。
- 通过BeanInfo实例获取所有属性描述符对象。
- 通过属性描述符对象操作对应JavaBean的属性。
public class Demo { @Test public void Demo() throws Exception{ Class c = User.class; Object obj = c.newInstance(); //1 通过Class类对象获取BeanInfo实例 BeanInfo info = Introspector.getBeanInfo(User.class); //2 通过BeanInfo实例获取所有属性描述符对象 PropertyDescriptor[] pds = info.getPropertyDescriptors(); /* * 3 通过属性描述符对象操作对应JavaBean的属性 * * 获取属性名称 * * 获取读方法 * * 获取写方法 */ for (PropertyDescriptor pd : pds) { // 获取并输出JavaBean的属性名称 System.out.println(pd.getName()); // 获取并输出JavaBean的属性类型 System.out.println(pd.getPropertyType()); // 判断当前获取的JavaBean的属性名称是否为"name" if (pd.getName().equals("name")) { // 获取JavaBean的name属性的写方法 Method wmd = pd.getWriteMethod(); wmd.invoke(obj, "longestory"); // 获取JavaBean的name属性的读方法 Method rmd = pd.getReadMethod(); System.out.println(rmd.invoke(obj)); } } } }
4.3. BeanUtils工具
虽然Java提供了反射和内省相关的API,用于操作JavaBean组件的属性。但这些API方法使用起来很复杂,BeanUtils工具是Apache基于Java的内省封装的一个工具包。
BeanUtils工具包使用时,需要依赖logging日志包。
- 通过BeanUtils工具操作JavaBean的属性相关简单了不少。
public class Demo { @Test public void Demo() throws Exception{ Class c = User.class; Object obj = c.newInstance(); BeanUtils.setProperty(obj, "name", "longestory"); BeanUtils.setProperty(obj, "age", "14"); BeanUtils.setProperty(obj, "married", true); String name = BeanUtils.getProperty(obj, "name"); System.out.println(name); } }
- 通过BeanUtils工具的populate()方法来操作JavaBean。
public class Demo { @Test public void Demo() throws Exception{ Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "longestory"); map.put("age", "18"); map.put("married", true); Class c = User.class; Object obj = c.newInstance(); BeanUtils.populate(obj, map); System.out.println(obj); } }
- 通过populate()方法将一个Map集合内容设置到对应的JavaBean中,自定义一个工具类来完成复用。
public class CommonUtils { public static <T> T toBean(Map map, Class<T> clazz) { try { T bean = clazz.newInstance(); BeanUtils.populate(bean, map); return bean; } catch (Exception e) { throw new RuntimeException(e); } } }
下面通过一个案例来掌握BeanUtils封装内省的内容。
- 创建一个JSP页面用于显示用户注册信息。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户注册页面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <form action="/12_jsp/regist" method="post"> 用户名:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/> 确认密码:<input type="password" name="repassword"/><br/> 邮箱:<input type="text" name="email"/><br/> <input type="submit" value="注册"/> </form> </body> </html>
- 创建一个JavaBean用于封装用户注册信息。
public class Person { private String username; private String password; private String email; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Person [username=" + username + ", password=" + password + ", email=" + email + "]"; } }
- 创建一个Servlet用于接收用户注册信息。
public class PersonServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Person person = CommonUtils.toBean(request.getParameterMap(), Person.class); System.out.println(person); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" 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_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>PersonServlet</servlet-name> <servlet-class>app.java.exam.PersonServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>PersonServlet</servlet-name> <url-pattern>/regist</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
- 发布Web工程,并访问http://localhost:8080/jsp/index.jsp进行测试。
4.4. JSP动作标签
在JSP中可以像使用普通类一样访问JavaBean,JSP提供了三个动作标签<jsp:useBean>、<jsp:setProperty>和<jsp:getProperty>来访问JavaBean。
- <jsp:useBean>动作标签
该动作标签用于实例化JavaBean,或者定位一个已经存在的JavaBean实例。
该动作标签的语法格式:
<jsp:useBean id="实例名称" class="实例全类名" scope="指定范围"></jsp:useBean>
-
- id属性:用于标识JavaBean实例的名称。需要注意的是,指定的名称是区分大小写的,并遵照Java语言变量命名的约定。
- class属性:指定JavaBean实例的完整类名。
- scope属性:指定一个范围,在这个范围中,JavaBean实例的引用是可用的,实际上也是指定JavaBean实例的生命周期。备选取值有page、request、session和application,默认值为page。
<jsp:useBean>动作标签的实际作用可以利用下述Java代码进行解释:
<jsp:useBean id="user" class="app.java.bean.User" scope="session" /> User user = (User)session.getAttribute("user"); if(user == null) { user = new User(); session.setAttribute("user", user); }
- <jsp:setProperty>动作标签
该动作标签与<jsp:useBean>一起使用,用于设置JavaBean的属性。
该动作标签的语法格式:
<jsp:setProperty property="属性名称" name="实例名称" value="属性值"/>
- <jsp:getProperty>动作标签
该动作标签用于访问一个Bean的属性,并把属性的值转化成一个String,然后发送到输出流中。如果属性是一个对象,将调用该对象的toString()方法。
该动作标签的语法格式:
<jsp:getProperty property="属性名称" name="实例名称"/>
5. EL表达式语言
5.1. EL表达式语法
JSP中可以使用EL(Expression Language)表达式。EL表达式是用“${}”括起来的脚本,用来更方便地读取对象。EL表达式写在JSP的HTML代码中,而不能写在“<%%>”的JSP脚本中。
如果在JSP页面中使用了<%@ page isELIgnored=”true”%>指令的话,该JSP页面会忽略EL表达式。如果忽略某个EL表达式的话,可以在EL表达式之前添加“\”(例如\${1+2})。
当EL表达式的值为null时,会在JSP页面上显示空白,即什么都不显示。
EL表达式具有一些运算符,如下表
运算符 |
说明 |
范例 |
结果 |
+ |
加 |
${17+5} |
22 |
- |
减 |
${17-5} |
12 |
* |
乘 |
${17*5} |
85 |
/或div |
除 |
${17/5}或${17 div 5} |
3 |
%或mod |
取余 |
${17%5}或${17 mod 5} |
2 |
==或eq |
等于 |
${5==5}或${5 eq 5} |
true |
!=或ne |
不等于 |
${5!=5}或${5 ne 5} |
false |
<或lt |
小于 |
${3<5}或${3 lt 5} |
true |
>或gt |
大于 |
${3>5}或${3 gt 5} |
false |
<=或le |
小于等于 |
${3<=5}或${3 le 5} |
true |
>=或ge |
大于等于 |
${3>=5}或${3 ge 5} |
false |
&&或and |
并且 |
${true&&false}或${true and false} |
false |
!或not |
非 |
${!true}或${not true} |
false |
||或or |
或者 |
${true||false}或${true or false} |
true |
empty |
是否为空 |
${empty “”},可以判断字符串、数据、集合的长度是否为0,为0返回true。empty还可以与not或!一起使用。${not empty “”} |
true |
值得注意的是旧版本的Servlet规范不支持EL表达式,例如Tomcat 4.x以及以前的版本都不支持EL表达式。
EL表达式提供了获取JavaBean对象以及属性的简单方式。某些情况下EL表达式完全可以替代JSP脚本或者JSP行为,例如:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'expression.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <jsp:useBean id="user" class="app.java.bean.User" scope="session" /> <!-- 相当于session.getArribute("person") --> 欢迎您,${person}. <!-- 相当于person.getAge() --> <!-- 也相当于<jsp:getProperty name="person" property="age"> --> 您的年龄为${person.age}. </body> </html>
5.2. EL表达式内置对象
EL表达式不仅可以读取对象,还内置了十一个隐藏对象,这些内置对象无需创建,可以直接使用。而EL表达式中的内置对象中,最重要的是获取四大域相关的内置对象,如下表:
标识符 |
描述 |
示例 |
pageScope |
包含apge作用域内变量的Map |
使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”page”>声明pageScope范围内的User对象后,${pageScope.user.name}将输出该对象的name属性值 |
requestScope |
包含request作用域内变量的Map |
使用<jsp:useBean id=”user” class=”app.java.bean.User” >声明requestScope范围内的User对象后,${requestScope.user.name}将输出该对象的name属性值。useBean标签默认的作用域为request |
sessionScope |
包含session作用域内变量的Map |
使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”session”>声明sessionScope范围内的User对象后,${sessionScope.user.name}将输出该对象的name属性值 |
applicationScope |
包含application作用域内变量的Map |
使用<jsp:useBean id=”user” class=”app.java.bean.User” scope=”applcation”>声明applcation Scope范围内的User对象后,${ applcation Scope.user.name}将输出该对象的name属性值 |
除了上述获取四大域相关的内置对象以外,还有其他内置对象,但实际使用率并不高。
类别 |
标识符 |
描述 |
示例 |
请求参数 |
param |
包含所有参数的Map,可以获取参数,返回String |
${param.foo}或${param[‘foo’]} |
paramValues |
包含所有参数的Map,可以获取参数数组,返回String[] |
当提交多个参数,例如index.jsp?a=first&a=second,提交的参数a为多个值{“first”, “second”}。使用param只能获取第一个值,而使用paramValues能获取到所有值,${paramValues.a[0]}将输出“first”, ${paramValues.a[1]}将输出“second” |
|
头信息 |
header |
包含所有头信息的Map,返回String |
${header.host}可能返回localhost:8080 |
headerValues |
包含所有头信息的Map,返回String[] |
${headerValues.host[0]},当头信息为数组时可以获取多个值。 |
|
初始化参数 |
initParam |
包含所有初始化参数的Map |
${initParam.encoding} |
Cookie |
cookie |
包含所有Cookie的Map,key为Cookie的name属性 |
使用<%response.addCookie(new Cookie(“user”, “king”))%>设置Cookie后,${cookie.user}返回该Cookie,${cookie.user.name}返回user,${cookie.user.value}返回king |
|
pageContext |
包含页面内的变量的Map,包含request、response、page等所有内置对象 |
${pageContext.request.remoteAddr}将返回客户端IP地址,相当于执行<%=pageContext.getRequest().getRemoteAddr()%> |
之前在页面中编写请求资源路径时,都是固定内容。在掌握了EL表达式后,可以如下方式编写请求资源路径:
<a href="${pageContext.request.contextPath }/index.jsp">请求</a>
5.3. EL表达式函数
EL函数库是由第三方对EL表达式的扩展,目前学习的EL函数库是由JSTL(关于JSTL会在后面的内容学到)添加的。EL函数库就是定义了一些有返回值的静态方法,然后通过EL表达式调用。当然不只是JSTL可以定义EL函数库,我们也可以自定义EL函数库。
因为EL函数库是第三方提供的,所有要想使用的话,首先需要使用taglib指令引入。
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
JSTL提供的EL函数库包含的函数具体如下:
- String toUpperCase(String input):将一个字符串转换成大写。
- String toLowerCase(String input):将一个字符串转换成小写。
- int indexOf(String input, String substring):检索字符串。
- boolean contains(String input, String substring):判断一个字符串是否包含另一个字符串。
- boolean containsIgnoreCase(String input, String substring):判断一个字符串是否包含另一个字符串(忽略大小写)。
- boolean startsWith(String input, String substring):判断一个字符串是否以另一个字符串开始。
- boolean endsWith(String input, String substring):判断一个字符串是否以另一个字符串结束。
- String substring(String input, int beginIndex, int endIndex):按照指定开始位置和结束位置截取字符串。
- String substringAfter(String input, String substring):截取指定字符后的所有字符串。
- String substringBefore(String input, String substring):截取指定字符前的所有字符串。
- String escapeXml(String input):将字符串内容进行转义。
- String trim(String input):将字符串的前后空格去掉。
- String replace(String input, String substringBefore, String substringAfter):将一个字符串中的某个字符,利用另一个字符替换。
- String[] split(String input, String delimiters):将一个字符串利用指定分隔符分割。
- int length(Object obj):返回指定内容的长度。
- String join(String array[], String separator):使用指定连接符将数组中的每个元素连接。
下面是上述函数的具体使用方式:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'MyJsp.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <% String[] strs = {"a", "b","c"}; List list = new ArrayList(); list.add("a"); pageContext.setAttribute("arr", strs); pageContext.setAttribute("list", list); %> ${fn:length(arr) }<br/><!--3--> ${fn:length(list) }<br/><!--1--> ${fn:toLowerCase("Hello") }<br/> <!-- hello --> ${fn:toUpperCase("Hello") }<br/> <!-- HELLO --> ${fn:contains("abc", "a")}<br/><!-- true --> ${fn:containsIgnoreCase("abc", "Ab")}<br/><!-- true --> ${fn:contains(arr, "a")}<br/><!-- true --> ${fn:containsIgnoreCase(list, "A")}<br/><!-- true --> ${fn:endsWith("Hello.java", ".java")}<br/><!-- true --> ${fn:startsWith("Hello.java", "Hell")}<br/><!-- true --> ${fn:indexOf("Hello-World", "-")}<br/><!-- 5 --> ${fn:join(arr, ";")}<br/><!-- a;b;c --> ${fn:replace("Hello-World", "-", "+")}<br/><!-- Hello+World --> ${fn:join(fn:split("a;b;c;", ";"), "-")}<br/><!-- a-b-c --> ${fn:substring("0123456789", 6, 9)}<br/><!-- 678 --> ${fn:substring("0123456789", 5, -1)}<br/><!-- 56789 --> ${fn:substringAfter("Hello-World", "-")}<br/><!-- World --> ${fn:substringBefore("Hello-World", "-")}<br/><!-- Hello --> ${fn:trim(" a b c ")}<br/><!-- a b c --> ${fn:escapeXml("<html></html>")}<br/> <!-- <html></html> --> </body> </html>
我们也可以自定义EL函数库,具体自定义EL函数库的步骤如下:
- 创建一个Java类,该类包含具有返回值的静态方法。
package app.java.el.functions; public class MyFunctions { public static String test() { return "自定义EL函数库测试"; } }
- 在WEB-INF目录下创建一个“.tld”文件,用于配置自定义EL函数库。
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>myfn</short-name> <uri>http://www.myfn.com/jsp/functions</uri> <function> <name>test</name> <function-class>app.java.el.functions</function-class> <function-signature>String test()</function-signature> </function> </taglib>
- 在JSP页面中添加tagllib指令,导入自定义EL函数库。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="ls" uri="/WEB-INF/myfunctions.tld" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>自定义EL函数库</title> </head> <body> <h1>${ls:test() }</h1> </body> </html>
没有高深的知识,没有进阶的技巧,万丈高楼平地起~!