Java?實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼并追蹤掃碼來源(最新推薦)
下面我將詳細(xì)介紹如何使用Java后臺(tái)實(shí)現(xiàn)這一功能。
一、整體架構(gòu)設(shè)計(jì)
- 前端:微信小程序
- 后端:Java (Spring Boot)
- 數(shù)據(jù)庫:MySQL/其他
- 微信接口:調(diào)用微信小程序碼生成API
二、數(shù)據(jù)庫設(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)入的場景:
App({
onLaunch: function(options) {
// 處理掃碼進(jìn)入的情況
if (options.scene === 1047 || options.scene === 1048 || options.scene === 1049) {
// 這些scene值表示是通過掃碼進(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è)績統(tǒng)計(jì)
* @param promoterId 推廣人員ID
* @param startDate 開始日期
* @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)表
通過以上Java實(shí)現(xiàn),你可以完整地構(gòu)建一個(gè)支持不同人員生成不同小程序碼并能追蹤掃碼來源的系統(tǒng)。
到此這篇關(guān)于Java 實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼并追蹤掃碼來源的文章就介紹到這了,更多相關(guān)Java 實(shí)現(xiàn)微信小程序不同人員生成不同小程序碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring @Async無法實(shí)現(xiàn)異步的解決方案
這篇文章主要介紹了Spring @Async無法實(shí)現(xiàn)異步的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
java實(shí)現(xiàn)ftp上傳 如何創(chuàng)建文件夾
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)ftp上傳的相關(guān)資料,教大家如何創(chuàng)建文件夾?具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
idea ssm項(xiàng)目java程序使用十六進(jìn)制rxtx包向串口發(fā)送指令的方法
這篇文章主要介紹了idea ssm項(xiàng)目java程序向串口發(fā)送指令并且使用十六進(jìn)制 rxtx包,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
java中JDBC實(shí)現(xiàn)往MySQL插入百萬級(jí)數(shù)據(jù)的實(shí)例代碼
這篇文章主要介紹了java中JDBC實(shí)現(xiàn)往MySQL插入百萬級(jí)數(shù)據(jù)的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01
SpringBoot+fileUpload獲取文件上傳進(jìn)度
這篇文章主要為大家詳細(xì)介紹了SpringBoot+fileUpload獲取文件上傳進(jìn)度,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Java中String類常用類型實(shí)例總結(jié)
在我們開發(fā)中經(jīng)常會(huì)用到很多的常用的工具類,這里做一個(gè)總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中String類常用類型的相關(guān)資料,String類代表字符串,需要的朋友可以參考下2021-12-12

