本文主要实现了获取省市区以及省市区信息落库。避免重复代码(主要代码在下文),文章末尾有使用场景说明。
一、百度地图api文档
行政区域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(); // 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 requestGetSN(Map 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 requestGetSN(String strUrl, Map 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的插入顺序排序;post请使用TreeMap保存 ,该方法会自动将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 Listdistricts; } @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(); params.put("keyword", "中国"); params.put("sub_admin", "4"); params.put("extensions_code", "1"); try { List 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 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 districts = baiduMapVO.getDistricts(); if (CollUtil.isNotEmpty(districts)){ for (BaiduMapVO mapVO : districts) { saveArea(areaId,mapVO); } } } }
五、应用场景
①物流配送:在物流领域,省市区信息是实现精确配送的基础。通过输入收货地址的省市区信息,物流公司可以准确地计算出配送路线,提高配送效率,减少错误和延误。
②电商平台:电商平台在用户注册或购买商品时,通常需要用户输入收货地址的省市区信息。通过获取这些信息,电商平台可以为用户提供更加精准的商品推荐和物流服务,提高用户满意度。
③人口普查和统计:政府机构或企事业单位在进行人口普查、统计或调查时,需要获取详细的行政区划信息。通过省市区查询API接口,可以快速、准确地获取这些信息,提高工作效率和数据准确性。
④地理信息系统:在地理信息系统中,省市区信息是构建地理数据库的基础。通过获取这些信息,可以实现地图绘制、位置查询、路径规划等功能,为各种应用提供地理数据支持。
⑤房地产平台:房地产平台通常需要展示房产的地理位置和周边环境。通过获取省市区信息,可以为用户提供更加详细的房产信息和位置展示,帮助用户更好地了解房产情况。
六、结尾
将这些省市区信息进行落库后,可以定时进行一个同步更新,当然这类地区内容基本上短时间是不会有太大的变动的。
非常感谢您花时间阅读本文,希望我的内容对您有所帮助。如果您觉得本文对您有帮助,用您发财的小手点赞和收藏以下吧,您的支持就是作者最大的动力。