`

自定义标签的编写

阅读更多
编写处理类
package com.oa;

import com.oa.manager.AclManager;

//JSTL函数,完成权限的即时认证
public class SecurityFunction {
	
	private static AclManager aclManager;
	public static boolean method(int userId,String sn,int permission) {
		
		return aclManager.hasPermissionByResourceSn(userId, sn, permission);
	}
 //该方法不能定义为public static ,否则spring无法注入
	public void setAclManager(AclManager aclManager) {
		SecurityFunction.aclManager = aclManager;
	}
}



在web-INF下创建my.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">

	<display-name>JSTL functions</display-name>
	<tlib-version>1.1</tlib-version>
	<short-name>my</short-name>
	<uri>http://www.oa.com/jsp/jstl/functions</uri>

	<function>
		<name>method</name>
		<function-class>com.oa.SecurityFunction</function-class>
		<function-signature>
			boolean method(int, java.lang.String, int)
		</function-signature>
		
	</function>

</taglib>


在web.xml中配置
<jsp-config>
		<taglib>
			<taglib-uri>http://www.oa.com/jsp/jstl/functions</taglib-uri>
			<taglib-location>/WEB-INF/my.tld</taglib-location>
		</taglib>
	</jsp-config>


在jsp中导入标签
<%@ taglib prefix="my"  uri="/WEB-INF/my.tld" %>

<c:if test="${my:method(id,searchString,p)}">
   .......
</c:if>


自定义分页标签的编写
第一步:
/**
 * 
 */

package com.cmsz.rist.common.page;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.log4j.Logger;

import com.cmsz.rist.init.RistConfig;

/**
 * 分页tag,生成分页的跳转标识

 * 
 * 
 */
public class PaginatorTag extends TagSupport
{

    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(PaginatorTag.class);

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private String form;// 页面的form名


    private String action;// 跳转的action URL

    private String name; // 分页器的名称

    private String scope = "request"; // 分页器所在位置page/request/session/application

    private static final Map<String, Integer> scopeMap = new HashMap<String, Integer>(); // 属性范围Map

    static
    {
        // 初始化属性范围Map
        scopeMap.put("page", PageContext.PAGE_SCOPE);
        scopeMap.put("request", PageContext.REQUEST_SCOPE);
        scopeMap.put("session", PageContext.SESSION_SCOPE);
        scopeMap.put("application", PageContext.APPLICATION_SCOPE);
    }

    public int doEndTag() throws JspTagException
    {
    	//工程路径
		String rootPath = com.cmsz.rist.common.util.SystemValue.ROOT; 
		String rootPathSp = rootPath.substring(0,rootPath.length()-1);
		String path = rootPathSp.substring(rootPathSp.lastIndexOf("\\")+1);
		
		//跳转
		//String GO = "\""+((HttpServletRequest) pageContext.getRequest()).getContextPath()+  "/images/GO.gif" + "\"";
		//String GO2 = "\""+((HttpServletRequest) pageContext.getRequest()).getContextPath()+  "/images/GO2.gif" + "\"";
		
        Paginator paginator = (Paginator) pageContext.getAttribute(name,
                        ((Integer) scopeMap.get(scope)).intValue());
        JspWriter out = pageContext.getOut();
        StringBuffer buffer = new StringBuffer(1000);
        int totalPage = paginator.getTotalPage();
        try
        {
            if (paginator.getTotalCount() > 0)
            {// 有记录

                buffer.append("<script language=\"JavaScript\">\n");
                buffer.append("<!--\n");
                buffer.append("function GotoPage(id) {\n");
                buffer.append("var pageTotal =document." + form + ".pageSize.value; \n");

                if(action.indexOf('?')>0){
                    buffer.append("document." + form + ".action='" + action+"&pageTotal='+pageTotal+'&pageNow='+"
                    		+"id"
                            + ";\n");                	
                }else{
                    buffer.append("document." + form + ".action='" + action+"?pageTotal='+pageTotal+'&pageNow='+"
                    		+"id"
                            + ";\n");                 	
                }
       
                buffer.append("if(id<=0){id=1;}\n");
                buffer.append("document." + form + ".pageIndex.value=id;\n");
                buffer.append("document." + form + ".submit();\n");
                buffer.append("}\n");
                
                buffer.append("function changePage(obj) {\n");
                buffer.append("var id = obj.value;\n");
                /*buffer.append("var ar = obj.options;\n");
                buffer.append("for(var i=0;i<ar.length;i++){\n");
                buffer.append("if(id==ar[i].value){\n");
                buffer.append("ar[i].selected=true;\n");
                buffer.append("}}\n");*/
            	
                
                if(action.indexOf('?')>0){
                    buffer.append("document." + form + ".action='" + action+"&pageTotal='+id+'&pageNow='+"
                    		+"1"
                            + ";\n");                	
                }else{
                    buffer.append("document." + form + ".action='" + action+"?pageTotal='+id+'&pageNow='+"
                    		+"1"
                            + ";\n");                 	
                }
                buffer.append("document." + form + ".pageIndex.value=1;\n");
                buffer.append("document." + form + ".submit();\n");
                buffer.append("}\n");
                
                buffer.append("function checkPage(size,page,total) {\n");
                buffer.append("if(total)");
                buffer.append("document." + form + ".action='" + action
                                + "';\n");
                buffer.append("document." + form + ".pageIndex.value=id;\n");
                buffer.append("document." + form + ".submit();\n");
                buffer.append("}\n");

                buffer.append("function checkPageSize(page,size,total){\n");
                buffer.append("var reg = /[^0-9]/;\n");
                buffer.append("if(size.match(reg) != null){\n");
                buffer.append("alert('每页记录数请输入整数');\n");
                buffer.append("document." + form + ".pageSize.focus();}\n");
                buffer.append("if(size<1){\n");
                buffer.append("document." + form + ".pageSize.value=10;}\n");
                buffer.append("if(size>300){\n");
                buffer.append("document." + form + ".pageSize.value=300;}\n");
                buffer.append("var newsize = document." + form
                                + ".pageSize.value;\n");
                buffer.append("checkPage(page,newsize,total);\n");
                buffer.append("}\n");

                buffer.append("function checkPage3(page,size,total){\n");
                buffer.append("if(!page){\n");
                buffer.append("alert('请输入跳转的页码!');\n");
                buffer.append("return false;\n");
                buffer.append("}\n");
                buffer.append("var reg = /^(([0-9]{1,})([0-9]))|([1-9]{1})$/;\n");
                buffer.append("if(!reg.exec(page)){\n");
                buffer.append("alert('跳转页数请输入大于0的整数');\n");
                //buffer.append("document." + form + ".pageIndex.focus();}\n");
                buffer.append("return false;\n");
                buffer.append("}\n");
                buffer.append("var num = total/size;  \n");
                buffer.append("var nums = Math.round(num+0.4999999);\n");
                buffer.append("if(page<1){\n");
                buffer.append("document." + form + ".pageIndex.value=1;}\n");
                buffer.append("if(page > nums){\n");
                buffer.append("document." + form + ".pageIndex.value=nums;}\n");
                buffer.append("GotoPage(page)");
                buffer.append("}\n");

                buffer.append("//-->\n");
                buffer.append("</script>\n");
                
                 buffer.append("<script language=\"JavaScript\" event=\"onkeydown\" for=\"document\">\n"); buffer.append("if(event.srcElement.name=='pageSize'){\n");
                 buffer.append("if(((event.keyCode>=48)&&(event.keyCode<=57))||((event.keyCode>=96)&&(event.keyCode<=105))||(event.keyCode==8)||(event.keyCode==46)||(event.keyCode==13)||(event.keyCode==9)){\n");
                 buffer.append("return true;\n"); buffer.append("}else{return false;}}"); buffer.append("if(event.srcElement.name=='pageIndex'){\n");
                 buffer.append("if(((event.keyCode>=48)&&(event.keyCode<=57))||((event.keyCode>=96)&&(event.keyCode<=105))||(event.keyCode==8)||(event.keyCode==46)||(event.keyCode==13)||(event.keyCode==9)){\n");
                 buffer.append("return true;\n"); buffer.append("}else{return false;}}"); buffer.append("</script>\n");
                 
                // 以上为页面跳转的JavaScript方法

                buffer.append("<table class=\"page\">\n");
                buffer.append("<tr>\n");
                buffer.append("<td width='20%'>\n");
                buffer.append("每页显示的数量&nbsp;<select  name='ps' id='ps' onchange='javascript:changePage(this)' class='w5'>");
                int size =  RistConfig.getConfig().getInt("core.setPageSize.value",10);
                if(size < 10){
                	size = 10;
        		}
       		  
                for(int i=10;i<=100;i=i+5){
                	if(i == paginator.getPageSize()){
             			buffer.append("<option value="+i+" selected>"+i+"</option>");
             		}else{           		
                    	buffer.append("<option value="+i+" >"+i+"</option>");
             		}	
                }
                /*buffer.append("<option value=\"20\">20</option>");
                buffer.append("<option value=\"30\">30</option>");
                buffer.append("<option value=\"40\">40</option>");
                buffer.append("<option value=\"50\">50</option>");
                buffer.append("<option value=\"60\">60</option>");
                buffer.append("<option value=\"70\">70</option>");
                buffer.append("<option value=\"80\">80</option>");
                buffer.append("<option value=\"90\">90</option>");
                buffer.append("<option value=\"100\">100</option>");*/
                buffer.append("</select>");
                buffer.append("</td>\n");
                buffer.append("<td  width='30%' class='info'>\n");
                buffer.append("共有<span class='orange fb'>" + totalPage + "</span>页");
                buffer.append("<span class='orange fb'>" + paginator.getTotalCount()
                                + "</span>条记录,");
                buffer.append("当前为第<span class='orange fb'>" + paginator.getPageIndex()
                                + "</span>页\n");
                buffer.append("</td>\n");
                buffer.append("<td width='35%' class='pagebuttons'>");
                if (paginator.getPageIndex() > 1)
                {// 不是第一页,显示“第一页”,“上一页”链接

                    buffer
                                    .append("<a href='javascript:GotoPage(1)' class='bt_pghome'><span>首页</span></a>");
                    buffer
                                    .append("<a class='bt_pgpre' href='javascript:GotoPage("
                                                    + (paginator.getPageIndex() - 1)
                                                    + ")'><span>上一页</span></a>");
                }
                else
                {// 是第一页,不显示“第一页”,“上一页”链接

                    buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pghome_gray'><span>首页</span></a>");
                    buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgpre_gray'><span>上一页</span></a>");
                }
                if (paginator.getPageIndex() == totalPage || totalPage <= 1)
                {// 是最后页或共只有一页,不显示“下一页”,“最后页”链接

                	 buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgnext_gray'><span>下一页</span></a>");
                     buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgend_gray'><span>尾页</span></a>");
                }
                else
                {// 不是最后页且总页数大于1页,显示“下一页”,“最后页”链接

                   /* buffer
                                    .append("<a class='bt_pgnext' href='javascript:GotoPage("
                                                    + (paginator.getPageIndex() + 1)
                                                    + ")'>下一页</a>");
                    buffer
                                    .append("<a class='bt_pgend' href='javascript:GotoPage("
                                                    + totalPage
                                                    + ")'>最后页</a>");*/
                	 buffer.append("<a href='javascript:GotoPage("
                                                    + (paginator.getPageIndex() + 1)
                                                    + ")' class='bt_pgnext'><span>下一页</span></a>");
                     buffer.append("<a href='javascript:GotoPage("
                                                    + totalPage
                                                    + ")' class='bt_pgend'><span>尾页</span></a>");
                }
                buffer.append("</td>");
                buffer
                                .append("<td width='2%' align='left'><input type='hidden' size='3' name='pageSize' value='"
                                                + paginator.getPageSize()
                                                + "' onkeyup=\"value=value.replace(/^[^1-9]+|[^\\d]/g,'');\"  onblur='checkPageSize(document.all.pageIndex.value,document.all.pageSize.value,"
                                                + paginator.getTotalCount()
                                                + ")'></td>\n");

                buffer
                                .append("<td width='2%' align='left'><input type='hidden' size='4' name='pageIndex' value='"
                                                + paginator.getPageIndex()
                                                + "'onkeyup=\"value=value.replace(/^[^1-9]+|[^\\d]/g,'');\" onblur='checkPage(document.all.pageIndex.value,document.all.pageSize.value,"
                                                + paginator.getTotalCount()
                                                + ")'></td>\n");
                buffer.append("<td width='15%' class='skip'>转至&nbsp;<input name='iPagePara' id='iPagePara' class='w2'   " 
				+ "type='text' size='5' maxlength='5' >&nbsp;页");
                //buffer.append("<img onmouseover='this.src=" 
		        //+ GO2 +"' style='CURSOR:pointer' onmouseout='this.src=" 
		        //+ GO +"' height='18' alt='跳转' src="+ GO +" width='35'" 
		        //+ " onclick=\"javascript:checkPage3(document.all.iPagePara.value,"+paginator.getPageSize()+","+paginator.getTotalCount()+");\" align='absmiddle'/></td>\n");
                buffer.append("<input type='button' class='bt_pggo' onmouseover='this.className=\"bt_pggo_o\"' onmouseout='this.className=\"bt_pggo\"' ");
                buffer.append(" onclick=\"javascript:checkPage3(document.all.iPagePara.value,"+paginator.getPageSize()+","+paginator.getTotalCount()+");\" /></td>");
                buffer.append("</tr>\n");
                buffer.append("</table>\n");
            }
            else
            {// 无记录

                buffer.append("<table class=page>\n");
                buffer.append("<tr>\n");
                buffer.append("<td  width='50%'class='info'>\n");
                buffer
                                .append("共有<span class='orange fb'>0</span>页<span class='orange fb'>0</span>条记录,");
                buffer.append("当前为第<span class='orange fb'>0</span>页</a></td>");
                buffer.append("<td width='35%' class='pagebuttons'>");
                buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pghome_gray'><span>首页</span></a>\n");
                buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgpre_gray'><span>上一页</span></a>\n");
                buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgnext_gray'><span>下一页</span></a>\n");
                buffer.append("<a disabled=\"disabled\" style=\"cursor: default\" href='javascript:;' class='bt_pgend_gray'><span>尾页</span></a>\n");
                buffer.append("</td>");
                buffer
                                .append("<td width='2%' align='left'>"
                                                + "</td>\n");

                buffer
                                .append("<td width='2%' align='left'><input type='hidden' size='4' name='pageIndex' value='"
                                                + paginator.getPageIndex()
                                                + "' onblur='checkPage(document.all.pageIndex.value,document.all.pageSize.value,"
                                                + paginator.getTotalCount()
                                                + ")'></td>\n");
               // buffer.append("<td width='15%'>转至&nbsp;<input name='iPagePara' id='iPagePara' class=\"text\"  " 
        		//		+ "type='text' size='3'>&nbsp;页");
                //        buffer.append("<img onmouseover='this.src=" 
        		//        + GO2 +"' style='CURSOR:pointer' onmouseout='this.src=" 
        		//        + GO +"' height='18' alt='跳转' src="+ GO +" width='35'" 
        		//        + " align='absmiddle'/></td>\n");
                //buffer.append("<input type='button' class='bt_pggo' onmouseover='this.className=\"bt_pggo\"' onmouseout='this.className=\"bt_pggo\"' disabled='disabled'/></td>");
                buffer.append("</tr>\n");
                buffer.append("</table><br>\n");
            }
            out.write(buffer.toString());
            out.flush();
        }
        catch (Exception e)
        {
            logger.error("生成分页html发生错误", e);
        }

        return EVAL_PAGE;
    }

    public void setForm(String form)
    {
        this.form = form;
    }

    public void setAction(String action)
    {
        HttpServletRequest request = (HttpServletRequest) pageContext
                        .getRequest();
        this.action = request.getContextPath() + action;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public void setScope(String scope)
    {
        this.scope = scope;
    }
}

第二步:
编写WEB_INF下tld目录下的paginator.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>paginator</short-name>
  <uri>http://www.huadu-tech.com/tags-paginator</uri>
  <description>
    paginator taglib.
  </description>
 <tag>
    <name>page</name>
    <tag-class>com.cmsz.rist.common.page.PaginatorTag</tag-class>
    <body-content>JSP</body-content>
    <description>
      Iterates over a specified array of objects, showing pages of information at a time.
    </description>
    <attribute>
      <name>name</name>
      <required>true</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
      <name>scope</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
      <name>action</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
      <name>form</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>

</taglib>

第三步:
引入标签体
<%@ taglib uri="/WEB-INF/tld/paginator.tld" prefix="paginator"%>

第四步:
在jsp页面上
<div align="center">
			<paginator:page name="paginator" form="smsClientForm"
					action="/querySmsClient.do?method=querySmsClient" />
	</div>

结束!
希望对忘记了的朋友有帮助,也是为了在项目中能迅速copy 谢谢~
分享到:
评论

相关推荐

    jsp自定义标签编写的分页

    本教程将深入探讨如何利用JSP自定义标签来编写一个灵活、可扩展的分页系统,该系统不依赖于特定的数据库,具有很高的通用性。 首先,理解JSP自定义标签的工作原理至关重要。自定义标签由三部分组成:标签库描述符...

    mybatis自定义标签.zip

    假设我们要实现一个根据某个字段值决定是否包含某个子查询的功能,可以编写如下的自定义标签: ```xml SELECT * FROM users LEFT JOIN user_roles ON users.id = user_roles.user_id ``` 4. **处理标签...

    jsp中自定义标签用法实例分析

    3. **维护简单**:一旦自定义标签编写完成,维护和升级变得更加容易。所有使用该标签的页面会自动受益于标签的更新。 ### 自定义标签的实现步骤 #### 步骤1:编写TLD文件 TLD (Tag Library Descriptor) 文件是一...

    tp自定义标签

    通过自定义标签,开发者可以在视图层直接调用,简化HTML和PHP的混合编写,使页面结构更加清晰。 2. **创建自定义标签** 在ThinkPHP 3.0中,自定义标签通常在`TagLib`类库下创建。首先,你需要在`ThinkPHP/Lib/...

    JSP标签、自定义标签,含有属性

    - 为每个自定义标签编写文档,解释其功能、参数及用法。 通过深入学习和实践这些知识点,开发者可以熟练掌握JSP标签技术,提升JSP应用的开发效率和质量。资料包中的"jsptag04"可能包含相关的示例代码和教程,建议...

    struts2 自定义标签

    在Struts2中,自定义标签是提高代码可读性和可维护性的重要工具。本文将深入探讨Struts2自定义标签的实现机制、优点以及如何在实际项目中进行应用。 一、Struts2自定义标签的概念 自定义标签是JSP的一种扩展,允许...

    jsp 自定义标签实例

    在JavaServer Pages (JSP) 技术中,自定义标签是扩展JSP功能的关键手段,它允许开发者创建可重用的组件,提高代码的可维护性和可读性。本实例将深入探讨如何实现一个简单的JSP自定义标签。 首先,自定义标签的实现...

    jsp2.0 自定义标签和自定标签函数

    它可能涵盖了从创建TLD文件,编写标签处理类,到在JSP页面上实际使用自定义标签的全过程。同时,这个文档可能会提供一些实际的例子,帮助读者理解自定义标签的工作原理。 而"test1.tld"文件则是对一个自定义标签库...

    JSP自定义标签学习笔记

    创建自定义标签需要编写处理类,继承自`javax.servlet.jsp.tagext.TagSupport`或`javax.servlet.jsp.tagext.SimpleTagSupport`,然后在TLD文件中定义标签属性、行为等信息。 三、自结束标签(不带标签体,TagSupport...

    Freemarker 自定义标签 简单案例

    1. **编写Java类**:你需要定义一个处理自定义标签的Java类,这个类需要继承`freemarker.template.TemplateDirectiveModel`接口,并实现其方法。在这个类中,你可以编写处理逻辑,如接收参数、处理数据、生成输出。 ...

    jsp 自定义标签的使用

    在JavaServer Pages (JSP) 技术中,自定义标签是提高代码可重用性和模块化的重要手段。自定义标签允许开发者创建自己的组件,这些组件可以像HTML标签一样在页面上使用,使得代码更加清晰易读。本教程将深入探讨JSP...

    html自定义标签的使用

    首先,创建自定义标签的目的是为了增加语义化,使网页内容更易于机器理解,同时提高人类阅读的清晰度。例如,可以定义`&lt;article&gt;`、`&lt;sidebar&gt;`等标签来明确内容区块的类型。自定义标签遵循驼峰式命名规则,如`...

    自定义标签库(自己写)

    自己写的自定义标签库,实现JSTL常用的功能。

    自定义标签,标签实例,ppt

    1. 编写TLD文件:TLD文件是XML格式的,用于描述自定义标签的属性、行为和事件。例如: ```xml &lt;name&gt;myTag &lt;tag-class&gt;com.example.MyTagHandler&lt;/tag-class&gt; &lt;body-content&gt;empty &lt;name&gt;param1 &lt;required&gt;...

    JSP自定义标签:最近在项目中要用到这种技术,所以自己就写一个经典的HelloWorld实例

    3. **编写TLD文件**:创建TLD文件,定义自定义标签的相关信息,包括标签名、处理类、属性等。 4. **编写标签处理程序类**:实现标签处理程序类,继承适当的接口并实现相关方法。 5. **使用自定义标签**:在JSP页面中...

    Web2.0体系学习(自定义标签)

    - Spring Web Flow、JSF等框架也提供了自定义标签的机制,进一步丰富了Web2.0开发中的自定义标签应用。 通过自定义标签,Web2.0应用可以更加灵活地构建用户界面,提供定制化的交互体验。同时,这也有助于提升...

    自定义标签

    - 提升代码复用率:自定义标签可以封装常用功能,避免重复编写相同代码。 - 易于团队协作:统一的自定义标签库可以帮助团队成员快速理解项目结构和逻辑。 5. **自定义标签的实践应用** - 数据绑定:比如,一个...

    由浅到深详细讲解JSP自定义标签

    JSP(JavaServer Pages)自定义标签是JSP技术中一个重要的特性,允许开发者创建可重用的、自定义的组件,从而提高代码的可读性和可维护性。本文将深入讲解JSP自定义标签的相关概念、格式、处理过程以及创建和使用...

    自定义标签的内容及使用

    自定义标签的本质是一个实现了特定接口的Java类,这些接口定义在`javax.servlet.jsp.tagext`包中,例如`Tag`、`IterationTag`和`BodyTag`等。这些类和接口用于封装常用功能,当JSP页面被转换为Servlet时,自定义标签...

Global site tag (gtag.js) - Google Analytics