欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Tomcat与JavaWeb 8.2 自定义标签的创建和使用(一)访问标签属性

程序员文章站 2022-04-29 12:46:47
...

1.    创建和使用message标签(访问标签属性)

在JSP文件中会包含许多静态文本,例如以下hello0.jsp中的“helloapp”"Nice to meet you:"都是静态文本:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>helloapp</title>
</head>
<body>
<b>Nice to meet you: ${param.username}</b>
</body>
</html>

下面创建一个能够替换JSP文件中的所有静态文本的message标签,它放在mytaglib标签库中,hello.jsp与hello0.jsp能生成同样的网页,区别在于hello.jsp使用了 message标签。在hello.jsp文件中使用message标签的步骤如下。

    1)    在JSP文件中引入这个标签库:

<%@ taglib prefix="mm" uri="/mytaglib" %>
    2)    用<mm:message>标签替换文件中的所有静态文本,以下是hello.jsp的源代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="mm" uri="/mytaglib" %>
<html>
<head>
    <title><mm:message key="hello.title"/></title>
</head>
<body>
<b><mm:message key="hello.hi"/>:${param.username}</b>
</body>
</html>

当客户访问hello.jsp时,message标签的处理类会根据key属性的值从一个特定的资源文件中找到与key匹配的字符串。假定与"hello.hi"字符串匹配的字符串为"Nice to meet you",那么message标签的处理类就将这个字符串输出到网页上。

对开发人员来说,采用message标签可以使JSP网页变得简洁并且易于维护。如果许多JSP网页的静态文本内容发生需求变更,那么无需修改这些JSP文件的代码,而只需要修改一个集中存放了所有网页的静态文本的资源文件即可。

采用message标签,还可以方便地实现同一个JSP文件支持多种语言版本。message标签可以根据客户选择的语言来输出响应的静态文本。使用不同语言的客户访问hello.jsp文件,message标签的处理过程如图所示:
Tomcat与JavaWeb 8.2 自定义标签的创建和使用(一)访问标签属性

1.1    创建message标签的处理类MessageTag

下面将创建message标签的处理类MessageTag,以及相关的资源文件和Servlet类。

    1)    创建包含JSP网页静态文本的资源文件

首先创建包含JSP网页静态文本的资源文件,这些文本以key/value的形式存放。在messageresource.properties资源文件中存放英文静态文本,在messageresource_ch.properties资源文件中存放中文静态文本,这两个文件都要存放在WEB_INF目录下:
messageresource.properties

hello.title = helloapp
hello.hi = Nice to meet you
login.title = helloapp
login.user = User Name
login.password = Password
login.submit = Submit

messageresource_ch.properties

hello.title = helloapp的hello页面
hello.hi = 你好
login.title = helloapp的登录页面
login.user = 用户名
login.password = 密码
login.submit = 提交

以上资源文件中包含了login.jsp和hello.jsp的静态文本,为了便于管理和区分不同JSP文件的文本,约定login.jsp中的静态文本的key以login开头,而hello.jsp中的静态文本以hello开头。

    2)    在Web应用启动时加载静态文本

尽管加载静态文本的任务可以直接由标签处理类来完成,但是把初始化的操作安排在Web应用启动时完成,更符合Web编程的规范。在本例中,将用LoadServlet类的init()方法来完成加载静态文本的任务。init()方法分别从messageresource.properties文件和messageresource_ch.properties文件中读取英文、中文静态文本,然后把它们加载到各自的Properties对象中,最后再把两个Properties对象作为属性保存到Web应用范围内。下面是其源代码:

LoadServlet.java

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Properties;

public class LoadServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        Properties ps = new Properties();
        Properties ps_ch = new Properties();
        try {
            ServletContext context = getServletContext();
            InputStream in = context.getResourceAsStream("/WEB_INF/messageresource.properties");
            ps.load(in);
            InputStream in_ch = context.getResourceAsStream("/WEB_INF/messageresource_ch.properties");
            ps_ch.load(in);

            in.close();
            in_ch.close();

            //在Web应用范围内存放包含静态文本的Properties对象
            context.setAttribute("ps",ps);
            context.setAttribute("ps_ch",ps_ch);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        init();
        PrintWriter out = resp.getWriter();
        out.println("The resource file is loaded.");
    }
}
为了保证在Web应用启动时就加载LoadServlet,应该在web.xml中配置这个Servlet时设置为<load-on-setup>子元素:
<web-app>
    <servlet>
        <servlet-name>LoadServlet</servlet-name>
        <servlet-class>LoadServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoadServlet</servlet-name>
        <url-pattern>/load</url-pattern>
    </servlet-mapping>
</web-app>

    3)    创建MessageTag类

MessageTag.java

package mypack;

import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.tagext.TagSupport;
import java.util.Properties;

public class MessageTag extends TagSupport {
    private String key = null;

    public String getKey() {
        return this.key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public int doEndTag() throws JspException {
        try {
            Properties ps = (Properties) pageContext.getServletContext().getAttribute("ps");
            Properties ps_ch = (Properties) pageContext.getServletContext().getAttribute("ps_ch");

            HttpSession session = pageContext.getSession();
            String language = (String) session.getAttribute("language");

            String message = null;
            if (language != null && language.equals("Chinese")) {
                message = (String) ps_ch.get(key);
            } else {
                message = (String) ps.get(key);
            }
            pageContext.getOut().print(message);
        } catch (Exception e) {
            throw  new JspTagException(e);
        }
        return EVAL_PAGE;
    }
}

MessageTag类包含一个成员变量key,它与<message>标签的属性key对应。在MessageTag中定义了getKey()和setKey()方法。LoadServlet的init()方法吧Properties对象保存在Web应用范围内。在MessageTag的doEndTag()方法中,首先从Web应用范围内读取包含静态文本的Properties对象,接着从会话范围内读取当前客户所使用的语言,然后根据使用的语言来选择相应的Properties对象,从中读取key对应的静态文本。如果用户选择的是中文语言,还要进行字符编码转换处理。Properties对象在通过InputStream流装载文件时,按照ISO-8859-1编码来读取数据,因此应该把葱Properties对象中读取的静态文本转换为中文编码GB2312.

1.2    创建标签库描述文件(TLD)

TLD文件采用XML文件格式,对标签库及库中的标签做了描述。TLD文件中的元素可以分为3类:<taglib>,标签库元素;<tag>,标签元素;<attribute>,标签属性元素。

    1)    标签库元素<taglib>

标签库元素用来设定标签库的相关信息,它的子元素包括:

  • tlib-version:指定标签库的版本
  • jsp-version:指定JSP的版本
  • short-name:指定标签库默认的前缀名(prefix)
  • uri:sh标签库的唯一访问标识符
  • info:设定标签库的说明信息。

    2)    标签元素<tag>

标签元素用来定义一个标签,它的子元素包括:

  • name:设定标签的名字
  • tag-class:设定标签的处理类
  • body-content:设定标签主体的类型
  • info:设定标签的说明信息

以上<tag>元素的<body-content>子元素用于设定标签主体的类型,可选值包括:

  • empty:标签主体为空。
  • scriptless:标签主体不为空,并且包含JSP的EL表达式和动作元素,但不能包含JSP的脚本元素。所谓动作元素是指<jsp:include>和<jsp:forward>等以"jsp"为前缀的JSP内置标签。所谓脚本元素是指以"<%!"、"<%="、"<%!"这三种以"<%"开头的JSP标记。
  • jsp:标签主体不为空,并且包含JSP代码,在JSP代码中可包含EL表达式、动作元素和脚本元素。<body-content>子元素的scriptless可选值与jsp可选值的区别在于前者不能包含JSP的脚本元素。
  • tagdependant:标签主体不为空,并且标签主体内容由标签处理类来解析和处理。标签主体内的所有代码都会原封不动地传给标签处理类,而不是把标签主体的执行结果传给标签处理类。加入用户定义了一个<sql:query>标签,它的<body-content>元素的值为tagdependant。以下JSP代码使用了该标签:
<sql:query>
 select * from MemberDB where ID<10
</sql:query>

    这段代码中的标签主体为一个SQL语句,它将由<sql:query>标签的处理类来处理,该类负责执行这个SQL语句。

    3)    标签属性元素<attribute>

标签属性元素用来描述标签的属性,该元素的子元素包括:

  • name:属性名称
  • required:属性是否是必须的,默认为false
  • rtexprvalue:属性值是否可以为基于"<%"和"%>"形式的Java表达式或EL表达式

对于<rtexprvalue>子元素,如果取值为true,表示标签的属性可以为普通的字符串,或者是Java表达式和EL表达式;如果是false,那么标签的属性只能为普通的字符串。例如对于以下mytag标签,它的num属性就是一个Java表达式,因此当TLD文件中定义mytag标签的num属性时,应该把<rtexprvalue>子元素设置为true。

<% int num = 1;%>
<prefix:mytag num="<%= num %>"/>

下面将创建TLD文件,命名为mytaglib.tld。在这个文件中定义了uri为"/mytaglib"的标签库,本章创建的所有标签都位于这个标签库中。下例程是mytaglib.tld文件的源代码,它定义了一个名为message的标签,这个标签有一个名为"key"的属性。本章后文还会介绍向mytaglib.tld文件中加入其他范例标签的定义代码。

WEB_INF/mytaglib.tld

<?xml version="1.0" encoding="ISO-8859-1"?>

<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>mytaglib</short-name>
    <uri>/mytaglib</uri>

    <tag>
        <description>produce message by key</description>
        <name>message</name>
        <tag-class>mypack.MessageTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>key</name>
            <required>true</required>
        </attribute>
    </tag>
</taglib>

由于<message>标签的主体为空,因此<body-content>子元素的值为"empty"。当在JSP文件中使用<message>标签时,必须为标签设置key属性,因此<attribute>元素的<required>子元素的值为"true".

1.3    在Web应用中使用标签

如果在Web应用中用到了特定标签库中的自定义标签,则应该在web.xml中加入<taglib>元素,它用于声明所引用的标签库:

    <jsp-config>
        <taglib>
            <taglib-uri>/mytaglib</taglib-uri>
            <taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
        </taglib>
    </jsp-config>
在JSP文件中需要通过<%@ taglib>指令来声明对标签库的引用,例如:
<%@ taglib uri="/mytaglib" prefix="mm" %>
以上指令中的uri属性用来指定标签库的标识符,它和web.xml中的<taglib-uri>元素的值保持一致。prefix属性表示在JSP文件中引用这个标签库中的标签的前缀,例如如下代码表示引用mytaglib标签库中的<message>标签:
<title><mm:message key="hello.title" /></title>

除了按照本章的方式在web.xml文件中声明引入的标签库,还可以直接使用第三方提供的符合特定规范的标签库的JAR打包文件下面在Web应用中加入3个负责产生网页的文件:index.html、login.jsp和hello.jsp,它们之间的链接关系为:index.html -> login.jsp -> hello.jsp,这三个文件组成了一个小小的支持中文和英文两个版本的Web应用。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>helloapp</title>
</head>
<body>
<p>Welcome to helloapp!</p>
<a href="login.jsp?language=English">English Version</a>
<a href="login.jsp?language=Chinese">中文版本</a>
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="mm" uri="/mytaglib" %>
<html>
<%
    String language = request.getParameter("language");
    if (language==null) language="English";
    session.setAttribute("language",language);
%>
<head>
    <title><mm:message key="login.title"/></title>
</head>
<body>
<br>
<form name="loginForm" method="post" action="hello.jsp">
    <table>
        <tr>
            <td><div align="right"><mm:message key="login.user"/>:</div> </td>
            <td><input type="text" name="username"> </td>
        </tr>
        <tr>
            <td><div align="right"><mm:message key="login.password"/>:</div> </td>
            <td><input type="password" name="username"> </td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" name="Submit" value=<mm:message key="login.submit"/> > </td>
        </tr>
    </table>
</form>
</body>
</html>
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="mm" uri="/mytaglib" %>
<html>
<head>
    <title><mm:message key="hello.title"/></title>
</head>
<body>
<b><mm:message key="hello.hi"/>:${param.username}</b>
</body>
</html> 

OK,需要的文件都已经写好,下面运行起来应用,进入index.html效果图:
Tomcat与JavaWeb 8.2 自定义标签的创建和使用(一)访问标签属性
分别点击中英文版本,会出现对应语言的表单。(如果点击中文版本显示Server Internal Error,可能是IDEA编码设置的问题,在IDEA的File ——Settings——Editor——File Encodings,把Global和Project Encoding设为UTF-8,把下方Default encoding for properties files设置为ISO-8859-1,并勾选旁边的Transparent native-to-ascii conversion)
Tomcat与JavaWeb 8.2 自定义标签的创建和使用(一)访问标签属性
Tomcat与JavaWeb 8.2 自定义标签的创建和使用(一)访问标签属性

相关标签: 自定义标签属性