Springboot 使用GeoIP数据库查询用户IP位置信息
Springboot 使用GeoIP数据库查询用户IP位置信息
引言
GeoIP 数据库是一个将 IP 地址映射到地理位置信息的工具。它在网络安全、内容本地化、广告投放和用户分析等领域发挥着重要作用。
虽然在线 IP 查询服务便捷,但存在网络依赖、隐私风险、查询限制和潜在高成本等问题。相比之下,使用 GeoIP 数据库进行离线查询具有显著优势:
- 高性能和稳定性
- 更好的隐私保护
- 无查询次数限制
- 长期使用更具成本效益
- 灵活性和可定制性更高
这种离线查询方式特别适合需要频繁、快速、私密 IP 地理信息查询的应用场景。
项目准备
- 首先在 MaxMaind 官网注册一个账号。
- 获取自己的账号和许可证密钥
- 手动下载对应的mmd数据库或使用命令下载
curl -O -J -L -u ACCOUNT:LICENSE_KEY 'https://download.maxmind.com/geoip/databases/GeoLite2-City/download?suffix=tar.gz'
实现步骤
-
为 Springboot 项目引入依赖
<dependency> <groupId>com.maxmind.geoip2</groupId> <artifactId>geoip2</artifactId> <version>${latest.version}</version> </dependency>
将
${latest.version}
替换为最新版本。 -
添加对应的配置类
/** @author devcxl */ @Getter @Setter @ConfigurationProperties(prefix = "geoip") public class GeoipProperties { /** * mmdb数据库资源路径 */ private Resource dbFile; /** * 地理信息展示语言 */ private String local = "zh-CN"; }
-
创建 DatabaseReader 实例
import com.example.demo.config.properties.GeoipProperties; import com.maxmind.db.CHMCache; import com.maxmind.geoip2.DatabaseReader; import java.io.IOException; import java.util.List; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; /** @author devcxl */ @Configuration @EnableConfigurationProperties({GeoipProperties.class}) public class Geoip2Config { @Bean DatabaseReader databaseReader(GeoipProperties geoipProperties) throws IOException { Resource dbFile = geoipProperties.getDbFile(); return new DatabaseReader.Builder(dbFile.getFile()) .withCache(new CHMCache()) .locales(List.of(geoipProperties.getLocal())) .build(); } }
-
配置 GeoIP 数据库路径
geoip: db-file: 'file:/usr/share/geoip/GeoLite2-City.mmdb' local: 'zh-CN'
-
编写 IP 查询服务
/**
* @author devcxl
*/
@Slf4j
@Service
public class GeoIpService {
@Resource
private DatabaseReader databaseReader;
/**
* 获取访问者IP的国家ISO代码
*
* @param ip
* @return
*/
public String getCountryIsoCode(String ip) {
try {
InetAddress ipAddress = InetAddress.getByName(ip);
CountryResponse country = databaseReader.country(ipAddress);
return country.getCountry().getIsoCode();
} catch (IOException | GeoIp2Exception exception) {
log.error("获取访问者IP的国家ISO代码 {} 错误:{}", ip, exception.getMessage());
return "US";
}
}
/**
* 获取城市名称
*
* @param ip
* @return
*/
public String getCity(String ip) {
try {
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse city = databaseReader.city(ipAddress);
return city.getCity().getName();
} catch (IOException | GeoIp2Exception exception) {
log.error("获取访问者IP的城市 {} 错误: {}", ip, exception.getMessage());
return null;
}
}
/**
* 获取国家名称
*
* @param ip
* @return
*/
public String getCountry(String ip) {
try {
InetAddress ipAddress = InetAddress.getByName(ip);
CountryResponse country = databaseReader.country(ipAddress);
return country.getCountry().getName();
} catch (IOException | GeoIp2Exception exception) {
log.error("获取访问者IP的国家 {} 错误:{}", ip, exception.getMessage());
return null;
}
}
/**
* 获取省/州名称
*
* @param ip
* @return
*/
public String getSubdivision(String ip) {
try {
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse city = databaseReader.city(ipAddress);
return city.getLeastSpecificSubdivision().getName();
} catch (IOException | GeoIp2Exception exception) {
log.error("获取访问者IP的省/州 {} 错误:{}", ip, exception.getMessage());
return null;
}
}
/**
* 获取用户的登录位置
*
* @param request
* @return
*/
public LoginLocation getLoginLocation(HttpServletRequest request) {
String clientIp = ServletUtils.getClientIp(request);
return getLoginLocationFromIp(clientIp);
}
/**
* 获取用户的登录位置
*
* @param ip
* @return
*/
public LoginLocation getLoginLocationFromIp(String ip) {
try {
LoginLocation loginLocation = new LoginLocation();
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse city = databaseReader.city(ipAddress);
loginLocation.setCity(city.getCity().getName());
loginLocation.setCountry(city.getCountry().getName());
loginLocation.setProvince(city.getLeastSpecificSubdivision().getName());
return loginLocation;
} catch (IOException | GeoIp2Exception exception) {
log.error("获取访问者的登录位置 ip:{} 错误:{}", ip, exception.getMessage());
return null;
}
}
}