在实际的业务中,涉及到攻防数据的演示,但是基础的数据只有攻击的IP,如何在地图上展示攻击的来源?
地图飞线或者坐标点的展示都是通过经纬度进行设置的,如果拿不到对应的经纬度则无法对地图攻击来源进行演示。为此查找方案,可以通过IP对经纬度的转换来实现攻击的展现(坐标点存在误差,非精确经纬度)。
通过输入一个IP地址,解析并获取信息,比如国家、国家代码、省份、省份代码、城市、邮政编码、经纬度等等信息
在线IP获取地区
- ip-api.com
一、GeoLite2 介绍
通过GeoLite2,Java根据IP获得城市、经纬度。
1179px下载地址:https://www.maxmind.com/en/accounts/561549/geoip/downloads


因为我需要获取城市信息,所以选择第三个,压缩包大概30MB,解压后里面的 mmdb 有60MB
二、springboot项目整合及使用
1、添加依赖
<dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.13.1</version></dependency>
2、实现工具类
package com.qingfeng.common.controller;import java.io.File;import java.io.IOException;import java.net.InetAddress;import javax.servlet.http.HttpServletRequest;import com.maxmind.geoip2.DatabaseReader;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** @ProjectName IpGeoUtils* @author Administrator* @version 1.0.0* @Description 获取客户端IP地址* @createTime 2021/6/3 14:29*/public class IpGeoUtils {private static Logger logger = LoggerFactory.getLogger(IpGeoUtils.class);/*** 获取客户端IP地址** 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址*/public static String getIP(HttpServletRequest request) {String ip = null;try {ip = request.getHeader("x-forwarded-for");if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}} catch (Exception e) {logger.error("IPUtils ERROR ", e);}return ip;}/**** @description: 获得国家* @param reader* @param ip* @return* @throws Exception*/public static String getCountry(DatabaseReader reader, String ip) throws Exception {return reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN");}/**** @description: 获得省份* @param reader* @param ip* @return* @throws Exception*/public static String getProvince(DatabaseReader reader, String ip) throws Exception {return reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN");}/**** @description: 获得城市* @param reader* @param ip* @return* @throws Exception*/public static String getCity(DatabaseReader reader, String ip) throws Exception {return reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN");}/**** @description: 获得经度* @param reader* @param ip* @return* @throws Exception*/public static Double getLongitude(DatabaseReader reader, String ip) throws Exception {// return reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();double data = 0;try {data = reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();}catch (Exception e){}return data;}/**** @description: 获得纬度* @param reader* @param ip* @return* @throws Exception*/public static Double getLatitude(DatabaseReader reader, String ip){double data = 0;try {data = reader.city(InetAddress.getByName(ip)).getLocation().getLatitude();}catch (Exception e){}return data;}public static void main(String[] args) throws Exception {// String path = req.getSession().getServletContext().getRealPath("/WEB-INF/classes/GeoLite2-City.mmdb");String path = "D:/java/GeoLite2-City/GeoLite2-City.mmdb";// 创建 GeoLite2 数据库File database = new File(path);// 读取数据库内容DatabaseReader reader = new DatabaseReader.Builder(database).build();// 访问IPString ip = "28.16.2.122";String site = IpGeoUtils.getCountry(reader, ip) + "-" + IpGeoUtils.getLongitude(reader, ip)+ "-" + IpGeoUtils.getLatitude(reader, ip);System.out.println(site);Double lon = IpGeoUtils.getLongitude(reader,ip);double lat = IpGeoUtils.getLatitude(reader,ip);System.out.println("Lon:"+lon+"---Lat:"+lat);}}
3、实现及调用
//引入GeoLite2String path = "D:/java/GeoLite2-City.mmdb";// 创建 GeoLite2 数据库File database = new File(path);// 读取数据库内容DatabaseReader reader = new DatabaseReader.Builder(database).build();Double lon = IpGeoUtils.getLongitude(reader,ip);double lat = IpGeoUtils.getLatitude(reader,ip);System.out.println("Lon:"+lon+"---Lat:"+lat);
4、完整案例代码
因为实际业务需要查询出攻击所在的IP地址,根据IP地址获取经纬度-更新信息,将获取的经纬度更新到库中。
为了快速的实现数据的获取及更新,直接使用demo连接mysql数据库进行操作,完整代码如下:
package com.qingfeng.example.controller;import com.maxmind.geoip2.DatabaseReader;import com.qingfeng.util.IpGeoUtils;import com.qingfeng.util.PageData;import com.qingfeng.util.Verify;import com.qingfeng.util.sqlutil.DBMysqlUtil;import org.apache.commons.lang3.StringUtils;import java.io.File;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;/*** @author Administrator* @version 1.0.0* @ProjectName qingfeng* @Description TODO* @createTime 2021年06月03日 14:35:00*/public class IpToGeo {/*** @title 根据ip获取经纬度* @description TODO* @author Administrator* @updateTime 2021/6/3 14:36*/public static void main(String[] args) throws Exception {String path = "D:/java/GeoLite2-City.mmdb";// 创建 GeoLite2 数据库File database = new File(path);// 读取数据库内容DatabaseReader reader = new DatabaseReader.Builder(database).build();String dbUrl = "jdbc:mysql://localhost:3306/perception?serverTimezone=UTC&autoReconnect=true&useUnicode=true&characterEncoding=utf8";DBMysqlUtil db = new DBMysqlUtil(dbUrl,"root","Root@123");db.getConnection();String querySql = "select id,attack_ip from egov_data where attack_lon is null and attack_ip not like '%192.0.0%' order by id asc";ResultSet rs = db.select(querySql);List<PageData> list = new ArrayList<PageData>();while (rs.next()) {PageData p = new PageData();String id = rs.getString("id");String attack_ip = rs.getString("attack_ip");System.out.println("id:"+id+"---IP:"+attack_ip);String ip = "";if(attack_ip.contains("(")){ip = attack_ip.substring(0,attack_ip.indexOf("("));}System.out.println("IP:"+ip);if(Verify.verifyIsNotNull(ip)){Double lon = IpGeoUtils.getLongitude(reader,ip);double lat = IpGeoUtils.getLatitude(reader,ip);System.out.println("Lon:"+lon+"---Lat:"+lat);p.put("id",id);p.put("lon",lon);p.put("lat",lat);list.add(p);}}for (PageData p:list) {//执行更新String updateSql = "update egov_data set attack_lon='"+p.get("lon")+"',attack_lat='"+p.get("lat")+"' where id="+p.get("id");db.executeupdate(updateSql);}}}

