Comprehensive Java SDK for WeChat MiniApp development with complete platform integration
—
Comprehensive analytics and data insights including user trends, visit patterns, retention analysis, user demographics, and performance metrics for WeChat MiniApp data-driven decision making.
Core analytics operations providing detailed insights into mini program usage and user behavior.
public interface WxMaAnalysisService {
// Overview Trends
List<WxMaSummaryTrend> getDailySummaryTrend(Date beginDate, Date endDate) throws WxErrorException;
// Visit Trends
List<WxMaVisitTrend> getDailyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
List<WxMaVisitTrend> getWeeklyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
List<WxMaVisitTrend> getMonthlyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
// User Analysis
WxMaVisitDistribution getVisitDistribution(Date beginDate, Date endDate) throws WxErrorException;
WxMaRetainInfo getDailyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
WxMaRetainInfo getWeeklyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
WxMaRetainInfo getMonthlyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
// Page Analysis
List<WxMaVisitPage> getVisitPage(Date beginDate, Date endDate) throws WxErrorException;
// User Demographics
WxMaUserPortrait getUserPortrait(Date beginDate, Date endDate) throws WxErrorException;
}Comprehensive data models for different types of analytics and metrics.
public class WxMaSummaryTrend implements Serializable {
private String refDate; // Reference date (YYYYMMDD format)
private Integer visitTotal; // Total visits
private Integer shareUv; // Unique users who shared
private Integer sharePv; // Total shares
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public Integer getVisitTotal();
public void setVisitTotal(Integer visitTotal);
public Integer getShareUv();
public void setShareUv(Integer shareUv);
public Integer getSharePv();
public void setSharePv(Integer sharePv);
// Utility methods
public Date getRefDateAsDate();
public static WxMaSummaryTrend fromJson(String json);
public String toJson();
}public class WxMaVisitTrend implements Serializable {
private String refDate; // Reference date
private Integer sessionCnt; // Session count
private Integer visitPv; // Page views
private Integer visitUv; // Unique visitors
private Integer visitUvNew; // New unique visitors
private Float stayTimeUv; // Average stay time per user
private Float stayTimeSession; // Average stay time per session
private Float visitDepth; // Average visit depth
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public Integer getSessionCnt();
public void setSessionCnt(Integer sessionCnt);
public Integer getVisitPv();
public void setVisitPv(Integer visitPv);
public Integer getVisitUv();
public void setVisitUv(Integer visitUv);
public Integer getVisitUvNew();
public void setVisitUvNew(Integer visitUvNew);
public Float getStayTimeUv();
public void setStayTimeUv(Float stayTimeUv);
public Float getStayTimeSession();
public void setStayTimeSession(Float stayTimeSession);
public Float getVisitDepth();
public void setVisitDepth(Float visitDepth);
// Utility methods
public Date getRefDateAsDate();
public static WxMaVisitTrend fromJson(String json);
}public class WxMaVisitDistribution implements Serializable {
private String refDate; // Reference date
private List<AccessSource> accessSource; // Traffic sources
public static class AccessSource {
private String accessSourceName; // Source name
private Integer accessSourceVisitUv; // Unique visitors from source
public String getAccessSourceName();
public void setAccessSourceName(String accessSourceName);
public Integer getAccessSourceVisitUv();
public void setAccessSourceVisitUv(Integer accessSourceVisitUv);
}
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public List<AccessSource> getAccessSource();
public void setAccessSource(List<AccessSource> accessSource);
}public class WxMaRetainInfo implements Serializable {
private String refDate; // Reference date
private List<RetainInfo> visitRetainInfo; // Retention data
public static class RetainInfo {
private Integer key; // Day offset (0, 1, 2, 3...)
private Float value; // Retention rate (0-1)
public Integer getKey();
public void setKey(Integer key);
public Float getValue();
public void setValue(Float value);
}
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public List<RetainInfo> getVisitRetainInfo();
public void setVisitRetainInfo(List<RetainInfo> visitRetainInfo);
// Convenience methods
public Float getRetentionRate(int dayOffset);
public Map<Integer, Float> getRetentionMap();
}public class WxMaVisitPage implements Serializable {
private String refDate; // Reference date
private String pagePath; // Page path
private Integer visitPv; // Page views
private Integer visitUv; // Unique visitors
private Float stayTimeUv; // Average stay time per user
private Float entryPagePv; // Entry page views
private Float exitPagePv; // Exit page views
private Float shareUv; // Share unique users
private Float sharePv; // Share page views
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public String getPagePath();
public void setPagePath(String pagePath);
public Integer getVisitPv();
public void setVisitPv(Integer visitPv);
public Integer getVisitUv();
public void setVisitUv(Integer visitUv);
public Float getStayTimeUv();
public void setStayTimeUv(Float stayTimeUv);
public Float getEntryPagePv();
public void setEntryPagePv(Float entryPagePv);
public Float getExitPagePv();
public void setExitPagePv(Float exitPagePv);
public Float getShareUv();
public void setShareUv(Float shareUv);
public Float getSharePv();
public void setSharePv(Float sharePv);
}public class WxMaUserPortrait implements Serializable {
private String refDate; // Reference date
private List<VisitUvNew> visitUvNew; // New user demographics
public static class VisitUvNew {
private Integer index; // Index identifier
private String province; // Province
private String city; // City
private Integer genders; // Gender (0: unknown, 1: male, 2: female)
private String platforms; // Platform (iPhone, Android, etc.)
private String devices; // Device model
private String ages; // Age range
private Integer value; // User count
// Getters and setters
public Integer getIndex();
public void setIndex(Integer index);
public String getProvince();
public void setProvince(String province);
public String getCity();
public void setCity(String city);
public Integer getGenders();
public void setGenders(Integer genders);
public String getPlatforms();
public void setPlatforms(String platforms);
public String getDevices();
public void setDevices(String devices);
public String getAges();
public void setAges(String ages);
public Integer getValue();
public void setValue(Integer value);
}
// Getters and setters
public String getRefDate();
public void setRefDate(String refDate);
public List<VisitUvNew> getVisitUvNew();
public void setVisitUvNew(List<VisitUvNew> visitUvNew);
// Analysis methods
public Map<String, Integer> getGenderDistribution();
public Map<String, Integer> getPlatformDistribution();
public Map<String, Integer> getLocationDistribution();
}@Service
public class AnalyticsService {
@Autowired
private WxMaService wxMaService;
public DailyAnalyticsReport getDailyReport(Date targetDate) {
try {
Date endDate = targetDate;
Date startDate = DateUtils.addDays(targetDate, -30); // Last 30 days
// Get summary trends
List<WxMaSummaryTrend> summaryTrends = wxMaService.getAnalysisService()
.getDailySummaryTrend(startDate, endDate);
// Get visit trends
List<WxMaVisitTrend> visitTrends = wxMaService.getAnalysisService()
.getDailyVisitTrend(startDate, endDate);
// Get traffic sources
WxMaVisitDistribution distribution = wxMaService.getAnalysisService()
.getVisitDistribution(startDate, endDate);
// Get top pages
List<WxMaVisitPage> topPages = wxMaService.getAnalysisService()
.getVisitPage(startDate, endDate);
return new DailyAnalyticsReport(summaryTrends, visitTrends, distribution, topPages);
} catch (WxErrorException e) {
logger.error("Failed to get daily analytics: {}", e.getMessage());
throw new AnalyticsException("Could not retrieve daily analytics", e);
}
}
}public class RetentionAnalyzer {
public RetentionReport analyzeRetention(Date startDate, int days) {
try {
Date endDate = DateUtils.addDays(startDate, days - 1);
// Get daily retention
WxMaRetainInfo dailyRetention = wxMaService.getAnalysisService()
.getDailyRetainInfo(startDate, endDate);
// Get weekly retention
WxMaRetainInfo weeklyRetention = wxMaService.getAnalysisService()
.getWeeklyRetainInfo(startDate, endDate);
// Get monthly retention
WxMaRetainInfo monthlyRetention = wxMaService.getAnalysisService()
.getMonthlyRetainInfo(startDate, endDate);
// Analyze retention patterns
RetentionReport report = new RetentionReport();
report.setDailyRetention(analyzeRetentionData(dailyRetention));
report.setWeeklyRetention(analyzeRetentionData(weeklyRetention));
report.setMonthlyRetention(analyzeRetentionData(monthlyRetention));
// Calculate key metrics
report.setDay1Retention(dailyRetention.getRetentionRate(1));
report.setDay7Retention(dailyRetention.getRetentionRate(7));
report.setDay30Retention(dailyRetention.getRetentionRate(30));
return report;
} catch (WxErrorException e) {
logger.error("Retention analysis failed: {}", e.getMessage());
throw new AnalyticsException("Retention analysis failed", e);
}
}
private Map<String, Object> analyzeRetentionData(WxMaRetainInfo retentionInfo) {
Map<String, Object> analysis = new HashMap<>();
Map<Integer, Float> retentionMap = retentionInfo.getRetentionMap();
// Calculate retention trend
List<Float> rates = new ArrayList<>(retentionMap.values());
analysis.put("trend", calculateTrend(rates));
analysis.put("avgRetention", calculateAverage(rates));
analysis.put("retentionCurve", retentionMap);
return analysis;
}
}@Component
public class TrafficAnalyzer {
public TrafficSourceReport analyzeTrafficSources(Date startDate, Date endDate) {
try {
WxMaVisitDistribution distribution = wxMaService.getAnalysisService()
.getVisitDistribution(startDate, endDate);
List<WxMaVisitDistribution.AccessSource> sources = distribution.getAccessSource();
// Calculate total traffic
int totalVisitors = sources.stream()
.mapToInt(WxMaVisitDistribution.AccessSource::getAccessSourceVisitUv)
.sum();
// Analyze each source
Map<String, SourceAnalysis> sourceAnalysis = new HashMap<>();
for (WxMaVisitDistribution.AccessSource source : sources) {
SourceAnalysis analysis = new SourceAnalysis();
analysis.setName(source.getAccessSourceName());
analysis.setVisitors(source.getAccessSourceVisitUv());
analysis.setPercentage((float) source.getAccessSourceVisitUv() / totalVisitors * 100);
sourceAnalysis.put(source.getAccessSourceName(), analysis);
}
// Identify top sources
List<SourceAnalysis> topSources = sourceAnalysis.values().stream()
.sorted((a, b) -> Integer.compare(b.getVisitors(), a.getVisitors()))
.limit(10)
.collect(Collectors.toList());
TrafficSourceReport report = new TrafficSourceReport();
report.setTotalVisitors(totalVisitors);
report.setSourceBreakdown(sourceAnalysis);
report.setTopSources(topSources);
report.setReportDate(distribution.getRefDate());
return report;
} catch (WxErrorException e) {
logger.error("Traffic source analysis failed: {}", e.getMessage());
throw new AnalyticsException("Traffic analysis failed", e);
}
}
}public class PagePerformanceAnalyzer {
public PagePerformanceReport analyzePagePerformance(Date startDate, Date endDate) {
try {
List<WxMaVisitPage> pages = wxMaService.getAnalysisService()
.getVisitPage(startDate, endDate);
// Sort pages by different metrics
List<WxMaVisitPage> topPagesByViews = pages.stream()
.sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
.limit(20)
.collect(Collectors.toList());
List<WxMaVisitPage> topPagesByUniqueVisitors = pages.stream()
.sorted((a, b) -> Integer.compare(b.getVisitUv(), a.getVisitUv()))
.limit(20)
.collect(Collectors.toList());
List<WxMaVisitPage> topPagesByEngagement = pages.stream()
.filter(p -> p.getStayTimeUv() != null)
.sorted((a, b) -> Float.compare(b.getStayTimeUv(), a.getStayTimeUv()))
.limit(20)
.collect(Collectors.toList());
// Calculate performance metrics
Map<String, PageMetrics> pageMetrics = new HashMap<>();
for (WxMaVisitPage page : pages) {
PageMetrics metrics = new PageMetrics();
metrics.setPath(page.getPagePath());
metrics.setPageViews(page.getVisitPv());
metrics.setUniqueVisitors(page.getVisitUv());
metrics.setAvgStayTime(page.getStayTimeUv());
metrics.setBounceRate(calculateBounceRate(page));
metrics.setShareRate(calculateShareRate(page));
pageMetrics.put(page.getPagePath(), metrics);
}
PagePerformanceReport report = new PagePerformanceReport();
report.setTopPagesByViews(topPagesByViews);
report.setTopPagesByUniqueVisitors(topPagesByUniqueVisitors);
report.setTopPagesByEngagement(topPagesByEngagement);
report.setPageMetrics(pageMetrics);
return report;
} catch (WxErrorException e) {
logger.error("Page performance analysis failed: {}", e.getMessage());
throw new AnalyticsException("Page analysis failed", e);
}
}
private Float calculateBounceRate(WxMaVisitPage page) {
if (page.getEntryPagePv() != null && page.getEntryPagePv() > 0) {
return (page.getExitPagePv() / page.getEntryPagePv()) * 100;
}
return null;
}
private Float calculateShareRate(WxMaVisitPage page) {
if (page.getVisitUv() != null && page.getVisitUv() > 0 && page.getShareUv() != null) {
return (page.getShareUv() / page.getVisitUv()) * 100;
}
return null;
}
}@Component
public class UserDemographicsAnalyzer {
public DemographicsReport analyzeDemographics(Date startDate, Date endDate) {
try {
WxMaUserPortrait portrait = wxMaService.getAnalysisService()
.getUserPortrait(startDate, endDate);
List<WxMaUserPortrait.VisitUvNew> userData = portrait.getVisitUvNew();
// Analyze gender distribution
Map<String, Integer> genderDist = analyzeGenderDistribution(userData);
// Analyze platform distribution
Map<String, Integer> platformDist = analyzePlatformDistribution(userData);
// Analyze geographic distribution
Map<String, Integer> geoDist = analyzeGeographicDistribution(userData);
// Analyze age distribution
Map<String, Integer> ageDist = analyzeAgeDistribution(userData);
// Analyze device distribution
Map<String, Integer> deviceDist = analyzeDeviceDistribution(userData);
DemographicsReport report = new DemographicsReport();
report.setGenderDistribution(genderDist);
report.setPlatformDistribution(platformDist);
report.setGeographicDistribution(geoDist);
report.setAgeDistribution(ageDist);
report.setDeviceDistribution(deviceDist);
report.setTotalNewUsers(userData.stream().mapToInt(WxMaUserPortrait.VisitUvNew::getValue).sum());
report.setReportDate(portrait.getRefDate());
return report;
} catch (WxErrorException e) {
logger.error("Demographics analysis failed: {}", e.getMessage());
throw new AnalyticsException("Demographics analysis failed", e);
}
}
private Map<String, Integer> analyzeGenderDistribution(List<WxMaUserPortrait.VisitUvNew> userData) {
Map<String, Integer> distribution = new HashMap<>();
for (WxMaUserPortrait.VisitUvNew user : userData) {
String gender = getGenderLabel(user.getGenders());
distribution.merge(gender, user.getValue(), Integer::sum);
}
return distribution;
}
private String getGenderLabel(Integer genderCode) {
switch (genderCode) {
case 1: return "Male";
case 2: return "Female";
default: return "Unknown";
}
}
private Map<String, Integer> analyzeGeographicDistribution(List<WxMaUserPortrait.VisitUvNew> userData) {
Map<String, Integer> distribution = new HashMap<>();
for (WxMaUserPortrait.VisitUvNew user : userData) {
String location = user.getProvince();
if (location != null && !location.isEmpty()) {
distribution.merge(location, user.getValue(), Integer::sum);
}
}
return distribution.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(20)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
}@RestController
@RequestMapping("/api/analytics")
public class AnalyticsDashboardController {
@GetMapping("/dashboard")
public ResponseEntity<AnalyticsDashboard> getDashboard(
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
try {
AnalyticsDashboard dashboard = new AnalyticsDashboard();
// Get overview metrics
List<WxMaSummaryTrend> summary = wxMaService.getAnalysisService()
.getDailySummaryTrend(startDate, endDate);
List<WxMaVisitTrend> visits = wxMaService.getAnalysisService()
.getDailyVisitTrend(startDate, endDate);
// Calculate key metrics
dashboard.setTotalVisits(summary.stream().mapToInt(WxMaSummaryTrend::getVisitTotal).sum());
dashboard.setTotalUniqueVisitors(visits.stream().mapToInt(WxMaVisitTrend::getVisitUv).sum());
dashboard.setTotalPageViews(visits.stream().mapToInt(WxMaVisitTrend::getVisitPv).sum());
dashboard.setAvgSessionDuration(visits.stream()
.filter(v -> v.getStayTimeSession() != null)
.mapToDouble(WxMaVisitTrend::getStayTimeSession)
.average().orElse(0.0));
// Get retention data
WxMaRetainInfo retention = wxMaService.getAnalysisService()
.getDailyRetainInfo(startDate, endDate);
dashboard.setRetentionData(retention.getRetentionMap());
// Get traffic sources
WxMaVisitDistribution traffic = wxMaService.getAnalysisService()
.getVisitDistribution(startDate, endDate);
dashboard.setTrafficSources(traffic.getAccessSource());
// Get top pages
List<WxMaVisitPage> topPages = wxMaService.getAnalysisService()
.getVisitPage(startDate, endDate);
dashboard.setTopPages(topPages.stream()
.sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
.limit(10)
.collect(Collectors.toList()));
return ResponseEntity.ok(dashboard);
} catch (WxErrorException e) {
logger.error("Dashboard data retrieval failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}@Component
public class AutomatedReportingService {
@Scheduled(cron = "0 0 9 * * ?") // Daily at 9 AM
public void generateDailyReport() {
Date yesterday = DateUtils.addDays(new Date(), -1);
Date lastWeek = DateUtils.addDays(yesterday, -6);
try {
// Generate comprehensive daily report
DailyReport report = new DailyReport();
// Get yesterday's data
List<WxMaSummaryTrend> summary = wxMaService.getAnalysisService()
.getDailySummaryTrend(yesterday, yesterday);
List<WxMaVisitTrend> visits = wxMaService.getAnalysisService()
.getDailyVisitTrend(yesterday, yesterday);
// Get week-over-week comparison
List<WxMaVisitTrend> weekTrend = wxMaService.getAnalysisService()
.getDailyVisitTrend(lastWeek, yesterday);
report.setDate(yesterday);
report.setSummary(summary.get(0));
report.setVisits(visits.get(0));
report.setWeeklyComparison(calculateWeeklyGrowth(weekTrend));
// Send report via email/notification
reportNotificationService.sendDailyReport(report);
} catch (WxErrorException e) {
logger.error("Failed to generate daily report: {}", e.getMessage());
}
}
@Scheduled(cron = "0 0 10 ? * MON") // Weekly on Monday at 10 AM
public void generateWeeklyReport() {
Date endDate = DateUtils.addDays(new Date(), -1);
Date startDate = DateUtils.addDays(endDate, -6);
try {
WeeklyReport report = new WeeklyReport();
// Get weekly analytics data
List<WxMaVisitTrend> weeklyData = wxMaService.getAnalysisService()
.getWeeklyVisitTrend(startDate, endDate);
WxMaRetainInfo retention = wxMaService.getAnalysisService()
.getWeeklyRetainInfo(startDate, endDate);
List<WxMaVisitPage> pagePerformance = wxMaService.getAnalysisService()
.getVisitPage(startDate, endDate);
WxMaUserPortrait demographics = wxMaService.getAnalysisService()
.getUserPortrait(startDate, endDate);
report.setWeeklyTrends(weeklyData);
report.setRetentionAnalysis(retention);
report.setTopPages(pagePerformance.stream()
.sorted((a, b) -> Integer.compare(b.getVisitPv(), a.getVisitPv()))
.limit(20)
.collect(Collectors.toList()));
report.setUserDemographics(demographics);
// Generate insights and recommendations
report.setInsights(generateInsights(report));
reportNotificationService.sendWeeklyReport(report);
} catch (WxErrorException e) {
logger.error("Failed to generate weekly report: {}", e.getMessage());
}
}
}@Component
public class PerformanceMonitor {
@EventListener
@Async
public void onAnalyticsRequest(AnalyticsRequestEvent event) {
long startTime = System.currentTimeMillis();
try {
// Monitor API response times
Object result = event.getAnalyticsCall().call();
long duration = System.currentTimeMillis() - startTime;
// Log performance metrics
logger.info("Analytics API call completed: {} ms for {}",
duration, event.getApiMethod());
// Alert if slow
if (duration > 5000) {
alertService.sendSlowApiAlert(event.getApiMethod(), duration);
}
} catch (Exception e) {
logger.error("Analytics API call failed: {}", e.getMessage());
alertService.sendApiFailureAlert(event.getApiMethod(), e);
}
}
}The analytics service provides comprehensive insights into mini program performance with detailed metrics, trend analysis, user behavior patterns, and automated reporting capabilities.
Install with Tessl CLI
npx tessl i tessl/maven-com-github-binarywang--weixin-java-miniapp