Java集成ip2region2.x实现ip属地功能
效果图/封面
一、前言
如今许多软件如B站、微博、抖音等都加上 IP 归属地防止恶意评论,境外用户显示的是国家,国内的用户显示的省份。兴致一起,我便想自己的博客项目加上此功能。
目前存在几种方式:
二、ip2region简介
ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java、php、c、python、nodejs、golang、c#等查询绑定和Binary,B树,内存三种查询算法。
三、ip2region的使用
1、下载ip2region.db
将项目从GitHub/Gitee仓库down下来,找到data目录,有三种不同文件格式的ip地址库,进入找到ip2region.xdb,将ip2region.xdb复制出来放到resources下。
2、pom.xml中引入依赖
1 2 3 4 5
| <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.6.5</version> </dependency>
|
3、IpUtils工具类
其中有三个方法,
其一是去获取请求中的真实客户端ip。
其二是通过ip获取城市信息。
其三在服务启动时加载 ip2region.db 这个数据资源到内存中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| package com.lll.blog.utils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils; import lombok.extern.slf4j.Slf4j; import org.lionsoul.ip2region.xdb.Searcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils;
import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import java.io.InputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map;
@Slf4j @Component public class IPUtils {
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
private static Searcher searcher;
public static String getIpAddr(HttpServletRequest request) { String ip = null; try { ip = request.getHeader("x-forwarded-for"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { log.error("getIpAddress exception:", e); } ip = inet.getHostAddress(); } } } catch (Exception e) { logger.error("IPUtils ERROR ", e); } return ip; }
public static Map getCityInfo(String ip) { HashMap<String, Object> cityInfo = new HashMap<>(); try { String searchIpInfo = searcher.search(ip); String[] splitIpInfo = searchIpInfo.split("\\|"); cityInfo.put("ip",ip); cityInfo.put("searchInfo", searchIpInfo); cityInfo.put("country",splitIpInfo[0]); cityInfo.put("region",splitIpInfo[1]); cityInfo.put("province",splitIpInfo[2]); cityInfo.put("city",splitIpInfo[3]); cityInfo.put("ISP",splitIpInfo[3]); return cityInfo; } catch (Exception e) { log.info("failed to search(%s): %s\n", ip, e); } return null; }
@PostConstruct private static void initIp2regionResource() { try { InputStream inputStream = new ClassPathResource("/ipdb/ip2region.xdb").getInputStream(); byte[] dbBinStr = FileCopyUtils.copyToByteArray(inputStream); searcher = Searcher.newWithBuffer(dbBinStr); } catch (Exception e) { log.info("failed to create content cached searcher: %s\n", e); } }
}
|
4、测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.lll.blog.controller;
import com.lll.blog.utils.IPUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest; import java.util.Map;
@Controller public class IpController {
@GetMapping(value = "/testIp") @ResponseBody public Object testIp(HttpServletRequest request) {
String ipAddr = IPUtils.getIpAddr(request); Map cityInfo = IPUtils.getCityInfo(ipAddr); System.out.println(cityInfo.get("province")); String ip = "183.213.81.138"; Map result = IPUtils.getCityInfo(ip); System.out.println(result.get("province")); return cityInfo; } }
|
四、需求实现-博客项目归属地
项目技术:Springboot + Vue
1、后端
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.lll.blog.controller;
import com.lll.blog.service.SysUserService; import com.lll.blog.utils.IPUtils; import com.lll.blog.vo.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import java.util.Map;
@RestController @RequestMapping("users") public class UsersController {
@Autowired private SysUserService SysUserService; @GetMapping("getIpRegion") public Result getIpRegion(HttpServletRequest request){ String ipAddr = IPUtils.getIpAddr(request); return SysUserService.getIpRegion(ipAddr); } }
|
Service
1 2 3 4
| public interface SysUserService {
Result getIpRegion(String ip); }
|
Impl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.lll.blog.service.impl;
import com.lll.blog.utils.IPUtils; import com.lll.blog.vo.ErrorCode; import com.lll.blog.vo.Result;
import java.util.Map;
@Service public class SysUserServiceImpl implements SysUserService {
@Override public Result getIpRegion(String ip) { Map cityInfo = IPUtils.getCityInfo(ip); if ("中国".equals(cityInfo.get("country"))){ System.out.println(cityInfo.get("province")); Object province = cityInfo.get("province"); return Result.success(province); } else if ("0".equals(cityInfo.get("country"))){ System.out.println(cityInfo); if ("内网IP".equals(cityInfo.get("ISP"))){ return Result.success("内网"); } return Result.success("未知"); } else { System.out.println(cityInfo.get("country")); return Result.success(cityInfo.get("country")); } }
}
|
2、前端
(下面仅仅展示部分关键代码)
api
1 2 3 4 5
| export function getIpRegionInfo() { return request({ url: '/users/getIpRegion', method: 'get' })
|
vue页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <el-card> <div class="me-author-description" v-if="!user.login"> <span><i class="el-icon-location-outline"></i> IP属地:{{ip}}</span> </div> </el-card> </template>
<script> import {getIpRegionInfo} from '@/api/login'
export default { name: 'CardMe', created() { this.getIpRegionInfo() }, data() { return { ip: null, } }, methods: { getIpRegionInfo() { getIpRegionInfo().then((data => { this.ip = data.data })).catch(error => { if (error !== 'error') { that.$message({type: 'error', message: 'ip归属地获取失败!', showClose: true}) } }) } } } </script>
|
五、扩展
1、好文
2、待尝试