jstl自定义标签-转载


开发自定义标记需要有两个组件:
1、一个是描述标记特征的标记库描述文件(TLD文件)
2、另一个是Java类,也称为标记处理器,为了完成标记的行为,JSP容器要执行标记处理器。
自定义标签实现过程:
1、写标签处理器类:TestTag.java。
2、写tld文档:用来指定标签的名字,标签库等。
3、用JSP来测试(指定标签库的位置tld,指定前缀名,使用标签)。

首先编写标签处理器类,标签处理器类需要继承javax.servlet.jsp.tagext.TagSupport或者javax.servlet.jsp.tagext.BodyTagSupport,二者区别暂时不知道,如果有高手知道,请给与指导,谢谢先。一般实现doStartTag和doEndTag方法,例如:

public class ExampleTag extends TagSupport{
public int doStartTag(){
//当处理开始标记的时候调用该方法
}
public int doEndTag(){
//当处理结束标记的时候调用该方法
}
}

doStartTag方法和doEndTag方法的返回值说明:

SKIP_BODY:跳过自定义标签间的代码;
SKIP_PAGE:跳过在此之后的所有页面内容;
EVAL_BODY_INCLUDE:执行自定义标签间内容;
EVAL_BODY_AGAIN:再次执行自定义标签间内容;
EVAL_PAGE:执行标签后页面内容;

常用的返回值为:EVAL_BODY_INCLUDE。

常用的属性有pageContex。

例如:

package com.test;
import java.io.IOException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class TestAttributeTag extends BodyTagSupport {

//自定义标签支持带参数
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int doStartTag(){
try {
pageContext.getOut().print("Hello "+name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return EVAL_BODY_INCLUDE;
}
public int doEndTag(){
return EVAL_BODY_INCLUDE;
}
}

然后讨论一下TLD文档编写,

<?xml version="1.0" encoding="UTF-8"?>
<!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> //标签依赖jsp的版本
<short-name>zl</short-name> //默认前缀名称
<uri>http://www.test.com</uri> //指定标签库德uri
<tag>
<name>testtag</name> //标签名称
<tag-class>com.test.TestAttributeTag</tag-class> //标签处理器类
<body-content>JSP</body-content> //标签主体内容,一般选择JSP
<attribute> //标签的参数name
<name>name</name>
<required>true</required> //参数是否必须,true表示必须,false反之
<rtexprvalue>true</rtexprvalue> //是否支持EL表达式
<type>java.lang.String</type> //参数类型
<description>用户名称</description> //参数描述
</attribute>
</tag>
</taglib>

最后用jsp页面测试自定义标签,例如:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="zl" uri="http://www.test.com" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'ZidingyiTag.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">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
This is my JSP page. <br>
<zl:testtagname="test"></zl:testtag>
</body>
</html>

例子比较简单,有什么不对地方,欢迎大家批评!




仅仅是个人的经验
不过希望对大家有帮助
先解释一下自定义标签的用法
网上粘来一段

自定义函数库步骤:
1.定义类和方法(方法必须是public static)
public class MyFunctions {
public static String testMyfn(String str) {
return "i am " + str;
}
}
2.编写自定义tld文件,并且将此文件放到WEB-INF目录下或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">
<description>myfn 1.1 functions library</description>
<display-name>myfn functions</display-name>
<tlib-version>1.0</tlib-version>
<short-name>myfn</short-name>
<uri>http://hi.baidu.com/2008_pc/functions</uri>
<function>
<name>testMyfn</name>
<function-class>com.struts.functions.MyFunctions</function-class>
<function-signature>java.lang.String testMyfn(java.lang.String)</function-signature>
</function>
</taglib>
3.在页面中采用taglib指令引入自定义函数库
<%@ taglib prefix="myfn" uri="http://hi.baidu.com/2008_pc/functions" %>
4.在struts的JstlFnAction里面设置值
request.setAttribute("name", "shiyuhao");
5.调用
${myfn:testMyfn(name) }
输出结果:i am shiyuhao

好了也就是说我们写了一个类 类里有个方法为static就行了ok
简单但是也有其他的情况
A:
jstl有这样一个特性 即 某对象instance存在一个getSomeThings()的方法 那么只要调用${instance.someThings}就行了
那么 调用自定义函数的时机就很明确了
假设 我现在某对象中需要获取一个List的长度,这个很麻烦,因为List类型没有提供给我们getSize方法
那么 我们可以调用fn 也可以自己写自定义函数
但是在这种情况下没必要 因为 我们如过能获取对象的引用 那么 只需在对象中加入 getListSzie()方法就行了
那么总结出jstl的自定义函数的特性
即在需要传参后才能确定返回值的情况下 我们只好使用自定义函数 如果不要传入参数 那么 写一个getter就可以了
B:
自定义函数情况下 我们肯传入一个List<String>或者 List<自定义类>
那么看看配置文件
假设一个方法 getMax() 获取List<String>中的最小值
传入一个List<String> 返回一个最大的String
其中一句
<function-signature>java.lang.String getMax(java.util.List<java.lang.String>)</function-signature>
好吧 如果你使用eclipse 那么一个大红叉叉已经呈现在眼前了
因为<>会在xml中解释成为一个标示符
简单的跳过去就行
写成
<function-signature>java.lang.String getMax(java.util.List)</function-signature>
然后在方法里去强制转换 这就没问题了
C:
我们经常出表的时候要去计算和
当然 有人说 加和最好在sql里写好
……我记得我一跳sql本来30行就ok了 为了在sql计算 合计 小记 累计 平均 加权平均
写到了快200行
复杂的中国式表我们不去讨论 客户的要求一定得满足
那么我们怎么办
其实页面上累加是非常简单的,如果你不用jstl的话轻松点
但是代码很难看 难看的代码 我们写了干嘛
假设 我需要列出一个表中的列累加
设 行row 列col
这个表就复杂
简化为两种情况
划一下看看
12
首先 构造我们的vo 从dao里出来以后,我们的数据室这样一个对象的List
class Inner{
private String row1;
private String row2;
private double value;//这个double不对 下面再说O(∩_∩)O
}
第一种情况下 我们只要设置一个变量 去累加就行了
第二种情况很麻烦,因为合计在数据最上头 那我们数据还没列出来呢 怎么累加
我们在仅仅讨论jstl的情况下
情况1可以用<c:set >这个标签来做累加
页面中用<c:forEach>去循环 每次<c:set value=${var+新的值 } var='var'/>
情况2 我们可以……还是用<c:forEach>去循环 每次<c:set value=${var+新的值 } var='var'/>
然后下面条条 在循环一次就好了
不过这样到底好么 页面中如果有多个累加 就必须增加多个<c:set>这样使得页面相当不整洁
考虑效率方面 反正是循环整个list去累加
因此 使用自定义函数取累加 效率上一样的 再加上迭代器比较好写 嘿嘿 写个自定义函数 不是更好嘛
D:
实际上 上面个两个表中 还存在精度问题
如同上例
class Inner{
private String row1;
private String row2;
private double value;//就是这个
}
jstl和java一样 实际上jsp中有自定义标签的说法,我是说jsp去写一个标签的意思
(有的教程上没,那么 推荐headfirst的jsp&servlet)
java本身对数据处理很糟搞,浮点型 或者double的精度都不能满足实际数据的需求
用<c:set>就相当于request.setAttribute
这样的累加无异于
double a = 0;
double b = 1;
a = a+b;
数据精度绝对会错
先讨论jstl的简单做法,我们知道
有一个<fmt:formatNumber value= pattern=/>这个value是一个字符串,所以个人建议在页面要输出的全部值都用String类型 这个类改一下
class Inner{
private String row1;
private String row2;
private Stringvalue;
}
相加的时候 <c:set value=<fmt:formatNumber>inner.value+var</fmt:formatNumber> var=‘var’/>
这里需要注意一下 fmt的四舍五入
因为默认情况下是4舍6入5奇偶
"4舍6入5奇偶":
<fmt:formatNumber value="${1170.5}" pattern="#,###,###,###"/>
"4舍5入":
<fmt:formatNumber value="${1170.5 + 0.0001}" pattern="#,###,###,###"/>
还得加个量才行
E:
那么实际上依然存在数据的精度问题,因为累加的时候去设置大量的<c:set>使页面不整洁
除此之外,为了显示出一个四舍五入的数,需要引入大量标签
因此个人建议的方法是 使用自定义标签
BigDecimal是个好东西,可以通过一个字符串来构造一个精确的数(实际上 也只有字符串是精确的)
而自定义函传入的参数恰恰又是字符串,这样 定义自己的累加函数
假设一个稍微复杂的例子
有多个班级 1 2 3
假设列出每个班级的人数 和学费的数目
做成如下表格

这个是典型的中国是报表
我们舍去dao部分
如下代码
vo:
import java.util.ArrayList;
import java.util.List;
public class StudentList {
private List<Inner> list = new ArrayList<Inner>();
public class Inner{
private String classNumber;//班级编号
private String personNumber;//班级人数
private String price;//钱数
public String getClassNumber() {
return classNumber;
}
public void setClassNumber(String classNumber) {
this.classNumber = classNumber;
}
public String getPersonNumber() {
return personNumber;
}
public void setPersonNumber(String personNumber) {
this.personNumber = personNumber;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
public List<Inner> getList() {
return list;
}
public void setList(List<Inner> list) {
this.list = list;
}
}
request.setAttribute("vo",list);
扔到了页面后 第一行需要显示合计
写一个自定义函数
class JSTLUtils{
public static String getPersonNumberSum(List list){
List<StudentList.Inner> innerList = (List<StudentList.Inner>)list;
Iterator<StudentList.Inner> iterator = innerList.iterator();
BigDecimal resultBigDecimal = new BigDecimal(0);
while(iterator.hasNext()){
StudentList.Inner inner = iterator.next();
BigDecimal innerBigDecimal = new BigDecimal(inner.getPersonNumber());
resultBigDecimal = resultBigDecimal.add(innerBigDecimal);
}
return resultBigDecimal.toString();
}
public static String getPriceSum(List list){
List<StudentList.Inner> innerList = (List<StudentList.Inner>)list;
Iterator<StudentList.Inner> iterator = innerList.iterator();
BigDecimal resultBigDecimal = new BigDecimal(0);
while(iterator.hasNext()){
StudentList.Inner inner = iterator.next();
BigDecimal innerBigDecimal = new BigDecimal(inner.getPrice());
resultBigDecimal = resultBigDecimal.add(innerBigDecimal);
}
return resultBigDecimal.toString();
}
}
这里基本上都用了BigDecimal这个类来进行加
然后配置一下
<?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.1</tlib-version>
<short-name>jstlUtils</short-name>
<uri>http://com.tool.JSTLFunctionUtils</uri>
<function>
<description>人数和</description>
<name>getPersonNumberSum</name>
<function-class>com.tool.JSTLFunctionUtils.JSTLUtils</function-class>
<function-signature>
java.lang.String getPersonNumberSum(java.util.List)
</function-signature>
</function>
<function>
<description>钱数和</description>
<name>getPriceSum</name>
<function-class>com.tool.JSTLFunctionUtils.JSTLUtils</function-class>
<function-signature>
java.lang.String getPriceSum(java.util.List)
</function-signature>
</function>
</taglib>
页面上调用就${jstlUtils:getPersonNumberSum(vo.list)}就ok了
之后的循环 调用 <c:forEach items="${vo.list}" var="var">
去循环就好了
实际上 是解决了数据的准确性问题
那么 对于合计在最下方的情况下,为了数据的准确还是使用自定义函数比较好,因为 对于管理系统中,钱这个东西绝对不能错而jstl的fmt具体怎么加的,与其我们花一天去看源代码 不如自己写的又快又好又准确
(我没看fmt的源代码 没找到……不过 感觉上时java.text.Format的那几个,上一篇已经提过了 即使使用了FormatNumber也不是很准确的)
F:
这么多情况后 还有最后一个比较垃圾的问题,就是数据0的问题
客户的情况很多,但是对于数据0无外乎两种
一 0就别显示出来
二 没有就显示0
但是jstl就是很烦人,因为没有的情况下,我们取到的是null jstl不会将null的显示出来这样就空了
第一种情况个人建议是改写vo和自定义函数
如果返回的是0就返回“”
对于第二种情况
只能去判断了 jstl或者自定义函数 感觉上没啥区别 (个人认为)

ok 罗嗦了这么多 第一 是为了对大家有点帮助 第二 是为了自己不忘
为了您的安全,请只打开来源可靠的网址

打开网站 取消
来自: http://hi.baidu.com/zhangxia6110/blog/item/a4e2aa0093e60a93e850cd61.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值