Java 实现微信小程序不同人员生成不同小程序码并追踪扫码来源
Java后台实现微信小程序不同人员生成不同小程序码并追踪扫码来源
下面我将详细介绍如何使用Java后台实现这一功能。
一、整体架构设计
- 前端:微信小程序
- 后端:Java (Spring Boot)
- 数据库:MySQL/其他
- 微信接口:调用微信小程序码生成API
二、数据库设计
1. 推广人员表(promoter)
CREATE TABLE `promoter` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '推广人员姓名',
`mobile` varchar(20) COMMENT '联系电话',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 用户-推广关系表(user_promoter_relation)
CREATE TABLE `user_promoter_relation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` varchar(64) NOT NULL COMMENT '小程序用户openid',
`promoter_id` bigint NOT NULL COMMENT '推广人员ID',
`first_scan_time` datetime NOT NULL COMMENT '首次扫码时间',
`last_scan_time` datetime NOT NULL COMMENT '最近扫码时间',
`scan_count` int NOT NULL DEFAULT '1' COMMENT '扫码次数',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_promoter` (`user_id`,`promoter_id`),
KEY `idx_promoter` (`promoter_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
三、Java后端实现
1. 添加微信小程序Java SDK依赖
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.1.0</version>
</dependency>
2. 配置微信小程序参数
@Configuration
public class WxMaConfiguration {
@Value("${wx.miniapp.appid}")
private String appid;
@Value("${wx.miniapp.secret}")
private String secret;
@Bean
public WxMaService wxMaService() {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(appid);
config.setSecret(secret);
WxMaService service = new WxMaServiceImpl();
service.setWxMaConfig(config);
return service;
}
}
3. 生成带参数的小程序码
@RestController
@RequestMapping("/api/qrcode")
public class QrCodeController {
@Autowired
private WxMaService wxMaService;
@Autowired
private PromoterService promoterService;
/**
* 生成推广二维码
* @param promoterId 推广人员ID
* @return 二维码图片字节流
*/
@GetMapping("/generate")
public void generatePromoterQrCode(@RequestParam Long promoterId,
HttpServletResponse response) throws IOException {
// 验证推广人员是否存在
Promoter promoter = promoterService.getById(promoterId);
if (promoter == null) {
throw new RuntimeException("推广人员不存在");
}
// 生成小程序码
String scene = "promoterId=" + promoterId;
WxMaQrcodeService qrcodeService = wxMaService.getQrcodeService();
File qrCodeFile = qrcodeService.createWxaCodeUnlimit(scene, "pages/index/index", 430, true, null, false);
// 返回图片流
response.setContentType("image/jpeg");
try (InputStream in = new FileInputStream(qrCodeFile);
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
}
}
4. 处理扫码进入事件
@RestController
@RequestMapping("/api/track")
public class TrackController {
@Autowired
private UserPromoterRelationService relationService;
/**
* 记录用户扫码行为
* @param dto 包含用户信息和推广信息
* @return 操作结果
*/
@PostMapping("/scan")
public Result trackScan(@RequestBody ScanTrackDTO dto) {
// 解析scene参数
String scene = dto.getScene();
Map<String, String> sceneParams = parseScene(scene);
String promoterIdStr = sceneParams.get("promoterId");
if (StringUtils.isBlank(promoterIdStr)) {
return Result.fail("缺少推广人员参数");
}
try {
Long promoterId = Long.parseLong(promoterIdStr);
relationService.recordUserScan(dto.getOpenid(), promoterId);
return Result.success();
} catch (NumberFormatException e) {
return Result.fail("推广人员参数格式错误");
}
}
private Map<String, String> parseScene(String scene) {
Map<String, String> params = new HashMap<>();
if (StringUtils.isBlank(scene)) {
return params;
}
String[] pairs = scene.split("&");
for (String pair : pairs) {
String[] kv = pair.split("=");
if (kv.length == 2) {
params.put(kv[0], kv[1]);
}
}
return params;
}
}
5. 用户-推广关系服务
@Service
public class UserPromoterRelationServiceImpl implements UserPromoterRelationService {
@Autowired
private UserPromoterRelationMapper relationMapper;
@Override
@Transactional
public void recordUserScan(String openid, Long promoterId) {
// 查询是否已有记录
UserPromoterRelation relation = relationMapper.selectByUserAndPromoter(openid, promoterId);
Date now = new Date();
if (relation == null) {
// 新建关系记录
relation = new UserPromoterRelation();
relation.setUserId(openid);
relation.setPromoterId(promoterId);
relation.setFirstScanTime(now);
relation.setLastScanTime(now);
relation.setScanCount(1);
relationMapper.insert(relation);
} else {
// 更新已有记录
relation.setLastScanTime(now);
relation.setScanCount(relation.getScanCount() + 1);
relationMapper.updateById(relation);
}
}
}
四、小程序前端处理
在小程序的app.js中处理扫码进入的场景:
App({
onLaunch: function(options) {
// 处理扫码进入的情况
if (options.scene === 1047 || options.scene === 1048 || options.scene === 1049) {
// 这些scene值表示是通过扫码进入
const scene = decodeURIComponent(options.query.scene);
// 上报扫码信息到后端
wx.request({
url: 'https://yourdomain.com/api/track/scan',
method: 'POST',
data: {
scene: scene,
openid: this.globalData.openid // 需要先获取用户openid
},
success: function(res) {
console.log('扫码记录成功', res);
}
});
}
}
})
五、数据统计接口实现
@RestController
@RequestMapping("/api/stat")
public class StatController {
@Autowired
private UserPromoterRelationMapper relationMapper;
/**
* 获取推广人员业绩统计
* @param promoterId 推广人员ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计结果
*/
@GetMapping("/promoter")
public Result getPromoterStats(@RequestParam Long promoterId,
@RequestParam(required = false) @DateTimeFormat(pattern="yyyy-MM-dd") Date startDate,
@RequestParam(required = false) @DateTimeFormat(pattern="yyyy-MM-dd") Date endDate) {
// 构建查询条件
QueryWrapper<UserPromoterRelation> query = new QueryWrapper<>();
query.eq("promoter_id", promoterId);
if (startDate != null) {
query.ge("first_scan_time", startDate);
}
if (endDate != null) {
query.le("first_scan_time", endDate);
}
// 执行查询
int totalUsers = relationMapper.selectCount(query);
List<Map<String, Object>> dailyStats = relationMapper.selectDailyStatsByPromoter(promoterId, startDate, endDate);
// 返回结果
Map<String, Object> result = new HashMap<>();
result.put("totalUsers", totalUsers);
result.put("dailyStats", dailyStats);
return Result.success(result);
}
}
六、安全注意事项
- 参数校验:所有传入的promoterId需要验证是否存在
- 防刷机制:限制同一用户频繁上报扫码记录
- HTTPS:确保所有接口使用HTTPS协议
- 权限控制:推广数据统计接口需要添加权限验证
- 日志记录:记录所有二维码生成和扫码行为
七、扩展功能建议
- 二级分销:可以扩展支持多级推广关系
- 奖励机制:根据扫码用户的活动情况给推广人员奖励
- 实时通知:当有新用户扫码时,实时通知推广人员
- 数据分析:提供更详细的数据分析报表
通过以上Java实现,你可以完整地构建一个支持不同人员生成不同小程序码并能追踪扫码来源的系统。
Java 实现微信小程序不同人员生成不同小程序码并追踪扫码来源的更多相关文章
- 微信小程序使用场景延伸:扫码登录、扫码支付
微信小程序使用场景延伸:扫码登录.扫码支付 小程序最适合的使用场景有哪些?相比大家能列举出来很多,但这个场景,大家可能多数没想到_^ 笔者团队近期接到了一个PC项目:转转游戏租号PC官网,该项目要求在 ...
- 行星万象表白墙微信小程序、社交微信小程序,后台完整,支持多区域运营,扫码体验。
简介 中国目前大概有5000个表白墙,累计用户近3000万,是一个庞大的群体,但现在大都以微信朋友圈为基础进行信息中转,但是这种模式经营者和用户都不友好,尤其是经营者无法变现,用户无法公开评论,这些种 ...
- asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
2018-08-13更新生成二维码的方法 在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付.H5支付.公众号支付.App支付等,本人使用的是asp.net mvc c ...
- 微信支付之扫码、APP、小程序支付接入详解
做电商平台的小伙伴都知道,支付服务是必不可少的一部分,今天我们开始就说说支付服务的接入及实现.目前在国内,几乎90%中小公司的支付系统都离不开微信支付和支付宝支付.那么大家要思考了,为什么微信支付和支 ...
- 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...
- 微信小程序~扫码
为了让用户减少输入,我们可以把复杂的信息编码成一个二维码,利用宿主环境wx.scanCode这个API调起微信扫一扫,用户扫码之后,wx.scanCode的success回调会收到这个二维码所对应的字 ...
- Authing新功能——小程序扫码登录
近期,Authing 发布了新功能--小程序扫码登录. 小程序扫码登录指使用Authing小程序身份管家在网页端或其它客户端执行微信登录,目前的SDK仅支持客户端JavaScript.其它语言若想使用 ...
- php微信支付(仅pc端扫码支付模式二)详细步骤.----仅适合第一次做微信开发的程序员
本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/10,所以微信支付 ...
- 记录:c#实现微信,支付宝扫码支付(一)
因为公司系统业务需要,这几天了解了一下微信和支付宝扫码支付的接口,并用c#实现了微信和支付宝扫码支付的功能. 微信支付分为6种支付模式:1.付款码支付,2.native支付,3.jsapi支付,4.a ...
- Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_182 之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内 ...
随机推荐
- js回忆录(4) -- 对象,构造函数
1.对象 && 构造函数 js是一门基于对象的语言,里边所有的数据类型都可以当对象使唤(当然null和undefined除外),当我们在v8引擎里声明一个对象时会发现每个对象属性里边都 ...
- etcd 快速入门
一.认识etcd 1.1 etcd 概念 从哪里说起呢?官网第一个页面,有那么一句话: "A distributed, reliable key-value store for the mo ...
- VRRP+BFD实验
VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议)的工作原理主要涉及多个路由器(或具备路由功能的设备)协同工作,通过VRRP报文和优先级机制来选举出一 ...
- Docker swarm集群增加节点
docker swarm初始化 docker swarm init docker swarm 增加节点 在已经初始化的机器上执行:# docker swarm join-token manager T ...
- 智能Agent如何改造传统工作流:从搜索到全能助手
智能Agent如何改造传统工作流:从搜索到全能助手 引言:当AI遇上工作流 还记得我们以前搜索信息的方式吗?输入关键词,浏览大量结果,筛选有用内容,再整合成我们需要的答案.这个过程不仅耗时,还常常让人 ...
- 【WinForm】WinForm 生成单文件程序
WinForm 生成单文件程序 零.解决 安装 Costura.Fody 安装好这个库后生成的就是单文件了. .Net 3.5 NuGet控制台 NuGet\Install-Package Costu ...
- restful 服务器一个问题,看ChatGPT的威力
看看是否牛逼: 真不是写代码的料,也没有这样的天赋,仅仅玩玩而已. 问题:客户端边缘路由中一段js代码,使用get请求一个方法,把json数据送入数据库相关表.由于种种原因导致长连接,通过资源管理器可 ...
- sql server2008r2其中一张表不能任何操作
用户的数据库一张高频表,使用select count(*) from t1 竟然一直在转圈,显示开始,而没有end. 找尽原因不得果.把数据库备份后在恢复,可以使用几小时,之后又是老毛病抽风. 用户生 ...
- 不同数据库Oracle、PostgreSQL、Vertical、Mysql常用操作
不同数据库Oracle.PostgreSQL.Vertical.Mysql常用操作 授权语句用于管理数据库用户的权限,常见的授权语句如下: 1.授权用户对表的SELECT权限 GRANT SELECT ...
- K8s新手系列之资源清单(Manifests)
Manifests的基本概念 在 Kubernetes 中,Manifests(清单)是用于定义集群中资源对象的声明式配置文件(通常以 YAML 或 JSON 格式编写,生产环境中通常以YAML编写) ...