在Google App Engine中使用Struts2框架
"GAE"(GoogleAppEngine)在早些时候发布了Java语言的支持,对广大的Java开发者来说,可以使用自己熟悉的语法来进行开发
,是很舒服的一件事情。Java世界中有大量已有的工具和框架,有一些是我们日常工作中就已经熟练使用的、而且广为流行的成熟
的,如果能够直接在GAE中使用,将大大提高我们的开发效率。
这几天利用Struts2,在GAE的Java版本支持环境中,写了个简单博客,现在将GAE+Struts2的组合经验,记录下来。
背景介绍
Python是一门有趣的语言,是作者第二个接触的动态脚本语言。第一个是大学时期做学生网站时期接触到Perl,后来工作后利
用Perl改写了公司的应用程序启动框架;几年后,由于Perl的语法实在是太过于羞涩难懂,便使用Python对启动框架进行了一次升
级。Python是面向对象的,同时也兼备了函数式编程的支持,另外,Python的语法强制缩进,非常容易读懂,因此Python版本的启
动框架对公司的Java开发者来说,也不难维护。
当然,这些都是题外话,GAE最先提供的是Python语言的支持,但是对我们Java开发者来说,要使用Python来进行大的应用开发
,还比较痛苦的一件事情。这时候GAE推出Java语言的支持,既是所有Java开发人员的福音,也是理所当然的一件事情,Google不可
能放弃目前企业应用开发领域里面最大的一股力量。
Struts2是目前应用最广泛的WEB开发框架,也是大部分的Java开发者最熟悉的开发框架,我们的GAE应用程序中,使用成熟的
Struts2可以减少很多额外的开发工作。
所需的Struts的库文件
目前Struts2的稳定版本是2.1.6,将下面的来自Struts-2.1.6的发行包的几个包,引入你的GAE项目工程中:
commons-fileupload-1.2.1.jareqpg2009-9-812:05
commons-io-1.3.2.jar
commons-logging-1.0.4.jar
commons-logging-api-1.1.jar
freemarker-2.3.13.jar
ognl-2.6.11.jar
struts2-core-2.1.6.jar
xwork-2.1.2.jar
如果你使用IDEA来创建项目,只要选择Struts的2.1.6版本的支持,IDEA会自动帮你引入所需要的库文件。
为AppEngine定制你的Struts
GAE里面的Servlet环境有一定的限制,不能使用线程(Thread),不能使用文件,还有别的一些要注意的地方。
首先,要加一个ServletContextListener的实现,在context初始化的时候,调用OgnlRuntime.setSecurityManager(null),让
Struts可以在GAE环境里面正常跑起来:
package your.servlet.pkg;
import ognl.OgnlRuntime;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class StrutsAppEngineAdapter implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
OgnlRuntime.setSecurityManager(null);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
在web.xml中配置这个ServletContextListener的实例:
<web-app>
<listener>
<listener-class>your.servlet.pkg.StrutsAppEngineAdapter</listener-class>
</listener>
</web-app> eqpg2009-9-812:06
做完上面的工作之后,就可以在你的GAE里面使用Struts的功能了!
定制GAE的常用对象的Converter
Struts提供了Converter的机制,让你常用的业务对象可以直接在页面中显示,或者接受类型为业务对象的请求数据。GAE里面
常用的一些对象,定义了对应的Converter之后,可以是业务代码更加简洁。下面介绍两个常用对象的Converter的代码:
TextConverter,是针对com.google.appengine.api.datastore.Text对象的转换器,Text是GAE的存储中,大文本内容的保存对
象,在业务中很常用。先来看看TextConverter大的代码:
package your.servlet.pkg;
import com.google.appengine.api.datastore.Text;
import ognl.DefaultTypeConverter;
import java.util.Map;
public class TextConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Map map, Object o, Class toType) {
if (toType == Text.class) {
String value = ((String[]) o)[0];
return new Text(value);
} else if (toType == String.class) {
Text text = (Text) o;
return text.getValue();
}
return null;
}
}
TextConverter的作用主要是用于在WEB页面中,直接显示存储对象中的大文本内容。
另外一个是KeyConverter,是对com.google.appengine.api.datastore.Key对象的转换器,Key是GAE中三种主键(Long,
String,Key)的一种,在接收请求数据以及页面显示的时候,会经常用到。直接看代码:eqpg2009-9-812:06
package your.servlet.pkg;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import ognl.DefaultTypeConverter;
import java.util.Map;
public class KeyConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Map map, Object o, Class toType) {
if (toType == Key.class) {
String s = ((String[]) o)[0];
return KeyFactory.stringToKey(s);
} else if (toType == String.class) {
Key k = (Key) o;
return KeyFactory.keyToString(k);
}
return null;
}
}
在源代码的根目录,创建xwork-conversion.properties文件,内容如下:
com.google.appengine.api.datastore.Text=your.servlet.pkg.TextConverter
com.google.appengine.api.datastore.Key=your.servlet.pkg.KeyConverter
上面的工作都完成以后,就可以在你的Action里面直接使用Key类型的类变量,无需手工去做String和Key之间的转换!
ConventionPlugin不能使用
Struts2里面,最常用的Plugin应该是Convertion了,"零配置"即减少了写配置文件的麻烦,代码的组织结构看起来也清晰很多
。
但是在GAE里面,无法读取文件系统,目前的Convertion版本还无法正常工作,非常可惜。不过建议你的GAE应用中,Action和
JSP文件,还是按照ConvertionPlugin的组织方式来存放,一方面有利于后面的升级和迁移工作,另一方面也让你的应用的文件看
起来更清晰。