主要內容:
- 防盜鏈
- 開發(fā)if標簽
- 開發(fā)if else標簽
- 開發(fā)foreach標簽
- 開發(fā)HTML轉義的標簽
- 打包標簽庫
一讨衣、防盜鏈
防盜鏈的意思是,比如一個網(wǎng)站有一個資源很好式镐,希望來訪者先進入首頁看完廣告才能看到這個資源反镇,如果不加防盜鏈,則別的網(wǎng)站可能加如此資源的超鏈接娘汞,那么就沒有進入首頁看廣告歹茶。我們需要防止除從首頁訪問資源的其他方式。(工程tag_example
)
相關代碼:
itcast.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" 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 web-jsptaglibrary_2_1.xsd">
<tlib-version>1.0</tlib-version>
<short-name>itcast</short-name>
<uri>/itcast</uri>
<!-- 防盜鏈標簽 -->
<tag>
<name>referer</name>
<tag-class>cn.itcast.web.tag.RefererTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>site</name><!-- 第一個屬性 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>page</name><!-- 第二個屬性 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
index.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 'index.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>
<a href="${pageContext.request.contextPath}/1.jsp">內容鏈接</a>
</body>
</html>
1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<itcast:referer site="http://localhost:8080/" page="/index.jsp"/>
<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>
This is my JSP page. <br>
</body>
</html>
RefererTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class RefererTag extends SimpleTagSupport {
private String site ;
private String page ;
@Override
public void doTag() throws JspException, IOException {
//拿到來訪者代表page的實例對象
PageContext pageContext = (PageContext) this.getJspContext();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
String referer = request.getHeader("referer");
//判斷
//如果地址為空或者地址不是我們給定的地址你弦,就跳轉到page頁面
if(referer == null || !referer.startsWith(site)){
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
String webroot = request.getContextPath();//得到/day11_example
//如果page="/day11_example/index.jsp"
if(page.startsWith(webroot)){
response.sendRedirect(page);
}else {
//如果page="/index.jsp"
response.sendRedirect(webroot + page);
}
//重定向之后我們不能讓保護頁面顯示惊豺,要讓瀏覽器先進入index.jsp再進入保護頁面
throw new SkipPageException();
}
}
public String getSite() {
return site;
}
public void setSite(String site) {
this.site = site;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
說明:
- 1.我們在首頁中給出資源頁面(保護頁面)的鏈接,在保護頁面(1.jsp)中使用自定義標簽進行檢測:
<itcast:referer site="http://localhost:8080/" page="/index.jsp"/>
禽作。如果資源不是從site指定的地址進入尸昧,則跳轉到index.jsp
頁面。當然為了更好的匹配page旷偿,我們提供兩種方式指定地址烹俗,一種是page="/index.jsp"
爆侣,一種是page="/tag_example/index.jsp"
。 - 2.需要注意的是當我們處理外來地址訪問之后需要拋出
SkipPageException
異常幢妄,不讓后面的頁面進行顯示兔仰。
二、開發(fā) if 標簽
相關代碼:
itcast.tld
<!-- if標簽 -->
<tag>
<name>if</name>
<tag-class>cn.itcast.web.tag.IfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>if標簽</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<itcast:if test="${user != null }">
xxxx
</itcast:if>
</body>
</html>
IfTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//開發(fā)if標簽
public class IfTag extends SimpleTagSupport {
private boolean test;
@Override
public void doTag() throws JspException, IOException {
//只有在滿足test條件的時候才執(zhí)行
if(test){
this.getJspBody().invoke(null);
}
}
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
說明:當滿足test為ture時才執(zhí)行相關頁面內容磁浇。
三斋陪、開發(fā)if else 標簽
相關代碼:
itcast.tld
<!-- if else標簽 -->
<tag>
<name>choose</name>
<tag-class>cn.itcast.web.tag.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>when</name>
<tag-class>cn.itcast.web.tag.WhenTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>otherwise</name>
<tag-class>cn.itcast.web.tag.OtherwiseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
ChooseTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ChooseTag extends SimpleTagSupport {
private boolean isOk;
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
}
public boolean isOk() {
return isOk;
}
public void setOk(boolean isOk) {
this.isOk = isOk;
}
}
WhenTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class WhenTag extends SimpleTagSupport {
private boolean test;
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent = (ChooseTag) this.getParent();
if(test == true && parent.isOk() == false){
this.getJspBody().invoke(null);
parent.setOk(true);
}
}
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
OtherwiseTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OtherwiseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent = (ChooseTag) this.getParent();
if(parent.isOk() == false){
this.getJspBody().invoke(null);
parent.setOk(true);
}
}
}
3.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>if else標簽</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<itcast:choose>
<itcast:when test="${user != null }">aaa</itcast:when>
<itcast:otherwise>bbb</itcast:otherwise>
</itcast:choose>
</body>
</html>
說明:開發(fā)if else
標簽需要三個標簽組合起來。同時我們在父標簽<itcast:choose>
中設置了一個標志位置吓,如果標志位為true表示已經(jīng)執(zhí)行了无虚。默認是false。
四衍锚、開發(fā)迭代標簽ForEach
相關代碼:
itcast.tld
<!-- foeach標簽 -->
<tag>
<name>foreach</name>
<tag-class>cn.itcast.web.tag.ForEachTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue><!-- 這里不能是表達式 -->
</attribute>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
ForEachTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ForEachTag extends SimpleTagSupport {
private List items;
private String var;
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) this.getJspContext();
Iterator it = items.iterator();
while(it.hasNext()){
//因為我們不知道集合中的內容是什么類型友题,所以一定要用Object類
Object obj = it.next();
//后一次的值會覆蓋前一次的值,將得到的值存到pageContext域中
pageContext.setAttribute(var, obj);
this.getJspBody().invoke(null);
}
}
public void setItems(List items) {
this.items = items;
}
public void setVar(String var) {
this.var = var;
}
}
4.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>ForEach標簽</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<%
List list = new ArrayList();
list.add("aa");
list.add("bb");
request.setAttribute("list", list);
%>
<itcast:foreach items="${list}" var="str">
${str }
</itcast:foreach>
</body>
</html>
說明:顯然這個標簽是不完善的戴质,因為只能處理List
集合度宦,我們需要進行改進。
相關代碼:(重點)
itcast.tld
<tag>
<name>foreach2</name>
<tag-class>cn.itcast.web.tag.ForEachTag2</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue><!-- 這里不能是表達式 -->
</attribute>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
ForEachTag2.java
package cn.itcast.web.tag;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Array;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ForEachTag2 extends SimpleTagSupport {
//不知道要迭代的類型使用Object代替
private Object items;
private String var;
private Collection collection;
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) this.getJspContext();
Iterator it = collection.iterator();
while(it.hasNext()){
Object obj = it.next();
pageContext.setAttribute(var, obj);
this.getJspBody().invoke(null);
}
}
public void setItems(Object items) {
this.items = items;
//如果傳遞進來的是一個集合
if(items instanceof Collection){
collection = (Collection) items;
}
//如果傳遞進來的是一個對象數(shù)組
/*if(items instanceof Object[]){
Object arg[] = (Object[]) items;
collection = Arrays.asList(arg);
}*/
//如果傳遞進來的是一個Map
if(items instanceof Map){
Map map = (Map) items;
collection = map.entrySet();
}
//如果傳遞進來的是一個基本數(shù)據(jù)類型數(shù)組
/*if(items instanceof int[]){
int temp[] = (int[]) items;
collection = new ArrayList();
for(int num : temp){
collection.add(num);
}
}*///對于基本數(shù)據(jù)類型這樣寫八次很麻煩告匠,sun公司的源碼也是這樣判斷的戈抄。。后专。
//對于數(shù)組類型(對象數(shù)組和基本數(shù)據(jù)數(shù)組)我們使用此種方式改進
if(items.getClass().isArray()){
collection = new ArrayList();
int len = Array.getLength(items);
for(int i = 0; i < len; i++){
Object obj = Array.get(items, i);
collection.add(obj);
}
}
}
public void setVar(String var) {
this.var = var;
}
public void setCollection(Collection collection) {
this.collection = collection;
}
}
5.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>ForEach標簽2</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<%
List list = new ArrayList();
list.add("aa");
list.add("bb");
request.setAttribute("list", list);
Integer arr[] = new Integer[]{1,2,3};
request.setAttribute("arr", arr);
Map map = new HashMap();
map.put("a", "aaa");
map.put("b", "bbb");
map.put("c", "ccc");
request.setAttribute("map", map);
%>
<itcast:foreach items="str" var="${list }">
${str }
</itcast:foreach><br>
<itcast:foreach2 items="num" var="${var }">
${num }
</itcast:foreach2><br>
<!-- 注意基本數(shù)據(jù)迭代 -->
<%
int arr1[] = new int[]{1,2,3};
request.setAttribute("arr1", arr1);
byte[] arr2 = new byte[]{3,2,1};
request.setAttribute("arr2", arr2);
%>
<itcast:foreach2 items="num" var="${arr1 }">
${num }
</itcast:foreach2>
<itcast:foreach2 items="num" var="${arr2 }">
${num }
</itcast:foreach2>
</body>
</html>
說明:
- 1.首先我們分析一些可能會遇到的數(shù)據(jù)類型划鸽。數(shù)據(jù)類型有集合、
Map
戚哎、數(shù)組裸诽,數(shù)組中又分對象數(shù)組和基本數(shù)據(jù)類型數(shù)組。我們可以在execute
方法中依次進行判斷型凳,但是會有很多重復代碼丈冬,于是我們統(tǒng)一在setItems
方法中進行判斷。首先對于集合甘畅、Map
埂蕊、對象數(shù)組我們可以統(tǒng)統(tǒng)將其轉換為Collection
對象。單數(shù)對于基本數(shù)據(jù)類型數(shù)組的處理其實sun公司是進行了八次判斷疏唾,顯然較為麻煩蓄氧。這里其實我們可以將數(shù)組統(tǒng)一處理,從代碼中可以看到荸实。 - 2.判斷過程匀们。如果本來就是一個
Collection
對象缴淋,則直接轉換准给。如果是對象數(shù)組泄朴,則先轉換成Object
對象,然后再轉換成Collection
對象露氮。如果是Map對象祖灰,其實本身這個對象在迭代的時候也是通過Set
集合進行迭代的,所以這里我們可以將其先轉換成Collection
對象畔规。然后是八種基本數(shù)據(jù)類型的轉換局扶,但是之后我們對數(shù)組的處理進行了修改,我們這里統(tǒng)一處理叁扫。
五三妈、開發(fā)HTML轉義標簽
相關代碼:
itcast.tld
<!--html轉義標簽 -->
<tag>
<name>htmlFilter</name>
<tag-class>cn.itcast.web.tag.HtmlFilterTag</tag-class>
<body-content>scriptless</body-content>
</tag>
HtmlFilterTag.java
package cn.itcast.web.tag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//這個方法在源碼中可以找到
public class HtmlFilterTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
//得到標簽體
String content = sw.getBuffer().toString();
content = filter(content);
//輸出
this.getJspContext().getOut().write(content);
}
private String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
6.jsp
<body>
<itcast:htmlFilter>
<a href="#">鏈接</a>
</itcast:htmlFilter>
</body>
說明:這個標簽中的方法filter其實我們可以在源碼中找到,地址是apache-tomcat-8.0.26-src\webapps\examples\WEB-INF\classes\util\HTMLFilter.java
莫绣。主要是為了在頁面中顯示HTML代碼畴蒲,不能讓頁面解析使用的。
六对室、打包標簽庫
我們在自定義了一些自己需要用到的標簽之后模燥,可能在別的地方也需要使用,這時我們最好像sun公司一樣將其打包成一個jar文件掩宜。
先將cn.itcast.web.tag
中所有的自定義標簽類全部拷貝到一個普通java工程中的src
目錄下面蔫骂,這時會發(fā)現(xiàn)有錯誤,這時因為我們沒有導入相應的包牺汤,這里我們需要將tomcat中的E:\software\tomcat\lib
中的jsp-api.jar
和servlet-api.jar
兩個包拷貝到新建的lib
包中辽旋,然后導入即可。最后還需要將配置文件itcast.tld
拷貝到新建目錄META-INF
目錄中慧瘤。這里我們可以看到需要建立一個lib
包保存相關的jar
包戴已,而META-INF
中一般保存相關的配置文件。然后選中工程右鍵->Export->Java->JAR file->Next->選中要打包的工程锅减,同時將右邊框中MyEclipse的配置文件取消選中糖儡,然后在JAR file選擇要保存的路徑和文件名,文件名后綴必須為.jar怔匣,然后點擊finish即可握联。
最后:
這些標簽其實sun公司已經(jīng)幫我寫好了,我們只需要拿過來用即可每瞒。這里只是讓我們更好的明白其是怎樣實現(xiàn)的金闽,以后碰到特殊的標簽我們可以自己開發(fā)。