本文源代码下载地址:
http://flashview.ddvip.com/2009_04/source.zip
上一节课,我们讲了如何配置开发环境,包括客房端flex开发环境,以及服务端java开发环境,并且编写了一个客房端示例程序helloworld,但遗憾的是,目前这一个helloworld不是动态的。如果客户端不能与服务端进行数据交互,那么我感觉我的flex还没有真正入门。
一,Google App项目目录结构及配置说明
我审视了一下eclipse为我创建的gapp_flexblog项目,它包括以下目录结构:
Guestbook/
src/
…Java source code…
META-INF/
…other configuration…
war/
…JSPs, images, data files…
WEB-INF/
…app configuration…
lib/
…JARs for libraries…
classes/
…compiled classes…
1,src下有我提定的sban.flexblog命名空间目录,有一些*.java文件,看样子这里是存放源文件的。从名称也可以看出。
2,src/META-INF/jdoconfig.xml是jdo配置文件,暂时还用不到它。
3,war是java web应用程序的一种标准打包格式,Google App Engine采用这种通用格式将应用程序布署到容器中。
3.1,war/lib目录下放置jar文件。jar是Java Archive File的缩写,是一种java文档,是编译之后类库集合。flex library project编译之后产生的swc文件,与此相仿
3.2,war/WEB-INF用于放置一些配置文件。web.xml是web应用配置文件,用于定义Servlet与url的映射,主页列表,过 滤器与安全约束条件等。
在web.xml中,以下片段用于定义一个servlet name到一个servlet class的映射:
<servlet>
<servlet-name>helloWorld</servlet-name>
<servlet-class>sban.flexblog.server.HelloWorldServlet</servlet-class>
</servlet>
而此时,如果我们再定义一个url到该servlet name的映射,访问这个url,控制权便交由sban.flexblog.server.HelloWorldServlet处理:
<servlet>
<servlet-name>helloWorld</servlet-name>
<url-pattern>/gapp_flexblog/hello</url-pattern>
</servlet>
思考问题1:如果我们直接定义一个url到servlet class的映射,是否也可以?
二,动态的hello world应用
在sban.flexblog.server下新建一个HelloWorldServlet类,代码如下:
package sban.flexblog.server;
import java.io.IOException;
import javax.servlet.http.*;
public class HelloWorldServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException
{
String[] name = req.getParameterValues("name");
resp.setContentType("text/plain");
resp.getWriter().println("Hi " + name[0] + ",Hello, world.");
}
}
这个类继承于HttpServlet,覆盖doGet方法,用于处理http get请求。让它处理来自于/gapp_flexblog/hello的url,在web.xml添加如下配置片段:
<servlet>
<servlet-name>helloWorld</servlet-name>
<servlet-class>sban.flexblog.server.HelloWorldServlet</servlet-class>
</servlet>
…
<servlet-mapping>
<servlet-name>helloWorld</servlet-name>
<url-pattern>/gapp_flexblog/hello</url-pattern>
</servlet-mapping>
启动gapp_flexblog项目,我们web server运行正常:
curl http://localhost:8080/gapp_flexblog/hello?name=sban
返回的结果如下:
现在我们要用flex来调用Servlet,在gapp_flexblog_client下,修改Index.mxml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<FxApplication xmlns="http://ns.adobe.com/mxml/2009">
<Script>
<![CDATA[
import mx.controls.Alert;
import flash.net.URLLoader;
import flash.net.URLRequest;
private function greet() : void
{
new URLLoader( new URLRequest("http://localhost:8080/gapp_flexblog/hello?name=" + vNameTxt.text) )
.addEventListener(Event.COMPLETE,
function(event : Event) : void
{
Alert.show(event.currentTarget.data);
vSendBtn.enabled = true;
}
);
vSendBtn.enabled = false;
}
]]>
</Script>
<HGroup>
<FxTextInput id="vNameTxt" text="sban" />
<FxButton id="vSendBtn" label="greet" click="greet()" />
</HGroup>
</FxApplication>我用URLLoader向服务端发起一个http get请求,参数为name,并对URLLoader注册了一个事件监听,监测其complete事件,该事件发生在请求返回数据之后,而URLloader的data属性记录了返回结果。URLLoader在实例化时,如果发现已有URLRequest做为构造参数传入,它会自动调用load方法,故而此处无须再显式调用load方法。
思考问题2:如果在Index.mxml中,请求的代码,写成如下模样,又当如何:
var request : URLRequest = new URLRequest("http://localhost:8080/gapp_flexblog/hello");
request.method = URLRequestMethod.POST;
request.data = new URLVariables("name=sban");
区别在于第二种写法使用的是http post请求。
运行flex客户端,效果如下:
为了验证思考问题1,我修改了web.xml文件,让/gapp_flexblog/hello直接映射到sban.flexblog.server.HelloWorldServlet,部分代码如下:
<servlet-mapping>
<servlet-name>sban.flexblog.server.HelloWorldServlet</servlet-name>
<url-pattern>/gapp_flexblog/hello</url-pattern>
</servlet-mapping>
运行,Oh My God!报出了No such Servlet错误。看来定义从url到servlet的映射时,必须要有servlet name做为中间人。
为了验证思考问题2,我修改了Index.mxml代码,用post方法发出请求,报出了error。error信息不再粘出,阅者可自行测试。而如果我在HelloWorldServlet中覆盖了doPost方法后,便可以了。
flex与server通讯,http并不是最好的选择。amf相对http协议有更高的通
讯效率。下一课我计划学习一下如何用remoting与server通讯。