Java?實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼并追蹤掃碼來(lái)源(最新推薦)
下面我將詳細(xì)介紹如何使用Java后臺(tái)實(shí)現(xiàn)這一功能。
一、整體架構(gòu)設(shè)計(jì)
- 前端:微信小程序
- 后端:Java (Spring Boot)
- 數(shù)據(jù)庫(kù):MySQL/其他
- 微信接口:調(diào)用微信小程序碼生成API
二、數(shù)據(jù)庫(kù)設(shè)計(jì)
1. 推廣人員表(promoter)
CREATE TABLE `promoter` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '推廣人員姓名', `mobile` varchar(20) COMMENT '聯(lián)系電話', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 用戶-推廣關(guān)系表(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 '首次掃碼時(shí)間', `last_scan_time` datetime NOT NULL COMMENT '最近掃碼時(shí)間', `scan_count` int NOT NULL DEFAULT '1' COMMENT '掃碼次數(shù)', PRIMARY KEY (`id`), UNIQUE KEY `idx_user_promoter` (`user_id`,`promoter_id`), KEY `idx_promoter` (`promoter_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
三、Java后端實(shí)現(xiàn)
1. 添加微信小程序Java SDK依賴
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>4.1.0</version> </dependency>
2. 配置微信小程序參數(shù)
@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. 生成帶參數(shù)的小程序碼
@RestController @RequestMapping("/api/qrcode") public class QrCodeController { @Autowired private WxMaService wxMaService; @Autowired private PromoterService promoterService; /** * 生成推廣二維碼 * @param promoterId 推廣人員ID * @return 二維碼圖片字節(jié)流 */ @GetMapping("/generate") public void generatePromoterQrCode(@RequestParam Long promoterId, HttpServletResponse response) throws IOException { // 驗(yàn)證推廣人員是否存在 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. 處理掃碼進(jìn)入事件
@RestController @RequestMapping("/api/track") public class TrackController { @Autowired private UserPromoterRelationService relationService; /** * 記錄用戶掃碼行為 * @param dto 包含用戶信息和推廣信息 * @return 操作結(jié)果 */ @PostMapping("/scan") public Result trackScan(@RequestBody ScanTrackDTO dto) { // 解析scene參數(shù) String scene = dto.getScene(); Map<String, String> sceneParams = parseScene(scene); String promoterIdStr = sceneParams.get("promoterId"); if (StringUtils.isBlank(promoterIdStr)) { return Result.fail("缺少推廣人員參數(shù)"); } try { Long promoterId = Long.parseLong(promoterIdStr); relationService.recordUserScan(dto.getOpenid(), promoterId); return Result.success(); } catch (NumberFormatException e) { return Result.fail("推廣人員參數(shù)格式錯(cuò)誤"); } } 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. 用戶-推廣關(guān)系服務(wù)
@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) { // 新建關(guān)系記錄 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中處理掃碼進(jìn)入的場(chǎng)景:
App({ onLaunch: function(options) { // 處理掃碼進(jìn)入的情況 if (options.scene === 1047 || options.scene === 1048 || options.scene === 1049) { // 這些scene值表示是通過(guò)掃碼進(jìn)入 const scene = decodeURIComponent(options.query.scene); // 上報(bào)掃碼信息到后端 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); } }); } } })
五、數(shù)據(jù)統(tǒng)計(jì)接口實(shí)現(xiàn)
@RestController @RequestMapping("/api/stat") public class StatController { @Autowired private UserPromoterRelationMapper relationMapper; /** * 獲取推廣人員業(yè)績(jī)統(tǒng)計(jì) * @param promoterId 推廣人員ID * @param startDate 開(kāi)始日期 * @param endDate 結(jié)束日期 * @return 統(tǒng)計(jì)結(jié)果 */ @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) { // 構(gòu)建查詢條件 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); } // 執(zhí)行查詢 int totalUsers = relationMapper.selectCount(query); List<Map<String, Object>> dailyStats = relationMapper.selectDailyStatsByPromoter(promoterId, startDate, endDate); // 返回結(jié)果 Map<String, Object> result = new HashMap<>(); result.put("totalUsers", totalUsers); result.put("dailyStats", dailyStats); return Result.success(result); } }
六、安全注意事項(xiàng)
- 參數(shù)校驗(yàn):所有傳入的promoterId需要驗(yàn)證是否存在
- 防刷機(jī)制:限制同一用戶頻繁上報(bào)掃碼記錄
- HTTPS:確保所有接口使用HTTPS協(xié)議
- 權(quán)限控制:推廣數(shù)據(jù)統(tǒng)計(jì)接口需要添加權(quán)限驗(yàn)證
- 日志記錄:記錄所有二維碼生成和掃碼行為
七、擴(kuò)展功能建議
- 二級(jí)分銷:可以擴(kuò)展支持多級(jí)推廣關(guān)系
- 獎(jiǎng)勵(lì)機(jī)制:根據(jù)掃碼用戶的活動(dòng)情況給推廣人員獎(jiǎng)勵(lì)
- 實(shí)時(shí)通知:當(dāng)有新用戶掃碼時(shí),實(shí)時(shí)通知推廣人員
- 數(shù)據(jù)分析:提供更詳細(xì)的數(shù)據(jù)分析報(bào)表
通過(guò)以上Java實(shí)現(xiàn),你可以完整地構(gòu)建一個(gè)支持不同人員生成不同小程序碼并能追蹤掃碼來(lái)源的系統(tǒng)。
到此這篇關(guān)于Java 實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼并追蹤掃碼來(lái)源的文章就介紹到這了,更多相關(guān)Java 實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring @Async無(wú)法實(shí)現(xiàn)異步的解決方案
這篇文章主要介紹了Spring @Async無(wú)法實(shí)現(xiàn)異步的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10JVM創(chuàng)建對(duì)象及訪問(wèn)定位過(guò)程詳解
這篇文章主要介紹了JVM創(chuàng)建對(duì)象及訪問(wèn)定位過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12java實(shí)現(xiàn)ftp上傳 如何創(chuàng)建文件夾
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)ftp上傳的相關(guān)資料,教大家如何創(chuàng)建文件夾?具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04idea ssm項(xiàng)目java程序使用十六進(jìn)制rxtx包向串口發(fā)送指令的方法
這篇文章主要介紹了idea ssm項(xiàng)目java程序向串口發(fā)送指令并且使用十六進(jìn)制 rxtx包,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08java中JDBC實(shí)現(xiàn)往MySQL插入百萬(wàn)級(jí)數(shù)據(jù)的實(shí)例代碼
這篇文章主要介紹了java中JDBC實(shí)現(xiàn)往MySQL插入百萬(wàn)級(jí)數(shù)據(jù)的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01SpringBoot+fileUpload獲取文件上傳進(jìn)度
這篇文章主要為大家詳細(xì)介紹了SpringBoot+fileUpload獲取文件上傳進(jìn)度,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08Java中String類常用類型實(shí)例總結(jié)
在我們開(kāi)發(fā)中經(jīng)常會(huì)用到很多的常用的工具類,這里做一個(gè)總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中String類常用類型的相關(guān)資料,String類代表字符串,需要的朋友可以參考下2021-12-12