主题:编写一个不含有脚本元素的JSP
JSP最佳实践告诉我们,JSP应当仅仅作为一个表现层的表示工具,不应当使JSP牵扯到业务层的东西。由于在JSP1.0标准中,脚本元素的使用不可避免,这个最佳实践也就成为空话。然而,JSP2.0已经可以让我们这么做了。下面将给出一个不含任何脚本元素的JSP页面。在这个页面中,JSP仅仅用来显示和传递数据,所有的业务处理,数据库的访问,都是通过JavaBean实现的。
这个试验是从一个页面获得name和age两个值,然后通过bean录入数据库。试验包含3个文件,并不是每个文件都有显示功能。下面将进行一一介绍。
1、Controller.jsp
这是一个前端控制器,用于控制转向的页面。使用JSTL技术进行控制,避免了脚本元素。
********************
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<c:choose>
<c:when test="${empty param.action}">
<jsp:forward page="RegisterMember.jsp"/>
</c:when>
</c:choose>
********************
由上面的代码可以清楚地看出,当param.action为空时(这是由一个EL的empty函数计算的),页面将转向RegisterMember.jsp。事实上,由于刚刚载入页面的时候,param.action当然是空的,因此,第一个页面一定会正确地转向RegisterMember.jsp。
2、RegisterMember.jsp
这是一个具有显示的页面,用于数据的输入。这个JSP实际上是一个很简单的HTML文档。
********************
<html>
<head>
<title>Register Member</title>
</head>
<body>
<h1>
Register member
</h1>
<form action="reg.jsp" method="post">
name:
<input type="text" maxlength="20" name="name">
age:
<input type="text" maxlength="5" name="age">
<input type="submit" value="Submit" name="submit">
</form>
</body>
</html>
********************
注意,这里的form的action指向的即下一个JSP页面。
3、reg.jsp
这个JSP进行数据的处理,因而可以算作是核心的JSP文档。
********************
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ taglib prefix="eShop" uri="http://www.galaxy_OPEN.org/eShop/eShop-taglib" %>
<%
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>Register Member</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>
<!--下面绿色部分仅仅是参数的再显示,不进行业务处理-->
name: ${param.name }
age: ${param.age }
<jsp:useBean id="regMem" class="org.galaxy_OPEN.www.member.Register" />
<jsp:setProperty name="regMem" property="*" />
${eShop:registerMember() }
</body>
</html>
*******************
使用<jsp:useBean>标准动作,可以将这个JSP页面同一个JavaBean联系起来。而<jsp:setProperty>标准动作就是进行参数的传递。这里使用了"*"技术。与之相等价的语法实现是:
<jsp:setProperty name="regMem" property="name" value="${param.name}">
<jsp:setProperty name="regMem" property="age" value="${param.age}">
可知,如果一个bean类的参数和传入的名称、数目完全相同,那么就可以使用*技术,使其自动匹配。
这样,一个JSP就和一个Bean联系起来了。如果使用脚本,那么下面的一句就可以是
<% regMem.registerMember(); %>
通过regMem对象调用其registerMember()方法。但是,我们并不希望使用脚本元素,所以事情没有这么简单。由于JSP是单纯的表现,除去脚本元素,JSP无法与JavaBean进行任何形式的通讯。这时,我们如果要访问bean的方法,唯一的途径就是将这个方法进行一下改写,然后把它包装成一个EL函数,通过EL访问。
EL函数要求bean方法必须是statuc的,因为EL需要通过类进行访问。于是,我们需要把registerMember()改写成静态的。
然后改动web.xml文档。由于EL函数必须具有一个前缀,所以我们需要在web.xml文档里定义一个自己的前缀。
*******************
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 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-app_2_4.xsd">
<taglib>
<taglib-uri>
http://www.galaxy_OPEN.org/eShop/eShop-taglib
</taglib-uri>
<taglib-location>/WEB-INF/eShop/eShopTags.tld</taglib-location>
</taglib>
</web-app>
*******************
这里,我们定义了一个URI映射,由JSP指令
<%@ taglib prefix="eShop" uri="http://www.galaxy_OPEN.org/eShop/eShop-taglib" %>
将我们自定义的前缀eShop指向这个URI:http://www.galaxy_OPEN.org/eShop/eShop-taglib 。同时,web.xml文档里把标签定义文件命名为eShopTags.tld,其位置在/WEB-INF/eShop/eShopTags.tld 。注意,所有的自定义TLD文件都必须在/WEB-INF/文件夹下。
然后在相应位置给出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 web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>
A taglib to define some EL accessible functions.
</description>
<tlib-version>1.0</tlib-version>
<short-name>ELFunctionTaglib</short-name>
<uri>/ELFunctionTagLibrary</uri>
<function>
<description>
Exposes the registerMember() function from
org.galaxy_OPEN.www.member.Register
</description>
<name>registerMember</name>
<function-class>
org.galaxy_OPEN.www.member.Register
</function-class>
<function-signature>
void registerMember()
</function-signature>
</function>
</taglib>
*******************
这个文件中同时给出了标签调用名、相关联的类和函数声明。这是调用EL函数必须的。
在这之后,就可以像使用EL一样使用自定义的EL函数了:
${eShop:registerMember() }
这个试验是从一个页面获得name和age两个值,然后通过bean录入数据库。试验包含3个文件,并不是每个文件都有显示功能。下面将进行一一介绍。
1、Controller.jsp
这是一个前端控制器,用于控制转向的页面。使用JSTL技术进行控制,避免了脚本元素。
********************
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<c:choose>
<c:when test="${empty param.action}">
<jsp:forward page="RegisterMember.jsp"/>
</c:when>
</c:choose>
********************
由上面的代码可以清楚地看出,当param.action为空时(这是由一个EL的empty函数计算的),页面将转向RegisterMember.jsp。事实上,由于刚刚载入页面的时候,param.action当然是空的,因此,第一个页面一定会正确地转向RegisterMember.jsp。
2、RegisterMember.jsp
这是一个具有显示的页面,用于数据的输入。这个JSP实际上是一个很简单的HTML文档。
********************
<html>
<head>
<title>Register Member</title>
</head>
<body>
<h1>
Register member
</h1>
<form action="reg.jsp" method="post">
name:
<input type="text" maxlength="20" name="name">
age:
<input type="text" maxlength="5" name="age">
<input type="submit" value="Submit" name="submit">
</form>
</body>
</html>
********************
注意,这里的form的action指向的即下一个JSP页面。
3、reg.jsp
这个JSP进行数据的处理,因而可以算作是核心的JSP文档。
********************
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ taglib prefix="eShop" uri="http://www.galaxy_OPEN.org/eShop/eShop-taglib" %>
<%
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>Register Member</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>
<!--下面绿色部分仅仅是参数的再显示,不进行业务处理-->
name: ${param.name }
age: ${param.age }
<jsp:useBean id="regMem" class="org.galaxy_OPEN.www.member.Register" />
<jsp:setProperty name="regMem" property="*" />
${eShop:registerMember() }
</body>
</html>
*******************
使用<jsp:useBean>标准动作,可以将这个JSP页面同一个JavaBean联系起来。而<jsp:setProperty>标准动作就是进行参数的传递。这里使用了"*"技术。与之相等价的语法实现是:
<jsp:setProperty name="regMem" property="name" value="${param.name}">
<jsp:setProperty name="regMem" property="age" value="${param.age}">
可知,如果一个bean类的参数和传入的名称、数目完全相同,那么就可以使用*技术,使其自动匹配。
这样,一个JSP就和一个Bean联系起来了。如果使用脚本,那么下面的一句就可以是
<% regMem.registerMember(); %>
通过regMem对象调用其registerMember()方法。但是,我们并不希望使用脚本元素,所以事情没有这么简单。由于JSP是单纯的表现,除去脚本元素,JSP无法与JavaBean进行任何形式的通讯。这时,我们如果要访问bean的方法,唯一的途径就是将这个方法进行一下改写,然后把它包装成一个EL函数,通过EL访问。
EL函数要求bean方法必须是statuc的,因为EL需要通过类进行访问。于是,我们需要把registerMember()改写成静态的。
然后改动web.xml文档。由于EL函数必须具有一个前缀,所以我们需要在web.xml文档里定义一个自己的前缀。
*******************
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 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-app_2_4.xsd">
<taglib>
<taglib-uri>
http://www.galaxy_OPEN.org/eShop/eShop-taglib
</taglib-uri>
<taglib-location>/WEB-INF/eShop/eShopTags.tld</taglib-location>
</taglib>
</web-app>
*******************
这里,我们定义了一个URI映射,由JSP指令
<%@ taglib prefix="eShop" uri="http://www.galaxy_OPEN.org/eShop/eShop-taglib" %>
将我们自定义的前缀eShop指向这个URI:http://www.galaxy_OPEN.org/eShop/eShop-taglib 。同时,web.xml文档里把标签定义文件命名为eShopTags.tld,其位置在/WEB-INF/eShop/eShopTags.tld 。注意,所有的自定义TLD文件都必须在/WEB-INF/文件夹下。
然后在相应位置给出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 web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>
A taglib to define some EL accessible functions.
</description>
<tlib-version>1.0</tlib-version>
<short-name>ELFunctionTaglib</short-name>
<uri>/ELFunctionTagLibrary</uri>
<function>
<description>
Exposes the registerMember() function from
org.galaxy_OPEN.www.member.Register
</description>
<name>registerMember</name>
<function-class>
org.galaxy_OPEN.www.member.Register
</function-class>
<function-signature>
void registerMember()
</function-signature>
</function>
</taglib>
*******************
这个文件中同时给出了标签调用名、相关联的类和函数声明。这是调用EL函数必须的。
在这之后,就可以像使用EL一样使用自定义的EL函数了:
${eShop:registerMember() }