起因

前段时间发现博客右边的FlagCounter计数器突然没了,又看到了博客园封杀了FlagCounter的消息,有点摸不着头脑。于是上FlagCounter的网站上看了一眼,发现最近出现的来自新国家访问居然来自台湾。又经过一轮百度,看到有博主发表声明说由于国家立场拒绝使用FlagCounter了。于是我赶紧把公告栏清空了,又苦于没有替代品,就想着干脆自己写一个。

FlagCounter将台湾显示为国家


显示效果对比(左:FlagCounter 右:自制)

前端显示的是HTML,比FlagCounter的图片格式要清晰很多。

开发环境以及线上环境

  • SpringBoot 2.1.8
  • Redis 5.0.x
  • 域名 + SSL证书 (博客园需要https)

使用到的接口及开源数据

  • www.taobao.com/help/getip.php 用于获取IP地址(可以直接用下面的接口获取,之前疏忽了)
  • http://ip-api.com/json/ 用于解析IP地理位置(只提供HTTP,所以请求需要通过后端发送)
  • https://github.com/mukeshsolanki/country-picker-android 国旗图片来源

开发思路

  用户访问时通过淘宝接口在前端获取访客IP地址,传给后端。后端向ip-api请求ip地址解析后的国家代码,并记录到Redis数据库。同时向后端请求访客数据,并显示在页面上。

  其实在找国家代码标准的数据的时候,发现有两种标准:一种是ISO-3166标准,还有一种是GB/T 2659-2000。区别在于,前者把香港、台湾等地区标为HK、TW,后者直接都标记为CN。可能FlagCounter也只是被这个标准坑了一波,把所有的国家代码标注的地区都当做了国家处理。

关键代码

package com.qf;  

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import java.util.HashMap;
import java.util.Set; @CrossOrigin
@RestController
@Transactional
public class Controller { @Autowired
private StringRedisTemplate redisTemplate; private RestTemplate restTemplate = new RestTemplate(); // 接口隐藏
@RequestMapping("xxxxxx")
public String getVisitor(){
// 取出排名前20的国家以及total(总数),所以是0-20共21个
Set<ZSetOperations.TypedTuple<String>> typedTupleSet = redisTemplate.opsForZSet().reverseRangeWithScores("visitor", 0, 20);
return JSON.toJSON(typedTupleSet).toString();
} // 接口隐藏
@RequestMapping("xxxxxx")
public void addVisitor(@PathVariable String ip){
// 请求ip-api接口,获取ip所属地信息
IPaddr iPaddr = restTemplate.getForObject("http://ip-api.com/json/"+ip, IPaddr.class, new HashMap<>());
String code = iPaddr.getCountryCode();
// 转换为GB/T 2659-2000标准
if (code.equals("HK") || code.equals("TW") || code.equals("MO")) {
code = "CN";
}
// 更新Redis中的记录
redisTemplate.opsForZSet().incrementScore("visitor", code, 1);
redisTemplate.opsForZSet().incrementScore("visitor", "total", 1);
}
}

FlagCounter被封杀?自己实现一个简单的多国访客计数器的更多相关文章

  1. 用mkdocs在gitee码云上建立一个简单的文档博客

    利用mkdocs建立简单的文档博客 一.概述 MkDocs 是一个用于创建项目文档的 快速, 简单 , 完美华丽 的静态站点生成器. 文档源码使用 Markdown 来撰写, 用一个 YAML 文件作 ...

  2. 从开发到部署,使用django创建一个简单可用的个人博客

    本文参考于: 简书-Django搭建简易博客教程:http://www.jianshu.com/p/d15188a74104 自强学堂-Django基础教程:http://www.ziqiangxue ...

  3. 一个简单的hexo搭建博客网站的故事

    首先安装hexo mkdir hexo #创建一个文件夹 cd hexo #切换到hexo目录下面 npm install -g hexo-cli npm install hexo --save 然后 ...

  4. 爬虫浅谈一:一个简单c#爬虫程序

    这篇文章只是简单展示一个基于HTTP请求如何抓取数据的文章,如觉得简单的朋友,后续我们再慢慢深入研究探讨. 图1: 如图1,我们工作过程中,无论平台网站还是企业官网,总少不了新闻展示.如某天产品经理跟 ...

  5. 哪种缓存效果高?开源一个简单的缓存组件j2cache

    背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...

  6. 在Openfire上弄一个简单的推送系统

    推送系统 说是推送系统有点大,其实就是一个消息广播功能吧.作用其实也就是由服务端接收到消息然后推送到订阅的客户端. 思路 对于推送最关键的是服务端向客户端发送数据,客户端向服务端订阅自己想要的消息.这 ...

  7. ASP.NET Aries 入门开发教程2:配置出一个简单的列表页面

    前言: 朋友们都期待我稳定地工作,但创业公司若要躺下,也非意念可控. 若人生注定了风雨飘摇,那就雨中前行了. 最机开始看聊新的工作机会,欢迎推荐,创业公司也可! 同时,趁着自由时间,抓紧把这系列教程给 ...

  8. 计算机程序的思维逻辑 (60) - 随机读写文件及其应用 - 实现一个简单的KV数据库

    57节介绍了字节流, 58节介绍了字符流,它们都是以流的方式读写文件,流的方式有几个限制: 要么读,要么写,不能同时读和写 不能随机读写,只能从头读到尾,且不能重复读,虽然通过缓冲可以实现部分重读,但 ...

  9. 如何开发一个简单的HTML5 Canvas 小游戏

    原文:How to make a simple HTML5 Canvas game 想要快速上手HTML5 Canvas小游戏开发?下面通过一个例子来进行手把手教学.(如果你怀疑我的资历, A Wiz ...

随机推荐

  1. java学习之- 线程继承Thread类

    标签(空格分隔): 线程 在java.lang包中有个Thread子类,大家可以自行查阅文档,及范例: 如何在自定义的代码中,自定义一个线程呢? 1.通过对api的查找,java已经提供了对线程这类事 ...

  2. MySQL之mysqldump的使用

    一.mysqldump 简介 mysqldump 是 MySQL 自带的逻辑备份工具. 它的备份原理是通过协议连接到 MySQL 数据库,将需要备份的数据查询出来,将查询出的数据转换成对应的inser ...

  3. 机器学习性能度量指标:ROC曲线、查准率、查全率、F1

    错误率 在常见的具体机器学习算法模型中,一般都使用错误率来优化loss function来保证模型达到最优. \[错误率=\frac{分类错误的样本}{样本总数}\] \[error=\frac{1} ...

  4. P2050 [NOI2012]美食节 动态连边优化费用流

    题意 类似的一道排队等候,算最小总等待时间的题目. 思路 但是这道题的边数很多,直接跑会tle,可以动态加边,就是先连上倒数第一次操作的边,跑一遍费用流,然后对使用了倒数第一条边的点,连上相应的倒数第 ...

  5. Codeforces 734D. Anton and Chess(模拟)

    Anton likes to play chess. Also, he likes to do programming. That is why he decided to write the pro ...

  6. shell 菜单选择命令

    devices=`adb devices | sed '1d;$d' | sed 's/device//g'`         */sed '1d;$d' : 删除第一行和最后一行*/ device_ ...

  7. redis数据库学习

    0 使用理由 0.1 高性能 纯内存操作,比在硬盘操作数据的速度有极大提升 0.2 高并发 承受请求比直接操作数据库大得多 0.3 单线程 至于redis单线程的原因.有点意思.CPU不是Redis的 ...

  8. 【Offer】[54] 【二叉搜索树的第k小节点】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 给定一棵二叉搜索树,请找出其中第k小的节点.例如,在下图的二叉搜索树里,按节点数值大小顺序,第三小节点的值是4.  牛客网刷题地址 思 ...

  9. 使用 jupyter-notebook + python + matplotlib 进行数据可视化

    上次用 python 脚本中定期查询数据库,监视订单变化,将时间与处理完成订单的数量进行输入写入日志,虽然省掉了人为定时查看数据库并记录的操作,但是数据不进行分析只是数据,要让数据活起来! 为了方便看 ...

  10. 数据库常用SQL语句(三):子查询

    一.为什么会使用子查询 虽然可以通过连接查询来实现多表查询数据记录,但不建议使用,因为连接查询的性能很差,为什么呢?我们来进行分析,例如 我们要查询部门表t_dept 和雇员表t_employee中的 ...