feat:后台增加日统计功能
This commit is contained in:
parent
441361cdee
commit
69728cdcd0
@ -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_";
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.fanxb.backend.util;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* redis分布式锁操作工具类
|
||||
*
|
||||
* @author fanxb
|
||||
*/
|
||||
@Component
|
||||
public class RedisLockUtil {
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user