双向交流
在上面的代码示例中,网络链接需要等待我们的刷新操作。幸运的是,我们可以让Google Earth以get方法定期地发送View窗口中用户的位置,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.0"> <Folder> <description>Examples of bi directional flow of information</description> <name>Network Links</name> <visibility>1</visibility> <open>1</open> <NetworkLink> <description>Lets send coordinates once in a while</description> <name>Message Pushing</name> <visibility>1</visibility> <open>1</open> <refreshVisibility>1</refreshVisibility> <flyToView>0</flyToView> <Url> <href>http://localhost:8081/Tour/message</href> <refreshInverval>2</refreshInverval> <viewRefreshMode>onStop</viewRefreshMode> <viewRefreshTime>1</viewRefreshTime> </Url> </NetworkLink> </Folder> </kml> |
实际的动作由Url实体完成。viewRefreshTime标签定义了经过多少秒服务器接收下一套Earth坐标,viewRefreshMode标签设置为onStop就意味着当停止在View窗口里移动时更新Earth坐标。图4是上述配置最终效果的一个截图。
图4 网络链接和关联HTML的GUI显示
好了,我们可以把那些讨厌的坐标发给服务器了。我们可以用它来做什么呢?让我们从创建一个消息服务开始。图5给出了两个流程。
图5 Google Earth、servlet和浏览器之间的信息流
首先,通过浏览器发送消息并接收坐标:
1. 浏览器以post方法发送参数名和消息
2. serlet以类似于以下形式的文本消息返回从Google Earth客户端收到的最后坐标:
Location: -0.134539,51.497,-0.117855,51.5034 IP address: 127.0.0.1 Updated: Fri Oct 21 11:42:45 CEST 2005
其次,在servlet与Google Earth客户端之间传递坐标并接收位置(placement):
1. 每经过ΔT时间,Google Earth通过get方法发送用户在View窗口中的坐标。
2. servlet把消息放在placement中返回,placement通过坐标来粗略计算在何处放置返回的消息。请注意我已从KML教程中将对中算法拷贝过来。
返回生成的位置(placement)类似于下面的KML:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.0"> <Placemark> <name><![CDATA[<font color="red">Alan Berg</font>]]></name>\ <description><![CDATA[BLAH BLAH <i> Fri Oct 21 11:42:45 CEST 2005</i>]]> </description> <Point> <coordinates>4.889999,52.369998,0</coordinates> </Point> </Placemark> </kml> |
以下就是构成这一协奏乐章的servlet代码:
MessageServlet.java package test.google.earth.servlet;
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.*;
import test.google.earth.bean.LastLocationBean; import test.google.earth.bean.LastMessageBean;
import java.util.Date;
public class MessageServlet extends HttpServlet { private static LastMessageBean lastMessage=new LastMessageBean(); private static LastLocationBean lastLocation= new LastLocationBean();
public void init(ServletConfig config) throws ServletException { super.init(config); lastMessage.setMessage("No message Yet"); lastMessage.setName("System"); lastMessage.setUpdated(new Date()); lastLocation.setCoords("No contact with a client yet"); lastLocation.setIpAddress(""); lastLocation.setUpdated(new Date()); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String coords = request.getParameter("BBOX"); if (coords==null){ return; }
String message; String name; Date lastDate; String ipAddress = request.getRemoteAddr();
synchronized(this) { lastLocation.setCoords(coords); lastLocation.setIpAddress(ipAddress); lastLocation.setUpdated(new Date()); message=lastMessage.getMessage(); name=lastMessage.getName(); lastDate=lastMessage.getUpdated(); }
response.setContentType("application/keyhole"); PrintWriter out = response.getWriter(); String[] coParts= coords.split(","); float userlon; float userlat; try{ userlon = ((Float.parseFloat(coParts[2]) - Float.parseFloat(coParts[0]))/2)+ Float.parseFloat(coParts[0]); userlat = ((Float.parseFloat(coParts[3]) - Float.parseFloat(coParts[1]))/2) + Float.parseFloat(coParts[1]); }catch(NumberFormatException e){ return; }
String klmString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n" + "<Placemark>\n" + "<name><![CDATA[<font color=\"red\">"+name+"</font>]]></name>\n"
+"<description><![CDATA["+message+"<br><i>"+lastDate+"</i>]]></description>\n" + "<Point>\n" + "<coordinates>"+userlon+","+userlat+",0</coordinates>\n" + "</Point>\n" + "</Placemark>\n" + "</kml>\n"; out.println(klmString); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); if (name==null){ return; } String message; PrintWriter out;
synchronized(this) { lastMessage.setMessage(request.getParameter("message")); lastMessage.setName(name); lastMessage.setUpdated(new Date()); message="<pre>\nLocation: "+lastLocation.getCoords()+ "\nIP address: "+lastLocation.getIpAddress()+ "\nUpdated: "+lastLocation.getUpdated(); }
response.setContentType("text/html"); out = response.getWriter(); out.println(message); } }
|
来自浏览器的消息保存在静态成员LastMessageBean中,坐标保存在LastLocationBean中,且每个bean都只有一个实例。此外,在执行getting或setting操作时对所有的静态bean都进行同步。我们用单个实例来达到简化的目的,有助于限制要编写的代码数量。然而,更有实用价值的示例应具备跟踪IP地址的会话管理功能并生成相应的处理结果。
有一个不起眼的错误,在placement实体的名字标签里使用HTML标签会导致显示问题:整个标签在Google Earth客户端的“places”菜单区按HTML显示,但在View窗口里却按文本显示。我认为这种不一致是个bug。
在本示例中Google Earth客户端推送坐标,servlet返回KML代码段。既然知道能用坐标推送上下文关联信息,我们可以强制通过段中的链接来进行交互,必要的话还可以让浏览器成为宿主。本文展示了如何控制Google Earth客户端,至此你已拥有了一个创建自己互动旅程的概念性工具箱。
-- 原文链接: http://dev.yesky.com/195/2293695_2.shtml
共3页: 上一页 [1] [2] 3 下一页
|