Web基础之自定义JSP标签
一、什么是JSP标签
JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写
java代码,造成jsp页面难以维护。
JSP标签是用来替换代码的,那么了解JSP标签,只需要了解JSP标签对应的代码即可。
二、常用的JSP标签
静态包含和静态包含的详细区别见上篇博客;
三、开发自定义标签步骤
四、标签执行流程
五、JSTL
使用JSTL时,需要导入jar包,并在jsp页面中使用taglib指令
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
JSTL核心标签库
六、自定义标签实例
项目整体架构:
该项目自定义了三个标签,分别是日期转换标签(对应上面的问题)、自定义的if标签、自定义格式化金额标签;
项目源代码:
思路:参照上面的自定义标签开发的步骤
自定义标签类继承SimpleTagSupport类
自定义日期标签类
package com.hx.servlet.tag;
import java.io.IOException;
import java.text.SimpleDateFormat;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class DateFormatTag extends SimpleTagSupport {
// 格式化的格式
private String pattern = "yyyy-MM-dd HH:mm:ss";
private Object date;
@Override
public void doTag() throws JspException, IOException {
// 获取标签体中的文本内容
// StringWriter sw = new StringWriter();
// this.getJspBody().invoke(sw);
// String content = sw.toString();
// 将给定的时间,按指定的格式转化为字符串
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
String str = sdf.format(date);
// 获取JSPContext对象
JspContext jc = this.getJspContext();
// 获取输出对象out
JspWriter out = jc.getOut();
// 使用out向外输出
// out.write(content);
out.write(str);
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public Object getDate() {
return date;
}
public void setDate(Object date) {
this.date = date;
}
}
自定义If标签类:
package com.hx.servlet.tag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class IfTag extends SimpleTagSupport {
// if 控制语句的条件表达式
private boolean test;
@Override
public void doTag() throws JspException, IOException {
if (test) {
// 获取标签体中的文本内容
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
String content = sw.toString();
// 获取JSPContext对象
JspContext jc = this.getJspContext();
// 获取输出对象out
JspWriter out = jc.getOut();
// 使用out向外输出
out.write(content);
}
}
public boolean getTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
自定义格式化金额类:
package com.hx.servlet.tag;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MoneyFormatTag extends SimpleTagSupport {
private String prefix = ""; // 前缀
private BigDecimal amount; // 要格式化的金额
private int scale = 2; // 小数点位数
@Override
public void doTag() throws JspException, IOException {
// 首先设置小数点位数,采用四舍五入
amount = amount.setScale(scale, RoundingMode.HALF_UP);
// 格式化金额
String amt = format(amount);
// 获取JSPContext对象
JspContext jc = this.getJspContext();
// 获取输出对象out
JspWriter out = jc.getOut();
// 使用out向外输出
String content = null;
if (!"".equals(prefix = prefix.trim())) {
content = prefix + " " + amt;
} else {
content = amt;
}
out.write(content);
}
/**
* 格式化金额. <br/>
* 如:1000.00 格式化为: 1, 000.00
*
* @version 1.0
*
* @param amount
* @return
*/
private String format(BigDecimal amount) {
if (amount == null) {
return "";
}
// 1. 设置为两位小数点
amount.setScale(2);
// 2. 将金额转化为字符串
String amt = amount.toPlainString();
// 3. 格式化
return formt(amt);
}
private String formt(String amount) {
// 找到小数点
int index = amount.indexOf(".");
// 获取整数部分
String zs = null;
if (index > 0) {
zs = amount.substring(0, index);
} else {
zs = amount;
}
StringBuilder sbuilder = new StringBuilder();
int length = zs.length();
int count = 0;
for (int i = length - 1; i >= 0; i--) {
count = count + 1;
sbuilder.append(zs.charAt(i));
if (count % 3 == 0 && count < length) {
sbuilder.append(",");
}
}
// 逆序
sbuilder.reverse();
// 获取格式化之后的整数部分
zs = sbuilder.toString();
if (index > 0) {
return zs + amount.substring(index);
}
return zs;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public int getScale() {
return scale;
}
public void setScale(int scale) {
this.scale = scale;
}
}
编写tld文件:hx-taglib.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/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<!-- 标签的名称 -->
<short-name>huaxin</short-name>
<!-- 标签库的URL,
如果当前工程下没有该描述文件,
@taglib 指令会去它的 uri 路径下查找对应的tld文件
-->
<uri>http://www.huaxin.com/tag-lib</uri>
<!-- JSP标签库的描述信息 -->
<description>
a simple for JSP tag
</description>
<tag>
<!-- 标签名称 -->
<name>formatdate</name>
<!-- 标签类的全限定名 -->
<tag-class>com.hx.servlet.tag.DateFormatTag</tag-class>
<!-- 标签体的类型 -->
<body-content>empty</body-content>
<description>format the given date to the specified pattern</description>
<attribute>
<!-- 标签的属性名称 -->
<name>pattern</name>
<!-- 该属性是否必填 -->
<required>false</required>
<!-- 该属性的值是否允许为表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>date</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>if</name>
<tag-class>com.hx.servlet.tag.IfTag</tag-class>
<!-- 标签体的类型 -->
<body-content>scriptless</body-content>
<description>If control</description>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>fomartmoney</name>
<tag-class>com.hx.servlet.tag.MoneyFormatTag</tag-class>
<!-- 标签体的类型 -->
<body-content>empty</body-content>
<description>format money, i.e € 2,000.00 OR 2,000</description>
<attribute>
<name>prefix</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>amount</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>scale</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
简单的登录(login.jsp)和主页(index.jsp)JSP以及逻辑处理的Servlet(LoginServlet.java)
主页JSP中使用了我们自定义的标签
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="error.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
request.setAttribute("bathPath", basePath);
%>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录</title>
</head>
<body style="text-align:center;">
<form action="${bathPath }/login" method="POST">
<table style="margin-top:50px; margin-left:auto; margin-right:auto;width:80%;">
<tr>
<td style="text-align:right;">用户名:</td>
<td style="text-align:left;"><input id="userName" type="text" name="userName"></td>
</tr>
<tr>
<td style="text-align:right;">密 码:</td>
<td style="text-align:left;"><input type="password" name="userPwd"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登录">
<input type="reset" value="重置"></td>
</tr>
</table>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.huaxin.com/tag-lib" prefix="hx" %> <%--prefix:前缀 --%>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<!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>主页</title>
</head>
<body>
欢迎你,${currentUser }。 最近一次登录时间:
<%--JAVA代码处理时间格式化 --%>
<%
Date lastLoginTime = (Date)pageContext.findAttribute("lastLoginTime");
if(lastLoginTime != null) {
//时间格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
out.write(sdf.format(lastLoginTime));
}
%><br/>
<%--自定义JSP标签处理时间格式化 --%>
最后一次登录时间:<hx:formatdate date="${lastLoginTime }" pattern="yyyy年MM月dd日 HH:mm:ss"/>
<br/>
<%--if分支控制 --%>
<hx:if test="${currentUser == '张三' }">
<a href="">查看全体成员</a>
</hx:if>
<br/>
账户余额:<hx:fomartmoney prefix="€" amount="${amount }"/>
</body>
</html>
Servlet逻辑处理
package com.hx.servlet;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String userName = req.getParameter("userName");
String userPwd = req.getParameter("userPwd");
// 2.登录校验成功,将登录信息保存到 Session
req.getSession().setAttribute("lastLoginTime", new Date());
req.getSession().setAttribute("currentUser", userName);
req.getSession().setAttribute("amount", new BigDecimal("999999999999999999999"));
// 应该重定向到主页
resp.sendRedirect("index.jsp");
}
}
当然,我们的配置文件也是不能少的(只需要配置我们自己写的Servlet,去处理对应的路径就好了)
web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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-app_2_5.xsd"
version="2.5">
<display-name>jsptag</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.hx.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
七、项目运行效果:
用张三登录
用李四登录
八、总结
主要学习了标签的意义,标签的运行原理以及如何开发我们自己的标签;通过自己开发标签来加深对JSTL标签库的理解;我们以后主要用的是JSTL标签库;但是,我们更要明白其中的原理;
学无止境!共勉!