This commit is contained in:
fanxb 2022-11-25 16:34:34 +08:00
parent 4c6e78d5f4
commit 1828c0755d
17 changed files with 201 additions and 20 deletions

View File

@ -73,6 +73,13 @@
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.7.21</version> <version>5.7.21</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -61,4 +61,17 @@ public class ApplicationController {
public ResultObject check(@Validated @RequestBody ApplicationSignVo body) { public ResultObject check(@Validated @RequestBody ApplicationSignVo body) {
return ResultObject.success(applicationService.check(body)); return ResultObject.success(applicationService.check(body));
} }
/**
* 下载统计数据
*
* @return com.fanxb.backend.entity.ResultObject
* @author fanxb
* date 2022-11-25 15:26
*/
@GetMapping("/download")
public void download(String key, String secret, HttpServletResponse response) throws Exception {
applicationService.download(key, secret, response);
}
} }

View File

@ -4,6 +4,8 @@ import com.fanxb.backend.entity.po.DetailPagePo;
import com.fanxb.backend.entity.po.HostPo; import com.fanxb.backend.entity.po.HostPo;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
import java.util.List;
/** /**
* @author fanxb * @author fanxb
* @date 2022/2/15 16:37 * @date 2022/2/15 16:37
@ -45,4 +47,15 @@ public interface DetailPageDao {
*/ */
@Update("update detail_page set uv=uv+#{uvIncrement},pv=pv+1 where id=#{id}") @Update("update detail_page set uv=uv+#{uvIncrement},pv=pv+1 where id=#{id}")
void updateUvPv(@Param("id") int id, @Param("uvIncrement") int uvIncrement); void updateUvPv(@Param("id") int id, @Param("uvIncrement") int uvIncrement);
/**
* 根据hostId查询数据
*
* @param hostId hostId
* @return java.util.List<com.fanxb.backend.entity.po.DetailPagePo>
* @author fanxb
* date 2022-11-25 15:47
*/
@Select("select * from detail_page where hostId=#{hostId}")
List<DetailPagePo> selectByHostId(int hostId);
} }

View File

@ -31,8 +31,8 @@ public interface HostDao {
* @author fanxb * @author fanxb
* date 2022-11-24 23:06 * date 2022-11-24 23:06
*/ */
@Select("select count(1) from host where `key`=#{key} and secret=#{secret}") @Select("select * from host where `key`=#{key} and secret=#{secret} limit 1")
boolean exist(@Param("key") String key, @Param("secret") String secret); HostPo selectByKeyAndSecret(@Param("key") String key, @Param("secret") String secret);
/** /**
* 根据key获取id * 根据key获取id

View File

@ -3,6 +3,8 @@ package com.fanxb.backend.dao;
import com.fanxb.backend.entity.po.HostDayPo; import com.fanxb.backend.entity.po.HostDayPo;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
import java.util.List;
/** /**
* @author fanxb * @author fanxb
*/ */
@ -12,7 +14,7 @@ public interface HostDayDao {
* 获取id * 获取id
* *
* @param hostId hostId * @param hostId hostId
* @param dayNum day * @param dayNum day
* @author fanxb * @author fanxb
*/ */
@Select("select id from host_day where hostId=#{hostId} and dayNum=#{dayNum}") @Select("select id from host_day where hostId=#{hostId} and dayNum=#{dayNum}")
@ -38,4 +40,15 @@ public interface HostDayDao {
*/ */
@Update("update host_day set uv=uv+#{uvIncrement},pv=pv+#{pvIncrement} where id=#{id}") @Update("update host_day set uv=uv+#{uvIncrement},pv=pv+#{pvIncrement} where id=#{id}")
void updatePvUv(@Param("id") int id, @Param("pvIncrement") int pvIncrement, @Param("uvIncrement") int uvIncrement); void updatePvUv(@Param("id") int id, @Param("pvIncrement") int pvIncrement, @Param("uvIncrement") int uvIncrement);
/**
* 根据hostId查询
*
* @param hostId hostId
* @return java.util.List<com.fanxb.backend.entity.po.HostDayPo>
* @author fanxb
* date 2022-11-25 15:41
*/
@Select("select * from host_day where hostId=#{hostId}")
List<HostDayPo> selectByHostId(int hostId);
} }

View File

@ -0,0 +1,25 @@
package com.fanxb.backend.entity.bo;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fanxb.backend.entity.po.DetailPagePo;
import com.fanxb.backend.entity.po.HostDayPo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
public class ReportDetailPageBo {
@ExcelProperty(value = "页面路径")
private String path;
@ExcelProperty(value = "PV")
private long pv;
@ExcelProperty(value = "UV")
private long uv;
public ReportDetailPageBo(DetailPagePo po) {
BeanUtil.copyProperties(po, this);
}
}

View File

@ -0,0 +1,26 @@
package com.fanxb.backend.entity.bo;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fanxb.backend.entity.po.HostPo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
public class ReportHostBo {
@ExcelProperty(value = "站点名称")
private String name;
@ExcelProperty(value = "站点地址")
private String host;
@ExcelProperty(value = "PV")
private Integer pv;
@ExcelProperty(value = "UV")
private Integer uv;
public ReportHostBo(HostPo hostPo) {
BeanUtil.copyProperties(hostPo, this);
}
}

View File

@ -0,0 +1,29 @@
package com.fanxb.backend.entity.bo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fanxb.backend.entity.po.HostDayPo;
import com.fanxb.backend.entity.po.HostPo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
public class ReportHostDayBo {
@ExcelProperty(value = "日期")
private String date;
@ExcelProperty(value = "PV")
private long pv;
@ExcelProperty(value = "UV")
private long uv;
public ReportHostDayBo(HostDayPo po) {
String temp = String.valueOf(po.getDayNum());
this.date = temp.substring(0, 4) + "-" + temp.substring(4, 6) + "-" + temp.substring(6);
this.pv = po.getPv();
this.uv = po.getUv();
}
}

View File

@ -48,4 +48,15 @@ public interface ApplicationService {
* date 2022-11-24 23:05 * date 2022-11-24 23:05
*/ */
boolean check(ApplicationSignVo body); boolean check(ApplicationSignVo body);
/**
* 下载站点数据
*
* @param key key
* @param secret secret
* @param response response
* @author fanxb
* date 2022-11-25 15:27
*/
void download(String key, String secret, HttpServletResponse response) throws Exception;
} }

View File

@ -2,6 +2,8 @@ package com.fanxb.backend.service.impl;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.http.Header; import cn.hutool.http.Header;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.fanxb.backend.constants.CommonConstant; import com.fanxb.backend.constants.CommonConstant;
import com.fanxb.backend.constants.RedisConstant; import com.fanxb.backend.constants.RedisConstant;
@ -9,6 +11,9 @@ import com.fanxb.backend.dao.DetailPageDao;
import com.fanxb.backend.dao.DetailPageDayDao; import com.fanxb.backend.dao.DetailPageDayDao;
import com.fanxb.backend.dao.HostDao; import com.fanxb.backend.dao.HostDao;
import com.fanxb.backend.dao.HostDayDao; import com.fanxb.backend.dao.HostDayDao;
import com.fanxb.backend.entity.bo.ReportDetailPageBo;
import com.fanxb.backend.entity.bo.ReportHostBo;
import com.fanxb.backend.entity.bo.ReportHostDayBo;
import com.fanxb.backend.entity.dto.ApplicationSignDto; import com.fanxb.backend.entity.dto.ApplicationSignDto;
import com.fanxb.backend.entity.exception.CustomBaseException; import com.fanxb.backend.entity.exception.CustomBaseException;
import com.fanxb.backend.entity.po.DetailPageDayPo; import com.fanxb.backend.entity.po.DetailPageDayPo;
@ -28,13 +33,17 @@ import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** /**
* 应用管理 * 应用管理
@ -77,7 +86,8 @@ public class ApplicationServiceImpl implements ApplicationService {
@Override @Override
public boolean check(ApplicationSignVo body) { public boolean check(ApplicationSignVo body) {
return hostDao.exist(body.getKey(), body.getSecret()); HostPo po = hostDao.selectByKeyAndSecret(body.getKey(), body.getSecret());
return po != null;
} }
private static Pattern PATTERN = Pattern.compile("googlebot|bingbot|yandex|baiduspider|360Spider|Sogou Spider|Bytespider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest\\/0\\.|pinterestbot|slackbot|vkShare|W3C_Validator|whatsapp"); private static Pattern PATTERN = Pattern.compile("googlebot|bingbot|yandex|baiduspider|360Spider|Sogou Spider|Bytespider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest\\/0\\.|pinterestbot|slackbot|vkShare|W3C_Validator|whatsapp");
@ -206,4 +216,23 @@ public class ApplicationServiceImpl implements ApplicationService {
return hostId; return hostId;
} }
@Override
public void download(String key, String secret, HttpServletResponse response) throws Exception {
HostPo po = hostDao.selectByKeyAndSecret(key, secret);
if (po == null) {
throw new CustomBaseException("key,secret不存在");
}
List<ReportHostBo> hostList = Collections.singletonList(new ReportHostBo(po));
List<ReportHostDayBo> hostDayList = hostDayDao.selectByHostId(po.getId()).stream().map(ReportHostDayBo::new).collect(Collectors.toList());
List<ReportDetailPageBo> detailPageList = detailPageDao.selectByHostId(po.getId()).stream().map(ReportDetailPageBo::new).collect(Collectors.toList());
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(po.getName() + "-站点导出数据", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
ExcelWriter writer = EasyExcel.write(response.getOutputStream()).build();
writer.write(hostList, EasyExcel.writerSheet(0, "站点数据").head(ReportHostBo.class).build());
writer.write(hostDayList, EasyExcel.writerSheet(1, "站点日数据").head(ReportHostDayBo.class).build());
writer.write(detailPageList, EasyExcel.writerSheet(2, "页面数据").head(ReportDetailPageBo.class).build());
writer.finish();
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

BIN
qiezi_front/public/ico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

View File

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="zh">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <link rel="icon" href="<%= BASE_URL %>ico.png" />
<title><%= htmlWebpackPlugin.options.title %></title> <title>茄子统计</title>
</head> </head>
<body> <body>
<noscript> <noscript>

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

View File

@ -4,22 +4,29 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/ico.png" />
<title>茄子统计</title> <title>茄子统计</title>
</head> </head>
<body> <body>
<div class="app"> <div class="app">
免费UV,PV统计也可直接使用,也可进行私有部署后使用。<br /> <div class="desc">
使用文档见:<a href="https://github.com/FleyX/qieziStatistics">开始使用</a> 个人站点UV、PV统计支持页面显示常用于个人博客展示阅读数。比如我的个人博客<a href="https://blog.fleyx.com/">FleyX's Blog</a><br />
支持开箱即用,只需几行代码即可为您的站点加上统计数据。<br />
代码完全开源于<a href="https://github.com/FleyX/qieziStatistics">github</a>,因此也支持自行独立部署使用。<br />
支持站点数据excel导出方便切换统计工具。<br />
<a href="/manage">开始使用吧</a>
</div>
</div> </div>
<!-- 页面PV --> <!-- 页面PV -->
<div style="text-align: center"> <div style="position: fixed; bottom: 0; width: 100%">
<div id="qieziStatisticHtmlPost" style="display: none">当前页面访问次数:<span id="qieziStatisticHtmlPostPv"></span>&nbsp;</div> <div style="text-align: center">
</div> <div id="qieziStatisticHtmlPost" style="display: none">当前页面访问次数:<span id="qieziStatisticHtmlPostPv"></span>&nbsp;</div>
<!-- 网站整体UV/PV --> </div>
<div style="text-align: center"> <!-- 网站整体UV/PV -->
<div id="qieziStatisticHtmlHostPv" style="display: none">总访问次数:<span id="qieziStatisticHtmlHostPvValue"></span>&nbsp;</div> <div style="text-align: center">
<div id="qieziStatisticHtmlHostUv" style="display: none">&nbsp;总访客数:<span id="qieziStatisticHtmlHostUvValue"></span></div> <div id="qieziStatisticHtmlHostPv" style="display: none">总访问次数:<span id="qieziStatisticHtmlHostPvValue"></span>&nbsp;</div>
<div id="qieziStatisticHtmlHostUv" style="display: none">&nbsp;总访客数:<span id="qieziStatisticHtmlHostUvValue"></span></div>
</div>
</div> </div>
<script> <script>
//设置实际部署的host和key //设置实际部署的host和key
@ -31,8 +38,13 @@
.app { .app {
width: 80%; width: 80%;
margin: 0 auto; margin: 0 auto;
margin-top: 20vh;
text-align: center; text-align: center;
} }
.desc {
font-size: 1.2em;
font-weight: 600;
}
</style> </style>
</body> </body>
</html> </html>

View File

@ -1,7 +1,10 @@
<template> <template>
<div class="home"> <div class="home">
<router-link to="/application/sign">应用注册</router-link><br /> <router-link to="/application/sign">应用注册</router-link><br />
<router-link to="/download">数据下载</router-link> <router-link to="/download">数据下载</router-link><br />
<div style="padding-top: 1em">
<a href="https://blog.fleyx.com/blog/detail/20221125" target="_blank">使用文档</a>
</div>
</div> </div>
</template> </template>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="title">数据下载</div> <div class="title">站点数据下载</div>
<a-form :model="form" :label-col="{ span: 4 }" :wrapper-col="{ span: 14 }" style="width: 80%; margin: 0 auto"> <a-form :model="form" :label-col="{ span: 4 }" :wrapper-col="{ span: 14 }" style="width: 80%; margin: 0 auto">
<a-form-item label="key"> <a-form-item label="key">
<a-input type="text" v-model:value="form.key" /> <a-input type="text" v-model:value="form.key" />
@ -11,7 +11,7 @@
<a-button type="primary" @click="onSubmit">下载</a-button> <a-button type="primary" @click="onSubmit">下载</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
<a id="download" :href="'/download?key=' + form.key + '&secret=' + form.secret" download class="download-a">download</a> <a id="download" :href="'/qiezi/api/application/download?key=' + form.key + '&secret=' + form.secret" download class="download-a">download</a>
</template> </template>
<script setup> <script setup>