private void shortLinkStats(String fullShortUrl,String gid,HttpServletRequest request,HttpServletResponse response){
/**
* uv,pv,ip监控
**/
AtomicBoolean uvFirstFlag =new AtomicBoolean();
Cookie[] cookies = request.getCookies();
try {
AtomicReference<String> uv =new AtomicReference<>();
Runnable addResponseCookieTask =()->{
uv.set( cn.hutool.core.lang.UUID.fastUUID().toString());
Cookie uvCookie = new Cookie("uv", uv.get());
uvCookie.setMaxAge(60*60*24*30);
//为什么要设置路径
uvCookie.setPath(StrUtil.sub(fullShortUrl,fullShortUrl.indexOf("/"),fullShortUrl.length()));
response.addCookie(uvCookie);
uvFirstFlag.set(Boolean.TRUE);
stringRedisTemplate.opsForSet().add("short-link-status:uv:"+fullShortUrl,uv.get());
};
if(ArrayUtil.isNotEmpty(cookies)){
//过滤流中cookie的名字是"uv"的
//找到第一个就不再遍历其他的元素
//将流中的所有元素用自己的的value代替
//ifPresentOrElse,如果找到了名字是"uv"的,就存redis的set,存成功了就给uvFirstFlag赋值true,否则就是false,如果没有找到名字是"uv"的,就执行addResponseCookieTask任务
Arrays.stream(cookies)
.filter(each -> Objects.equals(each.getName(),"uv"))
.findFirst()
.map(Cookie::getValue)
.ifPresentOrElse(each->{
uv.set(each);
Long added =stringRedisTemplate.opsForSet().add("short-link-status:uv:"+fullShortUrl,each);
uvFirstFlag.set(added!=null&&added>0L);
},addResponseCookieTask);
}else {
addResponseCookieTask.run();
}
//判断ip是否重复
String remoteAddr = LinkUtil.getIp(request);
Long uipAdded = stringRedisTemplate.opsForSet().add("short-link:stats:uip:" + fullShortUrl, remoteAddr);
boolean uipFirstFlag =uipAdded!=null&&uipAdded>0L;
//如果gid是空的就查一下路由表
if(StrUtil.isBlank(gid)){
LambdaQueryWrapper<ShortLinkGotoDO> eq = Wrappers.lambdaQuery(ShortLinkGotoDO.class)
.eq(ShortLinkGotoDO::getFullShortUrl, fullShortUrl);
ShortLinkGotoDO shortLinkGotoDO = shortLinkGotoMapper.selectOne(eq);
gid =shortLinkGotoDO.getGid();
}
int hour = DateUtil.hour(new Date(),true);
Week week = DateUtil.dayOfWeekEnum(new Date());
int weekValue = week.getIso8601Value();
LinkAccessStatsDO linkAccessStatsDO =LinkAccessStatsDO.builder()
.pv(1)
.uv(uvFirstFlag.get()?1:0)
.uip(uipFirstFlag?1:0)
.hour(hour)
.weekday(weekValue)
.fullShortUrl(fullShortUrl)
.gid(gid)
.date(new Date())
.build();
linkAccessStatsMapper.shortLinkStats(linkAccessStatsDO);
/**
* 地区信息监控
**/
//调用高德地图API获取地区信息
HashMap<String, Object> requestMap = new HashMap<>();
requestMap.put("key", statsLocaleAmapKey);
requestMap.put("ip",remoteAddr);
String result = HttpUtil.get(AMAP_REMOTE_URL, requestMap);
JSONObject localeResultObj= JSON.parseObject(result);
String infocode = localeResultObj.getString("infocode");
String province=null;
String city=null;
LinkLocaleStatsDO linkLocaleStatsDO;
if(StrUtil.isNotBlank(infocode)&&StrUtil.equals(infocode,"10000")){
province = StrUtil.equals("[]",localeResultObj.getString("province"))?"未知":localeResultObj.getString("province");
city = StrUtil.equals("[]",localeResultObj.getString("city"))?"未知":localeResultObj.getString("city");
String adcode = localeResultObj.getString("adcode");
linkLocaleStatsDO = LinkLocaleStatsDO.builder()
.city(city)
.province(province)
.adcode( StrUtil.isBlank(adcode)?"未知":adcode)
.country("中国")
.cnt(1)
.fullShortUrl(fullShortUrl)
.gid(gid)
.date(new Date())
.build();
linkLocaleStatsMapper.shortLinkLocaleStats(linkLocaleStatsDO);
}
/**
* 操作系统信息监控
**/
String os = LinkUtil.getOs(request);
LinkOsStatsDO linkOsStatsDO = LinkOsStatsDO.builder()
.cnt(1)
.fullShortUrl(fullShortUrl)
.os(os)
.gid(gid)
.date(new Date())
.build();
linkOsStatsMapper.shortLinkOsStats(linkOsStatsDO);
/**
* 浏览器监控
**/
String browser = LinkUtil.getBrowser(request);
LinkBrowserStatsDO linkBrowserStatsDO =LinkBrowserStatsDO.builder()
.cnt(1)
.fullShortUrl(fullShortUrl)
.browser(browser)
.gid(gid)
.date(new Date())
.build();
linkBrowserStatsMapper.shortLinkBrowserStats(linkBrowserStatsDO);
/**
* 访问设备监控
**/
String device = LinkUtil.getDevice(request);
LinkDeviceStatsDO linkDeviceStatsDO = LinkDeviceStatsDO.builder()
.device(device)
.cnt(1)
.fullShortUrl(fullShortUrl)
.date(new Date())
.build();
linkDeviceStatsMapper.shortLinkDeviceState(linkDeviceStatsDO);
/**
* 访问网络监控
**/
String network = LinkUtil.getNetwork(request);
LinkNetworkStatsDO linkNetworkStatsDO = LinkNetworkStatsDO.builder()
.network(network)
.cnt(1)
.gid(gid)
.fullShortUrl(fullShortUrl)
.date(new Date())
.build();
linkNetworkStatsMapper.shortLinkNetworkState(linkNetworkStatsDO);
/**
* 访问日志
**/
LinkAccessLogsDO linkAccessLogsDO = LinkAccessLogsDO.builder()
.ip(remoteAddr)
.user(uv.get())
.os(os)
.browser(browser)
.fullShortUrl(fullShortUrl)
.gid(gid)
.device(device)
.locale(StrUtil.join("-","中国",province,city))
.network(network)
.build();
linkAccessLogsMapper.insert(linkAccessLogsDO);
//增加该短链接的总访问数
baseMapper.incrementStats(gid, fullShortUrl, 1, uvFirstFlag.get() ? 1 : 0, uipFirstFlag ? 1 : 0);
LinkStatsTodayDO linkStatsTodayDO = LinkStatsTodayDO.builder()
.todayPv(1)
.todayUv(uvFirstFlag.get() ? 1 : 0)
.todayUip(uipFirstFlag ? 1 : 0)
.gid(gid)
.fullShortUrl(fullShortUrl)
.date(new Date())
.build();
linkStatsTodayMapper.shortLinkTodayState(linkStatsTodayDO);
}catch (Throwable e){
log.error("短链接访问统计异常",e);
}
}