title: Servlet之JSP
tags: []
notebook: javaWEB
---javascript
JSP就是Servlet,全名是"JavaServer Pages" 。由於Servlet不適合設置html響應體,須要大量的response.getWriter().print("<html>")
,而和html是靜態頁面,不能包含動態信息。JSP完美的解決了二者的缺點,在原有html的基礎上添加java腳本,構成jsp頁面。css
當jsp頁面第一次被訪問時,服務器會經過實現HttpJspPage接口(javax.servlet.jsp包下的接口)把jsp轉換成Servlet,也就是java文件(在tomcat的work目錄下能夠找到jsp轉換成.java源代碼),下圖是jsp轉成Servlet的樣子。html
上圖中,JSP頁面被翻譯成了Servelt ,能夠看出JSP頁面的主體被轉換成了一個_jspService()方法,即實現了HttpJspPage接口。而後再把java編譯成.class,再建立該類對象,最後調用它的service()方法完成對客戶端的響應(輸出內容到客戶端) 。 當第二次調用同一jsp時,直接調用service()方法。因此第一次的時間老是很長,常稱爲"第一次懲罰" 。java
jspweb
Servletsql
JSP的組成 = html + java腳本 + jsp標籤(指令)數據庫
<%...%>
: Scriptlet,就是java代碼片斷(經常使用) 。能放在裏面的內容,至關於java中方法的內容<%=...%>
:java表達式,用於輸出(經常使用),用於輸出一條表達式(或變量)的結果。至關於response.getWriter().print( ... );
裏面的內容<%!...%>
:聲明(幾乎不用),用來建立類的成員變量和成員方法 。 至關於類體中放的內容JSP標籤指令格式: <%@指令名 屬性=值 屬性=值 ..........%>
apache
page指令(重要)數組
重要屬性:瀏覽器
response.setContentType("text/html;charset=utf-8")
;<%@page import="java.net.*,java.util.*,java.sql.*"%>
<%@ 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指令---->導入標籤庫
兩個屬性;
用法在導入JSTL標籤中會用到
動做標籤是由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方法是同樣的。既然包含了其餘頁面,當前頁面就算了 */
內置對象 | 介紹 | 是哪一個類的實例(對象) |
---|---|---|
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是javaweb四大域對象之一,又稱爲page域,並且只有在JSP中有,Servlet沒有 . PageContext做爲內置對象,同時也是域對象之一,可以存取數據。並且PageContext一個頂九個,很是重要 。
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.
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.
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.
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).
JavaBean是一種規範,也就是對類的要求。要求以下:
String name ; public void setUserName(){....}
。屬性名是userName,而不是name .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(Person類),其成員是私有的。固然能夠經過反射去訪問Person類的私有成員,可是有危險。 通常都是經過get/set方法來操做私有成員 。 內省的目標就是獲得JavaBean屬性的讀、寫方法(get/set)。 這樣就能經過set/get方法操做javabean. 經過內省操做javabean的方式是這樣的:
具體API的方法以下:(javaSE6.0 API)
static BeanInfo getBeanInfo(Class<?> beanClass) 在 Java Bean 上進行內省,瞭解其全部屬性、公開的方法和事件。 PropertyDescriptor[] getPropertyDescriptors() 得到 beans PropertyDescriptor。 Method getReadMethod() 得到應該用於讀取屬性值的方法。 Method getWriteMethod() 得到應該用於寫入屬性值的方法。
使用內省的方法當然能行,可是太過繁瑣 。 commons-beanutils這個工具, 它底層使用了內省,對內省進行了大量的簡化! 因此要導入這個工具
下面的代碼完美演示了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:useBean>
<jsp:setProperty>
和<jsp:getProperty>
,這三個標籤在現在的model II 年代已通過時了 。 想學的自行百度
JSP2.0要求把html和css分離、要把html和javascript分離、要把Java腳本替換成標籤 。 而El表達式就是要替換掉java腳本中的輸出腳本<%=...%>
,也就是說EL表達式只能作輸出用 。 使用EL標籤的好處就是非java人員也可使用,EL全程是「Expression Language 」
若是要輸出的結果是一個對象中的屬性,能夠利用[]
和.
來訪問該屬性,就至關於調用get方法: 格式爲: ${對象.屬性}
或者${對象["屬性"]}
。當屬性不是有效的java變量名稱時,只能用${對象["屬性"]}
這種形式。
${list[0]}
${person.name}、${person[‘name’]}
,稱爲javaBean導航${map.key}、${map[‘key’]}
域相關的內置對象
內置對象 | 相關功能 |
---|---|
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 }
其餘的內置對象
${request.getparameter()}
,不一樣的是,即便參數不存在,返回空字符串,而不是null。 用法爲${param.name}
paramValues.hobby[0]
${header.Host}
${headerValue["accept-language"][0]}
${initParam.aaa}
<context-param> <param-name>aaa</param-name> <param-value>XXX</param-value> </context-param>
${cookie.unam.name}
和${cookie.unam.value}
如${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做爲輸出的表達式,固然用能夠進行計算,如${1+3}
。常見的運算符幾乎和常見的運算同樣,不在累贅 。
EL函數庫是由第三方對EL的擴展,JSTL的函數庫最是出名。EL函數庫裏定義了一些有返回值的靜態方法,而後經過EL來調用它們,這些函數庫裏面的函數是定義好的,能夠說就是官方的函數,固然咱們能夠本身定義函數庫。官方的函數包含了不少對字符串的操做方法,以及對集合對象的操做。
由於是第三方的函數庫,因此在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。 在這裏面可以發現fn
和http://java.sun.com/jsp/jstl/functions
。 這就是這兩個參數的由來。
函數庫中的函數以下:
用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> -->
第一步:寫一個有返回值的靜態方法的類
/** * 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是Apache對EL表達式的擴展,依賴EL 。JSTL是標籤語言。JSP在2.0之後開始放棄java腳本,EL表達式代替<%=...%>
解決了輸出的問題。而JSTL標籤將要代替<% ...%>
解決另外的Java腳本問題。
同EL函數庫的導入類似,若是使用MyEclipse開發工具,則不須要人爲導入jar包,由於項目發佈到Tomcat時,MyEclipse會在lib目錄下存放jstl的jar包。咱們只須要在JSP頁面中使用taglib指令導入標籤庫便可。
jstl一共有四個標籤庫,分別是:
c
,因此又叫作c標籤庫fmt
,因此又叫作c標籤庫以導入core核心標籤庫爲列: <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
out標籤<c:out>
:輸出
<c:set>
:設置(能夠建立域的屬性)
<c:set var="code" value="<script>alert('hello');</script>" scope="request"/> // 在request域中添加name爲a,值爲彈窗hello的數據 <c:out value="${code }" /> //全域查找,輸出nme爲a的值。 而且把<script>標籤給轉義了。全部直接輸出字符串,而不是彈窗
<c:remove>
:刪除域變量
<c:url>
:指定路徑
<c:url value="/index.jsp">
= ${pageContext.request.contextpath}/index.jsp
=/項目名字/index.jsp。 因此超連接或者表單中的路徑,可使用前兩種均可以。<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>
<c:if>
:對應java中的if語句
<c:if test="${empty param.name }"> //參數的name不爲空 輸出hello </c:if>
<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 { ...}
<c:forEach>
:用來循環遍歷數組、集合。能夠用計數方式來循環
<c:forEach var="i" begin="1" end="10" step="2">//for循環 ${i }<br/> </c:forEach>用來輸出數組、集合
<% String[] strs = {"one", "two"}; request.setAttribute("strs", strs); %> <c:forEach items="${strs }" var="str">//輸出數組和集合 ${str }<br/> </c:forEach>循環狀態
```
fmt標籤庫是用來格式化輸出的,一般須要格式化的有時間和數字
<fmt : formatDate value="" pattern="" />
<% Date date = new Date(); request.setAttribute("date", date); %> <fmt:formatDate value="${requestScope.date }" pattern="yyyy-MM-dd HH:mm:ss"/> // 按照給定的格式輸出時間
<% request.setAttribute("num1", 3.1415926); %> <fmt:formatNumber value="${requestScope.num1 }" pattern="0.000"/><br/> //按照0.000保留小數點後面的位數,四捨五入,不足補0 <fmt:formatNumber value="${requestScope.num1 }" pattern="#.###"/> //按照#.###保留小數點後面的位數,四捨五入,不足不補0
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調用:過程以下;
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.
<tag> <name></name> 指定當前標籤的名稱 <tag-class></tag-class> 指定當前標籤的標籤處理類! <body-content></body-content> 指定標籤體的類型 </tag>
標籤體的內容有以下四種;
|內容|說明|
| :---| :---|
|empty|無標籤體(經常使用)|
|scriptless|能夠是EL表達式或者其餘的標籤或者字符串(經常使用)|
|JSP|(不使用)|
|tagdependent|(不使用)|
<%@taglib %>
來導入tld文件<%@ taglib prefix= uri= %>
能夠設置,若是執行這個標籤,後面的標籤都會不執行。實現這一功能的方法是在標籤處理類中的doTag()方法中使用SkippageException來結束! Tomcat會調用標籤處理類的doTag()方法,而後Tomcat會獲得SkipPageException,它會跳過頁面其餘內容
public void doTag() throws JspException, IOException { throw new SkipPageException();//拋出這個異常後,在本標籤後面的內容,將看不到! }
添加屬性的步驟
<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()的參數能夠寫成null, 若是是null的話,表示使用的就是當前頁面的out !this.getJspBody().invoke(null); } }
/** * Class MyTag3 * 拋出SkipPageException異常,若是執行這個標籤,則後面的標籤都不會再執行了 */ package cn.kmust.tag; public class MyTag3 extends SimpleTagSupport { public void doTag() throws JspException, IOException { this.getJspContext().getOut().print("只能看到我,下面什麼都沒有!"); throw new SkipPageException();//拋出這個異常後,在本標籤後面的內容,將看不到! } }
/** * Class MyTag4 * 帶有一個屬性 */ package cn.kmust.tag; public class MyTag4 extends SimpleTagSupport { private boolean test; //定義這個屬性 /* * 這個方法會由tomcat來調用,而且在doTag()以前 */ public void setTest(boolean test) { this.test = test; } public void doTag() throws JspException, IOException { if(test) { /* * 執行標籤體 */ this.getJspBody().invoke(null);//若是傳遞的輸出流爲null,表示使用的就是當前頁面的out! } } }
/** * tld文件的配置 。 名字是kmust-tag.tld 。 位置: WEN-INF/tlds */ <?xml version="1.0" encoding="UTF-8" ?> <taglib 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-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <short-name>kmust</short-name> <uri>http://www.kmust.cn/tags/it-1.0</uri> //這是uri是隨便起的 <tag> <name>myTag1</name> <tag-class>cn.kmust.tag.MyTag2</tag-class> //標籤處理類的位置 <body-content>empty</body-content> //沒有標籤體 </tag> <tag> <name>myTag2</name> <tag-class>cn.kmust.tag.MyTag3</tag-class> <body-content>scriptless</body-content> //有標籤體 </tag> <tag> <name>myTag3</name> <tag-class>cn.kmust.tag.MyTag4</tag-class> <body-content>empty</body-content> </tag> <tag> <name>myTag4</name> <tag-class>cn.kmust.tag.MyTag5</tag-class> <body-content>scriptless</body-content> <attribute> //屬性 <name>test</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
/** * jsp頁面中利用自定義的標籤 */ <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="it" uri="/WEB-INF/tlds/kmust-tag.tld" %> //導入自定義的tld文件的路徑 <html> <body> <it:myTag4 test="${empty param.xxx }"> //test屬性的值是 「參數」 ,標籤處理類中的定義是 :若是參數不爲空,就執行標籤體中的內容 <it:myTag4/> //標籤體中也是一個自定義的標籤,這個標籤的意思是 : 執行我,後面的標籤就不執行了 </it:myTag4> <it:myTag1/> //輸出hello one! <% request.setAttribute("xxx", "zhangSan"); %> <it:myTag2> ${xxx } //標籤體中的這個EL表達式會到標籤處理類中執行。 </it:myTag3> <it:myTag2> 我是張三的大哥 //標籤體中的內容也能夠是字符串 </it:myTag3> </body> </html>
<error-page> <error-code>404</error-code> <location>/error404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error500.jsp</location> </error-page> <error-page> <exception-type>java.lang.RuntimeException</exception-type> <location>/error.jsp</location> </error-page> 當出現404時,會跳轉到error404.jsp頁面; 當出現RuntimeException異常時,會跳轉到error.jsp頁面; 當出現非RuntimeException的異常時,會跳轉到error500.jsp頁面。
PageContext(page域)、ServletRequest(request域)、HttpSession(session域)、ServletContext(application域)。page域、request域、session域、application域這幾個詞代表的是域的範圍。 。Sevlet只能使用後三個域。JSP能使用所用的域。 簡單來講, 域對象簡單說就是能在Servlet之間(page域使用在JSP頁面中)傳遞參數,由於要下降耦合度,因此咱們建立的每一個Servlet之間都是不能相互交流的,能夠說,域對象是串聯起多個Servlet的線,能夠爲多個Servlet之間的交流傳遞數據,這就顯得比較重要。域對象內部有個Map,用來存取數據。
全部的域對象都有以下的方法:
java void setAttribute(java.lang.String name, java.lang.Object o) //保存值 Stores an attribute in this request. java.lang. Object getAttribute(java.lang.String name) //獲取值 Returns the value of the named attribute as an Object, or null if no attribute of the given name exists. void removeAttribute(java.lang.String name) //移除值 Removes an attribute from this request.`
這四個域的範圍不一樣:
須要注意的是,PageContext可以代理其餘三個域,即,PageContext實現其餘三個域的存取操做
JSP的九大內置與上述的四大域對象能夠說沒有太大的關係。內置對象是JSP已經定義好的對象,這些對象中有的是Servlet中類的實例化對象,有點的io中類的實例化對象等等 。都是jSp中可能經常使用到的類 。 須要注意的是,pageContext這個內置對象一個頂九個,能夠獲取其餘八個內置對象。也就是說,一個pageContext內置對象就能夠實現其餘八個內置對象的功能 。