All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.hiwepy.ip2region.spring.boot.ext.XdbSearcher Maven / Gradle / Ivy

package com.github.hiwepy.ip2region.spring.boot.ext;

import com.github.hiwepy.ip2region.spring.boot.util.Util;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * https://github.com/lionsoul2014/ip2region/tree/master/binding/java
 */
@Slf4j
public class XdbSearcher implements ResourceLoaderAware, DisposableBean {

    public static final String NOT_MATCH = "0|0|0|内网IP|内网IP";
    public static final RegionAddress NOT_MATCH_REGION_ADDRESS = new RegionAddress(NOT_MATCH.split("\\|"));
    public static final String DEFAULT_LOCATION = "classpath:ip2region/ip2region.xdb";
    protected ResourceLoader resourceLoader;
    protected byte[] vIndex;
    protected byte[] xdbBuff;
    protected Searcher searcher = null;

    public XdbSearcher(ResourceLoader resourceLoader) throws IOException {
        this.resourceLoader = resourceLoader;
        this.searcher = this.loadWithBuffer(DEFAULT_LOCATION);
    }

    public XdbSearcher(ResourceLoader resourceLoader, String location) throws IOException {
        this.resourceLoader = resourceLoader;
        this.searcher = this.loadWithBuffer(location);
    }

    /**
     * 缓存整个 xdb 数据 (推荐)
     * 1、创建 searcher 对象
     * 2、加载数据
     * 3、关闭 searcher 对象
     * @param location
     * @throws IOException
     */
    public synchronized Searcher loadWithBuffer(String location) throws IOException {
        // 1、从 dbPath 加载整个 xdb 到内存。
        if (Objects.isNull(xdbBuff)) {
            try {
                if(new File(location).exists()) {
                    // load ip2region.db from java.nio.file.Path
                    xdbBuff = Searcher.loadContentFromFile(location);
                } else {
                    // 查找resource
                    Resource resource = resourceLoader.getResource(location);
                    try(ByteArrayOutputStream output = new ByteArrayOutputStream();) {
                        FileCopyUtils.copy(resource.getInputStream(), output);
                        xdbBuff = output.toByteArray();
                    }
                }
            } catch (Exception e) {
                log.error(String.format("failed to load content from `%s`: \n", location), e);
            }
        }
        // 2、使用上述的 xdbBuff 创建一个完全基于内存的查询对象。
        Searcher searcher = null;
        if (Objects.nonNull(xdbBuff)) {
            try {
                searcher = Searcher.newWithBuffer(xdbBuff);
            } catch (Exception e) {
                log.error("failed to create content cached searcher: \n", e);
            }
        }
        return searcher;
    }

    /**
     * get the region with a int ip address with memory binary search algorithm
     *
     * @param   ip
     * @throws IOException
     */
    public String memorySearch(long ip) throws IOException {
        if(Objects.isNull(xdbBuff) || Objects.isNull(searcher)){
            return NOT_MATCH;
        }
        long sTime = System.nanoTime();
        String region = searcher.search(ip);
        long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
        log.info(" IP : {} >> region: {}, ioCount: {}, took: {} μs \n", Searcher.long2ip(ip), region, searcher.getIOCount(), cost);
        // not matched
        if (!StringUtils.hasText(region)) {
            return NOT_MATCH;
        }
        return region;
    }

    /**
     * get the region throught the ip address with memory binary search algorithm
     *
     * @param   ip
     * @return  DataBlock
     * @throws  IOException
     */
    public String memorySearch(String ip) throws IOException {
        return memorySearch(Util.ip2long(ip));
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void destroy() throws Exception {
        if(Objects.nonNull(searcher)){
            searcher.close();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy