JSP自定义标签库和函数

一、基础知识

1. 常见的自定义标签库有哪些?

  • jstl中的c、fn、fmt等
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>123
  • strut2中的s标签
<!-- struts -->
<%@ taglib prefix="s" uri="/struts-tags"%>12
  • jsp标签
<jsp:include page="path" flush="true" /> 
<jsp:param name="paramName" value="paramValue" /> 
<jsp:forward page="path" /> 
<jsp:useBean id="name" scope="page | request | session | application" typeSpec /> 
<jsp:setProperty name="beanName" prop_expr /> 
<jsp:getProperty name="name" property="propertyName" /> 
1234567

2. 为什么要自定义标签?

封装JSP中常用的功能, 如可以封装一些html、js代码、jsp代码块(java代码<% %>)等,封装的标签可以看成实现一个独立的功能的JSP,引用标签相当于包含include了该jsp,使用封装的标签比单纯的引入jsp页面要更简洁,便于在JSP页面中复用

3. 自定义标签库有哪几种方式?

  1. .tag方式,引用时通过tagdir属性指定.tag文件的位置,例如 <%@ taglib prefix="x" tagdir="/WEB-INF/tags" %>
  2. .tld方式,引用时通过uri属性间接指定.tld文件的位置(需要在web.xml中jsp-config下配置taglib),例如 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

二:使用.tag自定义标签

基本知识

第一步: 引入web的基本依赖

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

<build>
    <finalName>platform-tag</finalName>
    <plugins>
            <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-compiler-plugin</artifactId>  
                <version>2.3.2</version>  
                <configuration>  
                    <source>1.8</source>  
                    <target>1.8</target>  
                </configuration>  
            </plugin>
     </plugins>
  </build>123456789101112131415161718192021222324252627282930313233

第二步: 在src/main/webapp/WEB-INF/tags目录下创建定义标签
此处定义了3个标签,calc.tag 用于数学运算,page.tag,page2.tag 用于测试,没有什么实际意义

calc.tag

<%@ tag body-content="empty" trimDirectiveWhitespaces="true" pageEncoding="UTF-8"%>
<%@ tag import="java.util.Arrays" %>
<%@ attribute name="x" required="true" rtexprvalue="true" %>
<%@ attribute name="y" required="true" rtexprvalue="true" %>
<%@ attribute name="operator" required="true" rtexprvalue="true" %>

<div>
    <% 
        if("+".equals(operator)){
    %>
    加法运算 :
    <%      
        }
    %>

  ${x}${operator}${y} = 
  <script type="text/javascript">
    document.write(eval("${x}${operator}${y}"))
  </script>
</div>1234567891011121314151617181920

page.tag

<%@ tag body-content="scriptless" trimDirectiveWhitespaces="true" pageEncoding="UTF-8"%>

<div style="background-color: gray; width=70px;">
    contextPath: ${pageContext.request.contextPath}

    <jsp:doBody />
</div>1234567

page2.tag

<%@ tag body-content="tagdependent" trimDirectiveWhitespaces="true" pageEncoding="UTF-8"%>

<div style="background-color: red; width=auto">
    contextPath: ${pageContext.request.contextPath}
    <jsp:doBody />
</div>123456

第三步:使用标签库

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="math" tagdir="/WEB-INF/tags/" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<math:calc x="1" operator="+" y="1"/>
<math:calc x="1" operator="-" y="1"/>
<math:calc x="1" operator="*" y="2"/>
<math:calc x="1" operator="/" y="2"/>

<hr/>
<math:page>
    <b>标签体内容。。。</b>
</math:page>

<hr/>
<math:page2>
    <b>标签体内容2。。。</b>
</math:page2>

</body>
</html>123456789101112131415161718192021222324252627

这里写图片描述

这里写图片描述

使用.tag自定义标签库相关知识

1、自定义标签时需要为该标签设置一些基本属性,如 body-content、trimDirectiveWhitespaces、pageEncoding 等

<%@ tag body-content="empty" trimDirectiveWhitespaces="true" pageEncoding="UTF-8"%>1
  • body-content :用于指定该自定义标签是否允许有标签体以及标签体中的内容该如何解析(是当做纯文本直接输出,还是当做html来渲染呢)
    • empty :该值说明当前自定义的标签不需要标签体,不需要结束标签,即单标签 ,如 <my:add x="1" y="2" />, 支持EL表达式
    • scriptless:标签体可以有内容,内容被当做JSP元素来处理,标签体内容可以是文本, EL表达式, 标准动作甚至另一个自定义标记.
    • tagdependent:标签体可以有内容,标签体重的内容被当做纯文本来解析
    • trimDirectiveWhitespaces:是否要删除多余的空行,一般设置为true
    • pageEncoding: 页面的字符编码,一般设置为UTF-8

2、 自定义标签时可以声明属性
<%@ attribute name="x" required="true" rtexprvalue="true" %>

- name : 属性名称
- required:属性是否必须,true/false
- rtexprvalue: 是否解析EL表达式,true:解析EL表达式,false: 当做纯文本
- type :属性的数据类型

3、 可以在.tag文件中使用java代码块,可以使用import属性导入使用到的类
<%@ tag import="java.util.Arrays" %>


三:使用.tld自定义标签

第一步: 在/WEB-INF/tld目录下定义.tld文件

ext.tld : 用于描述标签的名字和属性

<?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>  
    <jsp-version>1.1</jsp-version>  
    <short-name>ext</short-name>  
    <uri>http://www.mengdee.com/tag/ext</uri>

    <!-- 分页标签 -->
    <tag>
        <name>page</name>
        <tag-class>com.mengdee.manager.util.tag.PageHandler</tag-class>
        <body-content>JSP</body-content>

        <attribute>
            <name>page</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>

        <attribute>
            <name>action</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>

第二步:在web.xml中配置

<jsp-config>
    <taglib>
        <taglib-uri>http://www.mengdee.com/tag/ext</taglib-uri>
        <taglib-location>/WEB-INF/tld/ext.tld</taglib-location>
    </taglib>
</jsp-config>123456

第三步: 自定义标签的处理类

需要继承BodyTagSupport,重写doStartTag()和doEndTag()方法

PageHandler

package com.mengdee.manager.util.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;

public class PageHandler extends BodyTagSupport{

    private static final long serialVersionUID = 1L;

    private String action;
    private Page page;

    @Override
    public int doStartTag() throws JspException {
        return EVAL_BODY_BUFFERED;
    }

    // 该方法只是简单的演示一下分页,实际使用时还需要对该分页的html进行完善
    @Override
    public int doEndTag() throws JspException {
        int currentPage = page.getCurrentPage();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<div class='page_nav'> ");
        stringBuilder.append(" <span> 126条  共7页</span> ");
        stringBuilder.append(" <strong>" + currentPage + "</strong> ");
        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 1) + "'>" + (currentPage + 1) + "</a> ");
        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 2) + "'>" + (currentPage + 2) + "</a> ");
        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 3) + "'>" + (currentPage + 3) + "</a> ");
        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 4) +"'>" + (currentPage + 4) + "</a> ");

        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 5) + "'>...</a> ");
        stringBuilder.append(" <a href='" + action + "?no=" + (currentPage + 1) +"'>下一页</a> ");
        stringBuilder.append(" <a href='" + action + "?no=" + page.getTotalPageCount() +"'>尾页</a> ");
        stringBuilder.append("</div>");

        try {
            pageContext.getOut().print(stringBuilder.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return EVAL_PAGE;
    }



    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public Page getPage() {
        return page;
    }

    public void setPage(Page page) {
        this.page = page;
    }

}

Page:分页实体,用于封装分页相关的参数

package com.mengdee.manager.util.tag;

public class Page {

    /** 当前页码 */
    private int currentPage = 1; 

    /** 每页显示的条数 */
    private int count = 10;

    /** 总行数  */  
    private int totalRowCount;  

    /** 总页数 */  
    private int totalPageCount;


    public Page() {
        this.currentPage = 1;
        this.count = 10;
    }


    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getTotalRowCount() {
        return totalRowCount;
    }

    public void setTotalRowCount(int totalRowCount) {
        this.totalRowCount = totalRowCount;
    }

    public int getTotalPageCount() {
        return this.totalPageCount = (int) Math.ceil((double) totalRowCount / count);
    }

}

index.jsp: 引入自定义的标签库,引入page.css样式

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.mengdee.com/tag/ext" prefix="ext"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/page.css" />
<title>Insert title here</title>
</head>
<body>

<ext:page action="${pageContext.request.contextPath}/indexServlet" page="${page}"></ext:page>

</body>
</html>

page.css :为了美化分页的样式

@CHARSET "UTF-8";

.page_nav{margin:20px 0; color:#666; text-align:center;}
.page_nav a,.page_nav strong{display:inline-block; height:22px; margin:0 2px; padding:0 8px; border:solid 1px #dbe5ee; -moz-border-radius: 3px;-webkit-border-radius:3px; background:#fff; cursor:pointer; font:normal 12px/22px Arial, Helvetica, sans-serif;}
.page_nav strong {height:24px; margin:0 3px; border:none; background:#07519a; color:#fff; line-height:24px; text-decoration:none;}
.page_nav span{margin:0 10px;}

第四步: IndexServlet

indexServlet中需要将page参数包装到作用域中,index.jsp中自定义的标签需要使用到

package com.mengdee.manager.util.tag;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class IndexServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public IndexServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Page page = new Page();
        String pageIndex = request.getParameter("no");
        if (pageIndex == null) {
            pageIndex = "1";
        }
        page.setCurrentPage(Integer.parseInt(pageIndex));
        request.setAttribute("page", page);

        request.getRequestDispatcher("/index.jsp").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

访问: http://localhost:8080/custom-tag/indexServlet
这里写图片描述

流程分析:

首先访问indexServlet, 执行 doGet()方法,方法内部会将page对象保存到request请求中request.setAttribute(“page”, page);接着跳转到index.jsp, 然后 运行自定义标签,当运行自定义标签时就会执行配置的标签类<tag-class>com.mengdee.manager.util.tag.PageHandler</tag-class>该标签类通过pageContext.getOut().print(stringBuilder.toString()); 将分页的html字符串输出到页面

四:.tag 和.tld 的区别

两种方式都可以用来自定义标签,不同的是自定义标签时的逻辑写的位置不同

从以上示例可以看到.tag方式将逻辑写在.tag文件中,.tag可以看成一个.jsp文件,可以使用EL表达式、使用java代码库处理逻辑,.tld 文件将逻辑都写在Java类中了,对应复杂的业务使用.tld在Java类中处理更方便,在.tag中还要多个<% %>看起来太乱,可读性不太好对于逻辑比较简单的使用.tag方式比较方便,直接在.tag中封装


五:自定义标签库函数

在jsp页面中在使用jstl表达式中经常会用一些函数,如 fn:length(item)、fn:replace(string, before, after)、fn:startsWith(string, prefix) 等

<%@ taglib prefix="fn" uri="http://Java.sun.com/jsp/jstl/functions" %>

<c:if test="${fn:contains(name, searchString)}">

${fn:length(shoppingCart.products)}12345

自定义自己的函数库

第一步: 创建自己的工具类函数, 如:CommonTagLib

package com.mengdee.manager.web.taglib;

public class CommonTagLib {

    public static boolean isEmpty(String string){
        System.out.println("run ...");
        if (null == string || "".equals(string) || 
                "undefined".equals(string) || "null".equals(string)) {
            return true;
        }

        return false;
    }
}
123456789101112131415

方法定义为静态方法,可以注入Spring中的bean

第二步:创建tld文件用于描述标签库函数

一般放在/WEB-INF/tld目录下
common.tld

<?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>common</short-name>  
    <uri>http://www.mengdee.com/tag/common</uri>

    <function>
        <name>isEmpty</name>
        <function-class>com.mengdee.manager.web.taglib.CommonTagLib</function-class>
        <function-signature>boolean isEmpty(java.lang.String)</function-signature>
        <example>{common:isEmpty(string)}</example>
    </function>
</taglib>12345678910111213141516

function-class:指定Java类的全路径
function-signature:指定函数的方法签名
example:如何使用该函数,给出一个示例

第三步:在web.xml中配置.tld文件的位置

<jsp-config>
    <taglib>
        <taglib-uri>http://www.mengdee.com/tag/common</taglib-uri>
        <taglib-location>/WEB-INF/tld/common.tld</taglib-location>
    </taglib>
  </jsp-config>123456

第四步:在jsp页面中引用标签库函数

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<%@ taglib uri="http://www.mengdee.com/tag/common" prefix="common"%>


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <c:choose>
        <c:when test="${common:isEmpty('null')}"></c:when>
        <c:otherwise>
            有值
        </c:otherwise>
    </c:choose>

    <c:choose>
        <c:when test="${common:isEmpty('123456')}"></c:when>
        <c:otherwise>
            有值
        </c:otherwise>
    </c:choose>
</body>
</html>

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值