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.

Programmer DD
Programmer DD
Programmer DD
How to Determine User City from IP in Spring Boot: A Practical Guide

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootInterceptorIP geolocation
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.