# 集成 ip2region 实现离线 IP 地址定位
离线 IP 地址定位库主要用于内网或想减少对外访问 http 带来的资源消耗。(代码已兼容支持 jar 包部署)
# 1、引入依赖
1 2 3 4 5 6 <dependency > <groupId > org.lionsoul</groupId > <artifactId > ip2region</artifactId > <version > 1.7.2</version > </dependency >
# 2、添加工具类 RegionUtil.java
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 package com.ruoyi.common.utils;import java.io.File;import java.io.InputStream;import java.lang.reflect.Method;import org.apache.commons.io.FileUtils;import org.lionsoul.ip2region.DataBlock;import org.lionsoul.ip2region.DbConfig;import org.lionsoul.ip2region.DbSearcher;import org.lionsoul.ip2region.Util;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.io.ClassPathResource;public class RegionUtil { private static final Logger log = LoggerFactory.getLogger(RegionUtil.class); private static final String JAVA_TEMP_DIR = "java.io.tmpdir" ; static DbConfig config = null ; static DbSearcher searcher = null ; static { try { String dbPath = RegionUtil.class.getResource("/ip2region/ip2region.db" ).getPath(); File file = new File (dbPath); if (!file.exists()) { String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR); dbPath = tmpDir + "ip2region.db" ; file = new File (dbPath); ClassPathResource cpr = new ClassPathResource ("ip2region" + File.separator + "ip2region.db" ); InputStream resourceAsStream = cpr.getInputStream(); if (resourceAsStream != null ) { FileUtils.copyInputStreamToFile(resourceAsStream, file); } } config = new DbConfig (); searcher = new DbSearcher (config, dbPath); log.info("bean [{}]" , config); log.info("bean [{}]" , searcher); } catch (Exception e) { log.error("init ip region error:{}" , e); } } public static String getRegion (String ip) { try { if (searcher == null || StringUtils.isEmpty(ip)) { log.error("DbSearcher is null" ); return StringUtils.EMPTY; } long startTime = System.currentTimeMillis(); int algorithm = DbSearcher.MEMORY_ALGORITYM; Method method = null ; switch (algorithm) { case DbSearcher.BTREE_ALGORITHM: method = searcher.getClass().getMethod("btreeSearch" , String.class); break ; case DbSearcher.BINARY_ALGORITHM: method = searcher.getClass().getMethod("binarySearch" , String.class); break ; case DbSearcher.MEMORY_ALGORITYM: method = searcher.getClass().getMethod("memorySearch" , String.class); break ; } DataBlock dataBlock = null ; if (Util.isIpAddress(ip) == false ) { log.warn("warning: Invalid ip address" ); } dataBlock = (DataBlock) method.invoke(searcher, ip); String result = dataBlock.getRegion(); long endTime = System.currentTimeMillis(); log.debug("region use time[{}] result[{}]" , endTime - startTime, result); return result; }catch (Exception e) { log.error("error:{}" , e); } return StringUtils.EMPTY; } }
3、修改 AddressUtils.java
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 package com.ruoyi.common.utils.ip;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.ruoyi.common.config.RuoYiConfig;import com.ruoyi.common.utils.RegionUtil;import com.ruoyi.common.utils.StringUtils;public class AddressUtils { private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); public static final String UNKNOWN = "XX XX" ; public static String getRealAddressByIP2 (String ip) { String address = UNKNOWN; if (IpUtils.internalIp(ip)) { return "内网IP" ; } if (RuoYiConfig.isAddressEnabled()) { try { String rspStr = RegionUtil.getRegion(ip); if (StringUtils.isEmpty(rspStr)) { log.error("获取地理位置异常 {}" , ip); return UNKNOWN; } String[] obj = rspStr.split("\\|" ); String region = obj[2 ]; String city = obj[3 ]; return String.format("%s %s" , region, city); } catch (Exception e) { log.error("获取地理位置异常 {}" , e); } } return address; } }
4、添加离线 IP 地址库插件
下载前端插件相关包和代码实现 ruoyi / 集成 ip2region 离线地址定位.zip
链接: https://pan.baidu.com/s/13JVC9jm-Dp9PfHdDDylLCQ 提取码: y9jt
5、添加离线 IP 地址库
在 src/main/resources 下新建 ip2region 复制文件 ip2region.db 到目录下。
# 在线 Ip 地址统计
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 public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp" ;public static final String UNKNOWN = "XX XX" ;public static String getRealAddressByIP (String ip) { if (IpUtils.internalIp(ip)) { return "内网IP" ; } if (RuoYiConfig.isAddressEnabled()) { try { String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true" , Constants.GBK); if (StringUtils.isEmpty(rspStr)) { log.error("获取地理位置异常 {}" , ip); return UNKNOWN; } JSONObject obj = JSON.parseObject(rspStr); String region = obj.getString("pro" ); String city = obj.getString("city" ); return String.format("%s %s" , region, city); } catch (Exception e) { log.error("获取地理位置异常 {}" , ip); } } return UNKNOWN; }
返回字符串
# Ip 地址统计
首先利用 Aop 拦截发送的服务器的请求
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.durtime.frontapi.aspect;import cn.hutool.http.useragent.UserAgent;import cn.hutool.http.useragent.UserAgentUtil;import com.durtime.common.utils.DateUtils;import com.durtime.common.utils.StringUtils;import com.durtime.common.utils.ip.AddressUtils;import com.durtime.common.utils.ip.IpUtils;import com.durtime.frontapi.article.service.impl.VisitService;import com.durtime.noapp.domain.AppVisitRecord;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.text.SimpleDateFormat;import java.util.Date;@Aspect @Component public class FrontLogAspect { protected Logger log = LoggerFactory.getLogger(getClass()); @Autowired private VisitService visitService; @Pointcut("execution(* com.durtime.frontapi.controller.FrontArticleController.getList(..))" + " || execution(* com.durtime.frontapi.controller.FrontArticleController.getById(..))" + " || execution(* com.durtime.frontapi.controller.FrontUserController.getCurrentUser(..))") public void logpoint () {} @Before("logpoint()") public void beforeAction () { long beginTime = System.currentTimeMillis(); RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest request = sra.getRequest(); UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent" )); String browser = ua.getBrowser().toString(); System.out.println("浏览器 " +browser); String os = ua.getPlatform().toString(); System.out.println("os " +os); Object requestPath = request.getRequestURI(); String ip = IpUtils.getIpAddr(request); String optTime = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ).format(new Date ()); String realAddressByIP2 = AddressUtils.getRealAddressByIP2(ip); String province = new String ("内网IP" ); String city = new String ("内网IP" ); String country = new String ("内网IP" ); if (!IpUtils.internalIp(ip)){ String[] s = realAddressByIP2.split(" " ); province = s[0 ]; city = s[1 ]; } log.debug("*****************************************************************************************************************" ); log.debug("[访问时间]>>>>> " + optTime); log.debug("[访问 IP]>>>>> " + ip); log.debug("[访问 地址]>>>>> " + AddressUtils.getRealAddressByIP(ip)); log.debug("[访问 地址]>>>>> " + province+ " " +city); log.debug("[访问路由]>>>>> " + requestPath); log.debug("[耗费时间]>>>>> " + (System.currentTimeMillis() - beginTime) + " ms" ); log.debug("*****************************************************************************************************************\n" ); if (StringUtils.isEmpty(visitService.getRedisIp(ip))){ AppVisitRecord appVisitRecord = new AppVisitRecord (); appVisitRecord.setIp(ip); appVisitRecord.setCountry(country); appVisitRecord.setCity(city); appVisitRecord.setProvince(province); appVisitRecord.setOs(os); appVisitRecord.setBrowser(browser); appVisitRecord.setCreateTime(DateUtils.getNowDate()); visitService.addRecord(appVisitRecord); visitService.doCountByPass(); visitService.addIp(ip); } } }
访问量统计服务
VisitService.java
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 package com.durtime.frontapi.article.service.impl;import com.durtime.noapp.domain.AppVisitRecord;import com.durtime.noapp.service.IAppVisitRecordService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Service;import java.util.Set;import java.util.concurrent.TimeUnit;@Service public class VisitService { protected Logger log = LoggerFactory.getLogger(getClass()); private String prefix = "vc:" ; @Autowired private RedisTemplate redisTemplate; @Autowired private IAppVisitRecordService appVisitRecordService; public boolean initVisitCount () { redisTemplate.opsForValue().set("visitcount" ,0 ); return true ; } public int getVisitCount () { int visitcount = (int ) redisTemplate.opsForValue().get("visitcount" ); log.info("visitcount:" +visitcount); return visitcount; } public String getRedisIp (String ip) { String Ip = (String) redisTemplate.opsForValue().get(prefix+ip); log.info("Ip:" +Ip); return Ip; } public boolean setVisitCount (int vc) { redisTemplate.opsForValue().set("visitcount" ,vc); return true ; } public boolean addIp (String ip) { redisTemplate.opsForValue().setIfAbsent(prefix+ip,"1" ,30 , TimeUnit.MINUTES); return false ; } public boolean addRecord (AppVisitRecord appVisitRecord) { if (appVisitRecordService.insertAppVisitRecord(appVisitRecord)>0 ) return true ; return false ; } public boolean doCountByPass () { setVisitCount(getVisitCount()+1 ); log.info("统计vc:" +getVisitCount()); return true ; } }
# 网站访问量获取
1 visitService.getVisitCount();