feat:后台增加日统计功能

This commit is contained in:
fanxb 2022-03-14 16:54:08 +08:00
parent 441361cdee
commit 69728cdcd0
10 changed files with 193 additions and 13 deletions

View File

@ -22,4 +22,9 @@ public class RedisConstant {
*/
public static final String HOST_UV_PRE = "host_uv_pre_";
public static final String PAGE_UV_PRE = "page_uv_pre_";
/**
* 日统计数据id key前缀
*/
public static final String DAY_HOST_ID_PRE = "day_host_id_pre_";
public static final String DAY_DETAIL_PAGE_ID_PRE = "day_detail_page_id_pre_";
}

View File

@ -46,7 +46,7 @@ public class ApplicationController {
@GetMapping("/visit")
@ResponseBody
public void visit(HttpServletRequest request, HttpServletResponse response, @NotBlank(message = "回调函数不能为空") String callBack
, @NotBlank(message = "key不能为空") String key, @NotBlank(message = "path不能为空") String path, boolean notAdd) throws IOException {
, @NotBlank(message = "key不能为空") String key, @NotBlank(message = "path不能为空") String path, @RequestParam(defaultValue = "false") boolean notAdd) throws IOException {
applicationService.visit(request, response, callBack, key, path, notAdd);
}
}

View File

@ -20,6 +20,7 @@ public interface DetailPageDao {
* date 2022/2/15 16:39
*/
@Insert("insert into detail_page(hostId,path,pv,uv) value(#{hostId},#{path},#{pv},#{uv})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insertOne(DetailPagePo detailPagePo);
/**

View File

@ -0,0 +1,42 @@
package com.fanxb.backend.dao;
import com.fanxb.backend.entity.po.DetailPageDayPo;
import com.fanxb.backend.entity.po.HostDayPo;
import org.apache.ibatis.annotations.*;
/**
* @author fanxb
*/
@Mapper
public interface DetailPageDayDao {
/**
* 获取id
*
* @param detailPageId id
* @param dayNum day
* @author fanxb
*/
@Select("select id from detail_page_day where detailPageId=#{detailPageId} and dayNum=#{dayNum}")
Integer getId(@Param("detailPageId") int detailPageId, @Param("dayNum") int dayNum);
/**
* 插入一条数据
*
* @param po po
* @author fanxb
*/
@Insert("insert into detail_page_day(detailPageId,dayNum,pv,uv) value(#{detailPageId},#{dayNum},0,0)")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insert(DetailPageDayPo po);
/**
* 更新pv,uv
*
* @param id id
* @param pvIncrement pv增量
* @param uvIncrement uv增量
* @author fanxb
*/
@Update("update detail_page_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);
}

View File

@ -0,0 +1,41 @@
package com.fanxb.backend.dao;
import com.fanxb.backend.entity.po.HostDayPo;
import org.apache.ibatis.annotations.*;
/**
* @author fanxb
*/
@Mapper
public interface HostDayDao {
/**
* 获取id
*
* @param hostId hostId
* @param dayNum day
* @author fanxb
*/
@Select("select id from host_day where hostId=#{hostId} and dayNum=#{dayNum}")
Integer getId(@Param("hostId") int hostId, @Param("dayNum") int dayNum);
/**
* 插入一条数据
*
* @param hostDayPo po
* @author fanxb
*/
@Insert("insert into host_day(hostId,dayNum,pv,uv) value(#{hostId},#{dayNum},0,0)")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insert(HostDayPo hostDayPo);
/**
* 更新pv,uv
*
* @param id id
* @param pvIncrement pv增量
* @param uvIncrement uv增量
* @author fanxb
*/
@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);
}

View File

@ -0,0 +1,26 @@
package com.fanxb.backend.entity.po;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class DetailPageDayPo {
/**
* id
*/
private int id;
/**
* hostId
*/
private int detailPageId;
/**
* 日期20200202
*/
private int dayNum;
private long pv;
private long uv;
}

View File

@ -2,8 +2,10 @@ package com.fanxb.backend.entity.po;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class HostDayPo {
/**
@ -17,7 +19,7 @@ public class HostDayPo {
/**
* 日期20200202
*/
private int dateNum;
private int dayNum;
private long pv;
private long uv;

View File

@ -1,23 +1,25 @@
package com.fanxb.backend.service.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import com.alibaba.fastjson.JSON;
import com.fanxb.backend.constants.RedisConstant;
import com.fanxb.backend.constants.CommonConstant;
import com.fanxb.backend.constants.RedisConstant;
import com.fanxb.backend.dao.DetailPageDao;
import com.fanxb.backend.dao.DetailPageDayDao;
import com.fanxb.backend.dao.HostDao;
import com.fanxb.backend.dao.HostDayDao;
import com.fanxb.backend.entity.dto.ApplicationSignDto;
import com.fanxb.backend.entity.exception.CustomBaseException;
import com.fanxb.backend.entity.po.DetailPageDayPo;
import com.fanxb.backend.entity.po.DetailPagePo;
import com.fanxb.backend.entity.po.HostDayPo;
import com.fanxb.backend.entity.po.HostPo;
import com.fanxb.backend.entity.vo.ApplicationSignVo;
import com.fanxb.backend.entity.vo.UvPvVo;
import com.fanxb.backend.service.ApplicationService;
import com.fanxb.backend.util.NetUtil;
import com.fanxb.backend.util.ThreadPoolUtil;
import jdk.jfr.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@ -25,11 +27,10 @@ import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
@ -40,15 +41,20 @@ import java.util.concurrent.TimeUnit;
*/
@Service
public class ApplicationServiceImpl implements ApplicationService {
private final StringRedisTemplate stringRedisTemplate;
private final HostDao hostDao;
private final DetailPageDao detailPageDao;
private final HostDayDao hostDayDao;
private final DetailPageDayDao detailPageDayDao;
@Autowired
public ApplicationServiceImpl(StringRedisTemplate stringRedisTemplate, HostDao hostDao, DetailPageDao detailPageDao) {
public ApplicationServiceImpl(StringRedisTemplate stringRedisTemplate, HostDao hostDao, DetailPageDao detailPageDao, HostDayDao hostDayDao, DetailPageDayDao detailPageDayDao) {
this.stringRedisTemplate = stringRedisTemplate;
this.hostDao = hostDao;
this.detailPageDao = detailPageDao;
this.hostDayDao = hostDayDao;
this.detailPageDayDao = detailPageDayDao;
}
@Override
@ -94,10 +100,10 @@ public class ApplicationServiceImpl implements ApplicationService {
* @param hostPo hostPo
* @param detailPagePo detailPagePo
* @author fanxb
* date 2022/2/16 15:40
*/
private void updateData(String ip, HostPo hostPo, DetailPagePo detailPagePo) {
String hostKey = RedisConstant.HOST_UV_PRE + hostPo.getId() + "_" + ip;
//记录ip是否在当天访问过host
String hostVal = stringRedisTemplate.opsForValue().get(hostKey);
hostPo.setPv(hostPo.getPv() + 1);
long tomorrowZero = LocalDate.now().plusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
@ -106,6 +112,7 @@ public class ApplicationServiceImpl implements ApplicationService {
hostPo.setUv(hostPo.getUv() + 1);
}
String pageKey = RedisConstant.PAGE_UV_PRE + hostPo.getId() + ip + detailPagePo.getPath();
//记录ip是否在当天访问过页面
String pageVal = stringRedisTemplate.opsForValue().get(pageKey);
detailPagePo.setPv(detailPagePo.getPv() + 1);
if (pageVal == null) {
@ -121,16 +128,54 @@ public class ApplicationServiceImpl implements ApplicationService {
detailPageDao.updateUvPv(detailPagePo.getId(), pageVal == null ? 1 : 0);
}
//更新站点的日pv,uv
int dayNum = Integer.parseInt(LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE).replaceAll("-", ""));
hostDayDao.updatePvUv(getDayTableId(hostPo.getId(), dayNum, RedisConstant.DAY_HOST_ID_PRE), 1, hostVal == null ? 1 : 0);
detailPageDayDao.updatePvUv(getDayTableId(detailPagePo.getId(), dayNum, RedisConstant.DAY_DETAIL_PAGE_ID_PRE), 1, pageVal == null ? 1 : 0);
});
}
/**
* 获取表id数据行不存在时新增行
*
* @param id id
* @param day day(20220202)
* @param type 类型
* @author fanxb
*/
private int getDayTableId(int id, int day, String type) {
String key = type + "_" + id + "_" + day;
String val = stringRedisTemplate.opsForValue().get(key);
if (val != null) {
return Integer.parseInt(val);
}
//redis中没有,从数据库中查找
Integer dbId = RedisConstant.DAY_HOST_ID_PRE.equals(type) ? hostDayDao.getId(id, day) : detailPageDayDao.getId(id, day);
if (dbId == null) {
//TODO 此次应该加锁避免并发情况下重复创建报错
dbId = RedisConstant.DAY_HOST_ID_PRE.equals(type) ? hostDayDao.getId(id, day) : detailPageDayDao.getId(id, day);
if (dbId == null) {
//数据库中也没有需要先初始化数据库中数据
if (RedisConstant.DAY_HOST_ID_PRE.equals(type)) {
HostDayPo hostDayPo = new HostDayPo().setHostId(id).setDayNum(day);
hostDayDao.insert(hostDayPo);
dbId = hostDayPo.getId();
} else {
DetailPageDayPo detailPageDayPo = new DetailPageDayPo().setDetailPageId(id).setDayNum(day);
detailPageDayDao.insert(detailPageDayPo);
dbId = detailPageDayPo.getId();
}
}
}
stringRedisTemplate.opsForValue().set(key, dbId.toString());
return dbId;
}
/**
* 获取hostID
*
* @param key key
* @return {@link int}
* @author fanxb
* date 2022/2/16 15:37
*/
private int getHostId(String key) {
String id = stringRedisTemplate.opsForValue().get(key);
@ -141,7 +186,7 @@ public class ApplicationServiceImpl implements ApplicationService {
if (hostId == null) {
throw new CustomBaseException("key无效:" + key);
}
stringRedisTemplate.opsForValue().set(key, hostId.toString());
stringRedisTemplate.opsForValue().set(key, hostId.toString(), 2, TimeUnit.DAYS);
return hostId;
}

View File

@ -0,0 +1,14 @@
package com.fanxb.backend.util;
import org.springframework.stereotype.Component;
/**
* redis分布式锁操作工具类
*
* @author fanxb
*/
@Component
public class RedisLockUtil {
}

View File

@ -1,25 +1,29 @@
drop table host_day;
CREATE TABLE qiezi.host_day (
id INT auto_increment NOT NULL,
hostId int NOT NULL COMMENT 'host表主键',
dayNum INT NOT NULL COMMENT '日期20200202',
uv INT NOT NULL,
pv int NOT NULL,
CONSTRAINT host_day_pk PRIMARY KEY (hostId,dayNum)
CONSTRAINT host_day_pk PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
COMMENT='整站,日 uv/pv记录';
CREATE UNIQUE INDEX host_day_key_IDX USING BTREE ON qiezi.host_day (hostId,dayNum);
CREATE TABLE qiezi.detail_page_day (
id INT auto_increment NOT NULL,
detailPageId int NOT NULL COMMENT 'detail_page主键',
dayNum INT NOT NULL COMMENT '日期20200202',
uv INT NOT NULL,
pv int NOT NULL,
CONSTRAINT detail_page_day_pk PRIMARY KEY (detailPageId,dayNum)
CONSTRAINT detail_page_day_pk PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
COMMENT='具体页面,日 uv/pv记录';
CREATE UNIQUE INDEX detail_page_day_key_IDX USING BTREE ON qiezi.detail_page_day(detailPageId,dayNum);