Springboot利于第三方服务进行ip定位获取省份城市等信息

Springboot利于第三方服务进行ip定位获取省份城市等信息

在web应用的开发中,我们或许会想知道我们的用户请求的来源分布情况。本文基于springboot框架,调用百度地图、高德地图的开放平台api,在线对对请求来源的ip进行定位、解析,获取目标ip所对应的省份、城市、经纬度等信息,方便开发者将相关数据记录在操作日志中。

一. 共用部分

  • 统一响应类
/**











 * @author 摆渡人










 * @description 统一响应类
 * @date 2023/7/13 23:26
 */










@Data





@Builder
public class IpAnalyzeResponse {

    /**
     * 状态码
     */

    private String status;


    /**
     * 是否成功
     */
    private Boolean successFlag;



    /**


     * 失败原因
     */


    private String msg;


    /**

     * 省份名称
     */

    private String province;



    /**

     * 城市名称
     */

    private String city;


    /**

     * 经度
     */


    private Double x;


    /**

     * 维度
     */

    private Double y;
}
  • 定义接口

实现该接口,并在配置类中注入接口的实现类,即可拓展ip定位的更多实现方式

/**











 * @author 摆渡人










 * @description ip定位接口
 * @date 2023/7/13 23:25
 */










public interface IPlatFormIpAnalyzeService {

    /**
     * ip定位解析
     * @param ip
     * @return
     */

    IpAnalyzeResponse ipAnalyze(String ip);
}
  • http请求工具类(用于发送http请求)

源码来自SmartAdmin

/**











 * [ HttpUtils ]
 *
 * @author yandanyang
 * @version 1.0
 * @company 1024lab.net
 * @copyright (c) 2019 1024lab.netInc. All rights reserved.
 * @date
 * @since JDK1.8
 */
public class SmartHttpUtil {

    public static String sendGet(String url, Map<String, String> params, Map<String, String> header) throws Exception {
        HttpGet httpGet = null;
        String body = "";
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            List<String> mapList = new ArrayList<>();
            if (params != null) {
                for (Entry<String, String> entry : params.entrySet()) {
                    mapList.add(entry.getKey() + "=" + entry.getValue());
                }
            }
            if (CollectionUtils.isNotEmpty(mapList)) {
                url = url + "?";
                String paramsStr = StringUtils.join(mapList, "&");
                url = url + paramsStr;
            }
            httpGet = new HttpGet(url);
            httpGet.setHeader("Content-type", "application/json; charset=utf-8");
            httpGet.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            if (header != null) {
                for (Entry<String, String> entry : header.entrySet()) {
                    httpGet.setHeader(entry.getKey(), entry.getValue());
                }
            }
            HttpResponse response = httpClient.execute(httpGet);

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                throw new RuntimeException("请求失败");
            } else {
                body = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (httpGet != null) {
                httpGet.releaseConnection();
            }
        }
        return body;
    }

    public static String sendPostJson(String url, String json, Map<String, String> header) throws Exception {
        HttpPost httpPost = null;
        String body = "";
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            if (header != null) {
                for (Entry<String, String> entry : header.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            StringEntity entity = new StringEntity(json, Charset.forName("UTF-8"));
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            HttpResponse response = httpClient.execute(httpPost);

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                throw new RuntimeException("请求失败");
            } else {
                body = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
        }
        return body;
    }

    public static String sendPostForm(String url, Map<String, String> params, Map<String, String> header) throws Exception {
        HttpPost httpPost = null;
        String body = "";
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
            httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            if (header != null) {
                for (Entry<String, String> entry : header.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            List<NameValuePair> nvps = new ArrayList<>();
            if (params != null) {
                for (Entry<String, String> entry : params.entrySet()) {
                    nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            //设置参数到请求对象中
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                throw new RuntimeException("请求失败");
            } else {
                body = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
        }
        return body;
    }

}

二.百度地图开放平台实现

1. 使用准备

阅读文档普通IP定位 | 百度地图API SDK (baidu.com),成为开发者,获取服务密钥(AK)

2. 封装实体类

/**











 * @author 摆渡人










 * @description 地址解析的结果
 * @date 2023/7/10 20:29
 */










@Data





public class IpAnalyzeBaiduResponse implements Serializable {








    /**





     * 返回状态码
     */





    private Integer status;







    /**



     * 错误信息
     */



    private String message;


    /**

     * 地址
     */

    private String address;



    /**

     * 详细内容
     */
    private IpAnalyzeContent content;

}
/**











 * @author 摆渡人










 * @description 详细内容
 * @date 2023/7/10 20:42
 */










@Data





public class IpAnalyzeContent implements Serializable {








    /**





     * 简要地址
     */





    private String address;







    /**



     * 详细地址信息
     */



    @JsonProperty("address_detail")
    private IpAnalyzeAddressDetail addressDetail;



    /**


     *  百度经纬度坐标值
     */


    @JsonProperty("point")
    private IpAnalyzePoint point;

}
/**











 * @author 摆渡人










 * @description 详细地址信息
 * @date 2023/7/10 20:41
 */










@Data





public class IpAnalyzeAddressDetail implements Serializable {








    /**





     * 城市
     */





    private String city;







    /**



     * 百度城市代码
     */



    @JsonProperty("city_code")
    private Integer cityCode;



    /**


     *  区县
     */


    private String district;


    /**

     *  省份
     */

    private String province;



    /**

     * 街道
     */

    private String street;


    /**

     * 门地址
     */


    @JsonProperty("street_number")
    private String streetNumber;

}
/**











 * @author 摆渡人










 * @description 百度经纬度坐标值
 * @date 2023/7/10 20:43
 */










@Data





public class IpAnalyzePoint implements Serializable {








    private String x;


    private String y;
}

3.实现接口IPlatFormIpAnalyzeService

/**











 * @author 摆渡人










 * @description 百度地图开发平台实现类
 * @date 2023/7/10 20:27
 */










@Slf4j


public class PlatformBaiduService implements IPlatFormIpAnalyzeService {








    /**





     * 响应成功状态码

     */





    private final Integer OK_CODE = 0;







    @Value("${platform.conf.baidu.ak}")
    public String ak;


    @Override

    public IpAnalyzeResponse ipAnalyze(String ip) {

        String URL = "http://api.map.baidu.com/location/ip";
        Map<String,String> params = new HashMap<>();

        params.put("ip", ip);
        params.put("ak", ak);
        params.put("coor", "bd09ll");
        try {
            String json = SmartHttpUtil.sendGet(URL, params, null);
            IpAnalyzeBaiduResponse response = JSONUtil.toBean(json, IpAnalyzeBaiduResponse.class);
            if(OK_CODE.equals(response.getStatus())) {
                return IpAnalyzeResponse.builder()
                        .status(response.getStatus() + "")
                        .successFlag(true)
                        .msg(response.getMessage())
                        .province(response.getContent().getAddressDetail().getProvince())
                        .city(response.getContent().getAddressDetail().getCity())
                        .x(Double.parseDouble(response.getContent().getPoint().getX()))
                        .y(Double.parseDouble(response.getContent().getPoint().getY()))
                        .build();
            }
            return IpAnalyzeResponse.builder()
                    .status(response.getStatus() + "")
                    .successFlag(false)
                    .msg(response.getMessage())
                    .build();
        } catch (Exception e) {
            return IpAnalyzeResponse.builder()
                    .status("500")
                    .successFlag(false)
                    .msg(e.getMessage())
                    .build();
        }
    }
}

三.高德地图开放平台实现

1. 使用准备

根据文档获取Key-创建工程-开发指南-Web服务 API|高德地图API (amap.com)指引获取key

2. 封装实体类

/**











 * @author 摆渡人










 * @description 高德地图ip定位响应类
 * @date 2023/7/14 0:00
 */










@Data





public class IpAnalyzeGaodeResponse {








    /**





     * 返回结果状态值,值为0或1,0表示失败;1表示成功
     */





    private String status;







    /**



     * 返回状态说明,status为0时,info返回错误原因,否则返回“OK
     */



    private String info;


    /**

     * 返回状态说明,10000代表正确,详情参阅info状态表
     */

    private String infocode;



    /**

     * 若为直辖市则显示直辖市名称;
     *
     * 如果在局域网 IP网段内,则返回“局域网”;
     *
     * 非法IP以及国外IP则返回空
     */
    private String province;

    /**
     * 若为直辖市则显示直辖市名称;
     *
     * 如果为局域网网段内IP或者非法IP或国外IP,则返回空
     */


    private String city;


    /**

     * 城市的adcode编码
     */

    private String adcode;

    /**
     * 所在城市矩形区域范围,所在城市范围的左下右上对标对,如:116.0119343,39.66127144;116.7829835,40.2164962
     */
    private String rectangle;
}

3.实现接口IPlatFormIpAnalyzeService

/**











 * @author 摆渡人










 * @description 高德地图开放平台ip定位实现类
 * @date 2023/7/13 23:56
 */










@Slf4j


public class PlatformGaodeService implements IPlatFormIpAnalyzeService {








    /**





     * 响应成功状态码

     */





    private final String OK_CODE = "1";







    @Value("${platform.conf.gaode.key}")
    private String key;


    @Override

    public IpAnalyzeResponse ipAnalyze(String ip) {

        String URL = "https://restapi.amap.com/v3/ip";
        Map<String,String> params = new HashMap<>();

        params.put("key",key);
        params.put("ip",ip);
        try {
            String json = SmartHttpUtil.sendGet(URL, params, null);
            IpAnalyzeGaodeResponse response = JSONUtil.toBean(json, IpAnalyzeGaodeResponse.class);
            if(OK_CODE.equals(response.getStatus())) {
                IpAnalyzeResponse ipAnalyzeResponse = IpAnalyzeResponse.builder()
                        .status(response.getInfocode())
                        .successFlag(true)
                        .msg(response.getInfo())
                        .province(response.getProvince())
                        .city(response.getCity())
                        .build();
                // 对rectangle进行解析
                String rectangle = response.getRectangle();
                String[] split = rectangle.split(";|,");
                if(split.length == 1) {
                    ipAnalyzeResponse.setSuccessFlag(false);
                    ipAnalyzeResponse.setStatus("0");
                    ipAnalyzeResponse.setMsg("ip[" + ip + "]非法");
                    return ipAnalyzeResponse;
                }
                ipAnalyzeResponse.setX((Double.parseDouble(split[0]) + Double.parseDouble(split[2])) / 2.0);
                ipAnalyzeResponse.setY((Double.parseDouble(split[1]) + Double.parseDouble(split[3])) / 2.0);
                return ipAnalyzeResponse;
            }
            return IpAnalyzeResponse.builder()
                    .status(response.getInfocode())
                    .successFlag(false)
                    .msg(response.getInfo())
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            return IpAnalyzeResponse.builder()
                    .status(“500”)
                    .successFlag(false)
                    .msg(e.getMessage())
                    .build();
        }
    }
}

四. 使用

1.配置参数

# 第三方开放平台的服务
platform:
  # 目前支持百度[baidu] 高德[gaode]
  mode: # 您选择的服务
  # 相关配置
  conf:
    # 百度
    baidu:
      ak: # 您的百度地图开放平台服务密钥(AK)
    # 高德
    gaode:
      key: # 您的高德地图开放平台key

2.配置类

根据配置参数中platform.mode的值选择接口IPlatFormIpAnalyzeService的一个服务类注入Spring容器中去

/**











 * @author 摆渡人










 * @description 接口实现类配置
 * @date 2023/7/14 0:16
 */










@Configuration
public class PlatFormConfig {








    @Bean
    @ConditionalOnProperty(prefix = "platform",name = "mode",havingValue = "baidu")
    public IPlatFormIpAnalyzeService initBaiduIpAnalyzeService() {
        return new PlatformBaiduService();
    }


    @Bean
    @ConditionalOnProperty(prefix = "platform",name = "mode",havingValue = "gaode")
    public IPlatFormIpAnalyzeService initGaodeIpAnalyzeService() {
        return new PlatformGaodeService();
    }
}

3.单元测试

/**











 * @author 摆渡人










 * @description 
 * @date 2023/7/14 0:23
 */










@Slf4j


@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class PlatformTest {


     @Autowired
    private IPlatFormIpAnalyzeService platFormIpAnalyzeService;







     @Test
     public void testIpAnalyzeService() {
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze(null));
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze(""));
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze("127.0.0.1"));
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze("114.247.50.2"));
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze("219.137.148.0"));
         log.info("解析结果:{}",platFormIpAnalyzeService.ipAnalyze("114.80.166.240"));
     }



}

运行结果如下:

  • platform.mode=gaode
    image.png

    [2023-07-22 22:42:40,426][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[null]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:26)
    [2023-07-22 22:42:40,662][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:27)
    [2023-07-22 22:42:40,898][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[127.0.0.1]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:28)
    [2023-07-22 22:42:41,132][INFO ][main] 解析结果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=北京市, city=北京市, x=116.3974589, y=39.93888382) (PlatformTest.java:29)
    [2023-07-22 22:42:41,365][INFO ][main] 解析结果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=广东省, city=广州市, x=113.3893937, y=23.15653812) (PlatformTest.java:30)
    [2023-07-22 22:42:41,600][INFO ][main] 解析结果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=上海市, city=上海市, x=121.4767528, y=31.224348955) (PlatformTest.java:31)
    
  • platform.mode=baidu
    image.png

    [2023-07-22 22:40:48,774][INFO ][main] 解析结果:IpAnalyzeResponse(status=2, successFlag=false, msg=Request Parameter Error:ip illegal, province=null, city=null, x=null, y=null) (PlatformTest.java:26)
    [2023-07-22 22:40:48,825][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=广东省, city=广州市, x=113.27143134, y=23.13533631) (PlatformTest.java:27)
    [2023-07-22 22:40:48,862][INFO ][main] 解析结果:IpAnalyzeResponse(status=1, successFlag=false, msg=Internal Service Error:ip[127.0.0.1] loc failed, province=null, city=null, x=null, y=null) (PlatformTest.java:28)
    [2023-07-22 22:40:48,899][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=北京市, city=北京市, x=116.4133837, y=39.91092455) (PlatformTest.java:29)
    [2023-07-22 22:40:48,949][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=广东省, city=广州市, x=113.27143134, y=23.13533631) (PlatformTest.java:30)
    [2023-07-22 22:40:48,988][INFO ][main] 解析结果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=上海市, city=上海市, x=121.48789949, y=31.24916171) (PlatformTest.java:31)
    

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYwLdA3p' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片