精彩推荐
一百期Java面试题汇总
SpringBoot内容聚合
IntelliJ IDEA内容聚合
Mybatis内容聚合
SpringBoot+Echarts用户访问地图可视化
意义
public class IPUtil {
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
封装纯真ip的解析工具,根据ip获取请求地址所在城市,github有大量实现版本,我们这里不做赘述,具体代码见文末源码
//篇幅较长,截取的主要方法,详细在源码地址查看
public IPZone findIP(final String ip) {
final long ipNum = toNumericIP(ip);
final QIndex idx = searchIndex(ipNum);
if (idx == null) {
return new IPZone(ip);
}
return readIP(ip, idx);
}
自定义拦截器,对用户的登录请求进行拦截,在此处判断请求ip所在城市,并进行计数。我们这里只是简单逻辑的说明,在生产上时应该用redis来存放计数,并且专门提供一个rest接口来推送当前各城市访问数量情况,再由前端配合,隔一段时间发起一次请求,例如隔一小时请求一次该rest接口,从而进行前端数据的展示。
/**
登录拦截器*/
@Slf4j
br/>*/
@Slf4j
public class MyLoginInterceptor implements HandlerInterceptor {
private static final String LOGIN_PATH = "/user/login";
private static Map<String, AtomicInteger> visitCount;
private static final QQWry qqWry;
static {
visitCount = new HashMap<>(31);
qqWry = new QQWry();
}
//展示访问数量不是精确指标,如果要做到完全正确需要使用锁,防止计数存在并发问题@Override
br/>@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("【MyLoginInterceptor】调用了:{}", request.getRequestURI());
if (request.getRequestURI().equals(LOGIN_PATH)) {
String ipAddress = IPUtil.getIpAddress(request);
String province = qqWry.findIP(ipAddress).getMainInfo();
if (visitCount.containsKey(province)) {
visitCount.put(province,new AtomicInteger(visitCount.get(province).incrementAndGet()));
} else {
visitCount.put(province,new AtomicInteger());
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex){}
}
注册自定义的拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Override
br/>@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyLoginInterceptor());
}
}
登录controller模拟逻辑,注意:如果想看效果图需要自己写线程用不同的虚拟ip进行访问url,从而达到在不同城市访问接口的效果。
@RestController("user")
public class LoginController {
@GetMapping("login") public String login() { //登录逻辑 return "success"; }
}
**最终效果** ![](http://www.www.zyiz.net/i/li/?n=4&i=images/blog/202105/04/391e74b6481af22b8bb78ae5ec2d4577.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) **前后端源码**
https://github.com/Motianshi/distribute-tool