Java通过百度地图API获取定位-普通IP定位

news2024/11/18 11:38:00

项目中有一个登录邮箱提醒的功能,需要根据IP地址获取定位信息,从而更好地提示用户账号登录的所在地。为此,花费了一些时间来实现这个功能。

在CSDN搜索了一下,发现关于获取定位的文章说明都不够详细,于是决定自己创作一篇文章,希望能够帮助到有需求的小伙伴~

因为博主日常生活中用的导航APP就是百度地图,所以使用百度地图的API来实现这个功能。

目录

百度地图开放平台

开始前的准备工作

学习官网API文档

修改API的AK配置

Java代码获取定位

通过官网生成代码

运行生成的代码

创建接口返回对象

Point.java

Location.java

Content.java

AddressDetail.java

将JSON字符串转成Location对象

代码的最后优化


百度地图开放平台

本篇文章都是围绕百度地图的开放平台官网的相关说明来展开的,访问下面的链接

百度地图开放平台 | 百度地图API SDK | 地图开发icon-default.png?t=N7T8https://lbsyun.baidu.com/index.php?title=%E9%A6%96%E9%A1%B5这是开放平台的首页截图

开始前的准备工作

点击上方导航菜单的开发文档-Web服务API总览

 紧接着,点击左侧菜单中的定位,点击普通IP定位

然后根据开发文档的提示完成步骤1、2、3


 

学习官网API文档

最后点击步骤4,开始使用百度地图的API

如上图,文档已经给出了API的接口地址和参数说明,以及API接口返回的参数格式。

{
  "address": "CN|北京市|北京市|None|None|100|91",
  "content": {
    "address": "北京市",
    "address_detail": {
      "adcode": "110000",
      "city": "北京市",
      "city_code": 131,
      "district": "",
      "province": "北京市",
      "street": "",
      "street_number": ""
    },
    "point": {
      "x": "116.41338370",
      "y": "39.91092455"
    }
  },
  "status": 0
}

修改API的AK配置

在这里,需要修改一下创建的应用的相关设置。

点击上图的设置按钮来到这个页面,然后拉到页面的底部,修改应用的请求校验方式为sn校验方式,然后点击提交按钮。

把AK复制到示例代码的输入框中,点击确认按钮自动生成获取定位的Java代码,可以说非常方便。

Java代码获取定位

通过官网生成代码

新建一个类SearchHttpAK,把示例代码复制到SearchHttpAK类里,复制按钮在下图红框内。

调整之后的代码如下(真实的AK和SK都已经被博主替换了,这里的5个x改成自己的AK和SK就行了)。

package cn.edu.sgu.www.authority.util;

import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 选择AK使用SN校验:
 * @author heyunlin
 * @version 1.0
 */
public class SearchHttpSN {

    public static String AK = "xxxxx";

    public static String SK = "xxxxx";

    public static String URL = "https://api.map.baidu.com/location/ip?";

    public static void main(String[] args) throws Exception {

        SearchHttpSN snCal = new SearchHttpSN();

        Map<String, String> params = new LinkedHashMap<>(4);
        
        params.put("ip", "111.206.214.37");
        params.put("coor", "bd09ll");
        params.put("ak", AK);

        params.put("sn", snCal.caculateSn());

        snCal.requestGetSN(URL, params);
    }

    /**
     * 选择了ak,使用SN校验:
     * 根据您选择的AK已为您生成调用代码
     * 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码
     * @param strUrl
     * @param param
     * @throws Exception
     */
    public void requestGetSN(String strUrl, Map<String, String> param) throws Exception {
        if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
            return;
        }

        StringBuilder queryString = new StringBuilder();
        queryString.append(strUrl);
        
        for (Map.Entry<?, ?> pair : param.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            // 第一种方式使用的 jdk 自带的转码方式  第二种方式使用的 spring 的转码方法 两种均可
            // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        java.net.URL url = new URL(queryString.toString());
        System.out.println(queryString.toString());
        URLConnection httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.connect();

        InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
        BufferedReader reader = new BufferedReader(isr);
        StringBuilder buffer = new StringBuilder();
        String line;
        
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        
        reader.close();
        isr.close();
        
        System.out.println("SN: " + buffer);
    }

    public String caculateSn() throws UnsupportedEncodingException,
            NoSuchAlgorithmException {
        SearchHttpSN snCal = new SearchHttpSN();

        // 计算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请求中对应参数的出现顺序保持一致。
        Map<String, String> paramsMap = new LinkedHashMap<>(3);
        
        paramsMap.put("ip", "111.206.214.37");
        paramsMap.put("coor", "bd09ll");
        paramsMap.put("ak", AK);


        // 调用下面的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("/location/ip?" + 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) {
        StringBuilder queryString = new StringBuilder();
        
        for (Map.Entry<?, ?> pair : data.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            // 第一种方式使用的 jdk 自带的转码方式  第二种方式使用的 spring 的转码方法 两种均可
            // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");
        }
        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());
            StringBuilder sb = new StringBuilder();

            for (byte b : array) {
                sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
            }
            
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException ignored) { }
        
        return null;
    }
}

注意,不要修改这里的map的放入顺序,否则请求接口会报错~

Map<String, String> params = new LinkedHashMap<>(4);
        
params.put("ip", "111.206.214.37");
params.put("coor", "bd09ll");
params.put("ak", AK);

params.put("sn", snCal.caculateSn());

运行生成的代码

然后运行一下代码,如果能看到下面这样的运行结果,恭喜你,你已经成功了一大半~

不要纠结获取到的位置信息里很多16进制,因为马上就要把他转成一个自定义的实体类

创建接口返回对象

根据这个API返回的JSON格式字符串的结构,创建4个对应的实体类

Point.java
import lombok.Data;

/**
 * @author heyunlin
 * @version 1.0
 */
@Data
public class Point {

    private String x;

    private String y;
}

Location.java
import lombok.Data;

/**
 * @author heyunlin
 * @version 1.0
 */
@Data
public class Location {

    private Integer status;

    private String address;

    private Content content;
}

Content.java
import lombok.Data;

/**
 * @author heyunlin
 * @version 1.0
 */
@Data
public class Content {

    private Point point;

    private String address;

    private AddressDetail address_detail;
}

AddressDetail.java
import lombok.Data;

/**
 * @author heyunlin
 * @version 1.0
 */
@Data
public class AddressDetail {

    private String adcode;

    private String city;

    private String city_code;

    private String province;

    private String district;

    private String street;

    private String street_number;
}

将JSON字符串转成Location对象

修改一下部分方法的名称,然后把字符串通过fastjson的API转成Location对象

package cn.edu.sgu.www.authority.util;

import cn.edu.sgu.www.authority.location.Location;
import com.alibaba.fastjson.JSON;
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.util.LinkedHashMap;
import java.util.Map;

/**
 * 选择AK使用SN校验:
 * @author heyunlin
 * @version 1.0
 */
public class SearchHttpSN {

    public static String AK = "xxxxx";

    public static String SK = "xxxxx";

    public static String URL = "https://api.map.baidu.com/location/ip?";

    public static void main(String[] args) throws Exception {
        String ip = "111.206.214.37";
        String location = getLocation(ip);

        System.out.println(JSON.parseObject(location, Location.class));
    }

    public static String getLocation(String ip) throws Exception {
        Map<String, String> params = new LinkedHashMap<>(4);

        params.put("ip", ip);
        params.put("coor", "bd09ll");
        params.put("ak", AK);

        params.put("sn", caculateSn());

        return getLocation(URL, params);
    }

    /**
     * 选择了ak,使用SN校验:
     * 根据您选择的AK已为您生成调用代码
     * 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码
     * @param strUrl
     * @param param
     * @throws Exception
     */
    public static String getLocation(String strUrl, Map<String, String> param) throws Exception {
        if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
            return null;
        }

        StringBuilder queryString = new StringBuilder();
        queryString.append(strUrl);

        for (Map.Entry<?, ?> pair : param.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            // 第一种方式使用的 jdk 自带的转码方式  第二种方式使用的 spring 的转码方法 两种均可
            // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        java.net.URL url = new URL(queryString.toString());
        System.out.println(queryString);
        URLConnection httpConnection = url.openConnection();
        httpConnection.connect();

        InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
        BufferedReader reader = new BufferedReader(isr);
        StringBuilder sb = new StringBuilder();
        String line;

        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }

        reader.close();
        isr.close();

        return sb.toString();
    }

    public static String caculateSn() throws UnsupportedEncodingException {
        // 计算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请求中对应参数的出现顺序保持一致。
        Map<String, String> paramsMap = new LinkedHashMap<>(3);

        paramsMap.put("ip", "111.206.214.37");
        paramsMap.put("coor", "bd09ll");
        paramsMap.put("ak", AK);


        // 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
        String paramsStr = 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("/location/ip?" + paramsStr + SK);

        System.out.println(wholeStr);
        // 对上面wholeStr再作utf8编码
        String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

        // 调用下面的MD5方法得到最后的sn签名
        return MD5(tempStr);
    }

    // 对Map内所有value作utf8编码,拼接返回结果
    public static String toQueryString(Map<?, ?> data) {
        StringBuilder queryString = new StringBuilder();

        for (Map.Entry<?, ?> pair : data.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            // 第一种方式使用的 jdk 自带的转码方式  第二种方式使用的 spring 的转码方法 两种均可
            // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        return queryString.toString();
    }

    // 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制
    public static String MD5(String md5) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(md5.getBytes());
            StringBuilder sb = new StringBuilder();

            for (byte b : array) {
                sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException ignored) { }

        return null;
    }

}

运行代码,效果如下:

在使用的时候,只需要传入IP地址即可获取到定位信息~

代码的最后优化

上面的代码已经是进行了一定的优化,除此之外,可以把AK和SK配置到application.yml中,可以动态地修改。最后重命名一下这个类,改成类似LocationUtils这样的名字。

好了,文章就分享到这里了,看完如果觉得对你有所帮助,不要忘了点赞+收藏哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1662379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CAP与BASE分布式理论

一、分布式理论 1.CAP理论 CAP理论是说对于分布式数据存储&#xff0c;最多只能同时满足一致性&#xff08;C&#xff0c;Consistency&#xff09;、可用性&#xff08;A&#xff0c; Availability&#xff09;、分区容忍性&#xff08;P&#xff0c;Partition Tolerance&…

编程式导航

目录 一、问题引入 二、基本跳转 1.path路径跳转&#xff08;简易方便&#xff09; 2.name命名路由跳转&#xff08;适合path路径长的场景&#xff09; 三、路由传参 1.path路径跳转传参 &#xff08;1&#xff09;query传参 &#xff08;2&#xff09;动态路由传参 2.…

揭秘VSCode魔法工具箱:HTML5 CSS3超强插件集合 + Css Reset与Normalize.css的终极对决

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 ✍HTML5、CSS3常用的vscode插件&#x1f34e;1 HTML 标签同步重命名– Auto…

每日一题1:从表中创建DataFrame

本文通过一道题来对创建DataFrame知识点进行拓展&#xff0c;方便以后直接调用。下面先对知识点进行介绍&#xff1a; 在Python中&#xff0c;使用pandas库创建DataFrame有多种方法&#xff0c;这里列举几种常见的创建方式&#xff1a; 一、常见创建方式 1. 从二维列表创建 …

Android之给Button上添加按压效果

一、配置stateListAnimator参数实现按压效果 1、按钮控件 <Buttonandroid:id"id/mBtnLogin"android:layout_width"match_parent"android:layout_height"48dp"android:background"drawable/shape_jfrb_login_button"android:state…

融知财经:期货和现货的区别是什么?哪个风险大?

期货和现货在交易对象等方面存在明显的区别。期货交易是一种衍生金融工具&#xff0c;主要用于价格发现、风险管理和投机&#xff0c;而现货交易则是商品和服务的实际买卖。在选择进行期货交易还是现货交易时&#xff0c;投资者需要根据自己的需求和市场情况来决定。 期货和现货…

如何访问远程MySQL数据库服务器?

访问远程MySQL数据库服务器是一项常见的任务&#xff0c;它允许我们在不同的地点通过网络连接到MySQL服务器&#xff0c;并进行数据库管理和数据处理操作。我们将重点介绍一种名为【天联】的组网技术&#xff0c;该技术提供了一系列优势&#xff0c;使远程访问MySQL数据库服务器…

javac编译web项目中的src

对于单个文件的且不引用其他类文件的java源码用javac编译大家都很熟悉即 javac hello.java, 服务器未安装idea&#xff0c;现在在服务器里面直接编译src目录 1 idea项目结构如下 2 web目录为最终部署的代码 WEB-INF下面没有 classes 目录 3 使用javac 编译src javac -encod…

Nachi那智不二越机器人维修技术合集

一、Nachi机械手维护基础知识 1. 定期检查&#xff1a;定期检查机器人的各个部件&#xff0c;如机械手伺服电机、机器人减速器、机械臂传感器等&#xff0c;确保其运行正常。 2. 清洁与润滑&#xff1a;定期清洁Nachi工业机器人表面和内部&#xff0c;并使用合适的润滑油进行润…

在线旅游网站,基于 SpringBoot+Vue+MySQL 开发的前后端分离的在线旅游网站设计实现

目录 一. 前言 二. 功能模块 2.1. 登录界面 2.2. 管理员功能模块 2.3. 用户功能模块 三. 部分代码实现 四. 源码下载 一. 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;旅游网站当然…

OpenHarmony usb打开报错“usb fail error code = -3, error msg = LIBUSB_ERROR_ACCESS”

一、前言&#xff1a;最近公司项目需求&#xff0c;定位要求使用国产系统&#xff0c;国产系统无非就是 统信os &#xff0c;麒麟OS, 还有这两年比较热的 OpenHarmony。于是&#xff0c;老板要求公司产品适配OpenHarmony , 跟上时代步伐。 二、在开发中使用 usb 通讯时&#x…

党务政务服务热线|基于SSM的党务政务服务热线平台(源码+数据库+文档)

目录 基于SprinBootvue的党务政务服务热线平台 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2部门功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; …

Ubuntu搭建VsCode C++ 开发环境

Ubuntu搭建VsCode C 开发环境 安装VS Code 使用命令来安装VS Code&#xff1a;他会下载vscode的最新版本。 sudo snap install --classic code如果不使用命令 的方式 在官网下载vscode安装包&#xff08; 后缀为 .deb的包 &#xff09;之后&#xff08;可以选择版本 &#x…

克服 Prometheus 单值数据模型的局限性:GreptimeDB 的新路径

引言 Prometheus 已经成为监控和报警生态系统的基石&#xff0c;在高效、直接地处理实时指标&#xff08;Metric&#xff09;方面有着强大的表现。Prometheus 的核心是一个包含单个值和一系列标签的数据模型。这种设计在提升简单性和适应性的同时&#xff0c;也带来了一些挑战…

HarmonyOS NEXT星河版之美团外卖点餐功能实战(下)

文章目录 一、购物车逻辑1.1 购物车及加减菜1.2 菜品的加减---方案一1.3 菜品的加减---方案二1.4 购物车View完善1.5 清空购物车1.5 购物车数量和价格 二、小结 一、购物车逻辑 1.1 购物车及加减菜 在utils目录下新建CartStore.ets文件&#xff0c;如下&#xff1a; import …

Dubbo2.x迁移3.x过程及原理

Dubbo2.x迁移3.x过程及原理 1.Dubbo2.x迁移3.x1.1 快速升级步骤1.2 Provider 端升级过程详解1.2.1 双注册带来的资源消耗 1.3 Consumer 端升级过程1.3.1 APPLICATION_FIRST策略1.3.2 双订阅带来的资源消耗1.3.3 消费端更细粒度的控制 1.4 迁移状态的收敛1.4.1 不同的升级策略影…

一键局域网共享工具

一键局域网共享工具&#xff1a;实现文件快速共享的新选择 在数字化时代&#xff0c;文件共享已成为我们日常工作和生活中的重要需求。无论是在家庭还是在办公环境中&#xff0c;我们经常需要在不同的设备之间传输文件。为了满足这一需求&#xff0c;一键局域网共享工具应运而…

Leetcode—239. 滑动窗口最大值【困难】

2024每日刷题&#xff08;132&#xff09; Leetcode—239. 滑动窗口最大值 算法思想 用vector会超时的&#xff0c;用deque最好&#xff01; 实现代码 class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {deque<int> …

AI绘画的基本原理是什么?

目录 一、AI绘画的基本原理是什么&#xff1f; 二、Python中有几个库可以用于AI绘画&#xff1f; 三、OpenCV画一个人形 四、AI画的红苹果 一、AI绘画的基本原理是什么&#xff1f; AI绘画的原理基于机器学习和人工智能技术&#xff0c;通过这些技术模型能够理解文本描述并…

物联网D3——按键控制LED、光敏传感蜂鸣器

按键控制LED 按键抖动&#xff0c;电平发生变化&#xff0c;可用延时函数抵消按键抖动对系统的影响 传感器电路图 按键电路图 c语言对应类型 “_t”后缀表示使用typedef重命名的数据类型 枚举类型 #include<iostream> using namespace std; //定义枚举类型 typedef enu…