近期遇到一个奇怪的需求,行车记录仪的后台需要可以根据地理区域对用户推送广告信息。这里的地理区域不同于市、省的划分,而是广告发布者在地图上选择的任意区域(中国境内),这意味着我们可以向大到城市、小到一个洗车行、停车场、快餐店等等小企业出租广告,并且可以根据用户选择的区域大小、区域竞争(比如商家买断某块区域中同类广告的投放权)进行阶梯收费。
功能描述:
商家或管理员在广告投放页面中选择任意形状的地理区域,当用户进入此广告区域时,商家投放的广告将通过后台服务器推送给用户。
功能难点:
1.在页面中模拟用户选择区域范围
2.如何判断GPS中的经纬度是否在地图上的广告区域中
实现过程:
1.使用百度地图完成该功能
2.在广告投放页面中使用百度地图完成区域选择和获取地理位置点
3.将用户选择的区域地理位置点上传到后台并保存至数据库中
3.结合行车记录仪每3分钟上传一次行车轨迹,取轨迹记录中的一个经纬度
4.将轨迹记录的经纬度和数据库中的区域位置点进行比较,判断该经纬度是否在区域中
5.如果在广告区域中,服务器将广告信息推送给行车记录仪
实现效果:
用户选择地理区域看起来是这样的:
代码:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE>
<html>
<head>
<base href="<%=basePath%>">
<title>信息发布</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
<script type="text/javascript" src="style/jquery-1.10.2.js"></script>
</head>
<body>
<div style="width:100%;height:480px;border:1px solid gray" id="container"></div>
<p>
<input id="startBtn" type="button" onclick="startTool();" value="开始选取区域" />
<input type="button" onclick="map.clearOverlays();points=[];closeMark=0;document.getElementById('polygonArea').value='';" value="清除" />
<input type="hidden" id="polygonArea" value="" />
<hr>
<table>
<tr>
<td>发布IDAAD信息:</td>
<td><textarea name="message" id="message" clos="30" rows="7" style="height: 100%; width: 500px;
background-attachment: fixed; background-repeat: no-repeat; border-style: solid;
border-color: red";overflow-y:hidden;overflow-x:hidden;border:1;></textarea>
</td>
</tr>
<tr>
<td></td>
<td>
         
         
<label><input name="mesType" type="radio" value="0" />推送信息</label>
<label><input name="mesType" type="radio" value="1" checked />广告信息</label>
</td>
</tr>
<tr>
<td></td>
<td>
         
         
         
         
        
<input type="button" value="    发布信息    " onclick="message()" />
</td>
</tr>
</table>
<hr>
</body>
</html>
<script type="text/javascript">
var map = new BMap.Map("container");
map.centerAndZoom("深圳", 12);
map.enableScrollWheelZoom();
var key = 1;
var newpoint;
var points = [];
var polyline = new BMap.Polyline();
var polygon;
var closeMark = 0;
var dataPool = "";
function startTool(){
if(key==1){
document.getElementById("startBtn").style.background = "green";
document.getElementById("startBtn").style.color = "white";
document.getElementById("startBtn").value = "开启状态";
key=0;
} else{
document.getElementById("startBtn").style.background = "red";
document.getElementById("startBtn").value = "关闭状态";
key=1;
}
}
map.addEventListener("click",function(e){
if(closeMark == 1){
alert("已经闭合选择区域,请清除后重新选择!");
return false;
}
newpoint = new BMap.Point(e.point.lng,e.point.lat);
if(key==0){
var markerhead = new BMap.Marker(newpoint);
map.addOverlay(markerhead);
points.push(newpoint);
polyline.setPath(points);
map.addOverlay(polyline);
dataPool+=e.point.lng + "," + e.point.lat + "|";
}
});
map.addEventListener("dblclick",function(e){
if(key==0){
closeMark = 1;
map.disableDoubleClickZoom();
polygon = new BMap.Polygon(points);
map.addOverlay(polygon);
var polygonArea=document.getElementById("polygonArea");
polygonArea.value = dataPool;
}
});
function submitFun(){
if(key == 1){
alert("您还没有选择区域!");
return false;
}
if(closeMark == 0){
alert("开始提交");
}else{
alert("您选择的区域没有闭合,请双击闭合!");
}
}
function message(){
var message=document.getElementById("message").value.trim();
var mesTypes=document.getElementsByName("mesType");
var polygonArea=document.getElementById("polygonArea").value.trim();
var mesType="";
if(key == 1){
alert("您还没有选择区域!");
return false;
}
if(closeMark == 0){
alert("您选择的区域没有闭合,请双击闭合!");
return false;
}
if ( polygonArea.length < 1 ) {
alert("请选择区域");
return false;
};
if ( message.length < 1 ) {
alert("message不能为空");
document.getElementById("message").focus();
return false;
};
for(var i=0;i<mesTypes.length;i++){
if(mesTypes[i].checked){
//alert(mesTypes[i].value);
mesType = mesTypes[i].value;
break;
}
}
if ( mesType.length < 1 ) {
alert("请选择消息类型!");
return false;
};
$.ajax({
url:'message',
type:'GET',
data:"UserLmessage="+message+"&mesType="+mesType+"&polygonArea="+polygonArea,
success:function(data){
if(data=="OK"){
alert("发布成功!");
}else{
alert("发布失败!");
}
}
});
}
</script>
功能中的最难点,就是判断一个经纬度是否在广告投放的区域中。百度地图、高德地图只在javascriptAPI和AndroidSDK中提供了接口,所以如何判断成功了最大的难点,我想到的折中方法是在html页面中使用javascriptAPI中的接口进行判断,然后将判断结果回传到服务器中。
javascriptAPI代码:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>行政区域工具</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
String.prototype.getQueryString = function(name)
{
var reg = new RegExp("(^|&|\\?)"+ name +"=([^&]*)(&|$)"), r;
if (r=this.match(reg)) return unescape(r[2]); return null;
};
var polygonArea = location.search.getQueryString("polygonArea");
var carPoiont = location.search.getQueryString("carPoiont");
stringJudge(polygonArea,carPoiont);
function stringJudge(polygonArea,carPoiont){
var points=[];
var dps = polygonArea.split("|");
for(var i=0;i<dps.length-1;i++){
var dpArr = dps[i].split(",");
var newpoint = new BMap.Point(dpArr[0],dpArr[1]);
points.push(newpoint);
}
var ply = new BMap.Polygon(points);
var carPoionts = carPoiont.split(",");
var pt =new BMap.Point(carPoionts[0],carPoionts[1]);
var result = BMapLib.GeoUtils.isPointInPolygon(pt, ply);
if(result == true){
sentGeoResult(polygonArea,"YES");
}else{
}
}
function sentGeoResult(polygonArea,areaRangeMark){
$.ajax({
type: "GET",
url: "GeoResult?date="+new Date().getTime(),
data: {areaRangeMark:areaRangeMark,polygonArea:polygonArea},
success:function(data){
}
});
}
</script>
</head>
</html>
javascriptAPI很好的解决了这个难题,接下来如何在action中调用html页面,使之执行javascript代码并返回结果让我想了好久,使用了很多种方法还是无法重新调起执行,每一次都是将html页面获取过来,导致进度停滞了一天,今天终于让我找到了方法,嘿嘿~~~
使用htmlunit完美的解决了这个问题,灵感来自于网络爬虫,htmlunit能够将网页读取出来,执行完网页的代码并返回结果。
htmlunit代码:
public static void AreaJud(String url) throws Exception {
final WebClient webClient = new WebClient();
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.getPage(url);
}
仅仅三行代码就解决了,当然htmlunit不止这点功能,使用htmlunit来做这个完全是大材小用,关于htmlunit的使用将在下一篇博客中介绍。
至此,推送广告功能就做完了,其实不止推送广告模块,在关于车辆防盗的电子围栏功能中也可以使用,估计还能做得更好。