|
@@ -0,0 +1,488 @@
|
|
|
+package org.jeecg.modules.adweb.dmp.service;
|
|
|
+
|
|
|
+import static org.jeecg.modules.adweb.dmp.vo.report.SiteOverviewStatsVO.DailyStatsVO;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.google.common.base.Strings;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.google.common.collect.Sets;
|
|
|
+
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+import org.apache.commons.compress.utils.Lists;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.commons.lang3.tuple.ImmutableTriple;
|
|
|
+import org.jeecg.modules.adweb.common.enums.CountryCode;
|
|
|
+import org.jeecg.modules.adweb.common.util.AdwebRedisUtil;
|
|
|
+import org.jeecg.modules.adweb.common.util.DateUtil;
|
|
|
+import org.jeecg.modules.adweb.common.util.NumberUtil;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.GAPropertyDTO;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.report.GAReportRequestDTO;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.report.OrderByType;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.report.ReportConstant;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.report.ReportType;
|
|
|
+import org.jeecg.modules.adweb.dmp.dto.google.analytics.report.data.CustomReportData;
|
|
|
+import org.jeecg.modules.adweb.dmp.entity.GoogleGTM;
|
|
|
+import org.jeecg.modules.adweb.dmp.service.google.GAReportService;
|
|
|
+import org.jeecg.modules.adweb.dmp.vo.report.*;
|
|
|
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryMapper;
|
|
|
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
|
|
|
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
|
|
|
+import org.jeecg.modules.redis.CacheConfig;
|
|
|
+import org.jeecg.modules.redis.TTLCacheManager;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.cache.annotation.Cacheable;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 从DataBridge实时拉取GA报表数据,非DB离线查询 - http://data-bridge.v3.adwebcloud.com:9002/swagger-ui/index.html
|
|
|
+ *
|
|
|
+ * @author wfansh
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class RealtimeReportService {
|
|
|
+
|
|
|
+ @Autowired private IAdwebSiteService adwebSiteService;
|
|
|
+ @Autowired private IGoogleGTMService googleGTMService;
|
|
|
+ @Autowired private AdwebEnquiryMapper adwebEnquiryMapper;
|
|
|
+ @Autowired private GAReportService gaReportService;
|
|
|
+ @Autowired private AdwebRedisUtil redisUtil;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 拉取Google Analytics - Daily报表
|
|
|
+ *
|
|
|
+ * <p>如数据库中某天数据缺失,需填充空数据
|
|
|
+ *
|
|
|
+ * <p>填充每日询盘数据
|
|
|
+ */
|
|
|
+ @Cacheable(
|
|
|
+ cacheManager = CacheConfig.TTL_CACHE_MANAGER,
|
|
|
+ cacheNames =
|
|
|
+ "dmp:realtime:getDailyStats"
|
|
|
+ + TTLCacheManager.TTL_SPLITTER
|
|
|
+ + 60 * 10) // Redis TTL为10分钟
|
|
|
+ public List<SiteOverviewStatsVO.DailyStatsVO> getDailyStats(
|
|
|
+ String siteCode, Date start, Date end) {
|
|
|
+ GoogleGTM googleGTM = this.getGTMAccount(siteCode);
|
|
|
+ if (StringUtils.isBlank(googleGTM.getGaPropertyId())) {
|
|
|
+ log.info("Google Analytics帐号未配置, siteCode = {}", siteCode);
|
|
|
+ return Collections.EMPTY_LIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 0. 起止日期为空时,设置默认区间 - start = 网站发布日期 & end = 今天
|
|
|
+ if (start == null || end == null) {
|
|
|
+ AdwebSite adwebSite = adwebSiteService.getSiteByCode(siteCode);
|
|
|
+ start =
|
|
|
+ DateUtil.getTodayZeroTime(
|
|
|
+ Optional.ofNullable(adwebSite.getIssueTime())
|
|
|
+ .orElse(adwebSite.getCtime()));
|
|
|
+ end = DateUtil.getTodayZeroTime(new Date());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 构建GA报表请求参数
|
|
|
+ GAReportRequestDTO gaReportRequest =
|
|
|
+ this.buildGAReportRequest(
|
|
|
+ googleGTM.getGaPropertyId(),
|
|
|
+ start,
|
|
|
+ end,
|
|
|
+ List.of(
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ ReportConstant.METRIC_SESSIONS,
|
|
|
+ ReportConstant.METRIC_BOUNCE_RATE,
|
|
|
+ ReportConstant.METRIC_AVG_SESSION_DURATION,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS_PER_SESSION),
|
|
|
+ List.of(ReportConstant.DIMENSION_DATE),
|
|
|
+ OrderByType.DIMENSIONS,
|
|
|
+ ReportConstant.DIMENSION_DATE,
|
|
|
+ false);
|
|
|
+
|
|
|
+ // 2. 请求API接口
|
|
|
+ List<CustomReportData> reportDataList =
|
|
|
+ gaReportService.runGAReport(gaReportRequest, CustomReportData.class);
|
|
|
+
|
|
|
+ // 3. 转化为VOs
|
|
|
+ Map<String, DailyStatsVO> dailyStatsVOs = Maps.newHashMap();
|
|
|
+ for (CustomReportData reportData : reportDataList) {
|
|
|
+ DailyStatsVO dailyStatsVO = new DailyStatsVO();
|
|
|
+ dailyStatsVO.setDate(reportData.get(ReportConstant.DIMENSION_DATE));
|
|
|
+ dailyStatsVO.setTotalUsers(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_TOTAL_USERS)));
|
|
|
+ dailyStatsVO.setSessions(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SESSIONS)));
|
|
|
+ dailyStatsVO.setBounceRate(
|
|
|
+ Double.parseDouble(reportData.get(ReportConstant.METRIC_BOUNCE_RATE)));
|
|
|
+ dailyStatsVO.setAvgSessionDuration(
|
|
|
+ Double.parseDouble(reportData.get(ReportConstant.METRIC_AVG_SESSION_DURATION)));
|
|
|
+ dailyStatsVO.setPageViews(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SCREEN_PAGE_VIEWS)));
|
|
|
+ dailyStatsVO.setPageViewsPerSession(
|
|
|
+ Double.parseDouble(
|
|
|
+ reportData.get(ReportConstant.METRIC_SCREEN_PAGE_VIEWS_PER_SESSION)));
|
|
|
+
|
|
|
+ dailyStatsVOs.put(dailyStatsVO.getDate(), dailyStatsVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 缺失日期补充
|
|
|
+ Set<String> absentDays =
|
|
|
+ Sets.difference(
|
|
|
+ DateUtil.getAllDaysBetween(start, end).stream()
|
|
|
+ .map(date -> DateUtil.formatDate(date, DateUtil.DATE_FORMAT))
|
|
|
+ .collect(Collectors.toSet()),
|
|
|
+ dailyStatsVOs.keySet());
|
|
|
+ absentDays.forEach(
|
|
|
+ date -> {
|
|
|
+ DailyStatsVO dailyStatsVO = new DailyStatsVO();
|
|
|
+ dailyStatsVO.setDate(date); // 其它数值字段设置为默认值
|
|
|
+ dailyStatsVOs.put(date, dailyStatsVO);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 5. 询盘数据补充
|
|
|
+ List<ImmutableTriple<String, Long, Long>> enquiryDailyCounts =
|
|
|
+ adwebEnquiryMapper.getEnquiryDailyCounts(siteCode, start, end);
|
|
|
+ for (ImmutableTriple<String, Long, Long> enquiryDailyCount : enquiryDailyCounts) {
|
|
|
+ if (!dailyStatsVOs.containsKey(enquiryDailyCount.getLeft())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ DailyStatsVO dailyStatsVO = dailyStatsVOs.get(enquiryDailyCount.getLeft());
|
|
|
+ dailyStatsVO.setEnquires(enquiryDailyCount.getMiddle().intValue());
|
|
|
+ dailyStatsVO.setUnreadEnquires(enquiryDailyCount.getRight().intValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 根据日期排序并返回
|
|
|
+ return dailyStatsVOs.values().stream()
|
|
|
+ .sorted(Comparator.comparing(DailyStatsVO::getDate)) // 排日期升序排序
|
|
|
+ .collect(Collectors.toList()); // 使用toList()方法返回UnmodifiableList,导致Redis类型解析异常
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 拉取Google Analytics - Country报表 */
|
|
|
+ @Cacheable(
|
|
|
+ cacheManager = CacheConfig.TTL_CACHE_MANAGER,
|
|
|
+ cacheNames =
|
|
|
+ "dmp:realtime:getCountryStats"
|
|
|
+ + TTLCacheManager.TTL_SPLITTER
|
|
|
+ + 60 * 10) // Redis TTL为10分钟
|
|
|
+ public List<CountryStatsVO> getCountryStats(String siteCode, Date start, Date end) {
|
|
|
+ GoogleGTM googleGTM = this.getGTMAccount(siteCode);
|
|
|
+ if (StringUtils.isBlank(googleGTM.getGaPropertyId())) {
|
|
|
+ log.info("Google Analytics帐号未配置, siteCode = {}", siteCode);
|
|
|
+ return Collections.EMPTY_LIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 构建GA报表请求参数
|
|
|
+ GAReportRequestDTO gaReportRequest =
|
|
|
+ this.buildGAReportRequest(
|
|
|
+ googleGTM.getGaPropertyId(),
|
|
|
+ start,
|
|
|
+ end,
|
|
|
+ List.of(ReportConstant.METRIC_TOTAL_USERS),
|
|
|
+ List.of(ReportConstant.DIMENSION_COUNTRY),
|
|
|
+ OrderByType.METRICS,
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ true);
|
|
|
+
|
|
|
+ // 2. 请求API接口
|
|
|
+ List<CustomReportData> reportDataList =
|
|
|
+ gaReportService.runGAReport(gaReportRequest, CustomReportData.class);
|
|
|
+
|
|
|
+ // 3.1 转化为VOs
|
|
|
+ List<CountryStatsVO> countryStatsVOs = Lists.newArrayList();
|
|
|
+ for (CustomReportData reportData : reportDataList) {
|
|
|
+ CountryStatsVO countryStatsVO = new CountryStatsVO();
|
|
|
+ countryStatsVO.setCountry(reportData.get(ReportConstant.DIMENSION_COUNTRY));
|
|
|
+
|
|
|
+ CountryCode countryCode = CountryCode.valueOfName(countryStatsVO.getCountry());
|
|
|
+ countryStatsVO.setCountryName(countryCode.getCnName());
|
|
|
+ countryStatsVO.setCountryCode(countryCode.getCode());
|
|
|
+
|
|
|
+ countryStatsVO.setTotalUsers(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_TOTAL_USERS)));
|
|
|
+
|
|
|
+ countryStatsVOs.add(countryStatsVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3.2 时间区间内所有国家totalUsers总数
|
|
|
+ int totalUsersSum = countryStatsVOs.stream().mapToInt(CountryStatsVO::getTotalUsers).sum();
|
|
|
+
|
|
|
+ // 3.3 VO数据计算填充
|
|
|
+ for (CountryStatsVO countryStatsVO : countryStatsVOs) {
|
|
|
+ countryStatsVO.setTotalUsersProportion(
|
|
|
+ NumberUtil.formatPercentage(
|
|
|
+ NumberUtil.safeDivide(countryStatsVO.getTotalUsers(), totalUsersSum),
|
|
|
+ 2));
|
|
|
+ }
|
|
|
+
|
|
|
+ return countryStatsVOs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 拉取Google Analytics - Session Source Medium报表 */
|
|
|
+ @Cacheable(
|
|
|
+ cacheManager = CacheConfig.TTL_CACHE_MANAGER,
|
|
|
+ cacheNames =
|
|
|
+ "dmp:realtime:getSourceMediumStats"
|
|
|
+ + TTLCacheManager.TTL_SPLITTER
|
|
|
+ + 60 * 10) // Redis TTL为10分钟
|
|
|
+ public List<SourceMediumStatsVO> getSourceMediumStats(String siteCode, Date start, Date end) {
|
|
|
+ GoogleGTM googleGTM = this.getGTMAccount(siteCode);
|
|
|
+ if (StringUtils.isBlank(googleGTM.getGaPropertyId())) {
|
|
|
+ log.info("Google Analytics帐号未配置, siteCode = {}", siteCode);
|
|
|
+ return Collections.EMPTY_LIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 构建GA报表请求参数
|
|
|
+ GAReportRequestDTO gaReportRequest =
|
|
|
+ this.buildGAReportRequest(
|
|
|
+ googleGTM.getGaPropertyId(),
|
|
|
+ start,
|
|
|
+ end,
|
|
|
+ List.of(
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ ReportConstant.METRIC_NEW_USERS,
|
|
|
+ ReportConstant.METRIC_SESSIONS,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS,
|
|
|
+ ReportConstant.METRIC_AVG_SESSION_DURATION,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS_PER_SESSION),
|
|
|
+ List.of(ReportConstant.DIMENSION_SESSION_SOURCE_MEDIUM),
|
|
|
+ OrderByType.METRICS,
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ true);
|
|
|
+
|
|
|
+ // 2. 请求API接口
|
|
|
+ List<CustomReportData> reportDataList =
|
|
|
+ gaReportService.runGAReport(gaReportRequest, CustomReportData.class);
|
|
|
+
|
|
|
+ // 3.1 转化为VOs
|
|
|
+ List<SourceMediumStatsVO> sourceMediumStatsVOs = Lists.newArrayList();
|
|
|
+ for (CustomReportData reportData : reportDataList) {
|
|
|
+ SourceMediumStatsVO sourceMediumStatsVO = new SourceMediumStatsVO();
|
|
|
+ sourceMediumStatsVO.setType(
|
|
|
+ reportData.get(ReportConstant.DIMENSION_SESSION_SOURCE_MEDIUM));
|
|
|
+ sourceMediumStatsVO.setTotalUsers(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_TOTAL_USERS)));
|
|
|
+ sourceMediumStatsVO.setNewUsers(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_NEW_USERS)));
|
|
|
+ sourceMediumStatsVO.setSessions(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SESSIONS)));
|
|
|
+ sourceMediumStatsVO.setPageViews(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SCREEN_PAGE_VIEWS)));
|
|
|
+ sourceMediumStatsVO.setAvgSessionDuration(
|
|
|
+ NumberUtil.formatDecimal(
|
|
|
+ Double.parseDouble(
|
|
|
+ reportData.get(
|
|
|
+ ReportConstant.METRIC_AVG_SESSION_DURATION)),
|
|
|
+ 2)
|
|
|
+ .doubleValue());
|
|
|
+ sourceMediumStatsVO.setPageViewsPerSession(
|
|
|
+ NumberUtil.formatDecimal(
|
|
|
+ Double.parseDouble(
|
|
|
+ reportData.get(
|
|
|
+ ReportConstant
|
|
|
+ .METRIC_SCREEN_PAGE_VIEWS_PER_SESSION)),
|
|
|
+ 2)
|
|
|
+ .doubleValue());
|
|
|
+
|
|
|
+ sourceMediumStatsVOs.add(sourceMediumStatsVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3.2 时间区间内所有媒介totalUsers总数
|
|
|
+ int totalUsersSum =
|
|
|
+ sourceMediumStatsVOs.stream().mapToInt(SourceMediumStatsVO::getTotalUsers).sum();
|
|
|
+
|
|
|
+ // 3.3 VO数据计算填充
|
|
|
+ for (SourceMediumStatsVO sourceMediumStatsVO : sourceMediumStatsVOs) {
|
|
|
+ int totalUsers = sourceMediumStatsVO.getTotalUsers();
|
|
|
+ sourceMediumStatsVO.setTotalUsersProportion(
|
|
|
+ NumberUtil.formatPercentage(
|
|
|
+ NumberUtil.safeDivide(totalUsers, totalUsersSum), 2));
|
|
|
+
|
|
|
+ sourceMediumStatsVO.setNewUsersRatio(
|
|
|
+ NumberUtil.formatPercentage(
|
|
|
+ NumberUtil.safeDivide(sourceMediumStatsVO.getNewUsers(), totalUsers),
|
|
|
+ 2));
|
|
|
+ }
|
|
|
+
|
|
|
+ return sourceMediumStatsVOs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 拉取Google Analytics - Page Path报表 */
|
|
|
+ @Cacheable(
|
|
|
+ cacheManager = CacheConfig.TTL_CACHE_MANAGER,
|
|
|
+ cacheNames =
|
|
|
+ "dmp:realtime:getPagePathStats"
|
|
|
+ + TTLCacheManager.TTL_SPLITTER
|
|
|
+ + 60 * 10) // Redis TTL为10分钟
|
|
|
+ public List<PagePathStatsVO> getPagePathStats(
|
|
|
+ String siteCode, Date start, Date end, int limit) {
|
|
|
+ GoogleGTM googleGTM = this.getGTMAccount(siteCode);
|
|
|
+ if (StringUtils.isBlank(googleGTM.getGaPropertyId())) {
|
|
|
+ log.info("Google Analytics帐号未配置, siteCode = {}", siteCode);
|
|
|
+ return Collections.EMPTY_LIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 构建GA报表请求参数
|
|
|
+ GAReportRequestDTO gaReportRequest =
|
|
|
+ this.buildGAReportRequest(
|
|
|
+ googleGTM.getGaPropertyId(),
|
|
|
+ start,
|
|
|
+ end,
|
|
|
+ List.of(
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS,
|
|
|
+ ReportConstant.METRIC_USER_ENGAGEMENT_DURATION),
|
|
|
+ List.of(ReportConstant.DIMENSION_PAGE_PATH),
|
|
|
+ OrderByType.METRICS,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS,
|
|
|
+ true);
|
|
|
+
|
|
|
+ // 2. 请求API接口
|
|
|
+ List<CustomReportData> reportDataList =
|
|
|
+ gaReportService.runGAReport(gaReportRequest, CustomReportData.class);
|
|
|
+
|
|
|
+ // 3.1 转化为VOs
|
|
|
+ List<PagePathStatsVO> pagePathStatsVOs = Lists.newArrayList();
|
|
|
+ for (CustomReportData reportData : reportDataList) {
|
|
|
+ PagePathStatsVO pagePathStatsVO = new PagePathStatsVO();
|
|
|
+ pagePathStatsVO.setPagePath(reportData.get(ReportConstant.DIMENSION_PAGE_PATH));
|
|
|
+ pagePathStatsVO.setPageViews(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SCREEN_PAGE_VIEWS)));
|
|
|
+ pagePathStatsVO.setAvgTimeOnPage(
|
|
|
+ NumberUtil.formatDecimal(
|
|
|
+ Double.parseDouble(
|
|
|
+ reportData.get(
|
|
|
+ ReportConstant
|
|
|
+ .METRIC_USER_ENGAGEMENT_DURATION)),
|
|
|
+ 2)
|
|
|
+ .doubleValue());
|
|
|
+
|
|
|
+ pagePathStatsVOs.add(pagePathStatsVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3.2. 网站URL及格式化
|
|
|
+ AdwebSite adwebSite = adwebSiteService.getSiteByCode(siteCode);
|
|
|
+ String siteUrl = StringUtils.removeEnd(Strings.nullToEmpty(adwebSite.getDomain()), "/");
|
|
|
+
|
|
|
+ // 3.3. 时间区间内PV总数
|
|
|
+ int totalPVs = pagePathStatsVOs.stream().mapToInt(PagePathStatsVO::getPageViews).sum();
|
|
|
+
|
|
|
+ // 3.4 VO数据计算填充
|
|
|
+ for (PagePathStatsVO pagePathStatsVO : pagePathStatsVOs) {
|
|
|
+ pagePathStatsVO.setPagePath(siteUrl + pagePathStatsVO.getPagePath());
|
|
|
+ pagePathStatsVO.setPvProportion(
|
|
|
+ NumberUtil.formatPercentage(
|
|
|
+ NumberUtil.safeDivide(pagePathStatsVO.getPageViews(), totalPVs), 2));
|
|
|
+ }
|
|
|
+
|
|
|
+ return pagePathStatsVOs.stream()
|
|
|
+ .limit(limit)
|
|
|
+ .collect(Collectors.toList()); // 使用toList()方法返回UnmodifiableList,导致Redis类型解析异常
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 拉取Google Analytics - Device报表 */
|
|
|
+ @Cacheable(
|
|
|
+ cacheManager = CacheConfig.TTL_CACHE_MANAGER,
|
|
|
+ cacheNames =
|
|
|
+ "dmp:realtime:getDeviceStats"
|
|
|
+ + TTLCacheManager.TTL_SPLITTER
|
|
|
+ + 60 * 10) // Redis TTL为10分钟
|
|
|
+ public List<DeviceStatsVO> getDeviceStats(String siteCode, Date start, Date end) {
|
|
|
+ GoogleGTM googleGTM = this.getGTMAccount(siteCode);
|
|
|
+ if (StringUtils.isBlank(googleGTM.getGaPropertyId())) {
|
|
|
+ log.info("Google Analytics帐号未配置, siteCode = {}", siteCode);
|
|
|
+ return Collections.EMPTY_LIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 构建GA报表请求参数
|
|
|
+ GAReportRequestDTO gaReportRequest =
|
|
|
+ this.buildGAReportRequest(
|
|
|
+ googleGTM.getGaPropertyId(),
|
|
|
+ start,
|
|
|
+ end,
|
|
|
+ List.of(
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ ReportConstant.METRIC_SESSIONS,
|
|
|
+ ReportConstant.METRIC_SCREEN_PAGE_VIEWS),
|
|
|
+ List.of(ReportConstant.DIMENSION_PLATFORM_DEVICE_CATEGORY),
|
|
|
+ OrderByType.METRICS,
|
|
|
+ ReportConstant.METRIC_TOTAL_USERS,
|
|
|
+ true);
|
|
|
+
|
|
|
+ // 2. 请求API接口
|
|
|
+ List<CustomReportData> reportDataList =
|
|
|
+ gaReportService.runGAReport(gaReportRequest, CustomReportData.class);
|
|
|
+
|
|
|
+ // 3. 转化为VOs
|
|
|
+ List<DeviceStatsVO> deviceStatsVOs = Lists.newArrayList();
|
|
|
+ for (CustomReportData reportData : reportDataList) {
|
|
|
+ DeviceStatsVO deviceStatsVO = new DeviceStatsVO();
|
|
|
+ deviceStatsVO.setDevice(
|
|
|
+ reportData.get(ReportConstant.DIMENSION_PLATFORM_DEVICE_CATEGORY));
|
|
|
+ deviceStatsVO.setTotalUsers(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_TOTAL_USERS)));
|
|
|
+ deviceStatsVO.setSessions(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SESSIONS)));
|
|
|
+ deviceStatsVO.setPageViews(
|
|
|
+ Integer.parseInt(reportData.get(ReportConstant.METRIC_SCREEN_PAGE_VIEWS)));
|
|
|
+
|
|
|
+ deviceStatsVOs.add(deviceStatsVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ return deviceStatsVOs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取{@link GoogleGTM}帐号信息 - 放入Redis缓存,避免同一页面多个HTTP请求频繁DB查询
|
|
|
+ *
|
|
|
+ * <p>使用AdwebRedisUtil操作 - @Cacheable注解无法嵌套使用
|
|
|
+ */
|
|
|
+ private synchronized GoogleGTM getGTMAccount(String siteCode) {
|
|
|
+ final String redisKey = String.format("%s:account:%s", "googlegtm", siteCode);
|
|
|
+
|
|
|
+ GoogleGTM googleGTM = (GoogleGTM) redisUtil.get(redisKey);
|
|
|
+ if (Objects.nonNull(googleGTM)) {
|
|
|
+ return googleGTM;
|
|
|
+ }
|
|
|
+
|
|
|
+ // DB查询
|
|
|
+ googleGTM =
|
|
|
+ googleGTMService.getOne(
|
|
|
+ new LambdaQueryWrapper<GoogleGTM>().eq(GoogleGTM::getSiteCode, siteCode),
|
|
|
+ false);
|
|
|
+ googleGTM = Objects.nonNull(googleGTM) ? googleGTM : new GoogleGTM(); // Redis存储对象不允许为空
|
|
|
+ redisUtil.set(redisKey, googleGTM, 30); // Redis TTL为30秒
|
|
|
+
|
|
|
+ return googleGTM;
|
|
|
+ }
|
|
|
+
|
|
|
+ private GAReportRequestDTO buildGAReportRequest(
|
|
|
+ String propertyId,
|
|
|
+ Date start,
|
|
|
+ Date end,
|
|
|
+ List<String> metrics,
|
|
|
+ List<String> dimensions,
|
|
|
+ OrderByType orderByType,
|
|
|
+ String orderBy,
|
|
|
+ boolean orderByDesc) {
|
|
|
+ GAReportRequestDTO gaReportRequest = new GAReportRequestDTO();
|
|
|
+ gaReportRequest.setPropertyResourceName(GAPropertyDTO.toResourceName(propertyId));
|
|
|
+ gaReportRequest.setReportType(ReportType.ADWEB_CUSTOM_REPORT);
|
|
|
+ gaReportRequest.setStartDate(
|
|
|
+ DateUtil.formatDate(
|
|
|
+ Optional.ofNullable(start)
|
|
|
+ // 如果start为空,设置为无限早时间
|
|
|
+ .orElse(DateUtil.parseDate("2016-01-01", DateUtil.DATE_FORMAT)),
|
|
|
+ DateUtil.DATE_FORMAT));
|
|
|
+ gaReportRequest.setEndDate(
|
|
|
+ DateUtil.formatDate(
|
|
|
+ Optional.ofNullable(end).orElse(new Date()), DateUtil.DATE_FORMAT));
|
|
|
+ gaReportRequest.setMetrics(metrics);
|
|
|
+ gaReportRequest.setDimensions(dimensions);
|
|
|
+ gaReportRequest.setOrderByType(orderByType);
|
|
|
+ gaReportRequest.setOrderBy(orderBy);
|
|
|
+ gaReportRequest.setOrderByDesc(orderByDesc);
|
|
|
+ return gaReportRequest;
|
|
|
+ }
|
|
|
+}
|