起因

前段时间发现博客右边的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. PythonI/O进阶学习笔记_1.抽象、面向对象、class/object/type

    前言: 是自己在学习python进阶IO学习视频的时候的理解和笔记,因为很多都是本菜鸟学习时候的自己的理解,有可能理解有误. Content: - 抽象的概念和面向对象的概念?想要大概了解python ...

  2. Vuex模块化

    上图是vuex的结构图vuex即 store, 包含State,Action,Mutations, 每一个vue项目都需要使用vuex做组件之间的数据共享 使用场景: 数据最终存放在store的Sta ...

  3. .Net Core 三大Redis客户端对比和使用心得

    前言 稍微复杂一点的互联网项目,技术选型都可能会涉及Redis,.NetCore的生态越发完善,支持.NetCore的Redis客户端越来越多, 下面三款常见的Redis客户端,相信大家平时或多或少用 ...

  4. Spring框架的重要问题

    这篇文章总结了一些关于Spring框架的重要问题,这些问题都是你在面试或笔试过程中可能会被问到的. 目录 Spring概述 依赖注入 Spring Beans Spring注解 Spring的对象访问 ...

  5. 并发新特性—Executor框架与线程池

    http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的AP ...

  6. MapDB使用入门

    背景 MapDB官网:http://www.mapdb.org 官方翻译之后的话:MapDB基于堆外存储.磁盘存储提供了Java的Maps.Sets.Lists.Queues等功能.它混合了Java集 ...

  7. 前端开发-Web标准

    Web标准 1理解:结构 => html表现 => css行为 => js(dom + es) WEB标准(结构.表现.行为分离)有哪些优点呢? 易于维护:只需更改CSS文件,就可以 ...

  8. Android自动化测试探索(五)代码覆盖率统计

    Android 代码覆盖率统计 本周开始准备统计Android自动化用例的代码覆盖率,将最终使用的方法记录下来. 覆盖率监测的原理 覆盖率监测的原理跟iOS上的原理差不多,大致的思路参考下吧, iOS ...

  9. 逆向破解之160个CrackMe —— 026

    CrackMe —— 026 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  10. ST算法 Sliding Window algorithm template

    ST算法(Sliding Window):A easy way to slove the substring problems algorithm template to slove substrin ...