**
将客户端IP通过百度智能云反查具体地理位置,再根据中央气象台获取到具体的实时天气数据
**
根据IP反查定位
对于Web项目,可以从请求头中获取到客户端IP地址,为防止多次反向代理,则需获取客户端的真实IP地址
代码如下:
public static String getRemoteIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(",");
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
return ip;
}
return request.getRemoteAddr();
}
获取到IP地址之后,使用百度智能云提供的免费Api接口定位Ip,获取到具体的地址
局域网IP是不可以的,如127.0.0.1、192.168.1.1等都是局域网IP都是不可以的
如新疆的某个IP地址为218.195.219.255
https://qifu-api.baidubce.com/ip/geo/v1/district?ip=218.195.219.255
代码如下:
public static JSONObject district(String ip) {
try {
URL url = new URL("https://qifu-api.baidubce.com/ip/geo/v1/district?ip=" + ip);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
String string = content.toString();
return JSONObject.parseObject(string);
} catch (Exception e) {
e.printStackTrace(System.out);
}
return null;
}
获取到的JSON数据格式如下:
{
"code": "Success",
"data": {
"continent": "亚洲",
"country": "中国",
"zipcode": "830000",
"timezone": "UTC+8",
"accuracy": "区县",
"owner": "中国教育网",
"isp": "中国教育网",
"source": "数据挖掘",
"areacode": "CN",
"adcode": "650103",
"asnumber": "4538",
"lat": "43.800855",
"lng": "87.536048",
"radius": "19.2187",
"prov": "新疆维吾尔自治区",
"city": "乌鲁木齐市",
"district": "沙依巴克区"
},
"charge": true,
"msg": "查询成功",
"ip": "218.195.219.255",
"coordsys": "WGS84"
}
到这一步,解析JSON可以拿到prov(省)、city(市)
获取我国省份信息
这里通过调用中央气象台Api接口获取气象上我国省份信息
http://www.nmc.cn/rest/province
通过浏览器访问可以看到JSON数据格式如下
[
{
"code": "ABJ",
"name": "北京市",
"url": "/publish/forecast/ABJ.html"
},
{
"code": "ATJ",
"name": "天津市",
"url": "/publish/forecast/ATJ.html"
}
]
根据JSON数据格式可以建立与之对应的对象,通过JAVA代码调用API获取到JSON数据进行封装成一个ProvData类型的List集合对象
@Component
public class MapConstants {
/**
* 中国省份
*/
public static final String[] CHINA_PROVINCES = {"北京市", "天津市", "河北省", "山西省", "内蒙古自治区", "辽宁省", "吉林省",
"黑龙江省", "上海市", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省", "河南省", "湖北省", "湖南省", "广东省",
"广西壮族自治区", "海南省", "重庆市", "四川省", "贵州省", "云南省", "西藏自治区", "陕西省", "甘肃省", "青海省",
"宁夏回族自治区", "新疆维吾尔自治区", "香港特别行政区", "澳门特别行政区", "台湾省",};
/**
* 中国天气省份
*/
public static class ProvData {
private String code;
private String name;
private String url;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
public static final List<ProvData> CHINA_PROVINCES_WEATHER;
static {
try {
CHINA_PROVINCES_WEATHER = init();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@PostConstruct
public static List<ProvData> init() throws IOException {
URL url = new URL("http://www.nmc.cn/rest/province");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(content.toString(), new TypeReference<List<ProvData>>() {
});
}
/**
* 中国天气城市
*/
public static class CityData {
private String code;
private String province;
private String city;
private String url;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
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 getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
根据省份信息获取市信息
首先进行省份对比,拿到对应省份的code值
String code="";
for(MapConstants.ProvData provData:CHINA_PROVINCES_WEATHER){
if(provData.getName().equals(prov)){
code = provData.getCode();
break;
}
}
再根据code值获取省下有哪些市的信息
这里通过调用中央气象台Api接口根据省份信息获取市信息
如新疆的code值为AXJ
http://www.nmc.cn/rest/province/AXJ
通过浏览器访问可以看到JSON数据格式如下
[
{
"code": "51463",
"province": "新疆维吾尔自治区",
"city": "乌鲁木齐",
"url": "/publish/forecast/AXJ/wulumuqi.html"
},
{
"code": "51730",
"province": "新疆维吾尔自治区",
"city": "阿拉尔",
"url": "/publish/forecast/AXJ/alaer.html"
}
]
根据JSON数据格式可以建立与之对应的对象,通过JAVA代码调用API获取到JSON数据进行封装成一个CityData类型的List
集合对象(在上一步骤中代码部分已经创建好了)
URL url=new URL("http://www.nmc.cn/rest/province/"+code);
HttpURLConnection con=(HttpURLConnection)url.openConnection();
con.setRequestMethod("GET");
BufferedReader in=new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content=new StringBuffer();
while((inputLine=in.readLine())!=null){
content.append(inputLine);
}
in.close();
ObjectMapper objectMapper=new ObjectMapper();
List<MapConstants.CityData>cityData=objectMapper.readValue(content.toString(),new TypeReference<List<MapConstants.CityData>>(){
});
根据城市信息获取天气
首先进行城市对比,拿到对应城市的code值
for(MapConstants.CityData cityDatum:cityData){
if(city.contains(cityDatum.getCity())){
code = cityDatum.getCode();
break;
}
}
再根据code值查询该城市的实时天气
这里通过调用中央气象台Api接口根据省份信息获取市信息
如乌鲁木齐的code值为51463
http://www.nmc.cn/f/rest/real/51463
String weatherUrl="http://www.nmc.cn/f/rest/real/"+code;
StringBuilder sb=new StringBuilder();//获取拼接读取到的json字符
try{
URL u=new URL(weatherUrl);
URLConnection urlConnection=u.openConnection();
//字节输入流读取json数据,并将编码格式设置为utf8
InputStreamReader reader=new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8);
//字符流读取输入流的数据
BufferedReader br=new BufferedReader(reader);
String inputLines;//循环中间量
while((inputLines=br.readLine())!=null){
sb.append(inputLines);
}
br.close();
reader.close();
}catch(IOException e){
e.printStackTrace();
}
//将字符串转换为json对象
JSONObject json=JSON.parseObject(sb.toString());
这时已经拿到了该城市的实时天气,可以作进一步处理
乌鲁木齐现在的实时天气如下:
{
"station": {
"code": "51463",
"province": "新疆维吾尔自治区",
"city": "乌鲁木齐",
"url": "/publish/forecast/AXJ/wulumuqi.html"
},
"publish_time": "2023-09-05 22:10",
"weather": {
"temperature": 13.1,
"temperatureDiff": -4.3,
"airpressure": 9999,
"humidity": 87,
"rain": 0,
"rcomfort": 54,
"icomfort": -1,
"info": "多云",
"img": "1",
"feelst": 12.4
},
"wind": {
"direct": "9999",
"degree": 9999,
"power": "微风",
"speed": 0.1
},
"warn": {
"alert": "2023年09月04日18时新疆维吾尔自治区气象台发布雷电黄色预警信号",
"pic": "http://image.nmc.cn/assets/img/alarm/p0012003.png",
"province": "新疆维吾尔自治区",
"city": "9999",
"url": "/publish/alarm/65000041600000_20230904180345.html",
"issuecontent": "新疆维吾尔自治区气象台2023年9月4日18时2分发布雷电黄色预警信号:目前伊犁州、克拉玛依市、石河子市、乌鲁木齐市、克州、阿克苏地区西部北部、巴州北部等地的局部区域已出现雷电活动,预计今天夜间,上述区域和博州、塔城地区、阿勒泰地区、昌吉州等地的局部区域仍将有雷电活动,局地伴有短时强降水、8级以上雷暴大风、冰雹等强对流天气,请加强防范。",
"fmeans": "1.政府及相关部门按照职责做好防雷工作;2.密切关注天气,尽量避免户外活动。",
"signaltype": "雷电",
"signallevel": "黄色",
"pic2": "p0012003.png"
}
}
建议
除了最后一步获取动态获取某市的实时天气以外,前面的数据尽量做好缓冲或者入库处理,能够合理的节省资源浪费和避免对中央气象台的API接口造成负载运行