2-2-2.开发Java应用(Developing a Java App)

App Engine的Java网络应用使用了Java Servlet标准接口来和应用服务器交互。一个应用由一个或多个servlet类组成,每个都扩展了(extend)servlet基类。使用一个叫做部署描述(deployment descriptor)的标准配置文件,也就是web.xml,Servlets被映射到URLs。当App Engine接受到一个Java应用请求时,它会根据URL和部署描述来决定使用哪个servlet类,实例化这个类,然后调用servlet对象中的恰当的方法。

Java应用所有的文件,包括编译的Java类,配置文件,静态文件,用一个叫做Web Application Archive或”WAR“的标准目录结构来管理。在WAR目录中的所有东西都被部署到App Engine上。通常在你的开发工作流程中使用一个自动化构建过程或可识别WAR的开发工具根据一组源代码文件来构建WAR的内容。

如果你使用带有Google插件的Eclipse IDE,你可以使用Web Application向导来创建一个新项目。单击Google下拉按钮,然后选择New Web Application Project。(可选择的是,从File菜单选择New,然后是Web Application Project)在这个打开的窗体中,输入一个项目名(比如Clock)和一个包名(比如clock)。

不勾选“Use Google Web Toolkit"复选框,并确保“Use Google App Engine”复选框被勾选。(如果你让GWT复选框被选中,这个新项目将会用GWT启动文件创建。这是很酷的,但是它超出了本章的范围)图2-8显示了创建Clock应用的完成后的对话框。单击Finish来创建这个项目。

如果你不使用Google Plugin for Eclipse,你需要另外创建这个目录和文件。如果你已经对Java网络开发很熟悉,你可以使用你已有的工具和处理(tools and processes)来生成最终的WAR。这个小节的剩余部分,我们假定你使用由Eclipse插件创建的目录结构。

图2-9显示了这个项目文件的结构,在Eclipse包浏览窗口中被描述了。

这个项目的根路径(Clock)包含两个主要的子目录:src和war。src/目录包含项目所有的类文件,并使用了Java包结构。在clock包路径中,Eclipse在文件clock/ClockServlet.java中创建了一个叫做ClockServlet的Servlet类的源代码。

war/目录包含应用的完整的最终内容(the complete final contents)。Eclipse从src/自动编译源代码并将编译了的类文件放到war/WEB-INF/classes/目录,在Eclipse的包浏览窗口中默认是隐藏的。Eclipse也自动拷贝src/META-INF/的内容到war/WEB-INF/classes/META-INF中。其他的所有内容,比如CSS或JavaScript文件,必须在war/目录的预定位置中被创建。

让我们用一个简单的显示当前时间的Servlet开始我们的时钟应用。打开并编辑src/clock/ClockServlet.java文件(有必要的话,创建它),给它类似于例2-9的内容。

例2-9.一个简单的Java servlet

package clock;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;
import javax.servlet.http.*; @SuppressWarnings("serial")
public class ClockServlet extends HttpServlet{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws IOException{
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSSSSS");
fmt.setTimeZone(new SimpleTimeZone(0,"")); resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<p>The time is: " + fmt.format(new Date()) + "</p>");
}
}

这个servlet类继承自javax.servlet.http.HttpServlet,复写了它打算支持的HTTP 方法(overrides methods for each of the HTTP methods it intends to support.)。这个servlet复写了doGet()方法来处理HTTP GET请求。服务器用HttpServletRequest和HttpServletResponse对象作为参数来调用这个方法。这个HttpServletRequest包含请求的信息,比如URL,表单参数,和cookies。使用HttpServletResponse中方法,比如setContentType()和getWritter(),为响应做准备。当这个servlet方法退出时,App Engine发出响应。

为了告诉App Engine调用这个servlet来处理响应,我们需要一个部署解释器(development descriptor):一个描述哪些URLs调用哪些servlet类的XML配置文件,除了其他事情之外(among other things)。这个部署解释器是servlet标准的部分。打开或创建war/WEB-INF/web.xml文件,并添加类似例2-10的内容:

例2-10.web.xml文件,也就是所谓的部署解释器,将所有的URLs映射到ClockServlet。

<?xml version="1.0" encoding = "utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version = "2.5">
<servlet>
<servlet-name>clock</servlet-name>
<servlet-class>clock.ClockServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>clock</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

Eclipse可以在它的XML设计视图中打开这个文件,像表格一样显示元素和值。在编辑面板的底部选择Source tab来编辑XML源代码。

web.xml是一个根元素为<web-app>的XML文件。为了映射URL模式到servlets,你要用<servlet>元素声明每个servlet,然后用<servlet-mapping>元素声明映射。servlet映射的<url-pattarn>可以是一个完整的URL路径,或在开头或末尾有一个*来表示路径一部分的URL路径。在这个例子中,URL模式/仅仅匹配根URL路径。

※确保你的每一个<url-pattern>值以正斜杠开始。忽略这个开始斜杠在开发网络服务器上可能是正常的,但是在App Engine上表现出非预期的行为。

App Engine需要一个额外的配置文件,它不是servlet标准的一部分。打开或创建war/WEB-INF/appengine-web.xml文件,并添加类似例2-11的内容。

例2-11.appengine-web.xml文件,是Java应用的App Engine指定的配置。

<?xml version="1.0" encoding = "utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>clock</application>
<version>1</version>
<threadsafe>true</threadsafe>
</appengine-web-app>

在这个例子中,这个配置文件告诉App Engine这是clock应用的版本1。我们也声明应用是线程安全的,授权App Engine重复利用一个应用实例为多个同时的请求提供服务。(当然,这样做了之后,我们也必须确保我们的代码是线程安全的。)你也可以使用这个配置文件来控制其他的行为,比如静态文件和会话(sessions)。更多的信息,参见第3章。

应用的WAR必须包括一些来自App Engine SDK的JARs:Java EE实现JARs,和App Engine API JAR。Eclipse插件会自动安装这些JARs到WAR中。如果你不使用Eclipse插件,你必须手动拷贝这些JARs。查看SDK的目录lib/user和/lib/shared/subdirectories。从这些目录中拷贝每个.jar文件到你的项目的war/WEB-INF/lib/目录中。

最后,这个servlet类必须被编译。Eclipse按需自动编译你的所有类。如果你没有使用Eclipse,你大概想用一个编译工具,比如Apache Ant来编译源代码和执行其他的编译任务。查看官方App Engine的关于使用Apache Ant来编译App Engine项目的文档信息。

我认为解释如何在命令行中使用javac命令来编译Java项目是一个传统。你可以通过将war/WEB-INF/lib/和war/WEB-INF/classes目录下的每个JARs放到classpath下,并确保被编译的类(end up in the classes/ directory)最终处于classes/目录下。但是在真实世界中,你想要你的IDE或一个Ant脚本来为你照看这些事。

还有一件事,Eclipse用户要知道:Eclipse的新项目向导创建了叫做war/index.html的一个静态文件。在项目浏览窗口中通过在它上面右击,选择Delete,单击OK来删除。(如果你不删除它,这个静态文件会优先于我们刚刚创建的servlet映射)

是时候使用开发网络服务器来测试这个应用了。Eclipse插件可以在Eclipse调试器中运行这个应用和开发服务器。为了启动它,选择Run菜单,Debug As,Web Application。这个服务器启动,然后在控制台面板中输出下面的信息:

The server is  running at http://localhost:8888/

如果你使用的不是Eclipse,你可以使用dev_appserver命令启动开发服务器(对Mac OS x或Linux使用dev_appserver.sh)。这个命令将WAR目录路径作为参数,想这样(This command takes the path to the WAR directory as an argument,like so):

dev_appserver war

这个命令工具与Eclipse 插件相比,使用不同的默认端口(8080而不是8888)你可以使用命令行工具的--port argument改变这个端口,比如:--port=8888。

通过在浏览器中查看这个服务器URL来测试你的应用:

http://localhost:8888

浏览器显示类似Python例子的一个页面,在前面的图2-4中。

上一篇:iOS 沙盒路径获取,创建文件


下一篇:haploview画出所有SNP的LD关系图