cityType = 1;
}
if(!CollectionUtils.isEmpty(mpList)){
List weaList = new ArrayList<>();
Field[] fields = ReflectUtil.getField(CmsWeather.class);
if(fields != null && fields.length > 0){
weaList = getCityWeaList(fields,mpList,cityType);
}
if(!CollectionUtils.isEmpty(weaList)){
cityType = 2; //省级--->市县
weaList = setLevelWeather(weaList,cityType,syncUrl,fields);
logger.info("省级--->市县---天气同步完毕");
//市县级-->区级
cityType = 3; //市县级-->区级
setLevelWeather(weaList,cityType,syncUrl,fields);
logger.info("市县级-->区级---天气同步完毕");
}
//地理信息
//longitudeMng
CmsWeather tmpWea = new CmsWeather();
List weaDbLs = weatherMng.queryWeatherBy(tmpWea);
if(!CollectionUtils.isEmpty(weaDbLs)){
//这里通过谷歌的一个url请求获取城市的地理信息,可能会被墙,不过还好地理位置很长时间试只取一次(事实证明确实被墙,那这张表的数据可能需要现场导入,百度也可以做到,可是百度要appkey,切返回的没有范围区间,mdbd)
//String longitudeUrl = "http://maps.google.com/maps/api/geocode/json?address=";
for(int i = 0;i < weaDbLs.size();i++){
CmsWeather wea = weaDbLs.get(i);
String cityName = wea.getCityname();
String weaType = wea.getWeatherType();
if(StringUtils.isNotBlank(weaType) && ("2".equals(weaType) || "3".equals(weaType))){
CmsLongitude tmpLgt = new CmsLongitude();
tmpLgt.setCityName(cityName);
List logitudeLs = longitudeMng.queryBy(tmpLgt);
if(CollectionUtils.isEmpty(logitudeLs)){
GeoPoint gp = LocationUtil.getFromLocationName(cityName,"baidu");
if(gp != null){
CmsLongitude saveLgt = new CmsLongitude();
saveLgt.setCityCode(wea.getUrl());
saveLgt.setCityName(wea.getCityname());
saveLgt.setCityPy(wea.getPyName());
saveLgt.setLatMax(String.valueOf(gp.getLatMax()));
saveLgt.setLatMin(String.valueOf(gp.getLatMin()));
saveLgt.setLngMax(String.valueOf(gp.getLngMax()));
saveLgt.setLngMin(String.valueOf(gp.getLngMin()));
saveLgt.setApiLat(String.valueOf(gp.getApiLat()));
saveLgt.setApiLng(String.valueOf(gp.getApiLng()));
saveLgt = longitudeMng.save(saveLgt);
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
isOk = false;
}
}
return isOk;
}
private List setLevelWeather(List weaList, Integer cityType,String syncUrl, Field[] fields) throws Exception {
List nextLevelWeaLs = new ArrayList<>();
CmsWeather tmpWea = null;
String tmpPyName = "";
if(StringUtils.isNotBlank(syncUrl)){
Integer subIndex = syncUrl.lastIndexOf("/");
String baseUrl = syncUrl.substring(0, subIndex) + "/";
List
List tmpNextList = new ArrayList<>();
for(int i = 0;i < weaList.size();i++){
tmpWea = weaList.get(i);
tmpPyName = tmpWea.getPyName();
if(StringUtils.isNotBlank(tmpPyName)){
String provincialUrl = baseUrl + tmpPyName + ".xml";
logger.debug("-----------------");
logger.debug("-------------provincialUrl:"+provincialUrl);
logger.debug("===================");
String weaStr = HttpClientUtil.getInstance().get(provincialUrl);
if(StringUtils.isNotBlank(weaStr) && weaStr.indexOf("") < 0){
weaMpLs = XmlUtil.xmlStrToListMap(weaStr);
if(!CollectionUtils.isEmpty(weaMpLs)){
tmpNextList = this.getCityWeaList(fields,weaMpLs,cityType);
nextLevelWeaLs.addAll(tmpNextList);
weaMpLs.clear();
tmpNextList.clear();
}
}
}
}
}
return nextLevelWeaLs;
}
private List getCityWeaList(Field[] fields, List
List weaList = new ArrayList<>();
Map tmp = null;
CmsWeather pTmpWea = null;
for(int j = 0;j < mpList.size();j++){
tmp = mpList.get(j);
pTmpWea = new CmsWeather();
for(int m = 0 ;m < fields.length;m++){
Field fld = fields[m];
String fldName = ReflectUtil.getFieldName(fld);
if(StringUtils.isNotBlank(fldName)){
Object fldVal = tmp.get(fldName);
if(fldVal != null){
pTmpWea = (CmsWeather) ReflectUtil.setEntityValue(fldName, fldVal,pTmpWea);
pTmpWea.setWeatherType(cityType.toString());
}
}
}
pTmpWea = weatherMng.save(pTmpWea);
weaList.add(pTmpWea);
}
return weaList;
}
反射工具类:(自己写的,很简单,大家可以完善)
public class ReflectUtil {
public static Field[] getField(Class> model){
Field[] field = model.getDeclaredFields(); // 获取实体类的所有属性,返回Field数组
return field;
}
public static String getFieldName(Field field){
return field.getName();
}
public static String getFieldType(Field field){
return field.getGenericType().toString();
}
public static Object getFieldValue(Field field,Object entity){
String name = getFieldName(field);
Object value = null;
String type = field.getGenericType().toString(); // 获取属性的类型
try {
if (type.equals("class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名
Method m = entity.getClass().getMethod("get" + upperCaseFirst(name));
value = (String) m.invoke(entity); // 调用getter方法获取属性值
/*反射设置方法
* if (value == null) {
m = entity.getClass().getMethod("set"+name,String.class);
m.invoke(entity, "");
}*/
}
if (type.equals("class java.lang.Integer")) {
Method m = entity.getClass().getMethod("get" + upperCaseFirst(name));
value = (Integer) m.invoke(entity);
}
if (type.equals("class java.lang.Boolean")) {
Method m = entity.getClass().getMethod("get" + upperCaseFirst(name));
value = (Boolean) m.invoke(entity);
}
if (type.equals("class java.util.Date")) {
Method m = entity.getClass().getMethod("get" + upperCaseFirst(name));
value = (Date) m.invoke(entity);
}
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
public static String upperCaseFirst (String str){
StringBuilder sb = new StringBuilder(str);
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
return str = sb.toString();
}
public static Object setEntityValue(String attrName, Object attrValue,Object entity) throws Exception {
//反射设置方法
if(StringUtils.isNotBlank(attrName) && attrValue != null) {
String type = attrValue.getClass().toString();
Method m = null;
switch (type) {
case "class java.lang.String":
m = entity.getClass().getMethod("set"+upperCaseFirst(attrName),String.class);
break;
case "class java.lang.Integer":
m = entity.getClass().getMethod("set"+upperCaseFirst(attrName),Integer.class);
break;
case "class java.lang.Boolean":
m = entity.getClass().getMethod("set"+upperCaseFirst(attrName),Boolean.class);
break;
case "class java.util.Date":
m = entity.getClass().getMethod("set"+upperCaseFirst(attrName),Date.class);
break;
}
if(m != null){
m.invoke(entity, attrValue);
}
}
return entity;
}
}
GeoPoint 地理位置实体
public class GeoPoint {
/*int lat;
int lng;
public GeoPoint(int lat, int lng) {
this.lat = lat;
this.lng = lng;
}*/
private double lngMin;
private double lngMax;
private double latMin;
private double latMax;
private double apiLng;
private double apiLat;
public GeoPoint(double lngMin, double lngMax, double latMin, double latMax,double apiLng,double apiLat) {
this.lngMin = lngMin;
this.lngMax = lngMax;
this.latMin = latMin;
this.latMax = latMax;
this.apiLng = apiLng;
this.apiLat = apiLat;
}
public double getLngMin() {
return lngMin;
}
public void setLngMin(double lngMin) {
this.lngMin = lngMin;
}
public double getLngMax() {
return lngMax;
}
public void setLngMax(double lngMax) {
this.lngMax = lngMax;
}
public double getLatMin() {
return latMin;
}
public void setLatMin(double latMin) {
this.latMin = latMin;
}
public double getLatMax() {
return latMax;
}
public void setLatMax(double latMax) {
this.latMax = latMax;
}
public double getApiLng() {
return apiLng;
}
public void setApiLng(double apiLng) {
this.apiLng = apiLng;
}
public double getApiLat() {
return apiLat;
}
public void setApiLat(double apiLat) {
this.apiLat = apiLat;
}
}
LocationUtil 地理位置工具类,这个类很重要,这个里面就是把城市名传给API接口,返回经纬度,然后我自己再将经纬度存储,里面要说到的是关于最大最小经纬度,这里目前是+-0.5,这个精度应该来说还是稍微有点大,大家可以自己调整,大家这里可以想想为什么我这里取到城市的经纬度我要自己再转换一个最大最小值存储?
public class LocationUtil {
public static GeoPoint getFromLocationName(String address,String supper) {
JSONObject jsonObject = new JSONObject();
if(StringUtils.isNotBlank(supper)){
switch(supper){
case "google":
jsonObject = googelResult(address);
break;
case "baidu":
jsonObject = baiduResult(address);
break;
}
}
return getGeoPoint(jsonObject,supper);
}
private static JSONObject baiduResult(String address) {
//这里的ak秘钥码是要大家自己去百度申请的哦,地址:
http://lbsyun.baidu.com/
,所以我就不好意思了,要隐藏了。
String url = "http://api.map.baidu.com/geocoder/v2/?output=json&ak=你的秘钥码&address=";
HttpGet httpGet = new HttpGet(url + address);
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (Exception e) {
e.printStackTrace();
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
private static JSONObject googelResult(String address){
String url = "http://maps.google.com/maps/api/geocode/json";
HttpGet httpGet = new HttpGet(url + "?sensor=false&address=" + address);
HttpClient client = new DefaultHttpClient();
//其实可以设置代理,但是那也是个坑
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (Exception e) {
e.printStackTrace();
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
private static GeoPoint getGeoPoint(JSONObject jsonObject,String supper) {
if(StringUtils.isNotBlank(supper)){
switch(supper){
case "google":
try {
JSONArray array = (JSONArray) jsonObject.get("results");
JSONObject first = array.getJSONObject(0);
JSONObject geometry = first.getJSONObject("geometry");
JSONObject location = geometry.getJSONObject("location");
double lat = location.getDouble("lat");
double lng = location.getDouble("lng");
//return new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
//误差+—1度
double lngMin = lng - 0.5;
double lngMax = lng + 0.5;
double latMin = lat - 0.5;
double latMax = lat + 0.5;
return new GeoPoint(lngMin,lngMax, latMin,latMax,lng,lat);
} catch (JSONException e) {
e.printStackTrace();
}
break;
case "baidu":
try {
JSONObject resObj = jsonObject.getJSONObject("result");
JSONObject location = resObj.getJSONObject("location");
double lat = location.getDouble("lat");
double lng = location.getDouble("lng");
//return new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
double lngMin = lng - 0.5;
double lngMax = lng + 0.5;
double latMin = lat - 0.5;
double latMax = lat + 0.5;
return new GeoPoint(lngMin,lngMax, latMin,latMax,lng,lat);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
return null;
}
}
到这里通过这些方法就将天气取到存储到本地了,经纬度的转存这里里面也有判断,会一并存储的。当然也可以事后自己通过取到的天气数据查询单独转换存储,我这里就是写的单元测试类获取存储的。这就是这个带有城市名和拼音的好处。
下面就来说说查询获取的实现,也就是对外提供服务的接口实现。
这里的思路:其实就是手机获取到经纬度后传给后台,后台先查我自己存储的经纬度表,因为我设有最大最小经纬度,那么可以理解,我的一个区域实际就是一个1*1(因为我是+-0.5)的正方形区域,找到经纬度最接近的,那么就定位到最近的城市了,剩下的就是去天气表查询数据了。
先看单元测试类
@Test
public void testLgtQuery(){
//经纬度本地转换城市
CmsLongitude tmpLgt = new CmsLongitude();
tmpLgt.setLatMin("30.476654");
tmpLgt.setLngMin("114.401248");
List lgtLs = longitudeMng.queryBy(tmpLgt);
if(CollectionUtils.isEmpty(lgtLs)){
System.out.println("-------:"+lgtLs.size());
}
}
longitudeMng实现就一句,直接返回dao的调用结果,我们直接看dao的方法,我这里项目是用的Hibernate,如果大家是其他框架,明白思路里的自己实现吧。
@Override
public List queryBy(CmsLongitude tmpLgt) {
String hql="select bean from CmsLongitude bean where 1=1 ";
Finder finder=Finder.create(hql);
String cityName = tmpLgt.getCityName();
if(StringUtils.isNotBlank(cityName)){
finder.append(" and cityName=:cityName");
finder.setParam("cityName", cityName);
}
String cityPy = tmpLgt.getCityPy();
if(StringUtils.isNotBlank(cityPy)){
finder.append(" and cityPy=:cityPy");
finder.setParam("cityPy", cityPy);
}
String lng = tmpLgt.getLngMin();
String lat = tmpLgt.getLatMin();
//这里的经纬度范围过滤只能粗略,会出现多个城市和区的地理位置
if(StringUtils.isNotBlank(lng) && StringUtils.isNotBlank(lat)){
finder.append(" and lngMin <:lng");
finder.setParam("lng", lng);
finder.append(" and lngMax >:lng");
finder.setParam("lng", lng);
finder.append(" and latMin <:lat");
finder.setParam("lat", lat);
finder.append(" and latMax >:lat");
finder.setParam("lat", lat);
}
String cityCode = tmpLgt.getCityCode();
if(StringUtils.isNotBlank(cityCode)){
finder.append(" and cityCode=:cityCode");
finder.setParam("cityCode", cityCode);
}
//这里的取到最近的思路其实很简单,那就是:最大 + 最小 - 当前,然后取绝对值,降序排列,那么第一个就是最接近的区域了,有点绕,好好理解下,写到这其实我很佩服写算法的哥们,这里这么简单的算法,我当时都想了不少时间,数学果然是根本。现在明白当初哥转换经纬度为什么要存储经纬度的最低值最小值了吧?
if(StringUtils.isNotBlank(lng) && StringUtils.isNotBlank(lat)){
double tmpLng = Double.parseDouble(lng) * 2;
double tmpLat = Double.parseDouble(lat) * 2;
finder.append(" order by ABS(bean.lngMin + bean.lngMax -:tmpLng2) asc, ABS(bean.latMin + bean.latMax -:tmpLat2) asc");
finder.setParam("tmpLng2", String.valueOf(tmpLng));
finder.setParam("tmpLat2", String.valueOf(tmpLat));
}
finder.setCacheable(true);
return find(finder);
}
上面取到的地理位置就是最接近当前经纬度的了,然后就是去查询天气表了,经纬度表里有城市名和城市码,天气表里也有的,那查询的实现不用我上代码了吧。说到这我想到这个城市码了,这个城市码我其实不知道是谁编的,也不知道是不是大家都统一用的迈步会变的,所以我还是老老实实的应的名称。
就说这么多吧,内容有点多,谢谢大家了。
有问题的可以给我留言,我有时间会解答。