How to Determine User City from IP in Spring Boot: A Practical Guide
This article explains why identifying a user's city via IP is crucial for operations, outlines various IP-to-city methods, and provides a complete Spring Boot implementation—including IP extraction, QQWry library integration, custom interceptors, and REST endpoints—to count visits per city.
Significance
In e‑commerce, news, and social platforms, using operational cost efficiently requires knowing user city distribution, especially for city‑specific strategies.
Web (PC) cannot rely on GPS; IP must be used to infer geographic location.
Ways to Get City from IP
Commercial APIs (e.g., Taobao, Sina) provide IP‑to‑city services but may change URLs and have rate limits.
Open‑source pure IP database (e.g., QQWry) is continuously updated, self‑hosted, and sufficient for most scenarios.
Approach
First obtain the client IP address from the HTTP request. Below is a simple utility class:
public class IPUtil {
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}Wrap the QQWry library to resolve the IP to a city:
public IPZone findIP(final String ip) {
final long ipNum = toNumericIP(ip);
final QIndex idx = searchIndex(ipNum);
if (idx == null) {
return new IPZone(ip);
}
return readIP(ip, idx);
}Implement a custom interceptor to count visits per city. In production, store counts in Redis and expose a REST endpoint for the front‑end to fetch statistics.
@Slf4j
public class MyLoginInterceptor implements HandlerInterceptor {
private static final String LOGIN_PATH = "/user/login";
private static Map<String, AtomicInteger> visitCount;
private static QQWry qqWry;
static {
visitCount = new HashMap<>(31);
qqWry = new QQWry();
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("【MyLoginInterceptor】called:{}", request.getRequestURI());
if (request.getRequestURI().equals(LOGIN_PATH)) {
String ipAddress = IPUtil.getIpAddress(request);
String province = qqWry.findIP(ipAddress).getMainInfo();
visitCount.computeIfAbsent(province, k -> new AtomicInteger()).incrementAndGet();
}
return true;
}
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
}Register the interceptor in Spring MVC configuration:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyLoginInterceptor());
}
}Sample login controller (for testing the interceptor):
@RestController("user")
public class LoginController {
@GetMapping("login")
public String login() {
// login logic
return "success";
}
}The full source code is available at the provided GitHub repository.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
