125 lines
5.0 KiB
Java
125 lines
5.0 KiB
Java
package quant.rich.emoney.util;
|
|
|
|
import com.maxmind.geoip2.DatabaseReader;
|
|
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
|
import com.maxmind.geoip2.model.CityResponse;
|
|
import com.maxmind.geoip2.record.Subdivision;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import okhttp3.OkHttpClient;
|
|
import okhttp3.Request;
|
|
import okhttp3.Response;
|
|
import quant.rich.emoney.client.OkHttpClientProvider;
|
|
import quant.rich.emoney.entity.config.ProxyConfig;
|
|
import quant.rich.emoney.pojo.dto.IpInfo;
|
|
|
|
import java.io.IOException;
|
|
import java.net.InetAddress;
|
|
import java.net.Proxy;
|
|
import java.util.concurrent.TimeUnit;
|
|
import org.springframework.core.io.ClassPathResource;
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
|
@Slf4j
|
|
public class GeoIPUtil {
|
|
|
|
private static DatabaseReader cityReader;
|
|
public static String LOCALE = "zh-CN";
|
|
|
|
static {
|
|
try {
|
|
ClassPathResource geoLite2CityResource = new ClassPathResource("/conf/extra/GeoLite2-City.mmdb");
|
|
cityReader = new DatabaseReader.Builder(geoLite2CityResource.getInputStream()).build();
|
|
} catch (IOException e) {
|
|
throw new RuntimeException("IP 地址库初始化失败", e);
|
|
}
|
|
}
|
|
|
|
@Async
|
|
public static IpInfo getIpInfoThroughProxy(ProxyConfig proxyConfig) {
|
|
return CallerLockUtil.tryCallWithCallerLock(() -> {
|
|
Proxy proxy = proxyConfig.getProxy();
|
|
boolean ignoreHttpsVerification = proxyConfig.getIgnoreHttpsVerification();
|
|
// OkHttp 客户端配置
|
|
OkHttpClient client = OkHttpClientProvider.getInstance(
|
|
proxy, ignoreHttpsVerification,
|
|
builder -> builder
|
|
.connectTimeout(10, TimeUnit.SECONDS)
|
|
.readTimeout(10, TimeUnit.SECONDS));
|
|
|
|
// 使用 httpbin.org/ip 获取当前请求的公网 IP
|
|
Request requestIpv4 = new Request.Builder()
|
|
.url("https://ipv4.icanhazip.com")
|
|
.build();
|
|
|
|
IpInfo ipInfo = new IpInfo();
|
|
|
|
try (Response response = client.newCall(requestIpv4).execute()) {
|
|
if (!response.isSuccessful()) {
|
|
log.warn("Request ipv4 failed with code: {}", response.code());
|
|
return IpInfo.EMPTY;
|
|
}
|
|
|
|
String responseBody = response.body().string();
|
|
log.debug("Response ipv4 from proxy: {}", responseBody.trim());
|
|
ipInfo.setIp(responseBody);
|
|
} catch (IOException e) {
|
|
log.warn("Proxy ipv4 error: {}", e.getMessage());
|
|
return IpInfo.EMPTY;
|
|
}
|
|
Request requestIpv6 = new Request.Builder()
|
|
.url("https://ipv6.icanhazip.com")
|
|
.build();
|
|
try (Response response = client.newCall(requestIpv6).execute()) {
|
|
if (!response.isSuccessful()) {
|
|
log.warn("Request ipv6 failed with code: {}", response.code());
|
|
}
|
|
|
|
String responseBody = response.body().string();
|
|
log.debug("Response ipv6 from proxy: {}", responseBody.trim());
|
|
ipInfo.setIpv6(responseBody);
|
|
} catch (IOException e) {
|
|
log.warn("Proxy ipv6 error {}", e.getMessage());
|
|
}
|
|
return queryIpInfoGeoLite(ipInfo);
|
|
}, 100, proxyConfig).orElse(IpInfo.EMPTY);
|
|
}
|
|
|
|
/**
|
|
* 以 IPv4 为准
|
|
* @param ipInfo
|
|
*/
|
|
public static IpInfo queryIpInfoGeoLite(IpInfo ipInfo) {
|
|
try {
|
|
InetAddress ipv4Address = InetAddress.getByName(ipInfo.getIp());
|
|
CityResponse response = cityReader.city(ipv4Address);
|
|
|
|
if (response.getCountry() != null) {
|
|
String countryStr = response.getCountry().getNames().get(LOCALE);
|
|
ipInfo.setCountry(countryStr);
|
|
}
|
|
|
|
if (response.getSubdivisions() != null && !response.getSubdivisions().isEmpty()) {
|
|
// 省
|
|
Subdivision subdivision = response.getSubdivisions().get(0);
|
|
if (subdivision != null) {
|
|
String subdivisionStr = subdivision.getNames().get(LOCALE);
|
|
ipInfo.setSubdivision(subdivisionStr);
|
|
}
|
|
}
|
|
if (response.getCity() != null) {
|
|
// 市
|
|
String cityStr = response.getCity().getNames().get(LOCALE);
|
|
ipInfo.setCity(cityStr);
|
|
}
|
|
} catch (IOException | GeoIp2Exception e) {
|
|
log.warn("Get city response from GeoLite2-City database failed: {}", e.getMessage());
|
|
}
|
|
log.debug("ipInfo: {}", ipInfo);
|
|
return ipInfo;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.format("GeoLite2-City %s\r\n", queryIpInfoGeoLite(new IpInfo().setIp("46.3.98.216")));
|
|
}
|
|
} |