JSP Tag標籤與EL表達式

JSP Tag標籤

jsp tag標籤外表長得像html、xml等標記語言,但是內部其實就是封裝了的Java代碼。通過jsp標籤可以簡化一些需要在jsp上編寫的Java代碼,雖說是標籤,但是jsp只會在服務器上運行,不會跑到瀏覽器上運行,畢竟jsp歸根結底只是一個Servlet,以下介紹幾個常見的jsp標籤:
1.重定向標籤:

<jsp:forward page="index.jsp"></jsp:forward>

這個標籤與以下這段代碼等價,都是內部轉發:

<%
    request.getRequestDispatcher("index.jsp").forward(request, response);
%>

index.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <h1>Hello I'm index.jsp</h1>
</body>
</html>

使用Java代碼轉發示例:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <%
        request.getRequestDispatcher("index.jsp").forward(request, response);
    %>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

Hello I'm index.jsp

使用jsp標籤轉發示例:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:forward page="index.jsp"></jsp:forward>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

Hello I'm index.jsp

2.導入某頁面運行結果標籤:

<jsp:include page="head.jsp"></jsp:include>

這個標籤和jsp指令中的 <%@ include file="head.jsp" %> 類似,只不過指令是將head.jsp的頁面內容導入到當前頁面中,而jsp標籤則是僅導入head.jsp頁面的運行結果。它們兩者的區別在於這裏。使用示例:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:include page="index.jsp"></jsp:include>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

Hello I'm index.jsp

3.配置參數標籤:

<jsp:param value="lisi" name="name"/>

這個標籤是用來配置參數的,比如轉發時帶上參數,或者導入某頁面結果時加上參數,不過這個標籤必須配合jsp:include、jsp:forward、jsp:plugin等標籤來進行使用,不然就會報以下錯誤:

嚴重: Servlet.service() for servlet [jsp] in context with path [/jsp-tag_Test] threw exception [/test.jsp (line: [9], column: [6]) The jsp:param action must not be used outside the jsp:include, jsp:forward, or jsp:params elements] with root cause
org.apache.jasper.JasperException: /test.jsp (line: [9], column: [6]) The jsp:param action must not be used outside the jsp:include, jsp:forward, or jsp:params elements

1.jsp:param與jsp:include配合使用:
test.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:include page="index.jsp">
        <jsp:param value="lisi" name="name" />
    </jsp:include>
</body>
</html>

index.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <h1><%=request.getParameter("name") %></h1>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

lisi

2.jsp:param與jsp:forward配合使用:
test.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:forward page="index.jsp">
        <jsp:param value="lisi" name="name" />
    </jsp:forward>
</body>
</html>

index.jsp代碼與之前一致。

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

lisi

以上三個標籤是比較常用的。

4.此標籤用來在jsp頁面中創建一個Bean實例:

<jsp:useBean id=""></jsp:useBean> 

創建後的Bean示例可以存儲在request、session 、application(servletcontext)、page 等jsp內置對象中。

Java Bean簡介:
Java語言欠缺屬性、事件、多重繼承功能。所以,如果要在Java程序中實現一些面向對象編程的常見需求,只能手寫大量膠水代碼。Java Bean正是編寫這套膠水代碼的慣用模式或約定。這些約定包括getXxx、setXxx、isXxx、addXxxListener、XxxEvent等。遵守上述約定的類可以用於若干工具或庫。

使用jsp:useBean創建Bean實例對象,示例:
1.我有一個Student類,代碼如下:

public class Student {

    private String sname;

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String email;
    private int age;

}

2.test.jsp代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <!-- id是這個對象的唯一標識,class裏的值是該類的全名,scope是指定該實例存儲在哪個內置對象中 -->
    <jsp:useBean id="stu" class="org.zero01.test.Student" scope="request">這裏的文字會在對象創建的時候打印出來</jsp:useBean>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/test.jsp,運行結果:

這裏的文字會在對象創建的時候打印出來

5.此標籤用於設置Bean對象的屬性值:
property的值爲對象的屬性名稱,name的值爲jsp:useBean中定義的id值,param的值爲html表單中的name屬性的值

<jsp:setProperty property="sname" name="stu" param="sname" />

6.此標籤用於得到Bean對象的屬性值,默認會將值打印出來:
同樣的property的值爲對象的屬性名稱,name的值爲jsp:useBean中定義的id值

<jsp:getProperty property="sname" name="stu" />

示例:
index.jsp代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <form action="test.jsp">
        <input type="text" name="form_sname" placeholder="學生名字" /><br>
        <input type="text" name="form_email" placeholder="郵箱地址" /><br>
        <input type="text" name="form_age" placeholder="年齡" /><br>
        <button type="submit">提交</button>
    </form>
</body>
</html>

test.jsp代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:useBean id="stu" class="org.zero01.test.Student" scope="request">
        這裏的文字會在對象創建的時候打印出來
    </jsp:useBean><br>

    <jsp:setProperty property="sname" name="stu" param="form_sname"/>
    <jsp:setProperty property="email" name="stu" param="form_email"/>
    <jsp:setProperty property="age" name="stu" param="form_age"/>

    <jsp:getProperty property="sname" name="stu"/><br>
    <jsp:getProperty property="email" name="stu"/><br>
    <jsp:getProperty property="age" name="stu"/>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/index.jsp,輸入的表單內容:

lisibr/>[email protected]
15

跳轉到test.jsp後的打印結果:

這裏的文字會在對象創建的時候打印出來 br/>lisi
[email protected]
15

如果表單中的name屬性值與Bean對象的屬性名稱一致的話,可以使用以下方式,自動匹配相同的名稱:
index.jsp表單代碼如下:

<form action="test.jsp">
        <input type="text" name="sname" placeholder="學生名字" /><br>
        <input type="text" name="email" placeholder="郵箱地址" /><br>
        <input type="text" name="age" placeholder="年齡" /><br>
        <button type="submit">提交</button>
</form>

test.jsp代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <jsp:useBean id="stu" class="org.zero01.test.Student" scope="request">
        這裏的文字會在對象創建的時候打印出來
    </jsp:useBean><br>

    <!-- property的值爲*會自動匹配表單中相同的名稱 -->
    <jsp:setProperty property="*" name="stu"/>

    <jsp:getProperty property="sname" name="stu"/><br>
    <jsp:getProperty property="email" name="stu"/><br>
    <jsp:getProperty property="age" name="stu"/>
</body>
</html>

訪問http://localhost:8080/jsp-tag_Test/index.jsp,輸入的表單內容:

zerobr/>[email protected]
16

跳轉到test.jsp後的打印結果:

這裏的文字會在對象創建的時候打印出來 br/>zero
[email protected]
16

關於Bean實例存儲在session對象中的那拿值過程:

<jsp:useBean id="stu" class="org.zero01.test.Student" scope="session">

1.先在session中查找有沒有stu
2.有的話就直接拿出來,不會創建對象
3.沒有的話,就創建對象,存到session中之後再拿出來

EL表達式


EL(Expression Language) 是爲了使JSP寫起來更加簡單。表達式語言的靈感來自於 ECMAScript 和 XPath 表達式語言,它提供了在 JSP 中簡化表達式的方法,讓Jsp的代碼更加簡化。EL表達式和jsp標籤一樣,內部實際就是java代碼,以下是生成的源碼:

使用EL表達式後生成的源碼:

out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${param.sname}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));

使用jsp標籤後生成的源碼:

out.write("<br>\r\n");
      out.write("\t\r\n");
      out.write("\t<!-- property的值爲*會自動匹配表單中相同的名稱 -->\r\n");
      out.write("\t");
      org.apache.jasper.runtime.JspRuntimeLibrary.introspect(_jspx_page_context.findAttribute("stu"), request);
      out.write("\r\n");
      out.write("\t\r\n");
      out.write("\t");
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((org.zero01.test.Student)_jspx_page_context.findAttribute("stu")).getSname())));
      out.write("<br>\r\n");
      out.write("\t");
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((org.zero01.test.Student)_jspx_page_context.findAttribute("stu")).getEmail())));
      out.write("<br>\r\n");
      out.write("\t");
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((org.zero01.test.Student)_jspx_page_context.findAttribute("stu")).getAge())));
      out.write("\r\n");

EL表達式的語法結構:
${expression}

基本語法示例:

${name}

以上這個表達式會拿到一個值,這個表達式的拿值過程:
1.先在當前頁面中的pageContext裏找有沒有這個名爲name的值
2.沒有的話就會去request對象裏找
3.request也沒有的話就去session裏找
4.session都沒有的話就去application(servletContext)裏找
5.如果在這些對象中都找不到的話也不會報錯,也不會打印null,而是什麼都不顯示。

示例:
test.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <p>${name};</p>
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,顯示空白,因爲這個以上代碼並沒有表達式中所需要的值。

如果我在pageContext對象裏設置一個name屬性,看看是否能獲得到,代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<% 
    pageContext.setAttribute("name", "lisi");
%>
    <p>${name}</p>
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

lisi

或者在request裏設置一個name屬性,代碼如下:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<% 
    request.setAttribute("name", "request");
%>
    <p>${name}</p>
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

request

以上實驗就可以知道,只要這些對象其中有一個name屬性值,就可以被這個表達式獲得到。以上也提到了這種表達式尋找值是先從pageContext對象中找的,所以來實驗一下是否是先從pageContext對象中找,代碼如下:

<%@page import="org.zero01.test.Student"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <%
        request.setAttribute("name", "request");
        session.setAttribute("name", "session");
        pageContext.setAttribute("name", "pageContext");
        application.setAttribute("name", "application");
    %>

    ${name}
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

pageContext

除了這種只寫屬性名稱讓它自動去匹配的方式之外,還可以指定在某個對象中拿值,如下:

${pageScope.name}
${requestScope.name}
${sessionScope.name}
${applicationScope.name}

還可以訪問某個對象的屬性,例如我在頁面上實例化了Student對象,設置了屬性值之後放進了request對象中,然後就可以通過el表達式去獲得這個Student對象的屬性值,示例:

<%@page import="org.zero01.test.Student"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <%
        Student student = new Student();
        student.setSname("lisi");
        student.setAge(16);
        student.setEmail("[email protected]");

        request.setAttribute("student", student);
    %>

    ${student.sname}<br>
    ${student.email}<br>
    ${student.age}<br>
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

lisibr/>[email protected]
16

但是有一點要注意的就是,這個Student實例對象必須要有get方法才能獲得到相應的屬性值,否則是無法獲得的。

如果Student實例對象中有一個屬性存儲的是對象,那麼在el表達式中也可以拿到該對象的的屬性值:

<%@page import="org.zero01.test.Student"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <%
        Student stu = new Student();
        stu.setSname("lisi");
        stu.setAge(16);
        stu.setEmail("[email protected]");
        stu.setStudent(stu);

        request.setAttribute("stu", stu);
    %>

    ${requestScope.stu.student.sname}
    <br> 
    ${requestScope.stu.student.email}
    <br> 
    ${requestScope.stu.student.age}
    <br>
</body>
</html>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

lisibr/>[email protected]
16

除了可以在以上對象中拿值外,還可在以下對象中拿值:
1.param: 表單參數對象
2.paramValues:重複的表單參數的對象
3.header: http請求頭參數對象
4.headerValues:重複的http請求頭參數的對象
5.cookie: cookie對象
6.initParam: 通過這個對象,可以拿到servletContxt對象初始化時配置的參數值

示例:
index.jsp代碼:

<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <form action="test.jsp">
        <input type="text" name="sname" placeholder="學生名字" /><br>
        <input type="text" name="sname" placeholder="學生名字" /><br>
        <input type="text" name="sname" placeholder="學生名字" /><br>
        <input type="text" name="email" placeholder="郵箱地址" /><br>
        <input type="text" name="age" placeholder="年齡" /><br>
        <button type="submit">提交</button>
    </form>
</body>
</html>

test.jsp代碼:

<%@page import="org.zero01.test.Student"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    學生名字:${param.sname}<br>
    郵箱地址:${param.email}<br>
    年齡:${param.age}<br>
    type:${paramValues.sname[2]}<br>
    host:${header.host}<br>
    Accept:${headerValues.Accept[0]}<br>
    cookie:${cookie.JSESSIONID.value}<br>
</body>
</html>

訪問http://localhost:8080/EL-Test/index.jsp,輸入的表單內容如下:

lisi1br/>lisi2
lisi3
[email protected]
16

跳轉到test.jsp後的打印結果:

學生名字:lisi1
郵箱地址:[email protected]
年齡:16
type:lisi3
host:localhost:8080
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
cookie:E936637B285D60CA96B7CC3D258EBD50

initParam 示例:
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">

    <context-param>
        <param-name>name</param-name>
        <param-value>一拳超人</param-value>
    </context-param>

</web-app> 

test.jsp代碼如下:

<%@page import="org.zero01.test.Student"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    ${initParam.name}<br>
</body>
</html>

重啓Tomcat後,訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

一拳超人

el表達式除了可以從各種對象中獲得值之外還可以使用算術運算符、關係運算符、邏輯運算符等運算符,進行相關的運算,示例:

<%
  request.setAttribute("num", "1000.5");
%>

${num / 100}<br>
${num * 100}<br>
${num + 100}<br>
${num - 100}<br>
${num % 100}<br>
${num == 1000.05}<br>
${num > 1000.05}<br>
${num < 1000.05}<br>
${num >= 1000.05}<br>
${num <= 1000.05}<br>
${num != 1000.05}<br>
${num == 1000.05 && true}<br>
${num == 1000.05 || false}<br>
${num != 1000.05 ? 8:9}<br>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

10.005
100050.0
1100.5
900.5
0.5
false
true
false
true
false
true
false
false
8

除了以上這種常見的運算符形式外,還可使用英文單詞縮寫的形式,(注意,加減乘,這三項不支持縮寫的形式)如下:

<%
  request.setAttribute("num", 1000.5);
%>

${num div 100}<br>
${num * 100}<br>
${num + 100}<br>
${num - 100}<br>
${num mod 100}<br>
${num eq 1000.05}<br>
${num gt 1000.05}<br>
${num lt 1000.05}<br>
${num ge 1000.05}<br>
${num le 1000.05}<br>
${num ne 1000.05}<br>
${num eq 1000.05 and true}<br>
${num eq 1000.05 or false}<br>
${num ne 1000.05 ? 8:9}<br>

訪問http://localhost:8080/EL-Test/test.jsp,打印結果如下:

10.005
100050.0
1100.5
900.5
0.5
false
true
false
true
false
true
false
false
8

關於OGNL表達式:
OGNL是Object-Graph Navigation Language的縮寫,它是一種功能強大的表達式語言,通過它簡單一致的表達式語法,可以存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。所以OGNL和EL表達式蠻像的,在一些需要動態變化字段的場景下,OGNL非常的有用,例如流程控制語句中的條件需要動態變化的情況下,就需要使用OGNL。

下面簡單演示一下OGNL,maven工程配置如下依賴:

<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.0.4</version>
</dependency>

編寫代碼如下:

package org.zero01.test;

import java.util.Hashtable;

import ognl.Ognl;
import ognl.OgnlException;

public class TestOGUL{

    public static void main(String[] args) throws OgnlException {

        Student stu=new Student();

        //使用hashtable作爲表達式的root,也就是根元素
        Hashtable<String, Object> hashtable=new Hashtable<String, Object>();
        hashtable.put("stu", stu);

        //設置一個表達式
        Ognl.setValue("stu.sname", hashtable, "李四");
        //得到表達式的值
        System.out.println(Ognl.getValue("stu.sname", hashtable));

        //還可以進行運算
        System.out.println(Ognl.getValue("100*(500+90)*(500+90)", hashtable));
    }
}

運行結果:

李四
34810000

以上只是一個十分簡單的示例,目的是爲了稍作了解而已,知道除了EL表達式外還有這種表達式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章