diff --git a/pom.xml b/pom.xml index 411813c2..7e1c5939 100644 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,6 @@ ${redisson.version} - org.springframework.boot spring-boot-starter-websocket diff --git a/src/main/java/com/youlai/system/config/WebSocketConfig.java b/src/main/java/com/youlai/system/config/WebSocketConfig.java index a128f13f..bdadd200 100644 --- a/src/main/java/com/youlai/system/config/WebSocketConfig.java +++ b/src/main/java/com/youlai/system/config/WebSocketConfig.java @@ -20,13 +20,14 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; /** - * WebSocket 配置 + * WebSocket 自动配置类 * * @author haoxr * @since 2.4.0 */ +// 启用WebSocket消息代理功能和配置STOMP协议,实现实时双向通信和消息传递 +@EnableWebSocketMessageBroker @Configuration -@EnableWebSocketMessageBroker // 启用WebSocket消息代理功能和配置STOMP协议,实现实时双向通信和消息传递 @Slf4j public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @@ -36,9 +37,12 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry - .addEndpoint("/ws") // 注册了一个 /ws 的端点 - .setAllowedOriginPatterns("*") // 允许跨域的 WebSocket 连接 - .withSockJS(); // 启用 SockJS (浏览器不支持WebSocket,SockJS 将会提供兼容性支持) + // 注册 /ws 的端点 + .addEndpoint("/ws") + // 允许跨域的 WebSocket 连接 + .setAllowedOriginPatterns("*") + // 启用 SockJS (浏览器不支持WebSocket,SockJS 将会提供兼容性支持) + .withSockJS(); registry.addEndpoint("/ws-app").setAllowedOriginPatterns("*"); // 注册了一个 /ws-app 的端点,支持 uni-app 的 ws 连接协议 } diff --git a/src/main/java/com/youlai/system/controller/StatsController.java b/src/main/java/com/youlai/system/controller/StatsController.java new file mode 100644 index 00000000..a4bc3449 --- /dev/null +++ b/src/main/java/com/youlai/system/controller/StatsController.java @@ -0,0 +1,44 @@ +package com.youlai.system.controller; + +import com.youlai.system.common.result.Result; +import com.youlai.system.model.vo.VisitTrendVO; +import com.youlai.system.service.SysLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDate; + + +/** + * 统计数据控制层 + * + * @author Ray + * @since 2.10.0 + */ +@Tag(name = "09.统计数据") +@RestController +@RequestMapping("/api/v1/stats") +@RequiredArgsConstructor +public class StatsController { + + private final SysLogService logService; + + @Operation(summary = "获取访问趋势") + @GetMapping("/visit-trend") + public Result getVisitTrend( + @Parameter(description = "开始时间", example = "yyyy-MM-dd") @RequestParam String startDate, + @Parameter(description = "结束时间", example = "yyyy-MM-dd") @RequestParam String endDate + ) { + LocalDate start = LocalDate.parse(startDate); + LocalDate end = LocalDate.parse(endDate); + VisitTrendVO data = logService.getVisitTrend(start, end); + return Result.success(data); + } + +} diff --git a/src/main/java/com/youlai/system/controller/SysLogController.java b/src/main/java/com/youlai/system/controller/SysLogController.java index 1c82582b..36812516 100644 --- a/src/main/java/com/youlai/system/controller/SysLogController.java +++ b/src/main/java/com/youlai/system/controller/SysLogController.java @@ -2,6 +2,7 @@ package com.youlai.system.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.system.common.result.PageResult; +import com.youlai.system.model.query.LogPageQuery; import com.youlai.system.model.query.RolePageQuery; import com.youlai.system.model.vo.LogPageVO; import com.youlai.system.service.SysLogService; @@ -28,7 +29,7 @@ public class SysLogController { @Operation(summary = "日志分页列表") @GetMapping("/page") public PageResult listPagedLogs( - RolePageQuery queryParams + LogPageQuery queryParams ) { Page result = logService.listPagedLogs(queryParams); return PageResult.success(result); diff --git a/src/main/java/com/youlai/system/mapper/SysLogMapper.java b/src/main/java/com/youlai/system/mapper/SysLogMapper.java index 980b4c89..38a27432 100644 --- a/src/main/java/com/youlai/system/mapper/SysLogMapper.java +++ b/src/main/java/com/youlai/system/mapper/SysLogMapper.java @@ -1,12 +1,16 @@ package com.youlai.system.mapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.youlai.system.model.bo.VisitCount; import com.youlai.system.model.entity.SysLog; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.youlai.system.model.query.LogPageQuery; import com.youlai.system.model.query.RolePageQuery; import com.youlai.system.model.vo.LogPageVO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * 系统日志 数据库访问层 @@ -17,7 +21,32 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface SysLogMapper extends BaseMapper { - Page listPagedLogs(Page page, RolePageQuery queryParams); + /** + * 获取日志分页列表 + * + * @param page + * @param queryParams + * @return + */ + Page listPagedLogs(Page page, LogPageQuery queryParams); + + /** + * 统计浏览数(PV) + * + * @param startDate 开始日期 yyyy-MM-dd + * @param endDate 结束日期 yyyy-MM-dd + * @return + */ + List getPvCounts(String startDate, String endDate); + + /** + * 统计IP数 + * + * @param startDate 开始日期 yyyy-MM-dd + * @param endDate 结束日期 yyyy-MM-dd + * @return + */ + List getIpCounts(String startDate, String endDate); } diff --git a/src/main/java/com/youlai/system/model/bo/VisitCount.java b/src/main/java/com/youlai/system/model/bo/VisitCount.java new file mode 100644 index 00000000..3c9a22c0 --- /dev/null +++ b/src/main/java/com/youlai/system/model/bo/VisitCount.java @@ -0,0 +1,23 @@ +package com.youlai.system.model.bo; + +import lombok.Data; + +/** + * 特定日期访问统计 + * + * @author Ray + * @since 2.10.0 + */ +@Data +public class VisitCount { + + /** + * 日期 yyyy-MM-dd + */ + private String date; + + /** + * 访问次数 + */ + private Integer count; +} diff --git a/src/main/java/com/youlai/system/model/query/LogPageQuery.java b/src/main/java/com/youlai/system/model/query/LogPageQuery.java index 28760476..2d0d3942 100644 --- a/src/main/java/com/youlai/system/model/query/LogPageQuery.java +++ b/src/main/java/com/youlai/system/model/query/LogPageQuery.java @@ -4,6 +4,7 @@ import com.youlai.system.common.base.BasePageQuery; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import org.springframework.format.annotation.DateTimeFormat; /** * 日志分页查询对象 @@ -18,4 +19,13 @@ public class LogPageQuery extends BasePageQuery { @Schema(description="关键字(日志内容/请求路径/请求方法/地区/浏览器/终端系统)") private String keywords; + + @Schema(description="开始日期") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private String startDate; + + @Schema(description="结束日期") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private String endDate; + } diff --git a/src/main/java/com/youlai/system/model/query/RolePageQuery.java b/src/main/java/com/youlai/system/model/query/RolePageQuery.java index 102f8df4..02c0eb93 100644 --- a/src/main/java/com/youlai/system/model/query/RolePageQuery.java +++ b/src/main/java/com/youlai/system/model/query/RolePageQuery.java @@ -1,10 +1,13 @@ package com.youlai.system.model.query; +import com.fasterxml.jackson.annotation.JsonFormat; import com.youlai.system.common.base.BasePageQuery; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import java.time.LocalDateTime; + /** * 角色分页查询对象 * @@ -18,4 +21,12 @@ public class RolePageQuery extends BasePageQuery { @Schema(description="关键字(角色名称/角色编码)") private String keywords; + + @Schema(description="开始日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime startDate; + + @Schema(description="结束日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime endDate; } diff --git a/src/main/java/com/youlai/system/model/vo/VisitTrendVO.java b/src/main/java/com/youlai/system/model/vo/VisitTrendVO.java new file mode 100644 index 00000000..2e686d58 --- /dev/null +++ b/src/main/java/com/youlai/system/model/vo/VisitTrendVO.java @@ -0,0 +1,27 @@ +package com.youlai.system.model.vo; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Schema(description = "访问趋势VO") +@Getter +@Setter +public class VisitTrendVO { + + @Schema(description = "日期列表") + private List dates; + + @Schema(description = "浏览量(PV)") + private List pvList; + + @Schema(description = "访客数(UV)") + private List uvList; + + @Schema(description = "IP数") + private List ipList; + +} diff --git a/src/main/java/com/youlai/system/service/SysLogService.java b/src/main/java/com/youlai/system/service/SysLogService.java index a6b017c4..d1be9085 100644 --- a/src/main/java/com/youlai/system/service/SysLogService.java +++ b/src/main/java/com/youlai/system/service/SysLogService.java @@ -3,8 +3,12 @@ package com.youlai.system.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.youlai.system.model.entity.SysLog; import com.baomidou.mybatisplus.extension.service.IService; +import com.youlai.system.model.query.LogPageQuery; import com.youlai.system.model.query.RolePageQuery; import com.youlai.system.model.vo.LogPageVO; +import com.youlai.system.model.vo.VisitTrendVO; + +import java.time.LocalDate; /** * 系统日志 服务接口 @@ -14,5 +18,21 @@ import com.youlai.system.model.vo.LogPageVO; */ public interface SysLogService extends IService { - Page listPagedLogs(RolePageQuery queryParams); + /** + * 获取日志分页列表 + * + * @param queryParams 查询参数 + * @return + */ + Page listPagedLogs(LogPageQuery queryParams); + + + /** + * 获取访问趋势 + * + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return + */ + VisitTrendVO getVisitTrend(LocalDate startDate, LocalDate endDate); } diff --git a/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java index 2045187b..1a69b828 100644 --- a/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java @@ -2,13 +2,22 @@ package com.youlai.system.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.youlai.system.common.util.DateUtils; +import com.youlai.system.model.bo.VisitCount; import com.youlai.system.model.entity.SysLog; -import com.youlai.system.model.query.RolePageQuery; +import com.youlai.system.model.query.LogPageQuery; import com.youlai.system.model.vo.LogPageVO; +import com.youlai.system.model.vo.VisitTrendVO; import com.youlai.system.service.SysLogService; import com.youlai.system.mapper.SysLogMapper; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + /** * 系统日志 服务实现类 * @@ -26,10 +35,55 @@ public class SysLogServiceImpl extends ServiceImpl * @return */ @Override - public Page listPagedLogs(RolePageQuery queryParams) { + public Page listPagedLogs(LogPageQuery queryParams) { + // 格式化为数据库日期格式,避免日期比较使用格式化函数导致索引失效 + DateUtils.toDatabaseFormat(queryParams, "startDate", "endDate"); + return this.baseMapper.listPagedLogs(new Page(queryParams.getPageNum(), queryParams.getPageSize()), queryParams); } + + /** + * 获取访问趋势 + * + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return + */ + @Override + public VisitTrendVO getVisitTrend(LocalDate startDate, LocalDate endDate) { + VisitTrendVO visitTrend= new VisitTrendVO(); + List dates = new ArrayList<>(); + + // 获取日期范围内的日期 + while (!startDate.isAfter(endDate)) { + dates.add(startDate.toString()); + startDate = startDate.plusDays(1); + } + visitTrend.setDates(dates); + + // 获取访问量和访问 IP 数的统计数据 + List pvCounts = this.baseMapper.getPvCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); + List ipCounts = this.baseMapper.getIpCounts(dates.get(0) + " 00:00:00", dates.get(dates.size() - 1) + " 23:59:59"); + + // 将统计数据转换为 Map + Map pvMap = pvCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount)); + Map ipMap = ipCounts.stream().collect(Collectors.toMap(VisitCount::getDate, VisitCount::getCount)); + + // 匹配日期和访问量/访问 IP 数 + List pvList = new ArrayList<>(); + List ipList = new ArrayList<>(); + + for (String date : dates) { + pvList.add(pvMap.getOrDefault(date, 0)); + ipList.add(ipMap.getOrDefault(date, 0)); + } + + visitTrend.setPvList(pvList); + visitTrend.setIpList(ipList); + + return visitTrend; + } } diff --git a/src/main/resources/mapper/SysLogMapper.xml b/src/main/resources/mapper/SysLogMapper.xml index bbae642f..1056a8c1 100644 --- a/src/main/resources/mapper/SysLogMapper.xml +++ b/src/main/resources/mapper/SysLogMapper.xml @@ -33,8 +33,40 @@ t2.nickname LIKE concat('%',#{queryParams.keywords},'%') ) + + AND t1.create_time >= #{queryParams.startDate} + + + AND t1.create_time <= #{queryParams.endDate} + ORDER BY t1.create_time DESC + + + + + +