JavaScript 已禁用

为了获得更好的体验,请启用JavaScript,或点击下方链接跳转:

跳转至百度
Skip to content

网站访问统计系统设计方案

网站访问统计系统设计方案

我为您设计了一个基于 SpringBoot 和 VitePress 的网站访问统计系统,包含服务端 API 和前端埋点方案。

一、系统架构设计

plaintext
┌───────────────────┐      ┌───────────────────┐      ┌───────────────────┐
│     VitePress     │─────▶│    SpringBoot     │─────▶│      MySQL        │
│     博客前端      │      │    统计服务       │      │     数据库        │
└───────────────────┘      └───────────────────┘      └───────────────────┘
         │                                         ▲
         │                                         │
         └───────────────────┐                   │
                             │                   │
                         ┌───▼───────────────────┴───┐
                         │       可选:Redis        │
                         │      访问缓存           │
                         └─────────────────────────┘

二、数据库表设计

建议创建以下四张表来存储统计数据:

1. t_visit_site(网站信息表)

sql
CREATE TABLE `t_visit_site` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '网站ID',
  `site_name` varchar(100) NOT NULL COMMENT '网站名称',
  `site_domain` varchar(100) NOT NULL COMMENT '网站域名',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='网站信息表';

2. t_visit_page(页面信息表)

sql
CREATE TABLE `t_visit_page` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '页面ID',
  `site_id` bigint(20) NOT NULL COMMENT '所属网站ID',
  `page_url` varchar(500) NOT NULL COMMENT '页面URL',
  `page_title` varchar(200) DEFAULT NULL COMMENT '页面标题',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '首次访问时间',
  PRIMARY KEY (`id`),
  KEY `idx_site_id` (`site_id`),
  KEY `idx_page_url` (`page_url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='页面信息表';

3. t_visit_log(访问日志表)

sql
CREATE TABLE `t_visit_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID',
  `site_id` bigint(20) NOT NULL COMMENT '网站ID',
  `page_id` bigint(20) NOT NULL COMMENT '页面ID',
  `visitor_id` varchar(50) NOT NULL COMMENT '访问者ID',
  `ip_address` varchar(50) NOT NULL COMMENT 'IP地址',
  `user_agent` varchar(500) NOT NULL COMMENT 'User-Agent信息',
  `referer` varchar(500) DEFAULT NULL COMMENT '来源URL',
  `visit_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '访问时间',
  `visit_duration` int(11) DEFAULT NULL COMMENT '访问时长(秒)',
  `is_new_visitor` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否新访问者',
  PRIMARY KEY (`id`),
  KEY `idx_site_id` (`site_id`),
  KEY `idx_page_id` (`page_id`),
  KEY `idx_visitor_id` (`visitor_id`),
  KEY `idx_visit_time` (`visit_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志表';

4. t_visitor_info(访问者信息表)

sql
CREATE TABLE `t_visitor_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `visitor_id` varchar(50) NOT NULL COMMENT '访问者ID',
  `first_visit_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '首次访问时间',
  `last_visit_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后访问时间',
  `visit_count` int(11) NOT NULL DEFAULT '1' COMMENT '访问次数',
  `browser_name` varchar(50) DEFAULT NULL COMMENT '浏览器名称',
  `browser_version` varchar(50) DEFAULT NULL COMMENT '浏览器版本',
  `os_name` varchar(50) DEFAULT NULL COMMENT '操作系统名称',
  `os_version` varchar(50) DEFAULT NULL COMMENT '操作系统版本',
  `device_type` varchar(20) DEFAULT NULL COMMENT '设备类型(PC/Mobile/Tablet)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问者信息表';

三、SpringBoot 服务端实现思路

1. 核心依赖

xml
<dependencies>
  <!-- Web服务 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  
  <!-- 数据库访问 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>
  
  <!-- 工具库 -->
  <dependency>
    <groupId>eu.bitwalker</groupId>
    <artifactId>UserAgentUtils</artifactId>
    <version>1.21</version>
  </dependency>
  
  <!-- 可选:Redis缓存 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>
</dependencies>

2. 核心 API 设计

java
@RestController
@RequestMapping("/api/visit")
public class VisitController {

    @Autowired
    private VisitService visitService;

    /**
     * 记录页面访问
     */
    @PostMapping("/record")
    public Result recordVisit(@RequestBody VisitRecordDTO recordDTO,
                             HttpServletRequest request) {
        // 获取客户端IP
        String clientIp = getClientIp(request);
        
        // 获取User-Agent
        String userAgent = request.getHeader("User-Agent");
        
        // 记录访问
        visitService.recordVisit(recordDTO, clientIp, userAgent);
        
        return Result.success();
    }
    
    // 获取客户端真实IP
    private String getClientIp(HttpServletRequest request) {
        String xffHeader = request.getHeader("X-Forwarded-For");
        if (xffHeader == null) {
            return request.getRemoteAddr();
        }
        return xffHeader.split(",")[0];
    }
}

3. 访问记录处理服务

java
@Service
public class VisitServiceImpl implements VisitService {

    @Autowired
    private VisitLogRepository visitLogRepository;
    
    @Autowired
    private VisitorInfoRepository visitorInfoRepository;
    
    @Autowired
    private PageInfoRepository pageInfoRepository;
    
    @Override
    public void recordVisit(VisitRecordDTO recordDTO, String clientIp, String userAgent) {
        // 解析User-Agent获取浏览器和操作系统信息
        UserAgent userAgentInfo = UserAgent.parseUserAgentString(userAgent);
        Browser browser = userAgentInfo.getBrowser();
        OperatingSystem os = userAgentInfo.getOperatingSystem();
        
        // 生成或获取访问者ID (可使用Cookie或UUID)
        String visitorId = generateVisitorId(recordDTO.getVisitorId());
        
        // 保存或更新访问者信息
        saveOrUpdateVisitorInfo(visitorId, clientIp, userAgentInfo);
        
        // 获取或创建页面信息
        PageInfo pageInfo = getOrCreatePageInfo(recordDTO.getSiteId(), recordDTO.getPageUrl(), recordDTO.getPageTitle());
        
        // 保存访问日志
        saveVisitLog(visitorId, pageInfo.getId(), clientIp, userAgent, recordDTO);
    }
    
    // 其他方法实现...
}

四、VitePress 前端埋点方案

1. 创建统计插件

javascript
// .vitepress/theme/statistics.js
import { onMounted } from 'vue'
import { useRoute } from 'vitepress'

export default function useStatistics() {
  const route = useRoute()
  
  onMounted(() => {
    // 页面加载完成后发送统计请求
    sendVisitStatistics()
  })
  
  const sendVisitStatistics = () => {
    const siteId = 'YOUR_SITE_ID' // 替换为您的网站ID
    const pageUrl = route.path
    const pageTitle = document.title
    
    // 生成或获取访问者ID (使用localStorage存储)
    let visitorId = localStorage.getItem('visitor_id')
    if (!visitorId) {
      visitorId = generateUUID()
      localStorage.setItem('visitor_id', visitorId)
    }
    
    // 构建统计数据
    const visitData = {
      siteId,
      pageUrl,
      pageTitle,
      visitorId,
      referer: document.referrer
    }
    
    // 发送POST请求到统计API
    fetch('https://your-statistics-api.com/api/visit/record', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(visitData)
    })
    .catch(error => {
      console.error('统计数据发送失败:', error)
    })
  }
  
  // 生成UUID
  const generateUUID = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0
      const v = c === 'x' ? r : (r & 0x3 | 0x8)
      return v.toString(16)
    })
  }
  
  return {
    sendVisitStatistics
  }
}

2. 在主题中集成统计插件

javascript
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import useStatistics from './statistics.js'

export default {
  ...DefaultTheme,
  
  enhanceApp({ app, router }) {
    // 在应用启动时初始化统计
    app.mixin({
      setup() {
        const { sendVisitStatistics } = useStatistics()
        
        // 监听路由变化,记录每次页面访问
        router.afterEach(() => {
          sendVisitStatistics()
        })
        
        return {}
      }
    })
  }
}

五、数据统计与可视化

1. 统计 API 示例

java
@RestController
@RequestMapping("/api/statistics")
public class StatisticsController {

    @Autowired
    private StatisticsService statisticsService;

    /**
     * 获取网站总访问量
     */
    @GetMapping("/site/total")
    public Result getSiteTotalVisits(@RequestParam Long siteId) {
        return Result.success(statisticsService.getSiteTotalVisits(siteId));
    }
    
    /**
     * 获取网站每日访问趋势
     */
    @GetMapping("/site/daily-trend")
    public Result getSiteDailyTrend(@RequestParam Long siteId,
                                   @RequestParam(required = false) Integer days) {
        return Result.success(statisticsService.getSiteDailyTrend(siteId, days));
    }
    
    // 其他统计API...
}

2. 可视化展示

可以使用 ECharts 或 Chart.js 等前端图表库,基于统计 API 返回的数据生成图表:

javascript
// 示例:生成每日访问趋势图
const chart = echarts.init(document.getElementById('visit-trend-chart'));

fetch('/api/statistics/site/daily-trend?siteId=1&days=30')
  .then(response => response.json())
  .then(data => {
    const option = {
      xAxis: {
        type: 'category',
        data: data.dates
      },
      yAxis: {
        type: 'value'
      },
      series: [{
        data: data.visits,
        type: 'line'
      }]
    };
    
    chart.setOption(option);
  });

六、部署与优化建议

  1. 性能优化
    • 使用 Redis 缓存热门页面的统计数据
    • 异步处理访问日志(如使用 RabbitMQ 或 Kafka)
    • 定期归档历史数据
  2. 数据安全
    • 对 IP 地址进行脱敏处理(如只保留前三位)
    • 遵守 GDPR 等隐私法规,提供用户数据访问和删除接口
  3. 部署架构
    • 前端统计脚本可部署在 CDN 上
    • 服务端采用微服务架构,可水平扩展
    • 数据库使用主从复制,确保高可用性

通过以上设计,您可以实现一个完整的网站访问统计系统,既能收集详细的访问数据,又不会对 VitePress 博客的性能造成显著影响。

作者:威威

版权:此文章版权归 威威 所有,如有转载,请注明出处!

链接:可点击右上角分享此页面复制文章链接

最后更新于:

最近更新