炫酷!SpringBoot+Echarts實(shí)現(xiàn)用戶訪問地圖可視化項(xiàng)目(附源碼)
# 意義
在常見的電商、新聞、社交網(wǎng)站等,合理運(yùn)用運(yùn)營(yíng)成本才能最大化輸出自己的產(chǎn)品,其中最常見的功能就有針對(duì)不同訪問熱度的城市制定不同的運(yùn)營(yíng)手段,因此我們掌握用戶城市分布情況至關(guān)重要。關(guān)注Java開發(fā)寶典
pc端與移動(dòng)端不同,無(wú)法依托手機(jī)自帶的gps定位到用戶所在城市,只能通過ip來進(jìn)行判斷所在地理位置。
# 根據(jù)ip獲取城市的方式
淘寶、新浪等常年提供根據(jù)ip獲取城市的接口,但是隔一段時(shí)間會(huì)出現(xiàn)接口地址更改的情況,也有一定的限流
開源純真ip庫(kù):不斷迭代更新ip庫(kù)內(nèi)容,一般場(chǎng)景下足以使用,自主可控。(下載qqwry.dat庫(kù))關(guān)注公眾號(hào):Java開發(fā)寶典
# 思路
首先需要獲取用戶請(qǐng)求的ip地址,我們對(duì)該方法進(jìn)行簡(jiǎn)單封裝:
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的解析工具,根據(jù)ip獲取請(qǐng)求地址所在城市,github有大量實(shí)現(xiàn)版本,我們這里不做贅述,具體代碼見文末源碼
//篇幅較長(zhǎng),截取的主要方法,詳細(xì)在源碼地址查看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);}
自定義攔截器,對(duì)用戶的登錄請(qǐng)求進(jìn)行攔截,在此處判斷請(qǐng)求ip所在城市,并進(jìn)行計(jì)數(shù)。我們這里只是簡(jiǎn)單邏輯的說明,在生產(chǎn)上時(shí)應(yīng)該用redis來存放計(jì)數(shù),并且專門提供一個(gè)rest接口來推送當(dāng)前各城市訪問數(shù)量情況,再由前端配合,隔一段時(shí)間發(fā)起一次請(qǐng)求,例如隔一小時(shí)請(qǐng)求一次該rest接口,從而進(jìn)行前端數(shù)據(jù)的展示。
/*** 登錄攔截器*/@Slf4jpublic 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();}//展示訪問數(shù)量不是精確指標(biāo),如果要做到完全正確需要使用鎖,防止計(jì)數(shù)存在并發(fā)問題@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("【MyLoginInterceptor】調(diào)用了:{}", 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;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex){}}
注冊(cè)自定義的攔截器
@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyLoginInterceptor());}}
登錄controller模擬邏輯,注意:如果想看效果圖需要自己寫線程用不同的虛擬ip進(jìn)行訪問url,從而達(dá)到在不同城市訪問接口的效果。
@RestController("user")public class LoginController {@GetMapping("login")public String login() {//登錄邏輯return "success";}}
# 最終效果

# 前后端源碼獲取
在【武哥聊編程】里回復(fù):地圖可視化,即可獲取項(xiàng)目源碼
點(diǎn)贊是最大的支持 
