单车定位
数据
单车日志数据
这个数据是单车用户使用的后台记录数据,主要是开锁,保修等日志记录。字段说明如下:
- 触发事件
- 访问的url
- 时间
- 用户的id
- 经度
- 维度
- 省份
- 城市
- 区(县)
原始数据如下所示:
{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:14","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}
{"event_type":0,"page":"/pages/recharge/recharge","money":"100","channel":"wx","time":"2018-03-14 12:35:18","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}
{"page":"/pages/index/index","event_type":1,"time":"2018-03-14 12:35:22","uid":"oF-8j0aNka8IQYCZsxyrO6X7jzqY","longitude":112.12255,"latitude":32.009,"province":"湖北省","city":"襄阳市","district":"襄城区"}
{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:20","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}
位置信息数据
位置信息数据主要是北京的经纬度对应的位置信息数据,存储形式是csv(csv是以逗号分隔的文本数据)
字段的说明都在文件的一行,文件的第一行是表头,即文件字段的名字。
文件样例数据为:
项目说明
需求
单车位置信息太宽泛了,希望能够得到更为精准的地理位置信息。
依赖说明
<!-- json解析工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- geohash -->
<dependency>
<groupId>ch.hsr</groupId>
<artifactId>geohash</artifactId>
<version>1.3.0</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
项目原理图
geoHash原理介绍
geoHash算法是将经纬度信息的二维数据转换成为一维数据的一种算法,主要使用的是逼近思想,具体的说明可以进群看更为详细的文档。
geoHash算法使用测试
package cn.pengpeng.day03.test;
import ch.hsr.geohash.GeoHash;
/**
* 测试geohash
* @author pengpeng
*/
public class TestGeoHash {
public static void main(String[] args) {
String geohash = GeoHash.withCharacterPrecision(45.767525, 126.67032, 8).toBase32();
System.out.println(geohash);
}
}
httpClient使用说明
HttpClient是用来模拟浏览器上网请求数据的工具,
可以通过url进行网络访问从而获取所需要的数据。
HttpClient的使用如下说明:
package cn.pengpeng.day03.test;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
public class TestHttpClient {
public static void main(String[] args) throws Exception {
String uri = "这里可以填入需要访问的url";
//可以类似于浏览器对象
HttpClient httpClient = new HttpClient();
//uri 资源统一定位 url也是uri的一种
HttpMethod method = new GetMethod(uri);
//执行,类似于浏览器访问指定的网址
httpClient.executeMethod(method);
//返回结果
String ret = method.getResponseBodyAsString();
System.out.println(ret);
}
}
百度地图接口调用说明
这里面有些数据本地仓库是没有收录的,所以需要从网络中获取,所以需要从百度地图上获取,(这里可以使用其他的地图来获取,只需要看下其他的地图的接口是怎么使用的。)
百度地图提供很多的地图开发方式,以及接入方式,本地使用的是百度的web接口api提供的逆地理位置接口(根据经纬度查出相对应的地址信息)。这里需要注册下,申请开发者的key。
具体的接入方式,以及key的使用方式都在百度网站上有详细的说明,传入的参数,以及返回参数的说明都很详细。
百度web服务接口
开发流程
工具类
这里面实现了经纬度转化为一维数据的操作,和通过url来总网络上获取具体位置信息的数据。
package cn.pengpeng.day03.util;
import java.io.IOException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import ch.hsr.geohash.GeoHash;
public class Util {
public static void main(String[] args) {
String json = getAddrJsonByNet(126.67032, 45.767525);
System.out.println(json);
}
/**
* 经纬信息,转换成geohash
* @param longitude
* @param latitude
*/
public static String getGeoHash(double longitude, double latitude) {
String ret = GeoHash.withCharacterPrecision(latitude, longitude, 8).toBase32();
return ret;
}
/**
* 通过经纬度信息获取到返回的json数据
* @param longitude 经度
* @param latitude 维度
* @return geohash值
*/
public static String getAddrJsonByNet(double longitude, double latitude){
String uri = "http://api.map.baidu.com/geocoder/v2/?callback=renderReverse&location="+latitude+","+longitude+"&output=json&pois=1&ak=eZ9AW83ni3SKy34ypAEoQLqU1tov7Un1";
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(uri);
try {
client.executeMethod(method);
String ret = method.getResponseBodyAsString();
String substring = ret.substring("renderReverse && renderReverse(".length()-2, ret.length()-1);
return substring;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
使用到的JavaBean
封装单车数据
package cn.pengpeng.day03.bean;
/**
* 单车日志信息封装
* @author pengpeng
*/
public class BikeBean {
//{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:14",
//"uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省",
//"city":"哈尔滨市","district":"南岗区"}
private int event_type;
private String page;
private String time;
private String uid;
private double longitude;
private double latitude;
private String province;
private String city;
private String district;
public int getEvent_type() {
return event_type;
}
public void setEvent_type(int event_type) {
this.event_type = event_type;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
@Override
public String toString() {
return "BikeBean [event_type=" + event_type + ", page=" + page + ", time=" + time + ", uid=" + uid
+ ", longitude=" + longitude + ", latitude=" + latitude + ", province=" + province + ", city=" + city
+ ", district=" + district + "]";
}
}
以下三个bean是封装的网络结果bean
package cn.pengpeng.day03.bean;
/**
* 从百度地图获取的数据封装
* @author pengpeng
*/
public class ResultBean {
private int status;
private Result result;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
@Override
public String toString() {
return "ResultBean [status=" + status + ", result=" + result + "]";
}
}
package cn.pengpeng.day03.bean;
/**
* 从百度地图获取的json数据进行封装
* @author pengpeng
*/
public class Result {
private String formatted_address;
private AddressComponent addressComponent;
public String getFormatted_address() {
return formatted_address;
}
public void setFormatted_address(String formatted_address) {
this.formatted_address = formatted_address;
}
public AddressComponent getAddressComponent() {
return addressComponent;
}
public void setAddressComponent(AddressComponent addressComponent) {
this.addressComponent = addressComponent;
}
@Override
public String toString() {
return "Result [formatted_address=" + formatted_address + ", addressComponent=" + addressComponent + "]";
}
}
package cn.pengpeng.day03.bean;
public class AddressComponent {
private String country;
private String province;
private String city;
private String district;
private String town;
private String street;
private String street_number;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getStreet_number() {
return street_number;
}
public void setStreet_number(String street_number) {
this.street_number = street_number;
}
@Override
public String toString() {
return "AddressComponent [country=" + country + ", province=" + province + ", city=" + city + ", district="
+ district + ", town=" + town + ", street=" + street + ", street_number=" + street_number + "]";
}
}
构建本地仓库
本地仓库是根据bj-poi.csv文件进行一些列的操作进行构建的。主要是过滤掉一些不需要的字段,并且对经纬度信息进行转换。
具体代码如下:
package cn.pengpeng.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import cn.pengpeng.day03.util.Util;
/**
* 本地仓库生成
* @author pengpeng
*
*/
public class Repository {
public static void main(String[] args){
try {
String inpath = "d:\\data\\bj-poi-1.csv";
String outpath = "d:\\data\\Repository.tsv";
//乱码怎么解决
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inpath), "gbk"));
BufferedWriter bw = new BufferedWriter(new FileWriter(outpath));
br.readLine();//跳过第一行
String line = null;
//玉竹园小区1里5号楼,地名地址信息;门牌信息;楼栋号,116.150359,39.724234,北京市房山区拱辰街道昊天嘉园玉竹园一里,北京市,10,房山区,长虹东路,110111,
while((line = br.readLine())!=null){
try {
String[] split = line.split(",");
String name = split[0];
double longitude = Double.parseDouble(split[2]);//经度
double latitude = Double.parseDouble(split[3]);//维度
String city = split[5];
String district = split[7];
//geohash转换
String geoHash = Util.getGeoHash(longitude,latitude);
String ret = geoHash+"\t"+city+"\t"+city+"\t"+district+"\t"+name;
bw.write(ret);
bw.newLine();
} catch (Exception e) {
e.printStackTrace();
}
}
br.close();
bw.flush();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
查找位置信息
查找位置信息数据,主要是读取bikes.log单车日志数据,然后到仓库查找和去百度地图查找。
package cn.pengpeng.day03;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import cn.pengpeng.day03.bean.AddressComponent;
import cn.pengpeng.day03.bean.BikeBean;
import cn.pengpeng.day03.bean.ResultBean;
import cn.pengpeng.day03.util.Util;
/**
* 核心逻辑
* @author pengpeng
*
*/
public class TestMain {
static Map<String, String> map = null;
static{
map = loadRepositoryData();
}
public static void main(String[] args) {
String path = "d:\\data\\bikes.log";
try (BufferedReader br =new BufferedReader(new FileReader(path));){
String line = null;
while((line = br.readLine())!=null){
//解析数据
BikeBean bikeBean = JSON.parseObject(line, BikeBean.class);
//获取经纬度信息
double longitude = bikeBean.getLongitude();
double latitude = bikeBean.getLatitude();
//查找数据
String ret = findAddr(longitude,latitude);
System.out.println(ret);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据经纬度信息,查找到具体的位置信息
* 1:本地查找
* 2:网络中查找
* @param longitude
* @param latitude
* @return
*/
private static String findAddr(double longitude, double latitude) {
//本地查找
String ret = findAddrByLocal(longitude,latitude);
if(ret == null){
//本地查找不到的时候去网络中查找
ret = findAddrByNet(longitude,latitude);
}
return ret;
}
/**
* 从网络中查找数据
* @param longitude
* @param latitude
* @return
*/
private static String findAddrByNet(double longitude, double latitude) {
//获取json
String addrJsonByNet = Util.getAddrJsonByNet(longitude, latitude);
if(addrJsonByNet == null){
return null;
}
ResultBean retBean = JSON.parseObject(addrJsonByNet, ResultBean.class);
//字段提取,组合
AddressComponent addressComponent = retBean.getResult().getAddressComponent();
String geoHash = Util.getGeoHash(longitude, latitude);
String ret =geoHash+"\t"+addressComponent.getProvince()+"\t"+addressComponent.getCity()+"\t"+addressComponent.getDistrict()+"\t"
+ addressComponent.getTown()+addressComponent.getStreet()+addressComponent.getStreet_number();
//写到本地中 注意:追加数据
//写到内存(map)中一份
map.put(geoHash, ret);
return ret;
}
/**
* 本地查找数据
* @param longitude
* @param latitude
* @return
*/
private static String findAddrByLocal(double longitude, double latitude) {
String geoHash = Util.getGeoHash(longitude, latitude);
String ret = map.get(geoHash);
return ret;
}
/**
* 加载仓库数据
*/
public static Map<String, String> loadRepositoryData(){
Map<String, String> map = new HashMap<>();
String path = "d:\\data\\Repository.tsv";
try (BufferedReader br =new BufferedReader(new FileReader(path));){
String line = null;
while((line = br.readLine())!=null){
String geoHash = line.split("\t")[0];
map.put(geoHash, line);
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}