当前位置: 主页 > JAVA语言

java 获取xml 指定节点-java xml指定属性节点

发布时间:2023-03-26 07:14   浏览次数:次   作者:佚名

每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。

X-Real-IP

一般只记录真实发出请求的客户端IP。

Proxy-Client-IP

这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头。

WL-Proxy-Client-IP

也是通过 Apache http 服务器,在 weblogic 插件加上的头。

分析方法request.getRemoteAddr()

这种方法在大部分情况下都是有效的。

但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

如果使用了反向代理软件,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1或192.168.1.110或公网IP,而并不是客户端的真实IP。

获取ip属地

我们通过以上方法获取了ip完整地址后,该如何使用ip完整地址获取ip属地呢?

在浏览Gitee时,发现了Ip2region 这个库,我们可以使用Ip2region 来获取ip属地。

xml获取指定节点_java xml指定属性节点_java 获取xml 指定节点

Ip2region是什么

ip2region – 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。

Ip2region的特性标准化的数据格式

每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP。

只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0。

数据去重和压缩

xdb 格式生成程序会自动去重和压缩部分数据,默认的全部 IP 数据,生成的 ip2region.xdb 数据库是 11MiB,随着数据的详细度增加数据库的大小也慢慢增大。

极速查询响应

即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别,可通过如下两种方式开启内存加速查询:

vIndex 索引缓存 :使用固定的 512KiB 的内存空间缓存 vector index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间。

xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 IO 操作,保持微秒级别的查询效率。

IP 数据管理框架

java xml指定属性节点_xml获取指定节点_java 获取xml 指定节点

v2.0 格式的 xdb 支持亿级别的 IP 数据段行数,region 信息也可以完全自定义,例如:你可以在 region 中追加特定业务需求的数据,例如:GPS信息/国际统一地域信息编码/邮编等。也就是你完全可以使用 ip2region 来管理你自己的 IP 定位数据。

内置的三种查询算法

之所以全部的查询客户端单次查询都在 0.x 毫秒级别,是因为内置了三种查询算法:

memory 算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。

binary 算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别。

b-tree 算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。

使用ip2region安装依赖

 <dependency>
    <groupId>org.lionsoul</groupId>
         <artifactId>ip2region</artifactId>
     <version>2.6.5</version>
 </dependency>

下载 ip2region.xdb文件

我们可以登录ip2region的源代码,找到目录 ip2region/ data / ip2region.xdbjava 获取xml 指定节点,点击下载源文件,如下图所示:

在这里插入图片描述

配置ip2region.xdb文件

java xml指定属性节点_java 获取xml 指定节点_xml获取指定节点

我们把下载好的ip2region.xdb文件,放置在resources目录下,如下图所示:

配置ip2region.xdb文件

实现代码完全基于文件查询

 /**
   * @author zs
   * @datetime 2022/8/1:17:05
   * @param ipAddress ip地址,比如127.0.0.1
   * @desc 获取ip属地
   */
  public static String getIpBelong(String ipAddress) {
    // 1、 获取文件地址
    String dbPath = "./src/main/resources/ip2region.xdb";
    // 2、 创建 searcher 对象
    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 null;
    }
    // 3、查询地址
    String region = null;
    try {
      long sTime = System.nanoTime();
      region = searcher.search(ipAddress);
      long cost = TimeUnit.NANOSECONDS.toMicros((System.nanoTime() - sTime));
      System.out.printf(
          "输出日志 = {ip属地: %s, io次数: %d, 耗时: %d μs}\n", region, searcher.getIOCount(), cost);
    } catch (Exception e) {
      System.out.printf("failed to search(%s): %s\n", ipAddress, e);
    }
    // 4、关闭资源
    try {
      searcher.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return region;
  }

重要提醒

并发使用,每个线程需要创建一个独立的 searcher 对象单独使用。

使用缓存 VectorIndex 索引查询

我们可以提前从 xdb 文件中加载出来 VectorIndex 数据,然后全局缓存,每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作,从而加速查询,减少 IO 压力。

 /**
   * @author zs
   * @datetime 2022/8/1:17:15
   * @param ipAddress ip地址,比如127.0.0.1
   * @desc 使用缓存 VectorIndex 索引
   */
  public static String vectorIndexCache(String ipAddress) {
    // 1、获取文件地址
    String dbPath = "./src/main/resources/ip2region.xdb";
    // 2、从 dbPath 中预先加载 VectorIndex 缓存,并且把这个得到的数据作为全局变量,后续反复使用。
    byte[] vIndex;
    try {
      vIndex = Searcher.loadVectorIndexFromFile(dbPath);
    } catch (Exception e) {
      System.out.printf("failed to load vector index from `%s`: %s\n", dbPath, e);
      return null;
    }
    // 3、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
    Searcher searcher;
    try {
      searcher = Searcher.newWithVectorIndex(dbPath, vIndex);
    } catch (Exception e) {
      System.out.printf("failed to create vectorIndex cached searcher with `%s`: %s\n", dbPath, e);
      return null;
    }
    // 4、查询
    String region = null;
    try {
      long sTime = System.nanoTime();
      region = searcher.search(ipAddress);
      long cost = TimeUnit.NANOSECONDS.toMicros((System.nanoTime() - sTime));
      System.out.printf(
          "输出日志 = {ip属地: %s, io次数: %d, 耗时: %d μs}\n", region, searcher.getIOCount(), cost);
    } catch (Exception e) {
      System.out.printf("failed to search(%s): %s\n", ipAddress, e);
    }
    // 5、关闭资源
    try {
      searcher.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return region;
  }

重要提醒使用缓存整个 xdb 数据


 /**
   * @author zs
   * @datetime 2022/8/1:17:15
   * @param ipAddress ip地址,比如127.0.0.1
   * @desc 使用缓存整个 xdb 数据
   */
  public static String cacheXdb(String ipAddress) {
    // 1、获取文件地址
    String dbPath = "./src/main/resources/ip2region.xdb";
    // 2、从 dbPath 加载整个 xdb 到内存。
    byte[] cBuff;
    try {
      cBuff = Searcher.loadContentFromFile(dbPath);
    } catch (Exception e) {
      System.out.printf("failed to load content from `%s`: %s\n", dbPath, e);
      return;
    }
    // 3、使用上述的 cBuff 创建一个完全基于内存的查询对象。
    Searcher searcher;
    try {
      searcher = Searcher.newWithBuffer(cBuff);
    } catch (Exception e) {
      System.out.printf("failed to create content cached searcher: %s\n", e);
      return null;
    }
    // 4、查询
    String region = null;
    try {
      long sTime = System.nanoTime();
      region = searcher.search(ipAddress);
      long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
      System.out.printf(
          "输出日志 = {ip属地: %s, io次数: %d, 耗时: %d μs}\n", region, searcher.getIOCount(), cost);
    } catch (Exception e) {
      System.out.printf("failed to search(%s): %s\n", ipAddress, e);
    }
    // 5、关闭资源
    // searcher.close();
    return region;
  }

重要提醒

xml获取指定节点_java xml指定属性节点_java 获取xml 指定节点

关闭资源 – 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher。

并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。

获取具体属地

因为上述代码获取到的属地是原始属地,比如中国|0|上海|上海市|联通,因而,我们需要将其拆分,获取真正的属地,如下代码所示:

 /**
   * @author zs
   * @datetime 2022/8/1:17:31
   * @param cityInfo ip原始属地,比如:中国|0|上海|上海市|联通
   * @desc 将ip原始属地拆分,比如中国|0|上海|上海市|联通拆分成上海
   */
  public static String getIpPossession(String cityInfo) {
    if (null == cityInfo || cityInfo.equals("")) {
      return "未知";
    }
    cityInfo = cityInfo.replace("|", " ");
    String[] cityList = cityInfo.split(" ");
    if (cityList.length <= 0) {
      return "未知";
    }
    // 国内的显示到具体的省
    if ("中国".equals(cityList[0]) && cityList.length > 1) {
      return cityList[1];
    }
    // 国外显示到国家
    return cityList[0];
  }

测试代码测试国内ip

@Test
  public void testGetIpBelong() {
    String ipBelong = getIpBelong("220.248.12.158");
    System.out.println("\n输出ip原始属地:" + ipBelong);
    System.out.println("输出ip属地:" + getIpPossession(ipBelong));
  }

输出结果如下图:

在这里插入图片描述

测试国外ip

 @Test
  public void testGetIpBelong() {
    String ipBelong = getIpBelong("67.220.12.158");
    System.out.println("\n输出ip原始属地:" + ipBelong);
    System.out.println("输出ip属地:" + getIpPossession(ipBelong));
  }

输出结果如下图:

java 获取xml 指定节点_java xml指定属性节点_xml获取指定节点

在这里插入图片描述

总结源代码地址

因为代码时不断更新的,如果想要获取最新的maven,可以打开其源代码地址:

failed to create searcher: java.io.FileNotFoundException复现问题

在获取文件地址时java 获取xml 指定节点,报出了如下错误:

failed to create searcher with `./resources/ip2region.xdb`: 	
	java.io.FileNotFoundException: .\resources\ip2region.xdb (
		系统找不到指定的路径。
	)

分析问题

因为我使用文件的相对位置,即./resources/ip2region.xdb,但ip2region代码是从项目的根路径,去查找ip2region.xdb的文件的相对路径。

ip2region.xdb的完整路径是D:/project/demo/src/main/resources/ip2region.xdb,而我只写了./resources/ip2region.xdb,肯定找不到这个文件,就报出找不到文件异常。

如果我们不知道项目的位置,可以使用如下代码来查找,即:

 File file=new File("");
 try {
    System.out.println(file.getCanonicalPath());
  } catch (IOException e) {
    e.printStackTrace();
  }

输出结果是:D:\project\demo,便可以知道项目的根路径。

解决问题

既然知道了错误原因,便将文件的相对路径修改如下即可:

// 1. 获取文件地址
String dbPath = "./src/main/resources/ip2region.xdb";