回鍋的美食:JSP+EL+JSTL大雜燴湯

来源:http://www.cnblogs.com/zyuqiang/archive/2017/05/13/6850516.html
-Advertisement-
Play Games

title: Servlet之JSP tags: [] notebook: javaWEB JSP是什麼 ? JSP就是Servlet,全名是"JavaServer Pages" 。因為Servlet不適合設置html響應體,需要大量的 ,而和html是靜態頁面,不能包含動態信息。JSP完美的解決了 ...



title: Servlet之JSP
tags: []
notebook: javaWEB
---

JSP是什麼 ?

JSP就是Servlet,全名是"JavaServer Pages" 。因為Servlet不適合設置html響應體,需要大量的response.getWriter().print("<html>"),而和html是靜態頁面,不能包含動態信息。JSP完美的解決了兩者的缺點,在原有html的基礎上添加java腳本,構成jsp頁面。

JSP的運行機理

當jsp頁面第一次被訪問時,伺服器會通過實現HttpJspPage介面(javax.servlet.jsp包下的介面)把jsp轉換成Servlet,也就是java文件(在tomcat的work目錄下可以找到jsp轉換成.java源代碼),下圖是jsp轉成Servlet的樣子。

上圖中,JSP頁面被翻譯成了Servelt ,可以看出JSP頁面的主體被轉換成了一個_jspService()方法,即實現了HttpJspPage介面。然後再把java編譯成.class,再創建該類對象,最後調用它的service()方法完成對客戶端的響應(輸出內容到客戶端) 。 當第二次調用同一jsp時,直接調用service()方法。所以第一次的時間總是很長,常稱為"第一次懲罰" 。

JSP與Servlet的分工

jsp

  • 作為請求發起頁面,例如顯示表單、超鏈接。
  • 作為請求結束頁面,例如顯示數據 。

Servlet

  • 作為請求中處理數據的環節。

三大指令+三大java腳本+動作標簽

JSP的組成 = html + java腳本 + jsp標簽(指令)

3種java腳本

  • <%...%>: Scriptlet,就是java代碼片段(常用) 。能放在裡面的內容,相當於java中方法的內容
  • <%=...%>:java表達式,用於輸出(常用),用於輸出一條表達式(或變數)的結果。相當於response.getWriter().print( ... );裡面的內容
  • <%!...%>:聲明(幾乎不用),用來創建類的成員變數和成員方法 。 相當於類體中放的內容JSP標簽

三個指令

指令格式: <%@指令名 屬性=值 屬性=值 ..........%>

page指令(重要)

重要屬性:

  • pageEncoding:它指定當前jsp頁面的編碼 。
  • contentType:它表示添加一個響應頭:Content-Type!等同於response.setContentType("text/html;charset=utf-8");
  • import:導包!<%@page import="java.net.*,java.util.*,java.sql.*"%>
  • errorPage:當前頁面如果拋出異常,那麼要轉發到哪一個頁面,由errorPage來指定 。可以在web.xml中配置錯誤頁面
  • isErrorPage:它指定當前頁面是否為處理錯誤的頁面!當該屬性為true時,這個頁面會設置狀態碼為500!而且這個頁面可以使用9大內置對象中的exception!
  • isELIgnored:是否忽略el表達式,預設值為false,不忽略,即支持!
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

include指令---->靜態包含

與RequestDispatcher的include()方法的功能相似!%@include% 它是在jsp編譯成java文件時完成的!如果A 頁麵包含B頁面,那麼他們共同生成一個java(就是一個servlet)文件,然後再生成一個class!RequestDispatcher的include()是一個方法,包含和被包含的是兩個servlet,即兩個.class!他們只是把響應的內容在運行時合併了!

<%@include file="b.jsp" %>

需要註意的是,一個被包含的頁面不能出現與包含頁面相同的代碼,比如一些``標簽等 。這個指令的作用使一些不變的東西可重用

taglib指令---->導入標簽庫

兩個屬性;

  • prefix:指定標簽庫在本頁面中的首碼!由我們自己來起名稱!
  • uri: 指定標簽庫的位置!

用法在導入JSTL標簽中會用到

JSP動作標簽

動作標簽是由tomcat(伺服器)來解釋執行!它與java代碼一樣,都是在伺服器端執行的!

  • <jsp:forword>:轉發!它與RequestDispatcher的forward方法是一樣的,一個是在Servlet中使用,一個是在jsp中使用!
  • <jsp:include>:包含:它與RequestDispatcher的include方法是一樣的,一個是在Servlet中使用,一個是在jsp中使用!

<jsp:include><%@include>的區別是: <jsp:include>在編譯之間就把包含和被包含頁面合併成一個java文件,編譯成一個.class。而<%@include>是包含和被包含頁面各自編譯,然後包含頁面去調用被包含頁面的.class 。

  • <jsp:param>:它用來作為forward和include的子標簽!用來給轉發或包含的頁面傳遞參數!
/**
* 包含頁
*/
<h1>a.jsp</h1>
<%--動態包含 --%>
<jsp:include page="b.jsp" >
            <jsp:param value="zhangSan" name="username"/>
            <jsp:param value="123" name="password"/>
</jsp:include>            
/**
* 被包含頁
*/
<h1>b.jsp</h1>
<%
    String username = request.getParameter("username");
    String password = request.getParameter("password");
%>
/**
* <h1>a.jsp</h1>不會顯示,只顯示<h1>b.jsp</h1>。 因為包含動作標簽是它與RequestDispatcher的include方法是一樣的。既然包含了其他頁面,當前頁面就算了
*/

JSP九大內置對象和PageContext域對象

內置對象 介紹 是哪個類的實例(對象)
out jsp的輸出流,用來向客戶端響應 javax.servlet.jsp.JspWriter
page 當前jsp對象!當前JSP頁面的"this " javax.servlet.jsp.HttpJspPage
pageContext 頁面上下文對象 ,四大域對象之一 javax.servlet.jsp.PageContext
exception 只有在錯誤頁面中可以使用這個對象 java.lang.Throwable
config 就是Servlet中的ServletConfig 類的對象 javax.servlet.ServletConfig
request 就是HttpServletRequest類的對象 javax.servlet.http.HttpServletRequest
response 就是HttpServletResponse類的對象 javax.servlet.http.HttpServletResponse
application 就是ServletContext類的對象 javax.servlet.ServletContext
session 就是HttpSession類的對象 javax.servlet.http.HttpSession

什麼是內置對象

在JSP中通常會用到上述的九個對象,為了避免在JSP中出現繁瑣定義對象的語句,索性直接先定義好上述的九個對象,並且各自給對象起了名字,當我們用的時候,無需再定義對象,如HttpServletRequest request = new HttpServletRequest(),直接用request對象就可以了。而且JSP的本質就是Servlet ,我們寫的JSP頁面都會被翻譯成Servlet去執行,可以這麼說,JSP和Servlet中的對象是通用的。所以在Servlet中域對象中存儲的值,在JSP中直接就可以獲得。這是非常方便的。
ServletConfig、HttpServletRequest、HttpServletResponse 、ServletContext、HttpSession 的學習 請點擊這兒學習 。

PageContext域對象與pageContext內置對象

PageContext是javaweb四大域對象之一,又稱為page域,而且只有在JSP中有,Servlet沒有 . PageContext作為內置對象,同時也是域對象之一,能夠存取數據。而且PageContext一個頂九個,非常重要 。

  • 在一個jsp頁面中共用數據!這個域是在當前jsp頁面和當前jsp頁面中使用的標簽之間共用數據!
abstract  java.lang.Object getAttribute(java.lang.String name) 
          Returns the object associated with the name in the page scope or null if not found. 
abstract  void setAttribute(java.lang.String name, java.lang.Object value) 
          Register the name and value specified with page scope semantics.           
  • (page域特有)這個域對象可以代理其他域,能夠向其他域中存取東西pageContext.setAttribute("xxx", "XXX", PageContext.SESSION_SCOPE)
abstract  java.lang.Object getAttribute(java.lang.String name, int scope) 
         Return the object associated with the name in the specified scope or null if not found. 
abstract  void setAttribute(java.lang.String name, java.lang.Object value, int scope) 
          Register the name and value specified with appropriate scope semantics. 
  • (page域特有)全域查找(重要),在四大域中都能查找。 從小到大查找,小域優先大域。
abstract  java.lang.Object findAttribute(java.lang.String name) 
          Searches for the named attribute in page, request, session (if valid), and application scope(s) in order and returns the value associated or null. 
  • (pageContext內置對象特有)一個頂九個,能夠獲取其他的8個內置對象,也就是說,PageContext一個內置對象就可以當九個內置對象用。
abstract  JspWriter getOut() 
          The current value of the out object (a JspWriter). 
abstract  java.lang.Exception getException() 
          The current value of the exception object (an Exception). 
abstract  java.lang.Object getPage() 
          The current value of the page object (In a Servlet environment, this is an instance of javax.servlet.Servlet). 
abstract  ServletRequest getRequest() 
          The current value of the request object (a ServletRequest). 
abstract  ServletResponse getResponse() 
          The current value of the response object (a ServletResponse). 
abstract  ServletConfig getServletConfig() 
          The ServletConfig instance. 
abstract  ServletContext getServletContext() 
          The ServletContext instance. 
abstract  HttpSession getSession() 
          The current value of the session object (an HttpSession). 

javaweb四大域對象與jsp九大內置對象

點擊這兒

javaBean解析

什麼是javabean ?

JavaBean是一種規範,也就是對類的要求。要求如下:

  • 必須要為成員提供get/set方法(也就是讀方法和寫方法)(兩者只提供一個也是可以的)。
  • 對於有get/set方法的成員變數稱之為屬性
  • 屬性名是由set/get方法決定的,不是由成員名字決定的。 比如 String name ; public void setUserName(){....}。屬性名是userName,而不是name .
  • 有get/set方法的成員,但是沒有成員也是可以的。這也是有屬性
  • 必須要有預設構造器(沒參的)
  • boolean類型的屬性,它的讀方法可以是is開頭,也可以是get開頭!
public class Person {
    private String name;  //成員
    private int age; 
    private boolean bool;     //boolean類型成員
    public boolean isBool() {   //讀方法
        return bool;
    }
    public void setBool(boolean bool) {
        this.bool = bool;
    }
    public String getId() {  // 就算沒有成員id,也是有id屬性的
        return "fdsafdafdas";
    }
    public String getUserName() {
        return name;
    }
    public void setName(String username) {  //就算成員名字是name,但是屬性名字還是userName 。
        this.name = name;
    }
    public int getAge() {  //讀方法
        return age;
    }
    public void setAge(int age) { //寫方法
        this.age = age;
    }
    public Person() {  //必須有預設的無參的構造函數
        super();
        // TODO Auto-generated constructor stub
    }
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", gender=" + gender
                + "]";
    }
    public Person(String name, int age, String gender) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

操作javaBean的方法(一): 內省(一般不用)

內省,自我反省。 底層依賴的是反射 ,通過反射來操作javabean 。

如定義上述JavaBean(Person類),其成員是私有的。當然可以通過反射去訪問Person類的私有成員,但是有危險。 一般都是通過get/set方法來操作私有成員 。 內省的目標就是得到JavaBean屬性的讀、寫方法(get/set)。 這樣就能通過set/get方法操作javabean. 通過內省操作javabean的方式是這樣的:

  1. 通過內省類Introspector的getBeanInfo方法返回BeanInfo 對象
  2. 通過介面BeanInfo的getMethodDescriptors() 方法得到所有屬性描述符對象PropertyDescriptor
  3. 通過類PropertyDescriptor的getReadMethod() 和getWriteMethod()方法,也就是get/set方法

具體API的方法如下:(javaSE6.0 API)

static BeanInfo getBeanInfo(Class<?> beanClass) 
          在 Java Bean 上進行內省,瞭解其所有屬性、公開的方法和事件。 
 PropertyDescriptor[] getPropertyDescriptors() 
          獲得 beans PropertyDescriptor。  
 Method getReadMethod() 
          獲得應該用於讀取屬性值的方法。 
 Method getWriteMethod() 
          獲得應該用於寫入屬性值的方法。 

操作javaBean的方法(二): 使用Commons-beanutils 工具(方便簡單,常用)

使用內省的方法固然能行,但是太過繁瑣 。 commons-beanutils這個工具, 它底層使用了內省,對內省進行了大量的簡化! 所以要導入這個工具

  • commons-beanutils-1.8.3.jar 下載
  • commons-logging-1.1.1.jar 下載

下麵的代碼完美演示了Commons-beanutils 工具對javabean的操作。 (javabean 用上述的Person類)

/**
* 使用BeanUtils工具來操作User類(javabean)
*/
import org.apache.commons.beanutils.BeanUtils;
public void fun1() throws Exception {
    /**
    *    反射
    */
    String className = "包.Person";
    Class clazz = Class.forName(className);
    Object bean = clazz.newInstance();
    /**
    *   利用setProperty設置 屬性
    */  
    BeanUtils.setProperty(bean, "name", "張三");
    BeanUtils.setProperty(bean, "age", "23");   //會自動將字元串轉換成整形 。
    BeanUtils.setProperty(bean, "gender", "男");   //就算是Person中沒有gender這個屬性,一樣不會報錯
    /**
    *   利用getProperty獲取 屬性值
    */      
    String age = BeanUtils.getProperty(bean, "age");
    System.out.println(age); //輸入單個屬性
    System.out.println(bean);  //調用Person中的toString()方法整體輸出
    }
/**
*把map中的屬性直接封裝到一個bean中
*把map的數據封裝到一個javabean中!要求map的key與bean的屬性名相同!
*/
public void fun2() throws Exception {
    /**
    * 創建Map  
    */
    Map<String,String> map = new HashMap<String,String>();
    map.put("username", "zhangSan");
    map.put("age", "123");
    /**
    * 新建bean對象
    */      
    Person person = new Person();
    /**
    *  map中的屬性直接封裝到bean中
    */
    BeanUtils.populate(person, map);        
    System.out.println(person);
}
/**
* 把map中的數據封裝到Person中的第二種形式。 更加簡化了代碼
*/
/**
* 編寫CommonUtils類 
*/
public class CommonUtils {
    /**
     * 生成不重覆的32位長的大寫字元串
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "").toUpperCase();
    }
    
    /**
     * 把map轉換成指定類型的javaBean對象
     */
    public static <T> T toBean(Map map, Class<T> clazz) {
        try {
            /*
             * 1. 創建指定類型的javabean對象
             */
            T bean = clazz.newInstance();
            /*
             * 2. 把數據封裝到javabean中
             */
            BeanUtils.populate(bean, map);
            /*
             * 返回javabean對象
             */
            return bean;
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }
}
/**
* 把map中的數據封裝到Person中
*/
public void fun3() {
        Map<String,String> map = new HashMap<String,String>();
        map.put("username", "zhangSan");
        map.put("password", "123");
        /**
        * 一句代碼完成封裝
        */
        User user = CommonUtils.toBean(map, User.class);
        System.out.println(user);
    }

jsp中通過標簽操作javaBean (過時的東西)

<jsp:useBean> <jsp:setProperty><jsp:getProperty>,這三個標簽在如今的model II 年代已經過時了 。 想學的自行百度

EL表達式初窺門徑

EL是什麼? EL的作用是什麼

JSP2.0要求把html和css分離、要把html和javascript分離、要把Java腳本替換成標簽 。 而El表達式就是要替換掉java腳本中的輸出腳本<%=...%>,也就是說EL表達式只能做輸出用 。 使用EL標簽的好處就是非java人員也可以使用,EL全程是“Expression Language ”

EL的語法

如果要輸出的結果是一個對象中的屬性,可以利用[].來訪問該屬性,就相當於調用get方法: 格式為: ${對象.屬性}或者${對象["屬性"]}。當屬性不是有效的java變數名稱時,只能用${對象["屬性"]}這種形式。

  • 操作list和數組: ${list[0]}
  • 操作bean屬性 : ${person.name}、${person[‘name’]} ,稱為javaBean導航
  • 操作Map的值:${map.key}、${map[‘key’]}

EL的11大內置對象

域相關的內置對象

內置對象 相關功能
pageScope 能夠輸出各自域總的數據
requestScope
sessionScope
applicationScope


如果是${xxx}這種形式,就是全域查找名為xxx的屬性,如果不存在,輸出空字元串,而不是null。四個域都存在,按照小的來。千萬不要當成是輸出xxx字元串。

/**
* Class Address
*/
public class Address {
    private String city;
    private String street;
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getStreet() {
        return street;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    @Override
    public String toString() {
        return "Address [city=" + city + ", street=" + street + "]";
    }   
}
/**
* Class Person
*/
public class Employee {
    private String name;
    private double salary;
    private Address address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Employee [name=" + name + ", salary=" + salary + ", address="
                + address + "]";
    }
}
/**
* jsp中輸出Person的地址信息
*/
<%
    Address address = new Address();
    address.setCity("昆明");
    address.setStreet("昆明理工大學");
    
    Person p = new Person();
    p.setName("李小四");
    p.setSalary(123456);
    p.setAddress(address);
    <!--request域存數據-->
    request.setAttribute("person", p);
%>
    <!--使用EL表達式輸出-->
    ${requestScope.emp.address.street }

其他的內置對象

  • param: Map
  • paramValues:Map
  • header : Map
  • headerValues: Map
  • initParam :Map

    <context-param>
    <param-name>aaa</param-name>
    <param-value>XXX</param-value>
      </context-param>
  • cookie : Map
  • pageContext: PageContext類型 。在前文中學過,pageContext這個內置對象是一個頂九個,可以獲得其他8個內置對象,所以輸出的時候也可以用來輸出其他內置對象的東西。

${pageContext.request.contextPath},先獲得request對象,然後在調用request的contextpath方法獲取到的結果是 :/項目名。 如獲取session的ID${pageContext.session.id }

註意的是:項目名字可能會更改,那麼代碼中含有項目名的路徑就需要更改,所以,代碼有項目名的路徑,一般都要用${pageContext.request.contextPath}這種方法來獲取項目名,如超鏈接中:<a href="${pageContext.request.contextPath }/文件名/XX.jsp">點擊這裡</a>。 表單中:<form action="${pageContext.request.contextPath }/文件名/XXX" method="post">

EL運算符

EL作為輸出的表達式,當然用可以進行計算,如${1+3} 。常見的運算符幾乎和常見的運算一樣,不在累贅 。

官方的EL函數庫與自定義EL函數

什麼是EL函數庫? 怎麼使用 ?

EL函數庫是由第三方對EL的擴展,JSTL的函數庫最是出名。EL函數庫里定義了一些有返回值的靜態方法,然後通過EL來調用它們,這些函數庫裡面的函數是定義好的,可以說就是官方的函數,當然我們可以自己定義函數庫。官方的函數包含了很多對字元串的操作方法,以及對集合對象的操作。

JSP頁面導入函數庫

因為是第三方的函數庫,所以在JSP頁面中要使用函數庫中的函數,需要使用taglib指令導入函數庫
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>,其中 prefix和uri的值其實就是 如果用的MyEclipse開發工具的話,我們沒有必須要導入這個包,因為在發佈到伺服器上時候會在tomcat目錄下的web-inf下lib自動存在關於jsf的相關包,所以不需要人為的導入什麼jar包。我們做的只是在jsp頁面添加這個Page指令而已 。在這幾個關於jsf的包中,打開jstl-版本號.jar-->META-INF下的fn.tld。 在這裡面能夠發現fnhttp://java.sun.com/jsp/jstl/functions。 這就是這兩個參數的由來。

函數庫中函數 與 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):獲取大串中,小串所在位置後面的字元串
  • substringBefore(String input, String substring):獲取大串中,小串所在位置前面的字元串
  • String escapeXml(String input):把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):聯合字元串數組!

用EL表達式調用這些函數的案例:

<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
…
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> -->

自定義EL函數庫

自定義EL函數庫的步驟

  1. 寫一個類,寫一個有返回值的靜態方法
  2. 編寫xxx.tld文件(案例以kmust.tld文件為例)。把xxx.tld文件放在/WEB-INF目錄下
  3. 在頁面中添加taglib指令,導入自定義標簽庫

第一步:寫一個有返回值的靜態方法的類

/**
* Class MyFunctions.java
* 這個類中寫有返回值的靜態方法,也就是我們自定義的函數
*/
package cn.kmust.fn;
public class KmustFunctions {
    public static String func1() {
         return "這是我自己定義的函數" ;
    }
}

第二步: 編寫kmust.tld文件。把kmust.tld文件放在/WEB-INF目錄下

<?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>it</short-name>
  <uri>http://www.kmust.cn/el/functions</uri>
  
  <function>
    <name>func1</name>
    <function-class>cn.kmust.fn.MyFunction</function-class>
    <function-signature>java.lang.String func1()</function-signature>
  </function>
  
</taglib>

第三步 : 在頁面中添加taglib指令,導入自定義標簽庫

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="it" uri="/WEB-INF/tlds/kmust.tld" %>
<html>
  <body>
<h1>${it:func1() } </h1>
  </body>
</html>

JSTL標簽庫

什麼是JSTL標簽庫

JSTL是Apache對EL表達式的擴展,依賴EL 。JSTL是標簽語言。JSP在2.0以後開始放棄java腳本,EL表達式代替<%=...%>解決了輸出的問題。而JSTL標簽將要代替<% ...%> 解決另外的Java腳本問題。

導入標簽庫

同EL函數庫的導入相似,如果使用MyEclipse開發工具,則不需要人為導入jar包,因為項目發佈到Tomcat時,MyEclipse會在lib目錄下存放jstl的jar包。我們只需要在JSP頁面中使用taglib指令導入標簽庫即可。
jstl一共有四個標簽庫,分別是:

  • core: 核心標簽庫 (重點)。 因為首碼是c,所以又叫做c標簽庫
  • fmt: 格式化標簽庫 (裡面有兩個重要標簽)。因為首碼是fmt,所以又叫做c標簽庫
  • SQL: 資料庫標簽庫 (過時了)
  • XML: xml標簽庫 (過時了)

以導入core核心標簽庫為列: <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

core標簽庫常用標簽

  1. out標簽<c:out>:輸出
  • value屬性:可以是字元串常量,也可以是EL表達式
  • default屬性:當輸出的內容為null時,會輸出defaulst指定的值
  • escapeXml屬性: 預設為true,表示轉義
  1. set標簽<c:set>:設置(可以創建域的屬性)
  • var屬性:變數名
  • value屬性: 變數值,可以是EL表達式
  • scope屬性: 域,如果不寫,預設為page域。 可選的值: page、request、session、application

    <c:set var="code" value="<script>alert('hello');</script>" scope="request"/> // 在request域中添加name為a,值為彈窗hello的數據
    <c:out value="${code }" /> //全域查找,輸出nme為a的值。 並且把<script>標簽給轉義了。所有直接輸出字元串,而不是彈窗
  1. remove標簽<c:remove>:刪除域變數
  • var屬性: 變數名
  • scope屬性 : 如果不給出scope這個屬性,表示刪除所有域中的該名稱的變數;如果指定了域,只刪除該域的變數
  1. URL標簽<c:url>:指定路徑
  • var屬性: 指定變數名,一旦添加了這個屬性,那麼URL標簽就不會再輸出到頁面,而是把生成的URL保存到域中
  • value屬性: 指定的路徑。 會在路徑前面自動添加項目名<c:url value="/index.jsp"> = ${pageContext.request.contextpath}/index.jsp=/項目名字/index.jsp。 所以超鏈接或者表單中的路徑,可以使用前兩種都可以。
  • scope屬性 : 與var屬性一起使用把URL保存到域中。

    <a href="<c:url value='/index.jsp'/>">點擊這裡回到主頁</a>
    <c:url value='/index.jsp'>
      <c:param name="name" value="張三"/> //加了參數,如果參數包含中文,則自動URL編碼 ,輸出:/項目名/index.jsp?username=A%E%G%D%G%D%G%D%
    </c:url>
  1. if標簽<c:if>:對應java中的if語句
  • ,當test為值時,執行標簽體內容!

    <c:if test="${empty param.name }"> //參數的name不為空
    輸出hello  
    </c:if>
  1. choose標簽<c:choose>:對應Java中的if/else

    <c:choose>
      <c:when test="">...</c:when>
      <c:when test="">...</c:when>
      <c:when test="">...</c:when>
       ... 
      <c:otherwise> ...</c:otherwise>
    </c:choose>
    等同與
    if(...) {
    } else if( ....) {
    } else if( ....) {
    } else if( ....) {
    } ...
    else { ...}
  2. forEach標簽<c:forEach>:用來迴圈遍曆數組、集合。可以用計數方式來迴圈
  • var:迴圈變數
  • begin:設置迴圈變數從幾開始。
  • end:設置迴圈變數到幾結束。
  • step:設置步長!等同與java中的i++,或i+=2。step預設為1

    <c:forEach var="i" begin="1" end="10" step="2">//for迴圈
    ${i }<br/>
    </c:forEach>
    用來輸出數組、集合
  • items:指定要迴圈誰,它可以是一個數組或一個集合
  • var:把數組或集合中的每個元素賦值給var指定的變數。

    <%
    String[] strs = {"one", "two"};
    request.setAttribute("strs", strs);
    %>
    <c:forEach items="${strs }" var="str">//輸出數組和集合
     ${str }<br/>
    </c:forEach>
    迴圈狀態
  • count:迴圈元素的個數
  • index:迴圈元素的下標
  • first:是否為第一個元素
  • last:是否為最後一個元素
  • current:當前元素
    ```java
    <%
    ArrayList

    pageContext.setAttribute("list", list);
    %>

```

fmt標簽庫常用標簽

fmt標簽庫是用來格式化輸出的,通常需要格式化的有時間和數字

  1. 對時間的格式化 :<fmt : formatDate value="" pattern="" />
    • value: 指定一個Date類型的變數
    • pattern: 用來指定輸出的模板 ,例如yyyy-MM-dd HH:mm:ss
<%
    Date date = new Date();
    request.setAttribute("date", date);
    
%>
<fmt:formatDate value="${requestScope.date }" pattern="yyyy-MM-dd HH:mm:ss"/>   // 按照給定的格式輸出時間
  1. 對數字的格式化:
<%
    request.setAttribute("num1", 3.1415926);
%>
<fmt:formatNumber value="${requestScope.num1 }" pattern="0.000"/><br/> //按照0.000保留小數點後面的位數,四捨五入,不足補0
<fmt:formatNumber value="${requestScope.num1 }" pattern="#.###"/>  //按照#.###保留小數點後面的位數,四捨五入,不足不補0 

自定義標簽

自定義標簽步驟:

  1. 標簽處理類
    需要實現SimpleTag介面(javaSE下),其介面下的方法:

     void doTag()   //每次執行標簽時都會調用這個房
          Called by the container to invoke this tag. 
     JspTag getParent()  //返回父標簽
          Returns the parent of this tag, for collaboration purposes. 
     void setJspBody(JspFragment jspBody)  //設置 標簽體 
          Provides the body of this tag as a JspFragment object, able to be invoked zero or more times by the tag handler. 
     void setJspContext(JspContext pc)  //設置jsp上下文對象,兒子就是PageContext,一般都是用pageContext
          Called by the container to provide this tag handler with the JspContext for this invocation. 
     void setParent(JspTag parent) 
          Sets the parent of this tag, for collaboration purposes.          
    public class MyTag1 implements SimpleTag {
    private PageContext pageContext;
    private JspFragment body;
    /**
     * 所有的setXxx()方法都會在doTag()方法之前被tomcat調用!
     * 所在doTag()中就可以使用tomcat傳遞過來的對象了。
     */
    public void doTag() throws JspException, IOException {
        pageContext.getOut().print("Hello Tag!");
    }
    public JspTag getParent() {
        return null;
    }
    public void setJspBody(JspFragment body) {
        this.body = body;
    }
    public void setJspContext(JspContext context) { 
        this.pageContext = (PageContext) context;
    }
    public void setParent(JspTag arg0) {}
    }
    標簽處理類的這些方法都是由Tomcat調用:過程如下;
  • 當容器(Tomcat)第一次執行到某個標簽時,會創建標簽處理類的實例
  • 然後調用setJspContext(JspXontext)方法,把當前JSP頁面的pageContext對象傳遞給這個方法
  • 如果當前標簽有父標簽。那麼使用父標簽的標簽處理類對象調用setParent(JspTag)方法
  • 如果標簽有標簽體,那麼把標簽體轉換成JSPFragment對象,然後調用setJSPBody()方法
  • 每次執行標簽時,都調用doTage()方法,它是標簽處理方法
    實現SimpleTag介面過於繁瑣,有專門的一個類SimpleTagSupport可以繼承,只需要重寫doTag()方法就可以了,因為這個類幫我們創建寫好其他的方法。可以通過getXX()的方法獲取其他方法。具體的方法如下;

     void doTag() 
          Default processing of the tag does nothing. 
    static JspTag findAncestorWithClass(JspTag from, Class<?> klass) 
          Find the instance of a given class type that is closest to a given instance. 
    protected  JspFragment getJspBody() 
          Returns the body passed in by the container via setJspBody. 
    protected  JspContext getJspContext() 
          Returns the page context passed in by the container via setJspContext. 
     JspTag getParent() 
          Returns the parent of this tag, for collaboration purposes. 
     void setJspBody(JspFragment jspBody) 
          Stores the provided JspFragment. 
     void setJspContext(JspContext pc) 
          Stores the provided JSP context in the private jspContext field. 
     void setParent(JspTag parent) 
          Sets the parent of this tag, for collaboration purposes. 
  1. 編寫tld文件,放在WEN-INF下

    <tag>
    <name></name> 指定當前標簽的名稱
    <tag-class></tag-class> 指定當前標簽的標簽處理類!
    <body-content></body-content> 指定標簽體的類型
      </tag>
    標簽體的內容有如下四種;
    |內容|說明|
    | :---| :---|
    |empty|無標簽體(常用)|
    |scriptless|可以是EL表達式或者其他的標簽或者字元串(常用)|
    |JSP|(不使用)|
    |tagdependent|(不使用)|
  2. 頁面中使用<%@taglib %>來導入tld文件
    <%@ taglib prefix= uri= %>

自定義標簽進階 1 : 不再執行標簽下麵的內容

可以設置,如果執行這個標簽,後面的標簽都會不執行。實現這一功能的方法是在標簽處理類中的doTag()方法中使用SkippageException來結束! Tomcat會調用標簽處理類的doTag()方法,然後Tomcat會得到SkipPageException,它會跳過頁面其他內容

public void doTag() throws JspException, IOException {
        
        throw new SkipPageException();//拋出這個異常後,在本標簽後面的內容,將看不到!
    }

自定義標簽進階 2 :標簽屬性

添加屬性的步驟

  • 為標簽處理類添加屬性,屬性需要一個set()方法,這個set()方法會在doTag()方法之前被Tomcat執行,所以doTag()中就可以使用屬性了。
  • 在tld文件中對屬性進行配置

    <attribute>
        <name>test</name> 指定屬性名
        <required>true</required> 指定屬性是否為必需的
        <rtexprvalue>true</rtexprvalue> 指定屬性是否可以使用EL
    </attribute>

自定義標簽小案例 :

/**
* Class MyTag1
* 繼承SimpleTagSupport類,重寫doTag()方法。沒有標簽體
*/
package cn.kmust.tag;
public class MyTag1 extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
       //因為這個SimpleTagSupport中早就為我們寫好了出doTag()之外的其他方法,所以通過this.getXXX()即可獲得其他方法的返回對象。
        this.getJspContext().getOut().print("Hello one !");  //通過getJspContext獲得pageContext,然後getOut獲得輸出對象,通過print像頁面輸出 。
    }
}
/**
* Class MyTag2
* 有標簽體
*/
package cn.kmust.tag;
public class MyTag3 extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        Writer out = this.getJspContext().getOut();//獲取當前jsp頁面的輸出流
        this.getJspBody().invoke(out);//執行標簽體內容,把結果寫到指定的流中,即頁面上。
        //需要說明的是,invoke()的參數可以

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • eclipse里有一個功能叫做“打可執行(runnable) jar包”, 用這個功能可以把一個工程自身和所有依賴包打成一個fat jar,並且指定Main方法,這樣直接使用java jar xxx.jar就可以運行代碼了。 但是在不使用eclipse的時候呢?其實,藉助maven,我們很容易實現同 ...
  • 直接調用Math裡面的random即可,簡單方便int i = (int)(Math.random()*100+1); ...
  • 開始第二模塊的學習: 裝飾器 : 描述: 裝飾器原則: 1、不能修改被裝飾的函數的源代碼 2、不能修改裝飾的函數的調用方試 實現裝飾器的需要: 高階函數+嵌套函數=裝飾器 高階函數: 類型I:將函數做為實參的函數,可以稱為高階函數 類型II:返回值中包含函數名的函數,也可以稱為高階函數 嵌套函數: ...
  • Nginx具有反向代理(註意和正向代理的區別)和負載均衡等特點。 這次Nginx安裝在 192.168.1.108 這台linux 機器上。安裝Nginx 先要裝openssl庫,gcc,PCRE,zlib庫等。 Tomcat 安裝在192.168.1.168 和 192.168.1.178 這兩台 ...
  • 多線程 多線程是我們開發人員經常提到的一個名詞。為什麼會有多線程的概念呢?我們的電腦有可能會有多個cpu(或者CPU有多個內核)這就產生了多個線程。對於單個CPU來說,由於CPU運算很快,我們在電腦上運行多個軟體時,每個軟體在CPU上運行很短的時間就會切換成其他軟體。由於來回切換的時間很短,我們感覺 ...
  • java中常用的包、類、以及包中常用的類、方法、屬性 常用的包 java.io.*; java.util.*; java.lang.*; java.math.*; java.sql.*; java.text.*; java.awt.*; javax.swing.*; 包名 介面 類 方法 屬性 ja ...
  • 前面一篇文章講瞭如何快速搭建一個ActiveMQ的示常式序,ActiveMQ是JMS的實現,那這篇文章就再看下另外一種消息隊列AMQP的代表實現RabbitMQ的簡單示例吧。在具體講解之前,先通過一個圖來概覽下: 1.添加Maven依賴 2.Spring配置文件中添加rabbitmq相關配置 1)消 ...
  • java產生隨機數的幾種方式 一.在j2se里我們可以使用Math.random()方法來產生一個隨機數,這個產生的隨機數是0-1之間的一個double,用時需要int強制轉換,我們可以把他乘以一定的數,比如說乘以100,他就是個100以內的隨機,這個在j2me中沒有。 java.util.Rand ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...