Skip to content

Commit 7d1c193

Browse files
committed
优化
1 parent 9ab6564 commit 7d1c193

File tree

11 files changed

+2736
-769
lines changed

11 files changed

+2736
-769
lines changed

src/main/java/com/layor/tinyflow/Controller/StatsController.java

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package com.layor.tinyflow.Controller;
22

3-
import com.layor.tinyflow.entity.DailyVisitTrendDTO;
4-
import com.layor.tinyflow.entity.DistributionDTO;
5-
import com.layor.tinyflow.entity.ClickEventDTO;
6-
import com.layor.tinyflow.entity.ShortUrlOverviewDTO;
3+
import com.layor.tinyflow.entity.*;
74
import com.layor.tinyflow.dto.StatsQuery;
85
import com.layor.tinyflow.service.ShortUrlService;
96
import lombok.RequiredArgsConstructor;
107
import org.springframework.http.ResponseEntity;
118
import org.springframework.web.bind.annotation.*;
129

13-
import java.util.Arrays;
1410
import java.util.List;
1511
import java.util.Map;
1612

@@ -85,4 +81,99 @@ public ResponseEntity<byte[]> export(
8581
.header("Content-Disposition", "attachment; filename=stats-" + q.getCode() + "." + ("csv".equalsIgnoreCase(format) ? "csv" : "json"))
8682
.body(bytes);
8783
}
84+
85+
/**
86+
* 获取详细统计数据(包含所有维度)
87+
*/
88+
@GetMapping("/detailed/{shortCode}")
89+
public ResponseEntity<DetailedStatsDTO> getDetailedStats(
90+
@PathVariable String shortCode,
91+
@RequestParam(required = false) String start,
92+
@RequestParam(required = false) String end) {
93+
DetailedStatsDTO dto = shortUrlService.getDetailedStats(shortCode, start, end);
94+
return ResponseEntity.ok(dto);
95+
}
96+
97+
/**
98+
* 获取全局统计数据
99+
*/
100+
@GetMapping("/global")
101+
public ResponseEntity<GlobalStatsDTO> getGlobalStats(
102+
@RequestParam(required = false) String start,
103+
@RequestParam(required = false) String end) {
104+
GlobalStatsDTO dto = shortUrlService.getGlobalStats(start, end);
105+
return ResponseEntity.ok(dto);
106+
}
107+
108+
/**
109+
* 获取小时分布
110+
*/
111+
@GetMapping("/hour/{shortCode}")
112+
public ResponseEntity<List<KeyCountDTO>> getHourDistribution(
113+
@PathVariable String shortCode,
114+
@RequestParam(required = false) String start,
115+
@RequestParam(required = false) String end) {
116+
List<KeyCountDTO> list = shortUrlService.getHourDistribution(shortCode, start, end);
117+
return ResponseEntity.ok(list);
118+
}
119+
120+
/**
121+
* 获取星期分布
122+
*/
123+
@GetMapping("/weekday/{shortCode}")
124+
public ResponseEntity<List<KeyCountDTO>> getWeekdayDistribution(
125+
@PathVariable String shortCode,
126+
@RequestParam(required = false) String start,
127+
@RequestParam(required = false) String end) {
128+
List<KeyCountDTO> list = shortUrlService.getWeekdayDistribution(shortCode, start, end);
129+
return ResponseEntity.ok(list);
130+
}
131+
132+
/**
133+
* 获取浏览器分布
134+
*/
135+
@GetMapping("/browser/{shortCode}")
136+
public ResponseEntity<List<KeyCountDTO>> getBrowserDistribution(
137+
@PathVariable String shortCode,
138+
@RequestParam(required = false) String start,
139+
@RequestParam(required = false) String end) {
140+
List<KeyCountDTO> list = shortUrlService.getBrowserDistribution(shortCode, start, end);
141+
return ResponseEntity.ok(list);
142+
}
143+
144+
/**
145+
* 获取国家分布
146+
*/
147+
@GetMapping("/country/{shortCode}")
148+
public ResponseEntity<List<KeyCountDTO>> getCountryDistribution(
149+
@PathVariable String shortCode,
150+
@RequestParam(required = false) String start,
151+
@RequestParam(required = false) String end) {
152+
List<KeyCountDTO> list = shortUrlService.getCountryDistribution(shortCode, start, end);
153+
return ResponseEntity.ok(list);
154+
}
155+
156+
/**
157+
* 获取Referer详细分布
158+
*/
159+
@GetMapping("/referer/{shortCode}")
160+
public ResponseEntity<List<KeyCountDTO>> getRefererDistribution(
161+
@PathVariable String shortCode,
162+
@RequestParam(required = false) String start,
163+
@RequestParam(required = false) String end) {
164+
List<KeyCountDTO> list = shortUrlService.getRefererDistribution(shortCode, start, end);
165+
return ResponseEntity.ok(list);
166+
}
167+
168+
/**
169+
* 获取PV/UV数据
170+
*/
171+
@GetMapping("/pvuv/{shortCode}")
172+
public ResponseEntity<Map<String, Long>> getPvUv(
173+
@PathVariable String shortCode,
174+
@RequestParam(required = false) String start,
175+
@RequestParam(required = false) String end) {
176+
Map<String, Long> data = shortUrlService.getPvUv(shortCode, start, end);
177+
return ResponseEntity.ok(data);
178+
}
88179
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.layor.tinyflow.entity;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
import java.time.LocalDateTime;
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
/**
12+
* 详细统计数据DTO
13+
*/
14+
@Data
15+
@AllArgsConstructor
16+
@NoArgsConstructor
17+
public class DetailedStatsDTO {
18+
// 基础指标
19+
private long pv; // 页面访问量
20+
private long uv; // 独立访客数
21+
private double pvUvRatio; // PV/UV比率
22+
23+
// 时间分布
24+
private List<KeyCountDTO> hourDistribution; // 24小时分布
25+
private List<KeyCountDTO> weekdayDistribution; // 星期分布
26+
27+
// 地理分布
28+
private List<KeyCountDTO> countryDistribution; // 国家分布
29+
private List<KeyCountDTO> cityDistribution; // 城市分布
30+
31+
// 技术分布
32+
private List<KeyCountDTO> deviceDistribution; // 设备分布
33+
private List<KeyCountDTO> browserDistribution; // 浏览器分布
34+
35+
// 来源分布
36+
private List<KeyCountDTO> sourceDistribution; // 来源域名分布
37+
private List<KeyCountDTO> refererDistribution; // Referer详细分布
38+
39+
// 时间信息
40+
private LocalDateTime firstClick; // 首次访问时间
41+
private LocalDateTime lastClick; // 最后访问时间
42+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.layor.tinyflow.entity;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
import java.util.List;
8+
9+
/**
10+
* 全局统计概览DTO
11+
*/
12+
@Data
13+
@AllArgsConstructor
14+
@NoArgsConstructor
15+
public class GlobalStatsDTO {
16+
// 基础汇总
17+
private long totalUrls; // 总短链数
18+
private long totalClicks; // 总点击数(PV)
19+
private long totalUniqueIps; // 总独立访客(UV)
20+
private long todayClicks; // 今日点击
21+
private long activeUrls; // 活跃短链数(今日有点击)
22+
23+
// 趋势数据
24+
private List<KeyCountDTO> dailyTrend; // 日趋势
25+
26+
// 分布数据
27+
private List<KeyCountDTO> deviceDistribution; // 设备分布
28+
private List<KeyCountDTO> cityTop10; // 城市TOP10
29+
private List<KeyCountDTO> sourceTop10; // 来源TOP10
30+
31+
// 排行榜
32+
private List<UrlRankDTO> topUrls; // 热门短链TOP10
33+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.layor.tinyflow.entity;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
/**
8+
* URL排行榜DTO
9+
*/
10+
@Data
11+
@AllArgsConstructor
12+
@NoArgsConstructor
13+
public class UrlRankDTO {
14+
private String shortCode; // 短码
15+
private String longUrl; // 原始URL
16+
private long totalClicks; // 总点击数
17+
private int todayClicks; // 今日点击数
18+
}

src/main/java/com/layor/tinyflow/repository/ClickEventRepository.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,84 @@ Page<ClickEvent> findEvents(@Param("code") String code,
3838
@Param("device") String device,
3939
@Param("city") String city,
4040
Pageable pageable);
41+
42+
// 按小时统计访问量
43+
@Query("select hour(e.ts), count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end group by hour(e.ts) order by hour(e.ts)")
44+
List<Object[]> countByHour(@Param("code") String code,
45+
@Param("start") LocalDateTime start,
46+
@Param("end") LocalDateTime end);
47+
48+
// 按星期统计访问量
49+
@Query("select dayofweek(e.ts), count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end group by dayofweek(e.ts) order by dayofweek(e.ts)")
50+
List<Object[]> countByDayOfWeek(@Param("code") String code,
51+
@Param("start") LocalDateTime start,
52+
@Param("end") LocalDateTime end);
53+
54+
// 按国家统计
55+
@Query("select e.country, count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end group by e.country order by count(e) desc")
56+
List<Object[]> countByCountry(@Param("code") String code,
57+
@Param("start") LocalDateTime start,
58+
@Param("end") LocalDateTime end);
59+
60+
// 按UA/浏览器统计
61+
@Query("select e.ua, count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end group by e.ua order by count(e) desc")
62+
List<Object[]> countByUa(@Param("code") String code,
63+
@Param("start") LocalDateTime start,
64+
@Param("end") LocalDateTime end);
65+
66+
// 按Referer详细统计
67+
@Query("select e.referer, count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end and e.referer is not null group by e.referer order by count(e) desc")
68+
List<Object[]> countByReferer(@Param("code") String code,
69+
@Param("start") LocalDateTime start,
70+
@Param("end") LocalDateTime end);
71+
72+
// 统计总访问量
73+
@Query("select count(e) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end")
74+
long countTotal(@Param("code") String code,
75+
@Param("start") LocalDateTime start,
76+
@Param("end") LocalDateTime end);
77+
78+
// UV统计(独立IP)
79+
@Query("select count(distinct e.ip) from ClickEvent e where e.shortCode=:code and e.ts between :start and :end")
80+
long countUniqueIp(@Param("code") String code,
81+
@Param("start") LocalDateTime start,
82+
@Param("end") LocalDateTime end);
83+
84+
// 全局统计:按日期统计所有短链的访问量
85+
@Query("select date(e.ts), count(e) from ClickEvent e where e.ts between :start and :end group by date(e.ts) order by date(e.ts)")
86+
List<Object[]> countAllByDate(@Param("start") LocalDateTime start,
87+
@Param("end") LocalDateTime end);
88+
89+
// 全局统计:按设备统计
90+
@Query("select e.deviceType, count(e) from ClickEvent e where e.ts between :start and :end group by e.deviceType order by count(e) desc")
91+
List<Object[]> countAllByDevice(@Param("start") LocalDateTime start,
92+
@Param("end") LocalDateTime end);
93+
94+
// 全局统计:按城市统计
95+
@Query("select e.city, count(e) from ClickEvent e where e.ts between :start and :end group by e.city order by count(e) desc")
96+
List<Object[]> countAllByCity(@Param("start") LocalDateTime start,
97+
@Param("end") LocalDateTime end);
98+
99+
// 全局统计:按来源统计
100+
@Query("select e.sourceHost, count(e) from ClickEvent e where e.ts between :start and :end group by e.sourceHost order by count(e) desc")
101+
List<Object[]> countAllBySource(@Param("start") LocalDateTime start,
102+
@Param("end") LocalDateTime end);
103+
104+
// 全局统计:总量PV
105+
@Query("select count(e) from ClickEvent e where e.ts between :start and :end")
106+
long countAllTotal(@Param("start") LocalDateTime start,
107+
@Param("end") LocalDateTime end);
108+
109+
// 全局统计:总量UV
110+
@Query("select count(distinct e.ip) from ClickEvent e where e.ts between :start and :end")
111+
long countAllUniqueIp(@Param("start") LocalDateTime start,
112+
@Param("end") LocalDateTime end);
113+
114+
// 统计某短链的最早访问时间
115+
@Query("select min(e.ts) from ClickEvent e where e.shortCode=:code")
116+
LocalDateTime findFirstClickTime(@Param("code") String code);
117+
118+
// 统计某短链的最后访问时间
119+
@Query("select max(e.ts) from ClickEvent e where e.shortCode=:code")
120+
LocalDateTime findLastClickTime(@Param("code") String code);
41121
}

src/main/java/com/layor/tinyflow/repository/DailyClickRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,7 @@ INSERT INTO daily_click (short_code, date, clicks)
4545
ON DUPLICATE KEY UPDATE clicks = clicks + :delta
4646
""", nativeQuery = true)
4747
void incrementClickBy(@Param("shortCode") String shortCode, @Param("delta") long delta);
48+
49+
@Query("SELECT d.shortCode FROM DailyClick d WHERE d.date = CURRENT_DATE AND d.clicks > 0")
50+
List<String> findTodayActiveCodes();
4851
}

0 commit comments

Comments
 (0)