一.概述
GeoLite2是一款强大的数据库,用于提供地理定位服务,它包含了两个主要的产品:GeoLite2 City和GeoLite2 Country,每个季度更新一次。
-
GeoLite2 City: 覆盖全球城市层面的地理位置数据,精确到邮政编码级别。这为需要精细定位服务的应用提供了强大的支持。
-
GeoLite2 Country: 提供全球所有国家和地区的地理位置信息,虽然精度较GeoLite2 City略低,但足以满足大多数应用的需求。
二.代码下载
GeoLite2-City.mmdb 代码下载,公众号天梦星科技综合服务回复GeoLite即可获取下载链接;
三.上代码
1.pom.xml
<!--ip地理位置转换-->
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.16.1</version>
</dependency>
2.Config配置类和yml
import com.maxmind.geoip2.DatabaseReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.File;
import java.io.IOException;
@Configuration
public class GeoIPConfig {
@Value("${customInfo.geo.path}")
private String geoPath ;
@Bean
public DatabaseReader databaseReader() throws IOException {
File database = new File(geoPath);
return new DatabaseReader.Builder(database).build();
}
}
#YML
customInfo:
geo:
path: "src/main/resources/static/GeoLite2-City.mmdb"
#这是本地路径,打包部署前,单独拷贝一份文件放服务器,重写服务器路径,防止打包后找不到文件问题
3.Controller 控制类
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.portalwebsiteservice.demos.web.Dto.Result;
import com.portalwebsiteservice.demos.web.Service.GeoIPService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import static com.portalwebsiteservice.demos.web.Util.IpUtils.getIpAddr;
@RestController
public class GeoIPController {
@Resource
private GeoIPService geoIPService;
@GetMapping("/geo-ip")
public Result getGeoIPInfo(HttpServletRequest request) throws IOException, GeoIp2Exception {
String clientIp = getIpAddr(request);
return geoIPService.getCityInfo(clientIp);
}
}
4.Service业务方法
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.record.*;
import com.portalwebsiteservice.demos.web.Dto.IpGeo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.InetAddress;
@Service
public class GeoIPServiceImpl implements GeoIPService {
@Resource
private DatabaseReader databaseReader;
@Override
public Result getCityInfo(String ipAddress) throws IOException, GeoIp2Exception {
Result result = new Result();
InetAddress inetAddress = InetAddress.getByName(ipAddress);
CityResponse response = databaseReader.city(inetAddress);
if (response != null) {
IpGeo ipGeo = new IpGeo();
ipGeo.setCountryCode(response.getCountry().getIsoCode());
ipGeo.setCountryNameCode(response.getCountry().getName());
ipGeo.setCountryName(response.getCountry().getNames().get("zh-CN"));
Subdivision province = response.getMostSpecificSubdivision();
ipGeo.setProvinceCode(province.getIsoCode());
ipGeo.setProvinceNameCode(province.getName());
ipGeo.setProvinceName(province.getNames().get("zh-CN"));
City city = response.getCity();
ipGeo.setCityNameCode(city.getName());
ipGeo.setCityName(city.getNames().get("zh-CN"));
Location location = response.getLocation();
ipGeo.setLatitude(location.getLatitude());
ipGeo.setLongitude(location.getLongitude());
Traits traits = response.getTraits();
ipGeo.setNetwork(traits.getNetwork().getNetworkAddress() + "/" + traits.getNetwork().getPrefixLength());
ipGeo.setIpAddress(traits.getIpAddress());
result.setData(ipGeo);
} else {
result.setCode(400);
result.setMsg("服务端拒绝请求!");
}
return result;
}
}
import com.maxmind.geoip2.exception.GeoIp2Exception;
import java.io.IOException;
public interface GeoIPService {
Result getCityInfo(String ipAddress) throws IOException, GeoIp2Exception;
}
5.Dto实体类
import lombok.Data;
/**
* IpGeo 实体类,用于存储 IP 地址相关的地理位置信息。
*/
@Data
public class IpGeo {
// 国家简称编码
private String countryCode;
// 国家英文名称
private String countryNameCode;
// 国家中文名
private String countryName;
// 省份简称
private String provinceCode;
// 省份拼音
private String provinceNameCode;
// 省市名称
private String provinceName;
// 城市拼音
private String cityNameCode;
// 城市名称
private String cityName;
// 纬度
private Double latitude;
// 经度
private Double longitude;
// 网络信息
private String network;
// IP 地址
private String ipAddress;
}
6.Util工具类获取IP真实地址
/**
* 获取IP真实地址
* 备注:在本地运行是获取不到真实地址,需要部署到服务上才能获取得到
*/
public class IpUtils {
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress="";
}
return ipAddress;
}
}