近期遇到一个奇怪的需求,行车记录仪的后台需要可以根据地理区域对用户推送广告信息。这里的地理区域不同于市、省的划分,而是广告发布者在地图上选择的任意区域(中国境内),这意味着我们可以向大到城市、小到一个洗车行、停车场、快餐店等等小企业出租广告,并且可以根据用户选择的区域大小、区域竞争(比如商家买断某块区域中同类广告的投放权)进行阶梯收费。
功能描述:
商家或管理员在广告投放页面中选择任意形状的地理区域,当用户进入此广告区域时,商家投放的广告将通过后台服务器推送给用户。
功能难点:
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的使用将在下一篇博客中介绍。
至此,推送广告功能就做完了,其实不止推送广告模块,在关于车辆防盗的电子围栏功能中也可以使用,估计还能做得更好。