本文主要实现了获取省市区以及省市区信息落库。避免重复代码(主要代码在下文),文章末尾有使用场景说明。
一、百度地图api文档
响应示例
在使用百度API获取省市区内容时,我们需要注意以下几点。首先,确保您的API密钥安全,不要将其泄露给未经授权的人员。其次,遵守百度API的使用规则,不要进行恶意请求或滥用API资源。最后,对于获取到的省市区数据,我们需要注意数据的准确性和完整性,以确保我们的应用程序能够正确地处理和使用这些数据。
二、获取省市区工具类
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.UriUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class BaiduMapUtil {
// 用户服务访问密钥
public static String AK = "******";
// 用于生成请求url
public static String SK = "*******";
public static String URL = "https://api.map.baidu.com/api_region_search/v1/?";
public static void main(String[] args) throws Exception {
BaiduMapUtil snCal = new BaiduMapUtil();
Map paramsMap = new LinkedHashMap<String, String>();
// paramsMap.put("keyword", "石家庄市");
paramsMap.put("keyword", "中国");
paramsMap.put("sub_admin", "4");
paramsMap.put("extensions_code", "1");
System.out.println(JSONUtil.toJsonStr(snCal.requestGetSN(paramsMap)));
}
public static List<BaiduMapVO> requestGetSN(Map<String, String> param) throws Exception {
param.put("ak", AK);
param.put("sn", caculateSn(param));
return requestGetSN(URL, param);
}
/**
* 选择了ak,使用SN校验:
* 根据您选择的AK已为您生成调用代码
* 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码
* @param strUrl
* @param param
* @throws Exception
*/
public static List<BaiduMapVO> requestGetSN(String strUrl, Map<String, String> param) throws Exception {
if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
return null;
}
StringBuffer queryString = new StringBuffer();
queryString.append(strUrl);
for (Map.Entry<?, ?> pair : param.entrySet()) {
queryString.append(pair.getKey() + "=");
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
}
if (queryString.length() > 0) {
queryString.deleteCharAt(queryString.length() - 1);
}
URL url = new URL(queryString.toString());
log.info("请求百度地区url:{}",queryString);
URLConnection httpConnection = url.openConnection();
httpConnection.connect();
InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuffer buffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
isr.close();
JSONObject jsonObject = JSONUtil.parseObj(buffer.toString());
Object status = jsonObject.get("status");
if (status == null || Convert.toInt(status)!=0) {
log.info("获取百度地区失败:{}",buffer);
return null;
}
JSONArray districts = jsonObject.getJSONArray("districts");
return BeanUtil.copyToList(districts, BaiduMapVO.class);
}
public static String caculateSn(Map paramsMap) throws UnsupportedEncodingException,
NoSuchAlgorithmException {
BaiduMapUtil snCal = new BaiduMapUtil();
// 计算sn跟参数对出现顺序有关,get请求请使用LinkedHashMap保存<key,value>,该方法根据key的插入顺序排序;post请使用TreeMap保存<key,value>,该方法会自动将key按照字母a-z顺序排序。
// 所以get请求可自定义参数顺序(sn参数必须在最后)发送请求,但是post请求必须按照字母a-z顺序填充body(sn参数必须在最后)。
// 以get请求为例:http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak,paramsMap中先放入address,再放output,然后放ak,放入顺序必须跟get请求中对应参数的出现顺序保持一致。
//paramsMap
// 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
String paramsStr = snCal.toQueryString(paramsMap);
// 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
String wholeStr = new String("/api_region_search/v1/?" + paramsStr + SK);
System.out.println(wholeStr);
// 对上面wholeStr再作utf8编码
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
// 调用下面的MD5方法得到最后的sn签名
String sn = snCal.MD5(tempStr);
System.out.println(sn);
return sn;
}
// 对Map内所有value作utf8编码,拼接返回结果
public String toQueryString(Map<?, ?> data)
throws UnsupportedEncodingException {
StringBuffer queryString = new StringBuffer();
for (Map.Entry<?, ?> pair : data.entrySet()) {
queryString.append(pair.getKey() + "=");
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
}
if (queryString.length() > 0) {
queryString.deleteCharAt(queryString.length() - 1);
}
return queryString.toString();
}
// 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制
public String MD5(String md5) {
try {
java.security.MessageDigest md = java.security.MessageDigest
.getInstance("MD5");
byte[] array = md.digest(md5.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100)
.substring(1, 3));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
}
return null;
}
}
三、pojo对象
@Data
public class BaiduMapVO {
private String code;
private String name;
private String level;
private List<BaiduMapVO> districts;
}
@Data
@TableName("area")
public class area implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 区域id
*/
private String areaId;
/**
* 区域名称
*/
private String areaName;
/**
* 层级(0国,1 省,2 市,3 区,4 街道)
*/
private Integer level;
/**
* 上级区域Id
*/
private String parentId;
}
四、落库逻辑
@Slf4j
public class AreaService {
public static void main(String[] args) {
syncArea();
}
public static Boolean syncArea() {
Map params = new LinkedHashMap<String, String>();
params.put("keyword", "中国");
params.put("sub_admin", "4");
params.put("extensions_code", "1");
try {
List<BaiduMapVO> baiduMapVOList = BaiduMapUtil.requestGetSN(params);
fillArea(baiduMapVOList);
} catch (Exception e) {
e.printStackTrace();
log.info("同步异常:{}",e.getMessage());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
private static void fillArea(List<BaiduMapVO> baiduMapVOList) {
for (BaiduMapVO baiduMapVO : baiduMapVOList) {
saveArea(null,baiduMapVO);
}
}
// 递归写入/输出
private static void saveArea(String parentId, BaiduMapVO baiduMapVO) {
SysArea area = new SysArea();
String areaId = baiduMapVO.getCode();
area.setAreaId(areaId);
area.setAreaName(baiduMapVO.getName());
area.setLevel(Convert.toInt(baiduMapVO.getLevel()));
area.setParentId(parentId);
//todo 落库逻辑
// saveOrUpdate(area);
// log.info("area:{}",area);
List<BaiduMapVO> districts = baiduMapVO.getDistricts();
if (CollUtil.isNotEmpty(districts)){
for (BaiduMapVO mapVO : districts) {
saveArea(areaId,mapVO);
}
}
}
}
五、应用场景
①物流配送:在物流领域,省市区信息是实现精确配送的基础。通过输入收货地址的省市区信息,物流公司可以准确地计算出配送路线,提高配送效率,减少错误和延误。
②电商平台:电商平台在用户注册或购买商品时,通常需要用户输入收货地址的省市区信息。通过获取这些信息,电商平台可以为用户提供更加精准的商品推荐和物流服务,提高用户满意度。
③人口普查和统计:政府机构或企事业单位在进行人口普查、统计或调查时,需要获取详细的行政区划信息。通过省市区查询API接口,可以快速、准确地获取这些信息,提高工作效率和数据准确性。
④地理信息系统:在地理信息系统中,省市区信息是构建地理数据库的基础。通过获取这些信息,可以实现地图绘制、位置查询、路径规划等功能,为各种应用提供地理数据支持。
⑤房地产平台:房地产平台通常需要展示房产的地理位置和周边环境。通过获取省市区信息,可以为用户提供更加详细的房产信息和位置展示,帮助用户更好地了解房产情况。
六、结尾
将这些省市区信息进行落库后,可以定时进行一个同步更新,当然这类地区内容基本上短时间是不会有太大的变动的。
非常感谢您花时间阅读本文,希望我的内容对您有所帮助。如果您觉得本文对您有帮助,用您发财的小手点赞和收藏以下吧,您的支持就是作者最大的动力。