Java 实现微信小程序不同人员生成不同小程序码并追踪扫码来源(最新推荐)

 更新时间:2025年06月05日 08:58:02   作者:VipSoft  
这篇文章主要介绍了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 实现微信小程序不同人员生成不同小程序码并追踪扫码来源的文章就介绍到这了,更多相关Java 实现微信小程序不同人员生成不同小程序码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring @Async无法实现异步的解决方案

    Spring @Async无法实现异步的解决方案

    这篇文章主要介绍了Spring @Async无法实现异步的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • JVM创建对象及访问定位过程详解

    JVM创建对象及访问定位过程详解

    这篇文章主要介绍了JVM创建对象及访问定位过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12
  • Mybatis一对多查询列表属性处理示例详解

    Mybatis一对多查询列表属性处理示例详解

    使用MyBatis进行多表联查的关键是构建数据库中表的字段和java中对象的属性的映射关系,下面这篇文章主要给大家介绍了关于Mybatis一对多查询列表属性处理的相关资料,需要的朋友可以参考下
    2023-05-05
  • java实现ftp上传 如何创建文件夹

    java实现ftp上传 如何创建文件夹

    这篇文章主要为大家详细介绍了java实现ftp上传的相关资料,教大家如何创建文件夹?具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • idea ssm项目java程序使用十六进制rxtx包向串口发送指令的方法

    idea ssm项目java程序使用十六进制rxtx包向串口发送指令的方法

    这篇文章主要介绍了idea ssm项目java程序向串口发送指令并且使用十六进制 rxtx包,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java contains用法示例

    Java contains用法示例

    这篇文章主要介绍了Java contains的用法示例,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-11-11
  • java中JDBC实现往MySQL插入百万级数据的实例代码

    java中JDBC实现往MySQL插入百万级数据的实例代码

    这篇文章主要介绍了java中JDBC实现往MySQL插入百万级数据的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-01-01
  • SpringBoot+fileUpload获取文件上传进度

    SpringBoot+fileUpload获取文件上传进度

    这篇文章主要为大家详细介绍了SpringBoot+fileUpload获取文件上传进度,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • Java中String类常用类型实例总结

    Java中String类常用类型实例总结

    在我们开发中经常会用到很多的常用的工具类,这里做一个总结,下面这篇文章主要给大家介绍了关于Java中String类常用类型的相关资料,String类代表字符串,需要的朋友可以参考下
    2021-12-12
  • 浅析Java中的SPI原理

    浅析Java中的SPI原理

    SPI:由调用方制定接口标准,实现方来针对接口提供不同的实现,SPI其实就是"为接口查找实现"的一种服务发现机制。本文将浅谈一下SPI机制的原理,需要的可以参考一下
    2022-09-09

最新评论