/***棒棒唐****/
package MapserverServlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import edu.umn.gis.mapscript.*;
class MapServlet
{
/*
1、定义一个出图参数对象。
2、定义mapObj对象,属于全局级别(application),所有的Seesion都共用该对象。
###############################################################################################
两种方案:
1)、先前考虑过如果每个Seesion一个mapObj的话,mapObj的状态就不用管了,它自己会维护出图状态
而且能保证前一次出图和后一次出图的连续性。但是如果每个Seesion一个mapObj的话,并发量上
很受限制,内存都不够用。
不过,这样一个session一个mapObj有这样一个好处,每个session可以做自己的专题图,做自己的分析
:路径分析、缓冲分析等所产生的辅助线(多边形,点),而其他session不受一点影响。如果这样的话
缓存又不好实现。
当新的一个session产生时,调用mapObj的cloneMap很容易实现为该session生成一个mapObj,效率比
new要高多了。
2)、如果所有的session共用一个mapOjet的话,在并发量上,应该是没有什么问题,但是在控制每个session
出图的状态就比较复杂了(因为要考虑到前一次出图和后一次出图的连续性),需要把所有的出图参数,
根据相应的地图操作都执行一遍,如果管理不好的话,很容易回到最初状态,这个开销上是需要花时间的。
管理好出图参数是关键。有了出图参数,比较容易建立缓存。如果动态做专题图的话,这个状态的跟踪就
比较麻烦。(需要把每个图层的class信息在每个session中存储下来。)其实就是把每个layerObj复制一份cloneLayer
,在MapParam中,需要定义一个layerObj数组,这样每个Session都有一个自己的layerObj数组,在使用时候
把layerObj数组赋值给mapObj,但是mapOjet并没有getLayer这个方法,先需要removeLayer,然后需要一个一个地insertLayer,把layerObj添加到mapObj中,
这个过程不知道消耗的资源跟每个session一个mapObj消耗的资源差不多。
缓存对于这种个人行为比较多的操作,起的作用不大,估计不采用缓存,效果估计还好一些。
需要仔细权衡这量中思路。每种方案都自己的好处,如果做一个仅仅是看看的地图,那么采用第二种方式比较好(不需要在seesion中存储layerObj数组)。如果所进行的地图操作对于每个人来说都是很特别的
也就是说公共的东西比较少,采用第一种方式比较好,来得方便实在也容易实现。
基本上对于每个session,servlet都会给它开一个线程。
#################################################################################################
3)、如果采用缓存技术的话,需要考虑到线程同步性
hashtable是线程同步的而hashMap不是,尽量采用hashtable,可以省略自己关系线程安全的烦恼。
4)、对于一个mapfile,可以考虑用一个hashtable,也可以所有的mapfile共有一个hashtable做缓存
关键是看出图参数怎么定义咯。
原则上来将一个mapfile需要一个mapObj,当然也可以所有的mapfile共用一个mapobj,但是这样不好
线程的同步性不易控制,需要先关闭了,然后在new一个mapObj.
咱们原则上是为每个mapfile生成一个mapObj。方便控制与管理。
5)、在本MapServlet中,咱们只考虑一个mapfile,如果是多个mapflie的话,咱们就用多
个MapServlet来与之对应吧。在web.xml中设定就可以了。
*/
public void init() throws ServletException
{
//读取配置文件,根据配置文件找到mapfile,以及output目录
mapfile="D:/SuperMap/SuperMapISJava/thirdparty/tomcat/webapps/mapserver/tutorial.map";
outputDir="output/";
//构造一个默认的出图参数对象
/*
1、读取配置文件,根据配置文件找到mapfile,以及output目录
2、构造一个默认的出图参数对象MapParam
3、构造一个mapObj对象
4、定义一个hashtable,用MapParam作为key,用出图的图片名作为value,用于缓存。
hashtable是同步的,比hashMap相对要安全一些。
5、高级:
1)、采用一种策略管理hashtable表,不然内存就有可能耗光哦,
一般可以通过建立一个守候线程(进程)来实现。锁是关键
*/
}
public void destroy()
{
/*
1、hashtable清空
2、mapObj对象清理资源
*/
}
public void service(HttpServletRequest request,
HttpServletResponse response) throws
ServletException, IOException
{
//保证一个session一个地图对象(如果用地图出图参数对象节约的内存可能会更少一些,
//如果有出图参数对象,缓存实现起来也比较容易。
//这样地图对象的状态得以恢复
/*
1、先从Session里读取出图参数对象MapParam,如果有则使用该出图参数对象,如果没有则从
默认的出图对象clone一个。
2、读取request传进来的地图命令以及参数。并修改MapParam对象,只修改改变的成员变量。
3、根据MapParam对象出图。
判断是否使用了缓存,如果MapParam是一样的,就把放在hashtable中的图片名称返回。
否则,根据MapParam对象出图:其实就是根据request传进来的地图命令进行地图操作
最后,要根据MapParam执行一遍(主要是extent、图层显示状态、trackingLayer),最后
再出图。 drawQuery(mapObj map, imageObj image)
draw(mapObj map, imageObj image)
这两个都需要按顺序执行一遍,不然查询的状态就保存不下来了。
1)* 这个MapParam一定要做到冗余度最小,以免进行不必要的操作。
1)地图出图范围是最重要的。
2)地图的图层状态(是否可视)
3)trackingLayer,必须要这么一个图层哦,可以在该图层上绘制当前会话的一些临时操作结果
比如:缓冲分析是,所选中的featrue、以及缓冲的轮廓(比如点缓冲是一个圆)等辅助线(多边形)
距离量算所画的折线,以及面积量算所画的多边形或者圆等
查询时候,查询结果的高亮显示(就是就是在trackingLayer把选中的featrue再绘制了
一遍)
由于Mapserver没有trackingLayer这个说法,我们可以这样做:为每个session生成一个layerObj
对象,把需要绘制的featrue,通过addFeature(shapeObj shape)添加到该layerobj上 ,别忘记了
增加一个class哦,不然就绘制不出来
再设置这个class的style等。
不过也可以把距离,面积量算时,所绘制的线放到客户端以javascript来实现,其实想距离面积的量算
完全可以放在客户端来实现(关键是把地理范围用Ajax技术传输到客户端。)
2)*对于其他图层的编辑,就不需要每个seesion单独存储了,所有的session共用一个,但是必须处理
锁的问题。(数据如果是在数据库中,就不需要考虑加锁的问题,数据库中的锁有行锁、表锁、
列锁), 但是如果编辑的是一个shp文件或mif文件,就必须考虑加锁的问题。(现在不知道在Mapserver中
是否已经处理好了这个锁的问题。是不是线程安全的?)
在java中可以用synchronized来实现多线程的加锁问题(servlet是用多线程来处理每个session的),也可以自己来实现锁(标记,数据),在修改数据前,先查看标记看是否有其他线
程在修改数据,这个标记起它一个锁的作用。
加锁,需要考虑操作的原子性,在修改数据前,注意保存数据的前景,等修改完全成功了,才把数据前景给删除,否则需要回滚
4、根据request决定是否生成图例与比例尺
(也可以考虑是否采用缓存哦)
5、输出的XML字符串大致包括如下内容。
1)、图片的URL、Extent以及图片的高度宽度
2)、图例的URL、以及图片的高度宽度
3)、比例尺的URL、以及图片的高度宽度
6、客户端request请求的图片包括RUL和图片的地理范围等,服务器端只需要传送客户需要的图片,然后在
客户端进行拼接(对小图块)(这叫做在客户端缓存,仅仅传输需要的图块,节省网宽流量)
*/
}
}