整合Java 6 脚本、Groovy实现动态MVC模式(一)
【IT168 专稿】一个有弹性的和动态的开发环境正在受到前所未有的关注,甚至连脚本语言也显现出这方面的特性,这也正是我们所需要的,也就是说,我们永远需要建立易维护,并且可满足我们需求的应用程序。如果我们要想使用脚本语言参与进来,我想我们应该考虑一下Java SE 6所提供的一个新的脚本API:一个与语言无关的允许开发人员在Java代码中使用脚本语言的框架。使用这套新API,我们不仅可以利用脚本语言的特性,而且还能使用很多和Java相关器工具。
在本文中,我们提供了一个实例,这个实例将尽可能体现这套API的特性。并且使用这套API实现一个基于Model View Controller(MVC)模式的Web应用程序,这个程序同时还使用了Groovy框架(一个基于Java平台的动态脚本语言,Groovy负责实现商业逻辑,也就是MVC中的M层)。并且使用了不同的技术来实现MVC中的View层。对于控制层(Controller)层来说,我们使用WebLEAF,这是一个用于开发基于MVC模式的Web程序的开源框架。为了使这个例子更容易部署和运行,我们使用了一个基于Java的数据库:HSQLDB,这个数据库允许的们只通过两个文本文件来创建一个简单的数据库。为了实现可以产生HTML用户接口的view层,在本文中我们采用了XSLT技术,这是一种可以将XML文档转换成另外一种形式的语言,同时还使用了FreeMarker,这是一个流行的处理XML的模板引擎,如它可以使XML作为输入数据变得很容易。
在本文的例子中我们将首先开发一个web页,它将显示数据库的不同项,并允许我们选择一个,以便我们可以查看某项的详细信息。虽然这个程序很简单,但它足以清楚地表述本文要讲的内容了。
一、进行准备工作
第一步是建立健全个基本的标准Web应用程序结构,并且将最新的WebLEAF 3.x库加进来,这个版本可以非常好地支持新的Java脚本API,我们可按如下的五步进行:
1. 首先建立一个叫Test的目录。
2. 然后在Test目录中建立一个WEB-INF目录。
3. 在WEB-INF目录中建立两个目录:lib和classes。
4. 将开载的WebLEAF3.jar文件放到Test\WEB-INF\lib中。
5. 然后在Test\WEB-INF中建立一个标准化sevlet描述文件web.xml,它的内容如下:
<?xml version="1.0"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!--
WebLEAF controller servlet configuration
-->
<servlet>
<servlet-name>WebLEAFController</servlet-name>
<servlet-class>org.leaf.LEAFManager</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- End controller servlet -->
</web-app>
这个配置文件告诉Servlet容器实例化一个WebLEAF控制Servlet,并当Context开始时启动它。在这里我们要注意一个<load-on-startup>的值是2,一会我们要解释一下这个值为什么不是1,而是2。
最后,我们需要在WEB-INF中建立一个WebLEAF配置文件test.leaf.conf,内容如下:
虽然上面的配置文件只是最小化配置,但它对于本文的例子已经足够了。<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE WADSET SYSTEM "http://www.uib.es/leaf/LEAFwad.dtd">
<WADSET>
<WAD
NAME="Test"
INIT_MODE="INITS_ON_START_UP"
XML_ALLOW_SHOW="TRUE"
XSLT_NO_CACHE="TRUE"
>
</WAD>
</WADSET>
二、建立数据库
在这一节我们来为本文的例子建立一个数据库。按着我们上面所说的,将使用HSQLDB数据库,第一步是下载HSQLDB JDBC驱动,本文使用的是1.8.0版本,将其解压后的jar文件复制到Test\WEB-INF\lib中。
在这一节我们来为本文的例子建立一个数据库。按着我们上面所说的,将使用HSQLDB数据库,第一步是下载HSQLDB JDBC驱动,本文使用的是1.8.0版本,将其解压后的jar文件复制到Test\WEB-INF\lib中。
然后,我们需要建立一个test数据库,并向数据库中加入一些模拟数据。因此,我们在WEB-INF中建立一个db目录,并在这个目录中放两个文件。第一个文件叫Test.properties,它的内容如下:
#HSQL Database Engine
#Fri Apr 20 18:52:47 CEST 2007
hsqldb.script_format=0
runtime.gc_interval=0
sql.enforce_strict_size=false
hsqldb.cache_size_scale=10
readonly=false
hsqldb.nio_data_file=true
hsqldb.cache_scale=14
version=1.8.0
hsqldb.default_table_type=memory
hsqldb.cache_file_scale=1
sql.compare_in_locale=false
hsqldb.log_size=200
modified=no
hsqldb.cache_version=1.7.0
hsqldb.original_version=1.7.1
hsqldb.compatible_version=1.8.0第二个文件叫Test.script,它的内容如下:
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE TTST_ITEM(ITE_CODE CHAR(32) NOT NULL PRIMARY KEY,ITE_NAME VARCHAR(100) NOT NULL,ITE_DESCRIPTION VARCHAR(300))
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 60
SET SCHEMA PUBLIC
INSERT INTO TTST_ITEM VALUES('06e8da2682ce842b01a47de7823ec779','Parents','Links for parents')
INSERT INTO TTST_ITEM VALUES('1ab94df54312961a015749157fe05097','Web related','Item description')
INSERT INTO TTST_ITEM VALUES('1acc5e9d4312961a0157491547be91fa','Source control','That must be about source')
INSERT INTO TTST_ITEM VALUES('1ad80b204312961a015749159fe5205a','JBuilder Plugins','Plugin? What's that')
在使用时应注意,HSQLDB驱动只有在发布时还使用完全路径,我们将使用WebLEAF中的AutoConfigurer Servlet来自动配置路径。为了达到这个目的,我们在classes中建立一个webapp.properties文件,这个文件只有简单的一行,内容如下:
db.location=REAL_PATH/WEB-INF/db
我们还需要在web.xml中加入Autoconfigurer Sevvlet,内容如下:
我们还需要在web.xml中加入Autoconfigurer Sevvlet,内容如下:
上面的培植告诉Autoconfigurer Servlet检查webapp.properties文件和验证db.location属性是否指向了正确的路径。而且Autoconfigurer Servlet首先被装载,而且是在WebLEAF Controller Servlet之前,这应该感谢load-on-startup的功劳(值小的先装载,值大的后装载)。这将保证Autoconfigurer Servlet在WebLEAF Controller Servlet(LEAFManager)访问数据库之前验证db.location属性是否正确。<?xml version="1.0"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!--
Autoconfiguration servlet
-->
<servlet>
<servlet-name>AutoConfigurer</servlet-name>
<servlet-class>org.leaf.util.AutoConfigurer</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>FILE_NAME.1</param-name>
<param-value>WEB-INF/classes/webapp.properties</param-value>
</init-param>
<init-param>
<param-name>NODES_NAME.1</param-name>
<param-value>db.location</param-value>
</init-param>
<init-param>
<param-name>PATTERN.1</param-name>
<param-value>(.*)/WEB-INF/(.*)</param-value>
</init-param>
<init-param>
<param-name>FORMAT.1</param-name>
<param-value>{0}WEB-INF/{1}</param-value>
</init-param>
</servlet>
<!-- End Autoconfiguration servlet -->
<!--
WebLEAF controller servlet configuration
-->
<servlet>
<servlet-name>WebLEAFController</servlet-name>
<servlet-class>org.leaf.LEAFManager</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- End controller servlet -->
</web-app>
三、使用Groovy实现商业逻辑
现在我们已经建立了数据,下面我们开始实现商业逻辑。在上面已经提到过,Java 6直接在JVM层直接支持脚本语言,我们可以使用Java 6支持的Mozilla's Rhino JavaScript脚本引擎,这是一个默认的脚本引擎。WebLEAF可以利用这个特性允许我们使用任何支持者脚本语言来实现商业逻辑。由于Groovy引擎并不直接支持Java 6,因此,为了使用Java 6的脚本功能,我们必须使用java.net工程,这个工程是一个支持不同语言的脚本引擎实现。
现在我们已经建立了数据,下面我们开始实现商业逻辑。在上面已经提到过,Java 6直接在JVM层直接支持脚本语言,我们可以使用Java 6支持的Mozilla's Rhino JavaScript脚本引擎,这是一个默认的脚本引擎。WebLEAF可以利用这个特性允许我们使用任何支持者脚本语言来实现商业逻辑。由于Groovy引擎并不直接支持Java 6,因此,为了使用Java 6的脚本功能,我们必须使用java.net工程,这个工程是一个支持不同语言的脚本引擎实现。
下面让我们先下载Groovy,在本例中,我们使用了Groovy 1.0,将groovy-all-1.0.jar放到lib目录中。然后我们从java.net脚本工程中下载jsr223-engines,解压,将groovy-engine.jar文件放lib中。
现在我们已经拥有所有的要求的库了,下面我们开始写代码。首先,我们在WEB-INF中建立一个scr目录,并在scr目录中建立一个Item.groovy文件,它的代码如:
现在我们已经拥有所有的要求的库了,下面我们开始写代码。首先,我们在WEB-INF中建立一个scr目录,并在scr目录中建立一个Item.groovy文件,它的代码如:
为了可以使用上面的Groovy脚本,我们需要编辑WebLEAF配置文件(Test.leaf.conf),并加一个XMLOPERATION来将这个脚本作为商业逻辑实现。加入这个操作后,系统将响应showitems.fm请求,配置文件的内容如下:import groovy.xml.MarkupBuilder
import groovy.sql.Sql
import java.util.*
![]()
def ShowAllItems(builder,sql)
...{
sql.eachRow(
"select * from TTST_ITEM",
...{
itemToXML(builder,it)
}
);
}
![]()
def showItem(builder,sql,codeItem)
...{
if(codeItem)
...{
item =
sql.firstRow("select * from TTST_ITEM where ITE_CODE = ?"
,[codeItem])
if(item)
...{
builder.ITEM_QUERY(Type:'Selected')...{
itemToXML(builder,item)
}
}
}
}
![]()
def itemToXML(builder, item)
...{
builder.ITEM( Code:item.ite_code,
Name:item.ite_name,
Description:item.ite_description
)
}
![]()
def show(param)
...{
def bundle = ResourceBundle.getBundle("webapp");
def sql = Sql.newInstance("jdbc:hsqldb:"
+ bundle.getString("db.location")
+ "/Test;shutdown=true;ifexists=true"
, "sa","", "org.hsqldb.jdbcDriver")
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
def groovy = xml.ITEM_QUERY(Type:'All')...{
ShowAllItems(xml,sql)
}
showItem(xml,sql,param.p_ite_code)
// Not efficient but it's just to prevent
// HSQLDB to block on the DB files
// when the servlet context is restarted
sql.execute("SHUTDOWN")
return writer.toString()
}
为了我们的应用程序可以处理以".fm"结尾的请求,我们还需要编辑web.xml文件,将这种请求加入到WebLEAF controller servlet中。也就是使用<servlet-mapping/>标签。web.xml的内容如下:<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE WADSET SYSTEM "http://www.uib.es/leaf/LEAFwad.dtd">
<WADSET>
<WAD
NAME="Test"
INIT_MODE="INITS_ON_START_UP"
XML_ALLOW_SHOW="TRUE"
XSLT_NO_CACHE="TRUE"
>
<OPERATIONSET>
<SUFFIX VALUE="fm"/>
<XMLOPERATION
NAME="showItems"
DESCRIPTION="Shows all the items and the selected one"
CLASSNAME="org.leaf.XMLOperation"
>
<SOURCES
GLOBAL_TAG="XML_APP"
>
<SOURCE XML_SOURCE="xml/Labels.xml"/>
<SOURCE XML_SOURCE="script://scr/Item.groovy/show?w_"/>
</SOURCES>
</XMLOPERATION>
</OPERATIONSET>
</WAD>
</WADSET>
![]()
我们还需要加一些标签,以备后面的view使用。我们通过向Test\WEB-INF\xml\Labels.xml中加以下内容达到这个目的:
![]()
<LABELS
Title="Test application"
>
<ITEM
Title="Item Management"
FieldSetLegend="Item data"
SelectDefault="... select an item to display its data"
Code="Code"
Name="Name"
Description="Description"
/>
</LABELS>
现在我们来对这个应用程序进行第一次测试。我们可以使用我们喜欢的servlet容器来发布这个程序(如tomcat等)。虽然我们可以使用任意的上下文名子进行发布,但为了方便起见,我建议读者使用"test"来作为上下文名子。对于一些流行的servlet容器,最快速的方法就是将这个程序复制到自动发布目录中(如tomcat的webapps目录)。<?xml version="1.0"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!--
Autoconfiguration servlet
-->
<servlet>
<servlet-name>AutoConfigurer</servlet-name>
<servlet-class>org.leaf.util.AutoConfigurer</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>FILE_NAME.1</param-name>
<param-value>WEB-INF/classes/webapp.properties</param-value>
</init-param>
<init-param>
<param-name>NODES_NAME.1</param-name>
<param-value>db.location</param-value>
</init-param>
<init-param>
<param-name>PATTERN.1</param-name>
<param-value>(.*)/WEB-INF/(.*)</param-value>
</init-param>
<init-param>
<param-name>FORMAT.1</param-name>
<param-value>{0}WEB-INF/{1}</param-value>
</init-param>
</servlet>
<!-- End Autoconfiguration servlet -->
<!--
WebLEAF controller servlet configuration
-->
<servlet>
<servlet-name>WebLEAFController</servlet-name>
<servlet-class>org.leaf.LEAFManager</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- End controller servlet -->
<servlet-mapping>
<servlet-name>WebLEAFController</servlet-name>
<url-pattern>*.fm</url-pattern>
</servlet-mapping>
</web-app>
现在让我们来启动servlet容器,然后在浏览器的地址栏中输入http://localhost:8080/test/showItems.fm(要注意的是,这个端口号一般是tomcat默认的,如果使用其他的servlet容器,请将这个端口号改成其它的)。然后在浏览器中的显示如图1所示:

0
相关文章