Backend Development 15 min read

Retrieving User IP Address and Geolocation in Java with ip2region

This article explains how to obtain a client’s IP address from an HttpServletRequest, convert it to a geographic location using the ip2region library, and provides multiple Java implementation options, Maven dependencies, and performance testing commands for efficient backend IP lookup.

Architect's Guide
Architect's Guide
Architect's Guide
Retrieving User IP Address and Geolocation in Java with ip2region

Many Chinese platforms now display a user’s IP location (province for domestic users, country for overseas users) and the feature cannot be disabled. As developers we may want to understand how this is implemented.

The article first shows how to extract the client IP address in Java using HttpServletRequest . It lists the typical request headers (x-forwarded-for, Proxy-Client-IP, WL-Proxy-Client-IP) and falls back to request.getRemoteAddr() . Special handling for localhost and multiple proxy scenarios is also demonstrated.

A utility class NetUtils is provided to encapsulate the IP‑retrieval logic, including fallback to the machine’s network interface when the address is 127.0.0.1 or localhost . The same class also contains a method to obtain the MAC address.

/**
 * Network utility class
 */
public class NetUtils {
    /**
     * Get client IP address
     */
    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.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                try {
                    InetAddress inet = InetAddress.getLocalHost();
                    ip = inet.getHostAddress();
                } catch (Exception e) { e.printStackTrace(); }
            }
        }
        // handle multiple proxies
        if (ip != null && ip.length() > 15 && ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(","));
        }
        // handle localhost aliases
        if ("localhost".equalsIgnoreCase(ip) || "127.0.0.1".equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) {
            try {
                InetAddress inet = InetAddress.getLocalHost();
                ip = inet.getHostAddress();
            } catch (UnknownHostException e) { e.printStackTrace(); }
        }
        return ip;
    }

    /**
     * Get MAC address
     */
    public static String getMacAddress() throws Exception {
        byte[] mac = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) sb.append("-");
            String s = Integer.toHexString(mac[i] & 0xFF);
            sb.append(s.length() == 1 ? "0" + s : s);
        }
        return sb.toString().trim().toUpperCase();
    }
}

After obtaining the IP, the article moves to the geolocation step. The previously popular Taobao IP library has been discontinued, so the author introduces ip2region , an open‑source offline IP‑to‑region database that offers microsecond‑level query speed and high accuracy (≈99.9%).

ip2region stores data in an .xdb file with a fixed region format (country|region|province|city|ISP). It supports custom fields, data deduplication, compression, and three cache policies: file‑only, vector‑index cache (512 KiB), and full‑content cache.

The article lists Maven dependencies needed to use ip2region in a Spring Boot project:

<dependency>
  <groupId>com.github.hiwepy</groupId>
  <artifactId>ip2region-spring-boot-starter</artifactId>
  <version>2.0.1.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.lionsoul</groupId>
  <artifactId>ip2region</artifactId>
  <version>2.7.0</version>
</dependency>

Three Java usage patterns are demonstrated:

1. File‑only query

import org.lionsoul.ip2region.xdb.Searcher;
import java.io.*;
import java.util.concurrent.TimeUnit;

public class SearcherTest {
    public static void main(String[] args) {
        String dbPath = "ip2region.xdb file path";
        Searcher searcher = null;
        try {
            searcher = Searcher.newWithFileOnly(dbPath);
        } catch (IOException e) {
            System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);
            return;
        }
        try {
            String ip = "1.2.3.4";
            long sTime = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sTime);
            System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
        } catch (Exception e) {
            System.out.printf("failed to search(%s): %s\n", ip, e);
        }
        // each thread should create its own Searcher instance
    }
}

2. Vector‑index cache

byte[] vIndex = Searcher.loadVectorIndexFromFile(dbPath);
Searcher searcher = Searcher.newWithVectorIndex(dbPath, vIndex);

This reduces one disk I/O per query.

3. Full‑content cache

byte[] cBuff = Searcher.loadContentFromFile(dbPath);
Searcher searcher = Searcher.newWithBuffer(cBuff);

The entire database resides in memory, allowing safe concurrent access.

Compilation is performed with Maven ( mvn compile package ), producing ip2region-{version}.jar . The resulting JAR can be used to run search or benchmark commands:

java -jar ip2region-2.6.0.jar search --db=../../data/ip2region.xdb
java -jar ip2region-2.6.0.jar bench --db=../../data/ip2region.xdb --src=../../data/ip.merge.txt

The benchmark reports total queries, elapsed time, and average latency (e.g., 2 µs per operation). Different cache policies (file, vectorIndex, content) can be compared by changing the --cache-policy option.

Overall, the article provides a complete, production‑ready guide for backend developers to retrieve client IPs, map them to geographic regions, and evaluate performance using the ip2region library.

backendJavaNetworkmavenIP Geolocationip2region
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login 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.